Merge branch 'trunk' into PCP-895-buttons-not-working-on-single-product-page-for-woo-commerce-bookings-product

This commit is contained in:
Pedro Silva 2023-07-05 09:34:11 +01:00
commit c00b5906f7
No known key found for this signature in database
GPG key ID: E2EE20C0669D24B3
55 changed files with 1039 additions and 683 deletions

View file

@ -28,6 +28,8 @@ const cardsSpinner = new Spinner('#ppcp-hosted-fields');
const bootstrap = () => {
const checkoutFormSelector = 'form.woocommerce-checkout';
const context = PayPalCommerceGateway.context;
const errorHandler = new ErrorHandler(
PayPalCommerceGateway.labels.error.generic,
document.querySelector(checkoutFormSelector) ?? document.querySelector('.woocommerce-notices-wrapper')
@ -58,7 +60,7 @@ const bootstrap = () => {
}
});
const onSmartButtonClick = (data, actions) => {
const onSmartButtonClick = async (data, actions) => {
window.ppcpFundingSource = data.fundingSource;
const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input');
requiredFields.each((i, input) => {
@ -120,25 +122,21 @@ const bootstrap = () => {
freeTrialHandler.handle();
return actions.reject();
}
};
let smartButtonsOptions = {
onInit: null,
init: function (actions) {
this.actions = actions;
if (typeof this.onInit === 'function') {
this.onInit();
if (context === 'checkout' && !PayPalCommerceGateway.funding_sources_without_redirect.includes(data.fundingSource)) {
try {
await formSaver.save(form);
} catch (error) {
console.error(error);
}
}
};
const onSmartButtonsInit = (data, actions) => {
const onSmartButtonsInit = () => {
buttonsSpinner.unblock();
smartButtonsOptions.init(actions);
};
const renderer = new Renderer(creditCardRenderer, PayPalCommerceGateway, onSmartButtonClick, onSmartButtonsInit, smartButtonsOptions);
const renderer = new Renderer(creditCardRenderer, PayPalCommerceGateway, onSmartButtonClick, onSmartButtonsInit);
const messageRenderer = new MessageRenderer(PayPalCommerceGateway.messages);
const context = PayPalCommerceGateway.context;
if (context === 'mini-cart' || context === 'product') {
if (PayPalCommerceGateway.mini_cart_buttons_enabled === '1') {
const miniCartBootstrap = new MiniCartBootstap(

View file

@ -1,4 +1,5 @@
import CartActionHandler from '../ActionHandler/CartActionHandler';
import BootstrapHelper from "../Helper/BootstrapHelper";
import {setVisible} from "../Helper/Hiding";
class CartBootstrap {
@ -6,6 +7,10 @@ class CartBootstrap {
this.gateway = gateway;
this.renderer = renderer;
this.errorHandler = errorHandler;
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
this.handleButtonStatus();
}, true);
}
init() {
@ -14,9 +19,11 @@ class CartBootstrap {
}
this.render();
this.handleButtonStatus();
jQuery(document.body).on('updated_cart_totals updated_checkout', () => {
this.render();
this.handleButtonStatus();
fetch(
this.gateway.ajax.cart_script_params.endpoint,
@ -40,10 +47,18 @@ class CartBootstrap {
});
}
handleButtonStatus() {
BootstrapHelper.handleButtonStatus(this);
}
shouldRender() {
return document.querySelector(this.gateway.button.wrapper) !== null;
}
shouldEnable() {
return BootstrapHelper.shouldEnable(this);
}
render() {
const actionHandler = new CartActionHandler(
PayPalCommerceGateway,

View file

@ -5,6 +5,8 @@ import {
isSavedCardSelected, ORDER_BUTTON_SELECTOR,
PaymentMethods
} from "../Helper/CheckoutMethodState";
import BootstrapHelper from "../Helper/BootstrapHelper";
import {disable, enable} from "../Helper/ButtonDisabler";
class CheckoutBootstap {
constructor(gateway, renderer, messages, spinner, errorHandler) {
@ -15,10 +17,15 @@ class CheckoutBootstap {
this.errorHandler = errorHandler;
this.standardOrderButtonSelector = ORDER_BUTTON_SELECTOR;
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
this.handleButtonStatus();
}, true);
}
init() {
this.render();
this.handleButtonStatus();
// Unselect saved card.
// WC saves form values, so with our current UI it would be a bit weird
@ -28,6 +35,7 @@ class CheckoutBootstap {
jQuery(document.body).on('updated_checkout', () => {
this.render()
this.handleButtonStatus();
});
jQuery(document.body).on('updated_checkout payment_method_selected', () => {
@ -43,6 +51,10 @@ class CheckoutBootstap {
this.updateUi();
}
handleButtonStatus() {
BootstrapHelper.handleButtonStatus(this);
}
shouldRender() {
if (document.querySelector(this.gateway.button.cancel_wrapper)) {
return false;
@ -51,6 +63,10 @@ class CheckoutBootstap {
return document.querySelector(this.gateway.button.wrapper) !== null || document.querySelector(this.gateway.hosted_fields.wrapper) !== null;
}
shouldEnable() {
return BootstrapHelper.shouldEnable(this);
}
render() {
if (!this.shouldRender()) {
return;

View file

@ -1,4 +1,5 @@
import CartActionHandler from '../ActionHandler/CartActionHandler';
import BootstrapHelper from "../Helper/BootstrapHelper";
class MiniCartBootstap {
constructor(gateway, renderer, errorHandler) {
@ -15,9 +16,22 @@ class MiniCartBootstap {
this.errorHandler,
);
this.render();
this.handleButtonStatus();
jQuery(document.body).on('wc_fragments_loaded wc_fragments_refreshed', () => {
this.render();
this.handleButtonStatus();
});
this.renderer.onButtonsInit(this.gateway.button.mini_cart_wrapper, () => {
this.handleButtonStatus();
}, true);
}
handleButtonStatus() {
BootstrapHelper.handleButtonStatus(this, {
wrapper: this.gateway.button.mini_cart_wrapper,
skipMessages: true
});
}
@ -26,6 +40,12 @@ class MiniCartBootstap {
|| document.querySelector(this.gateway.hosted_fields.mini_cart_wrapper) !== null;
}
shouldEnable() {
return BootstrapHelper.shouldEnable(this, {
isDisabled: !!this.gateway.button.is_mini_cart_disabled
});
}
render() {
if (!this.shouldRender()) {
return;

View file

@ -1,7 +1,7 @@
import UpdateCart from "../Helper/UpdateCart";
import SingleProductActionHandler from "../ActionHandler/SingleProductActionHandler";
import {hide, show} from "../Helper/Hiding";
import {disable, enable} from "../Helper/ButtonDisabler";
import BootstrapHelper from "../Helper/BootstrapHelper";
class SingleProductBootstap {
constructor(gateway, renderer, messages, errorHandler) {
@ -12,11 +12,9 @@ class SingleProductBootstap {
this.mutationObserver = new MutationObserver(this.handleChange.bind(this));
this.formSelector = 'form.cart';
if (this.renderer && this.renderer.smartButtonsOptions) {
this.renderer.smartButtonsOptions.onInit = () => {
this.handleChange();
};
}
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
this.handleChange();
}, true);
}
form() {
@ -25,7 +23,7 @@ class SingleProductBootstap {
handleChange() {
if (!this.shouldRender()) {
this.renderer.disableSmartButtons();
this.renderer.disableSmartButtons(this.gateway.button.wrapper);
hide(this.gateway.button.wrapper, this.formSelector);
hide(this.gateway.messages.wrapper);
return;
@ -33,7 +31,7 @@ class SingleProductBootstap {
this.render();
this.renderer.enableSmartButtons();
this.renderer.enableSmartButtons(this.gateway.button.wrapper);
show(this.gateway.button.wrapper);
show(this.gateway.messages.wrapper);
@ -41,15 +39,9 @@ class SingleProductBootstap {
}
handleButtonStatus() {
if (!this.shouldEnable()) {
this.renderer.disableSmartButtons();
disable(this.gateway.button.wrapper, this.formSelector);
disable(this.gateway.messages.wrapper);
return;
}
this.renderer.enableSmartButtons();
enable(this.gateway.button.wrapper);
enable(this.gateway.messages.wrapper);
BootstrapHelper.handleButtonStatus(this, {
formSelector: this.formSelector
});
}
init() {
@ -94,7 +86,7 @@ class SingleProductBootstap {
const form = this.form();
const addToCartButton = form ? form.querySelector('.single_add_to_cart_button') : null;
return this.shouldRender()
return BootstrapHelper.shouldEnable(this)
&& !this.priceAmountIsZero()
&& ((null === addToCartButton) || !addToCartButton.classList.contains('disabled'));
}

View file

@ -0,0 +1,40 @@
import {disable, enable} from "./ButtonDisabler";
/**
* Common Bootstrap methods to avoid code repetition.
*/
export default class BootstrapHelper {
static handleButtonStatus(bs, options) {
options = options || {};
options.wrapper = options.wrapper || bs.gateway.button.wrapper;
options.messagesWrapper = options.messagesWrapper || bs.gateway.messages.wrapper;
options.skipMessages = options.skipMessages || false;
if (!bs.shouldEnable()) {
bs.renderer.disableSmartButtons(options.wrapper);
disable(options.wrapper, options.formSelector || null);
if (!options.skipMessages) {
disable(options.messagesWrapper);
}
return;
}
bs.renderer.enableSmartButtons(options.wrapper);
enable(options.wrapper);
if (!options.skipMessages) {
enable(options.messagesWrapper);
}
}
static shouldEnable(bs, options) {
options = options || {};
if (typeof options.isDisabled === 'undefined') {
options.isDisabled = bs.gateway.button.is_disabled;
}
return bs.shouldRender()
&& options.isDisabled !== true;
}
}

View file

@ -36,7 +36,10 @@ export const setEnabled = (selectorOrElement, enable, form = null) => {
if (form) {
// Trigger form submit to show the error message
jQuery(form).find(':submit').trigger('click');
let $form = jQuery(form);
if ($form.find('.single_add_to_cart_button').hasClass('disabled')) {
$form.find(':submit').trigger('click');
}
}
})
.find('> *')

View file

@ -1,12 +1,14 @@
import merge from "deepmerge";
class Renderer {
constructor(creditCardRenderer, defaultSettings, onSmartButtonClick, onSmartButtonsInit, smartButtonsOptions) {
constructor(creditCardRenderer, defaultSettings, onSmartButtonClick, onSmartButtonsInit) {
this.defaultSettings = defaultSettings;
this.creditCardRenderer = creditCardRenderer;
this.onSmartButtonClick = onSmartButtonClick;
this.onSmartButtonsInit = onSmartButtonsInit;
this.smartButtonsOptions = smartButtonsOptions;
this.buttonsOptions = {};
this.onButtonsInitListeners = {};
this.renderedSources = new Set();
}
@ -78,7 +80,10 @@ class Renderer {
style,
...contextConfig,
onClick: this.onSmartButtonClick,
onInit: this.onSmartButtonsInit,
onInit: (data, actions) => {
this.onSmartButtonsInit(data, actions);
this.handleOnButtonsInit(wrapper, data, actions);
},
});
if (!btn.isEligible()) {
return;
@ -108,18 +113,42 @@ class Renderer {
this.creditCardRenderer.enableFields();
}
disableSmartButtons() {
if (!this.smartButtonsOptions || !this.smartButtonsOptions.actions) {
return;
}
this.smartButtonsOptions.actions.disable();
onButtonsInit(wrapper, handler, reset) {
this.onButtonsInitListeners[wrapper] = reset ? [] : (this.onButtonsInitListeners[wrapper] || []);
this.onButtonsInitListeners[wrapper].push(handler);
}
enableSmartButtons() {
if (!this.smartButtonsOptions || !this.smartButtonsOptions.actions) {
handleOnButtonsInit(wrapper, data, actions) {
this.buttonsOptions[wrapper] = {
data: data,
actions: actions
}
if (this.onButtonsInitListeners[wrapper]) {
for (let handler of this.onButtonsInitListeners[wrapper]) {
if (typeof handler === 'function') {
handler({
wrapper: wrapper,
...this.buttonsOptions[wrapper]
});
}
}
}
}
disableSmartButtons(wrapper) {
if (!this.buttonsOptions[wrapper]) {
return;
}
this.smartButtonsOptions.actions.enable();
this.buttonsOptions[wrapper].actions.disable();
}
enableSmartButtons(wrapper) {
if (!this.buttonsOptions[wrapper]) {
return;
}
this.buttonsOptions[wrapper].actions.enable();
}
}