diff --git a/modules/ppcp-button/resources/js/button.js b/modules/ppcp-button/resources/js/button.js index 8b63b26bb..cd3bcaeb4 100644 --- a/modules/ppcp-button/resources/js/button.js +++ b/modules/ppcp-button/resources/js/button.js @@ -19,6 +19,7 @@ import FreeTrialHandler from "./modules/ActionHandler/FreeTrialHandler"; import FormSaver from './modules/Helper/FormSaver'; import FormValidator from "./modules/Helper/FormValidator"; import {loadPaypalScript} from "./modules/Helper/ScriptLoading"; +import MessagesBootstrap from "./modules/ContextBootstrap/MessagesBootstap"; // TODO: could be a good idea to have a separate spinner for each gateway, // but I think we care mainly about the script loading, so one spinner should be enough. @@ -158,7 +159,6 @@ const bootstrap = () => { const singleProductBootstrap = new SingleProductBootstap( PayPalCommerceGateway, renderer, - messageRenderer, errorHandler, ); @@ -169,7 +169,6 @@ const bootstrap = () => { const cartBootstrap = new CartBootstrap( PayPalCommerceGateway, renderer, - messageRenderer, errorHandler, ); @@ -180,7 +179,6 @@ const bootstrap = () => { const checkoutBootstap = new CheckoutBootstap( PayPalCommerceGateway, renderer, - messageRenderer, spinner, errorHandler, ); @@ -199,6 +197,11 @@ const bootstrap = () => { payNowBootstrap.init(); } + const messagesBootstrap = new MessagesBootstrap( + PayPalCommerceGateway, + messageRenderer, + ); + messagesBootstrap.init(); }; const hasMessages = () => { diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js index 1deaafd54..c40e03ce1 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js @@ -2,12 +2,10 @@ import CartActionHandler from '../ActionHandler/CartActionHandler'; import BootstrapHelper from "../Helper/BootstrapHelper"; class CartBootstrap { - constructor(gateway, renderer, messages, errorHandler) { + constructor(gateway, renderer, errorHandler) { this.gateway = gateway; this.renderer = renderer; - this.messages = messages; this.errorHandler = errorHandler; - this.lastAmount = this.gateway.messages.amount; this.renderer.onButtonsInit(this.gateway.button.wrapper, () => { this.handleButtonStatus(); @@ -15,16 +13,16 @@ class CartBootstrap { } init() { - if (!this.shouldRender()) { - return; - } - - this.render(); - this.handleButtonStatus(); - - jQuery(document.body).on('updated_cart_totals updated_checkout', () => { + if (this.shouldRender()) { this.render(); this.handleButtonStatus(); + } + + jQuery(document.body).on('updated_cart_totals updated_checkout', () => { + if (this.shouldRender()) { + this.render(); + this.handleButtonStatus(); + } fetch( this.gateway.ajax.cart_script_params.endpoint, @@ -49,16 +47,19 @@ class CartBootstrap { } // handle button status - if (result.data.button || result.data.messages) { - this.gateway.button = result.data.button; - this.gateway.messages = result.data.messages; + const newData = {}; + if (result.data.button) { + newData.button = result.data.button; + } + if (result.data.messages) { + newData.messages = result.data.messages; + } + if (newData) { + BootstrapHelper.updateScriptData(this, newData); this.handleButtonStatus(); } - if (this.lastAmount !== result.data.amount) { - this.lastAmount = result.data.amount; - this.messages.renderWithAmount(this.lastAmount); - } + jQuery(document.body).trigger('ppcp_cart_total_updated', [result.data.amount]); }); }); } @@ -76,6 +77,10 @@ class CartBootstrap { } render() { + if (!this.shouldRender()) { + return; + } + const actionHandler = new CartActionHandler( PayPalCommerceGateway, this.errorHandler, @@ -99,7 +104,7 @@ class CartBootstrap { actionHandler.configuration() ); - this.messages.renderWithAmount(this.lastAmount); + jQuery(document.body).trigger('ppcp_cart_rendered'); } } diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js index eb9aa3885..27f9ca882 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js @@ -8,13 +8,11 @@ import { import BootstrapHelper from "../Helper/BootstrapHelper"; class CheckoutBootstap { - constructor(gateway, renderer, messages, spinner, errorHandler) { + constructor(gateway, renderer, spinner, errorHandler) { this.gateway = gateway; this.renderer = renderer; - this.messages = messages; this.spinner = spinner; this.errorHandler = errorHandler; - this.lastAmount = this.gateway.messages.amount; this.standardOrderButtonSelector = ORDER_BUTTON_SELECTOR; @@ -37,7 +35,7 @@ class CheckoutBootstap { this.render() this.handleButtonStatus(); - if (this.shouldRenderMessages()) { // currently we need amount only for Pay Later + if (this.shouldShowMessages() && document.querySelector(this.gateway.messages.wrapper)) { // currently we need amount only for Pay Later fetch( this.gateway.ajax.cart_script_params.endpoint, { @@ -51,10 +49,7 @@ class CheckoutBootstap { return; } - if (this.lastAmount !== result.data.amount) { - this.lastAmount = result.data.amount; - this.updateUi(); - } + jQuery(document.body).trigger('ppcp_checkout_total_updated', [result.data.amount]); }); } }); @@ -69,6 +64,12 @@ class CheckoutBootstap { }) }); + jQuery(document).on('ppcp_should_show_messages', (e, data) => { + if (!this.shouldShowMessages()) { + data.result = false; + } + }); + this.updateUi(); } @@ -138,16 +139,11 @@ class CheckoutBootstap { setVisibleByClass(this.standardOrderButtonSelector, (isPaypal && isFreeTrial && hasVaultedPaypal) || isNotOurGateway || isSavedCard, 'ppcp-hidden'); setVisible('.ppcp-vaulted-paypal-details', isPaypal); setVisible(this.gateway.button.wrapper, isPaypal && !(isFreeTrial && hasVaultedPaypal)); - setVisible(this.gateway.messages.wrapper, isPaypal && !isFreeTrial); setVisible(this.gateway.hosted_fields.wrapper, isCard && !isSavedCard); for (const [gatewayId, wrapper] of Object.entries(paypalButtonWrappers)) { setVisible(wrapper, gatewayId === currentPaymentMethod); } - if (this.shouldRenderMessages()) { - this.messages.renderWithAmount(this.lastAmount); - } - if (isCard) { if (isSavedCard) { this.disableCreditCardFields(); @@ -155,12 +151,13 @@ class CheckoutBootstap { this.enableCreditCardFields(); } } + + jQuery(document.body).trigger('ppcp_checkout_rendered'); } - shouldRenderMessages() { + shouldShowMessages() { return getCurrentPaymentMethod() === PaymentMethods.PAYPAL - && !PayPalCommerceGateway.is_free_trial_cart - && this.messages.shouldRender(); + && !PayPalCommerceGateway.is_free_trial_cart; } disableCreditCardFields() { diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/MessagesBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/MessagesBootstap.js new file mode 100644 index 000000000..fe1c49438 --- /dev/null +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/MessagesBootstap.js @@ -0,0 +1,55 @@ +import {setVisible} from "../Helper/Hiding"; + +class MessagesBootstrap { + constructor(gateway, messageRenderer) { + this.gateway = gateway; + this.renderer = messageRenderer; + this.lastAmount = this.gateway.messages.amount; + } + + init() { + jQuery(document.body).on('ppcp_cart_rendered ppcp_checkout_rendered', () => { + this.render(); + }); + jQuery(document.body).on('ppcp_script_data_changed', (e, data) => { + this.gateway = data; + + this.render(); + }); + jQuery(document.body).on('ppcp_cart_total_updated ppcp_checkout_total_updated ppcp_product_total_updated', (e, amount) => { + if (this.lastAmount !== amount) { + this.lastAmount = amount; + + this.render(); + } + }); + + this.render(); + } + + shouldShow() { + if (this.gateway.messages.is_hidden === true) { + return false; + } + + const eventData = {result: true} + jQuery(document.body).trigger('ppcp_should_show_messages', [eventData]); + return eventData.result; + } + + shouldRender() { + return this.shouldShow() && this.renderer.shouldRender(); + } + + render() { + setVisible(this.gateway.messages.wrapper, this.shouldShow()); + + if (!this.shouldRender()) { + return; + } + + this.renderer.renderWithAmount(this.lastAmount); + } +} + +export default MessagesBootstrap; diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index f6633d50f..5ff7f2a80 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -6,12 +6,12 @@ import {loadPaypalJsScript} from "../Helper/ScriptLoading"; import {getPlanIdFromVariation} from "../Helper/Subscriptions" import SimulateCart from "../Helper/SimulateCart"; import {strRemoveWord, strAddWord, throttle} from "../Helper/Utils"; +import merge from "deepmerge"; class SingleProductBootstap { - constructor(gateway, renderer, messages, errorHandler) { + constructor(gateway, renderer, errorHandler) { this.gateway = gateway; this.renderer = renderer; - this.messages = messages; this.errorHandler = errorHandler; this.mutationObserver = new MutationObserver(this.handleChange.bind(this)); this.formSelector = 'form.cart'; @@ -36,7 +36,6 @@ class SingleProductBootstap { if (!this.shouldRender()) { this.renderer.disableSmartButtons(this.gateway.button.wrapper); hide(this.gateway.button.wrapper, this.formSelector); - hide(this.gateway.messages.wrapper); return; } @@ -44,7 +43,6 @@ class SingleProductBootstap { this.renderer.enableSmartButtons(this.gateway.button.wrapper); show(this.gateway.button.wrapper); - show(this.gateway.messages.wrapper); this.handleButtonStatus(); } @@ -78,6 +76,12 @@ class SingleProductBootstap { .observe(addToCartButton, { attributes : true }); } + jQuery(document).on('ppcp_should_show_messages', (e, data) => { + if (!this.shouldRender()) { + data.result = false; + } + }); + if (!this.shouldRender()) { return; } @@ -232,7 +236,18 @@ class SingleProductBootstap { this.gateway.ajax.simulate_cart.nonce, )).simulate((data) => { - this.messages.renderWithAmount(data.total); + jQuery(document.body).trigger('ppcp_product_total_updated', [data.total]); + + let newData = {}; + if (typeof data.button.is_disabled === 'boolean') { + newData = merge(newData, {button: {is_disabled: data.button.is_disabled}}); + } + if (typeof data.messages.is_hidden === 'boolean') { + newData = merge(newData, {messages: {is_hidden: data.messages.is_hidden}}); + } + if (newData) { + BootstrapHelper.updateScriptData(this, newData); + } if ( this.gateway.single_product_buttons_enabled !== '1' ) { return; @@ -260,13 +275,6 @@ class SingleProductBootstap { jQuery(this.gateway.button.wrapper).trigger('ppcp-reload-buttons'); } - if (typeof data.button.is_disabled === 'boolean') { - this.gateway.button.is_disabled = data.button.is_disabled; - } - if (typeof data.messages.is_hidden === 'boolean') { - this.gateway.messages.is_hidden = data.messages.is_hidden; - } - this.handleButtonStatus(false); }, products); diff --git a/modules/ppcp-button/resources/js/modules/Helper/BootstrapHelper.js b/modules/ppcp-button/resources/js/modules/Helper/BootstrapHelper.js index 65f457ec3..41eb62e25 100644 --- a/modules/ppcp-button/resources/js/modules/Helper/BootstrapHelper.js +++ b/modules/ppcp-button/resources/js/modules/Helper/BootstrapHelper.js @@ -1,5 +1,5 @@ import {disable, enable, isDisabled} from "./ButtonDisabler"; -import {hide, show} from "./Hiding"; +import merge from "deepmerge"; /** * Common Bootstrap methods to avoid code repetition. @@ -9,15 +9,6 @@ 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; - - // Handle messages hide / show - if (this.shouldShowMessages(bs, options)) { - show(options.messagesWrapper); - } else { - hide(options.messagesWrapper); - } const wasDisabled = isDisabled(options.wrapper); const shouldEnable = bs.shouldEnable(); @@ -26,17 +17,9 @@ export default class BootstrapHelper { if (shouldEnable && wasDisabled) { bs.renderer.enableSmartButtons(options.wrapper); enable(options.wrapper); - - if (!options.skipMessages) { - enable(options.messagesWrapper); - } } else if (!shouldEnable && !wasDisabled) { bs.renderer.disableSmartButtons(options.wrapper); disable(options.wrapper, options.formSelector || null); - - if (!options.skipMessages) { - disable(options.messagesWrapper); - } } if (wasDisabled !== !shouldEnable) { @@ -54,12 +37,15 @@ export default class BootstrapHelper { && options.isDisabled !== true; } - static shouldShowMessages(bs, options) { - options = options || {}; - if (typeof options.isMessagesHidden === 'undefined') { - options.isMessagesHidden = bs.gateway.messages.is_hidden; - } + static updateScriptData(bs, newData) { + const newObj = merge(bs.gateway, newData); - return options.isMessagesHidden !== true; + const isChanged = JSON.stringify(bs.gateway) !== JSON.stringify(newObj); + + bs.gateway = newObj; + + if (isChanged) { + jQuery(document.body).trigger('ppcp_script_data_changed', [newObj]); + } } }