From a37594643af2a59303fc95bdead1abf301087acd Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Fri, 22 Dec 2023 16:02:00 +0000 Subject: [PATCH 1/3] Add Basic Checkout Validation and Early Checkout Validation to Card Fields --- modules/ppcp-button/resources/js/button.js | 38 ++++++++++++------- .../ActionHandler/CheckoutActionHandler.js | 12 ++++-- .../js/modules/Renderer/CardFieldsRenderer.js | 13 ++++++- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/modules/ppcp-button/resources/js/button.js b/modules/ppcp-button/resources/js/button.js index 40997d15a..9bc2e4b49 100644 --- a/modules/ppcp-button/resources/js/button.js +++ b/modules/ppcp-button/resources/js/button.js @@ -40,11 +40,6 @@ const bootstrap = () => { ); const spinner = new Spinner(); - let creditCardRenderer = new HostedFieldsRenderer(PayPalCommerceGateway, errorHandler, spinner); - if (typeof paypal.CardFields !== 'undefined') { - creditCardRenderer = new CardFieldsRenderer(PayPalCommerceGateway, errorHandler, spinner); - } - const formSaver = new FormSaver( PayPalCommerceGateway.ajax.save_checkout_form.endpoint, PayPalCommerceGateway.ajax.save_checkout_form.nonce, @@ -73,13 +68,7 @@ const bootstrap = () => { && document.querySelector(PayPalCommerceGateway.messages.wrapper); } - const onSmartButtonClick = async (data, actions) => { - window.ppcpFundingSource = data.fundingSource; - const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input'); - requiredFields.each((i, input) => { - jQuery(input).trigger('validate'); - }); - + const doBasicCheckoutValidation = () => { if (PayPalCommerceGateway.basic_checkout_validation_enabled) { // A quick fix to get the errors about empty form fields before attempting PayPal order, // it should solve #513 for most of the users, but it is not a proper solution. @@ -117,9 +106,26 @@ const bootstrap = () => { errorHandler.message(PayPalCommerceGateway.labels.error.required.generic); } - return actions.reject(); + return false; } } + return true; + }; + + const onCardFieldsBeforeSubmit = () => { + return doBasicCheckoutValidation(); + }; + + const onSmartButtonClick = async (data, actions) => { + window.ppcpFundingSource = data.fundingSource; + const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input'); + requiredFields.each((i, input) => { + jQuery(input).trigger('validate'); + }); + + if (!doBasicCheckoutValidation()) { + return actions.reject(); + } const form = document.querySelector(checkoutFormSelector); if (form) { @@ -149,6 +155,12 @@ const bootstrap = () => { jQuery(document).trigger('ppcp-smart-buttons-init', this); buttonsSpinner.unblock(); }; + + let creditCardRenderer = new HostedFieldsRenderer(PayPalCommerceGateway, errorHandler, spinner); + if (typeof paypal.CardFields !== 'undefined') { + creditCardRenderer = new CardFieldsRenderer(PayPalCommerceGateway, errorHandler, spinner, onCardFieldsBeforeSubmit); + } + const renderer = new Renderer(creditCardRenderer, PayPalCommerceGateway, onSmartButtonClick, onSmartButtonsInit); const messageRenderer = new MessageRenderer(PayPalCommerceGateway.messages); diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js index 93ecf7c8f..75b5f9848 100644 --- a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js +++ b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js @@ -18,7 +18,7 @@ class CheckoutActionHandler { try { await validateCheckoutForm(this.config); } catch (error) { - throw {type: 'form-validation-error'}; + throw { type: 'form-validation-error' }; } return actions.subscription.create({ @@ -48,7 +48,13 @@ class CheckoutActionHandler { configuration() { const spinner = this.spinner; - const createOrder = (data, actions) => { + const createOrder = async (data, actions) => { + try { + await validateCheckoutForm(this.config); + } catch (error) { + throw { type: 'form-validation-error' }; + } + const payer = payerData(); const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ? this.config.bn_codes[this.config.context] : ''; @@ -136,7 +142,7 @@ class CheckoutActionHandler { console.error(err); spinner.unblock(); - if (err && err.type === 'create-order-error') { + if (err && (err.type === 'create-order-error' || err.type === 'form-validation-error')) { return; } diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js index 377568fcb..babb2b4fc 100644 --- a/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js +++ b/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js @@ -3,7 +3,7 @@ import {cardFieldStyles} from "../Helper/CardFieldsHelper"; class CardFieldsRenderer { - constructor(defaultConfig, errorHandler, spinner) { + constructor(defaultConfig, errorHandler, spinner, onCardFieldsBeforeSubmit) { this.defaultConfig = defaultConfig; this.errorHandler = errorHandler; this.spinner = spinner; @@ -11,6 +11,7 @@ class CardFieldsRenderer { this.formValid = false; this.emptyFields = new Set(['number', 'cvv', 'expirationDate']); this.currentHostedFieldsInstance = null; + this.onCardFieldsBeforeSubmit = onCardFieldsBeforeSubmit; } render(wrapper, contextConfig) { @@ -110,10 +111,20 @@ class CardFieldsRenderer { return; } + if (typeof this.onCardFieldsBeforeSubmit === 'function' && !this.onCardFieldsBeforeSubmit()) { + this.spinner.unblock(); + return; + } + cardField.submit() .catch((error) => { this.spinner.unblock(); console.error(error) + + if (error.type === 'form-validation-error') { + return; + } + this.errorHandler.message(this.defaultConfig.hosted_fields.labels.fields_not_valid); }); }); From 282d1a73e07ed296375b3c2d035189ed0e39f570 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Wed, 3 Jan 2024 11:13:01 +0000 Subject: [PATCH 2/3] Rollback button early validation and add support for Credit Card Gateway. --- .../js/modules/ActionHandler/CheckoutActionHandler.js | 10 ++-------- .../js/modules/Renderer/CardFieldsRenderer.js | 5 ----- .../ppcp-button/src/Endpoint/CreateOrderEndpoint.php | 2 +- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js index 75b5f9848..da0ca7a4f 100644 --- a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js +++ b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js @@ -18,7 +18,7 @@ class CheckoutActionHandler { try { await validateCheckoutForm(this.config); } catch (error) { - throw { type: 'form-validation-error' }; + throw {type: 'form-validation-error'}; } return actions.subscription.create({ @@ -49,12 +49,6 @@ class CheckoutActionHandler { configuration() { const spinner = this.spinner; const createOrder = async (data, actions) => { - try { - await validateCheckoutForm(this.config); - } catch (error) { - throw { type: 'form-validation-error' }; - } - const payer = payerData(); const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ? this.config.bn_codes[this.config.context] : ''; @@ -142,7 +136,7 @@ class CheckoutActionHandler { console.error(err); spinner.unblock(); - if (err && (err.type === 'create-order-error' || err.type === 'form-validation-error')) { + if (err && (err.type === 'create-order-error')) { return; } diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js index babb2b4fc..13f37cda0 100644 --- a/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js +++ b/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js @@ -120,11 +120,6 @@ class CardFieldsRenderer { .catch((error) => { this.spinner.unblock(); console.error(error) - - if (error.type === 'form-validation-error') { - return; - } - this.errorHandler.message(this.defaultConfig.hosted_fields.labels.fields_not_valid); }); }); diff --git a/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php b/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php index 2150b931f..ca34e59fb 100644 --- a/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php +++ b/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php @@ -294,7 +294,7 @@ class CreateOrderEndpoint implements EndpointInterface { if ( $this->early_validation_enabled && $this->form && 'checkout' === $data['context'] - && in_array( $payment_method, array( PayPalGateway::ID, CardButtonGateway::ID ), true ) + && in_array( $payment_method, array( PayPalGateway::ID, CardButtonGateway::ID, CreditCardGateway::ID ), true ) ) { $this->validate_form( $this->form ); } From c2946b0516aed47f3a5aa8c5f9532860435c094b Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Wed, 3 Jan 2024 11:18:30 +0000 Subject: [PATCH 3/3] Revert unneeded changes. --- .../js/modules/ActionHandler/CheckoutActionHandler.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js index da0ca7a4f..93ecf7c8f 100644 --- a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js +++ b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js @@ -48,7 +48,7 @@ class CheckoutActionHandler { configuration() { const spinner = this.spinner; - const createOrder = async (data, actions) => { + const createOrder = (data, actions) => { const payer = payerData(); const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ? this.config.bn_codes[this.config.context] : ''; @@ -136,7 +136,7 @@ class CheckoutActionHandler { console.error(err); spinner.unblock(); - if (err && (err.type === 'create-order-error')) { + if (err && err.type === 'create-order-error') { return; }