From a37594643af2a59303fc95bdead1abf301087acd Mon Sep 17 00:00:00 2001
From: Pedro Silva
Date: Fri, 22 Dec 2023 16:02:00 +0000
Subject: [PATCH] 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);
});
});