♻️ Decouple init logic from global PPCP config

Allow Google Pay logic to initialize on pages that do not provide a global PayPalCommerceGateway object. Required to use CheckoutBootstrap to popuplate billing fields in continuation mode.
This commit is contained in:
Philipp Stracker 2024-08-27 12:34:50 +02:00
parent 07c73985e3
commit 5b05458103
No known key found for this signature in database
2 changed files with 83 additions and 34 deletions

View file

@ -13,12 +13,34 @@ export class CheckoutBootstrap {
#storage; #storage;
/** /**
* @type {null|HTMLFormElement} * @type {HTMLFormElement|null}
*/ */
#checkoutForm = null; #checkoutForm;
/**
* @param {GooglePayStorage} storage
*/
constructor( storage ) { constructor( storage ) {
this.#storage = storage; this.#storage = storage;
this.#checkoutForm = CheckoutBootstrap.getCheckoutForm();
}
/**
* Indicates if the current page contains a checkout form.
*
* @return {boolean} True if a checkout form is present.
*/
static isPageWithCheckoutForm() {
return null !== CheckoutBootstrap.getCheckoutForm();
}
/**
* Retrieves the WooCommerce checkout form element.
*
* @return {HTMLFormElement|null} The form, or null if not a checkout page.
*/
static getCheckoutForm() {
return document.querySelector( CHECKOUT_FORM_SELECTOR );
} }
/** /**
@ -27,37 +49,32 @@ export class CheckoutBootstrap {
* @return {HTMLFormElement|null} The form, or null if not a checkout page. * @return {HTMLFormElement|null} The form, or null if not a checkout page.
*/ */
get checkoutForm() { get checkoutForm() {
if ( null === this.#checkoutForm ) {
this.#checkoutForm = document.querySelector(
CHECKOUT_FORM_SELECTOR
);
}
return this.#checkoutForm; return this.#checkoutForm;
} }
/** /**
* Indicates, if the current page contains a checkout form. * Initializes the checkout process.
* *
* @return {boolean} True, if a checkout form is present. * @throws {Error} If called on a page without a checkout form.
*/ */
get isPageWithCheckoutForm() {
return null !== this.checkoutForm;
}
init() { init() {
if ( ! this.isPageWithCheckoutForm ) { if ( ! this.#checkoutForm ) {
return; throw new Error(
'Checkout form not found. Cannot initialize CheckoutBootstrap.'
);
} }
this.#populateCheckoutFields(); this.#populateCheckoutFields();
} }
/**
* Populates checkout fields with stored or customer data.
*/
#populateCheckoutFields() { #populateCheckoutFields() {
const loggedInData = getWooCommerceCustomerDetails(); const loggedInData = getWooCommerceCustomerDetails();
// If customer is logged in, we use the details from the customer profile.
if ( loggedInData ) { if ( loggedInData ) {
// If customer is logged in, we use the details from the customer profile.
return; return;
} }
@ -68,11 +85,17 @@ export class CheckoutBootstrap {
} }
setPayerData( billingData, true ); setPayerData( billingData, true );
this.checkoutForm.addEventListener( 'submit', () => this.checkoutForm.addEventListener(
this.#onFormSubmit() 'submit',
this.#onFormSubmit.bind( this )
); );
} }
/**
* Clean-up when checkout form is submitted.
*
* Immediately removes the payer details from the localStorage.
*/
#onFormSubmit() { #onFormSubmit() {
this.#storage.clearPayer(); this.#storage.clearPayer();
} }

View file

@ -1,3 +1,12 @@
/**
* Initialize the GooglePay module in the front end.
* In some cases, this module is loaded when the `window.PayPalCommerceGateway` object is not
* present. In that case, the page does not contain a Google Pay button, but some other logic
* that is related to Google Pay (e.g., the CheckoutBootstrap module)
*
* @file
*/
import { loadCustomScript } from '@paypal/paypal-js'; import { loadCustomScript } from '@paypal/paypal-js';
import { loadPaypalScript } from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading'; import { loadPaypalScript } from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading';
import GooglepayManager from './GooglepayManager'; import GooglepayManager from './GooglepayManager';
@ -5,31 +14,48 @@ import { setupButtonEvents } from '../../../ppcp-button/resources/js/modules/Hel
import { CheckoutBootstrap } from './ContextBootstrap/CheckoutBootstrap'; import { CheckoutBootstrap } from './ContextBootstrap/CheckoutBootstrap';
import moduleStorage from './Helper/GooglePayStorage'; import moduleStorage from './Helper/GooglePayStorage';
( function ( { buttonConfig, ppcpConfig } ) { ( function ( { buttonConfig, ppcpConfig = {} } ) {
const context = ppcpConfig.context; const context = ppcpConfig.context;
let manager; function bootstrapPayButton() {
if ( ! buttonConfig || ! ppcpConfig ) {
return;
}
const bootstrap = function () { const manager = new GooglepayManager( buttonConfig, ppcpConfig );
manager = new GooglepayManager( buttonConfig, ppcpConfig );
manager.init(); manager.init();
if ( 'continuation' === context || 'checkout' === context ) {
const checkoutBootstap = new CheckoutBootstrap( moduleStorage );
checkoutBootstap.init();
}
};
setupButtonEvents( function () { setupButtonEvents( function () {
if ( manager ) {
manager.reinit(); manager.reinit();
}
} ); } );
}
function bootstrapCheckout() {
if ( context && ! [ 'continuation', 'checkout' ].includes( context ) ) {
// Context must be missing/empty, or "continuation"/"checkout" to proceed.
return;
}
if ( ! CheckoutBootstrap.isPageWithCheckoutForm() ) {
return;
}
const checkoutBootstrap = new CheckoutBootstrap( moduleStorage );
checkoutBootstrap.init();
}
function bootstrap() {
bootstrapPayButton();
bootstrapCheckout();
}
document.addEventListener( 'DOMContentLoaded', () => { document.addEventListener( 'DOMContentLoaded', () => {
if ( ! buttonConfig || ! ppcpConfig ) { if ( ! buttonConfig || ! ppcpConfig ) {
// No PayPal buttons present on this page. /*
* No PayPal buttons present on this page, but maybe a bootstrap module needs to be
* initialized. Run bootstrap without trying to load an SDK or payment configuration.
*/
bootstrap();
return; return;
} }