mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
🐛 Address some errors in preview (Settings page)
This commit is contained in:
parent
7f3636348b
commit
9ac4300995
4 changed files with 155 additions and 53 deletions
|
@ -139,6 +139,12 @@ export default class PaymentButton {
|
|||
*/
|
||||
#ppcpConfig;
|
||||
|
||||
/**
|
||||
* A variation of a context handler object, like CheckoutHandler.
|
||||
* This handler provides a standardized interface for certain standardized checks and actions.
|
||||
*/
|
||||
#contextHandler;
|
||||
|
||||
/**
|
||||
* Whether the current browser/website support the payment method.
|
||||
*
|
||||
|
@ -197,7 +203,8 @@ export default class PaymentButton {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a list with all wrapper IDs for the implemented payment method, categorized by context.
|
||||
* Returns a list with all wrapper IDs for the implemented payment method, categorized by
|
||||
* context.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Object} buttonConfig - Payment method specific configuration.
|
||||
|
@ -210,7 +217,8 @@ export default class PaymentButton {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all button styles for the implemented payment method, categorized by context.
|
||||
* Returns a list of all button styles for the implemented payment method, categorized by
|
||||
* context.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Object} buttonConfig - Payment method specific configuration.
|
||||
|
@ -229,21 +237,27 @@ export default class PaymentButton {
|
|||
* to avoid multiple button instances handling the same context.
|
||||
*
|
||||
* @private
|
||||
* @param {string} context - Button context name.
|
||||
* @param {Object} buttonConfig - Payment button specific configuration.
|
||||
* @param {Object} ppcpConfig - Plugin wide configuration object.
|
||||
* @param {string} context - Button context name.
|
||||
* @param {Object} buttonConfig - Payment button specific configuration.
|
||||
* @param {Object} ppcpConfig - Plugin wide configuration object.
|
||||
* @param {Object} contextHandler - Handler object.
|
||||
*/
|
||||
constructor( context, buttonConfig, ppcpConfig ) {
|
||||
constructor( context, buttonConfig, ppcpConfig, contextHandler ) {
|
||||
if ( this.methodId === PaymentButton.methodId ) {
|
||||
throw new Error( 'Cannot initialize the PaymentButton base class' );
|
||||
}
|
||||
|
||||
if ( ! buttonConfig ) {
|
||||
buttonConfig = {};
|
||||
}
|
||||
|
||||
const isDebugging = !! buttonConfig?.is_debug;
|
||||
const methodName = this.methodId.replace( /^ppcp?-/, '' );
|
||||
|
||||
this.#context = context;
|
||||
this.#buttonConfig = buttonConfig;
|
||||
this.#ppcpConfig = ppcpConfig;
|
||||
this.#contextHandler = contextHandler;
|
||||
|
||||
this.#wrappers = this.constructor.getWrappers(
|
||||
this.#buttonConfig,
|
||||
|
@ -325,6 +339,31 @@ export default class PaymentButton {
|
|||
return this.#ppcpConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the button's context handler.
|
||||
* When no context handler was provided (like for a preview button), an empty object is returned.
|
||||
*
|
||||
* @return {Object} The context handler instance, or an empty object.
|
||||
*/
|
||||
get contextHandler() {
|
||||
return this.#contextHandler || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether customers need to provide shipping details during payment.
|
||||
*
|
||||
* Can be extended by child classes to take method specific configuration into account.
|
||||
*
|
||||
* @return {boolean} True means, shipping fields are displayed and must be filled.
|
||||
*/
|
||||
get requiresShipping() {
|
||||
// Default check: Is shipping enabled in WooCommerce?
|
||||
return (
|
||||
'function' === typeof this.contextHandler.shippingAllowed &&
|
||||
this.contextHandler.shippingAllowed()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Button wrapper details.
|
||||
*
|
||||
|
@ -395,6 +434,15 @@ export default class PaymentButton {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags a preview button without actual payment logic.
|
||||
*
|
||||
* @return {boolean} True indicates a preview instance that has no payment logic.
|
||||
*/
|
||||
get isPreview() {
|
||||
return PaymentContext.Preview === this.context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the browser can accept this payment method.
|
||||
*
|
||||
|
@ -514,12 +562,19 @@ export default class PaymentButton {
|
|||
this.#logger.error( ...args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the button instance. Must be called before the initial `init()`.
|
||||
*
|
||||
* Parameters are defined by the derived class.
|
||||
*
|
||||
* @abstract
|
||||
*/
|
||||
configure() {}
|
||||
|
||||
/**
|
||||
* Must be named `init()` to simulate "protected" visibility:
|
||||
* Since the derived class also implements a method with the same name, this method can only
|
||||
* be called by the derived class, but not from any other code.
|
||||
*
|
||||
* @protected
|
||||
*/
|
||||
init() {
|
||||
this.#isInitialized = true;
|
||||
|
@ -529,8 +584,6 @@ export default class PaymentButton {
|
|||
* Must be named `reinit()` to simulate "protected" visibility:
|
||||
* Since the derived class also implements a method with the same name, this method can only
|
||||
* be called by the derived class, but not from any other code.
|
||||
*
|
||||
* @protected
|
||||
*/
|
||||
reinit() {
|
||||
this.#isInitialized = false;
|
||||
|
|
|
@ -67,9 +67,9 @@ class GooglepayButton extends PaymentButton {
|
|||
*/
|
||||
static getWrappers( buttonConfig, ppcpConfig ) {
|
||||
return combineWrapperIds(
|
||||
buttonConfig.button.wrapper,
|
||||
buttonConfig.button.mini_cart_wrapper,
|
||||
ppcpConfig.button.wrapper,
|
||||
buttonConfig?.button?.wrapper || '',
|
||||
buttonConfig?.button?.mini_cart_wrapper || '',
|
||||
ppcpConfig?.button?.wrapper || '',
|
||||
'ppc-button-googlepay-container',
|
||||
'ppc-button-ppcp-googlepay'
|
||||
);
|
||||
|
@ -79,7 +79,10 @@ class GooglepayButton extends PaymentButton {
|
|||
* @inheritDoc
|
||||
*/
|
||||
static getStyles( buttonConfig, ppcpConfig ) {
|
||||
const styles = combineStyles( ppcpConfig.button, buttonConfig.button );
|
||||
const styles = combineStyles(
|
||||
ppcpConfig?.button || {},
|
||||
buttonConfig?.button || {}
|
||||
);
|
||||
|
||||
if ( 'buy' === styles.MiniCart.type ) {
|
||||
styles.MiniCart.type = 'pay';
|
||||
|
@ -95,9 +98,11 @@ class GooglepayButton extends PaymentButton {
|
|||
externalHandler,
|
||||
contextHandler
|
||||
) {
|
||||
super( context, buttonConfig, ppcpConfig );
|
||||
super( context, buttonConfig, ppcpConfig, contextHandler );
|
||||
|
||||
this.contextHandler = contextHandler;
|
||||
this.onPaymentAuthorized = this.onPaymentAuthorized.bind( this );
|
||||
this.onPaymentDataChanged = this.onPaymentDataChanged.bind( this );
|
||||
this.onButtonClick = this.onButtonClick.bind( this );
|
||||
|
||||
this.log( 'Create instance' );
|
||||
}
|
||||
|
@ -113,6 +118,21 @@ class GooglepayButton extends PaymentButton {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Preview buttons only need a valid environment.
|
||||
if ( this.isPreview ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! this.googlePayConfig ) {
|
||||
this.error( 'No API configuration - missing configure() call?' );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! this.transactionInfo ) {
|
||||
this.error( 'No transactionInfo - missing configure() call?' );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! typeof this.contextHandler?.validateContext() ) {
|
||||
this.error( 'Invalid context handler.', this.contextHandler );
|
||||
return false;
|
||||
|
@ -121,6 +141,13 @@ class GooglepayButton extends PaymentButton {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
get requiresShipping() {
|
||||
return super.requiresShipping && this.buttonConfig.shipping?.enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Google Pay API.
|
||||
*
|
||||
|
@ -140,29 +167,33 @@ class GooglepayButton extends PaymentButton {
|
|||
return this.#paymentsClient;
|
||||
}
|
||||
|
||||
init( config = null, transactionInfo = null ) {
|
||||
/**
|
||||
* Configures the button instance. Must be called before the initial `init()`.
|
||||
*
|
||||
* @param {Object} apiConfig - API configuration.
|
||||
* @param {Object} transactionInfo - Transaction details; required before "init" call.
|
||||
*/
|
||||
configure( apiConfig, transactionInfo ) {
|
||||
this.googlePayConfig = apiConfig;
|
||||
this.transactionInfo = transactionInfo;
|
||||
|
||||
this.allowedPaymentMethods = this.googlePayConfig.allowedPaymentMethods;
|
||||
this.baseCardPaymentMethod = this.allowedPaymentMethods[ 0 ];
|
||||
|
||||
this.log( 'CONFIG', transactionInfo );
|
||||
}
|
||||
|
||||
init() {
|
||||
// Stop, if the button is already initialized.
|
||||
if ( this.isInitialized ) {
|
||||
return;
|
||||
}
|
||||
if ( config ) {
|
||||
this.googlePayConfig = config;
|
||||
}
|
||||
if ( transactionInfo ) {
|
||||
this.transactionInfo = transactionInfo;
|
||||
}
|
||||
|
||||
if ( ! this.googlePayConfig || ! this.transactionInfo ) {
|
||||
this.error( 'Missing config or transactionInfo during init.' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop, if configuration is invalid.
|
||||
if ( ! this.isConfigValid ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.allowedPaymentMethods = config.allowedPaymentMethods;
|
||||
this.baseCardPaymentMethod = this.allowedPaymentMethods[ 0 ];
|
||||
|
||||
super.init();
|
||||
this.#paymentsClient = this.createPaymentsClient();
|
||||
|
||||
|
@ -170,6 +201,7 @@ class GooglepayButton extends PaymentButton {
|
|||
this.log( 'Payment wrapper not found', this.wrapperId );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! this.paymentsClient ) {
|
||||
this.log( 'Could not initialize the payments client' );
|
||||
return;
|
||||
|
@ -179,7 +211,7 @@ class GooglepayButton extends PaymentButton {
|
|||
.isReadyToPay(
|
||||
this.buildReadyToPayRequest(
|
||||
this.allowedPaymentMethods,
|
||||
config
|
||||
this.googlePayConfig
|
||||
)
|
||||
)
|
||||
.then( ( response ) => {
|
||||
|
@ -201,22 +233,34 @@ class GooglepayButton extends PaymentButton {
|
|||
this.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an object with relevant paymentDataCallbacks for the current button instance.
|
||||
*
|
||||
* @return {Object} An object containing callbacks for the current scope & configuration.
|
||||
*/
|
||||
preparePaymentDataCallbacks() {
|
||||
const callbacks = {};
|
||||
|
||||
// We do not attach any callbacks to preview buttons.
|
||||
if ( this.isPreview ) {
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
callbacks.onPaymentAuthorized = this.onPaymentAuthorized;
|
||||
|
||||
if ( this.requiresShipping ) {
|
||||
callbacks.onPaymentDataChanged = this.onPaymentDataChanged;
|
||||
}
|
||||
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
createPaymentsClient() {
|
||||
if ( ! this.googlePayApi ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const callbacks = {
|
||||
onPaymentAuthorized: this.onPaymentAuthorized.bind( this ),
|
||||
};
|
||||
|
||||
if (
|
||||
this.buttonConfig.shipping.enabled &&
|
||||
this.contextHandler.shippingAllowed()
|
||||
) {
|
||||
callbacks.onPaymentDataChanged =
|
||||
this.onPaymentDataChanged.bind( this );
|
||||
}
|
||||
const callbacks = this.preparePaymentDataCallbacks();
|
||||
|
||||
/**
|
||||
* Consider providing merchant info here:
|
||||
|
@ -253,7 +297,7 @@ class GooglepayButton extends PaymentButton {
|
|||
* @see https://developers.google.com/pay/api/web/reference/client#createButton
|
||||
*/
|
||||
const button = this.paymentsClient.createButton( {
|
||||
onClick: this.onButtonClick.bind( this ),
|
||||
onClick: this.onButtonClick,
|
||||
allowedPaymentMethods: [ baseCardPaymentMethod ],
|
||||
buttonColor: color || 'black',
|
||||
buttonType: type || 'pay',
|
||||
|
@ -314,10 +358,7 @@ class GooglepayButton extends PaymentButton {
|
|||
paymentDataRequest.transactionInfo = this.transactionInfo;
|
||||
paymentDataRequest.merchantInfo = googlePayConfig.merchantInfo;
|
||||
|
||||
if (
|
||||
this.buttonConfig.shipping.enabled &&
|
||||
this.contextHandler.shippingAllowed()
|
||||
) {
|
||||
if ( this.requiresShipping ) {
|
||||
paymentDataRequest.callbackIntents = [
|
||||
'SHIPPING_ADDRESS',
|
||||
'SHIPPING_OPTION',
|
||||
|
|
|
@ -30,13 +30,19 @@ class GooglepayManager {
|
|||
|
||||
this.buttons.push( button );
|
||||
|
||||
const initButton = () => {
|
||||
button.configure( this.googlePayConfig, this.transactionInfo );
|
||||
button.init();
|
||||
};
|
||||
|
||||
// Initialize button only if googlePayConfig and transactionInfo are already fetched.
|
||||
if ( this.googlePayConfig && this.transactionInfo ) {
|
||||
button.init( this.googlePayConfig, this.transactionInfo );
|
||||
initButton();
|
||||
} else {
|
||||
await this.init();
|
||||
|
||||
if ( this.googlePayConfig && this.transactionInfo ) {
|
||||
button.init( this.googlePayConfig, this.transactionInfo );
|
||||
initButton();
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
@ -54,7 +60,8 @@ class GooglepayManager {
|
|||
}
|
||||
|
||||
for ( const button of this.buttons ) {
|
||||
button.init( this.googlePayConfig, this.transactionInfo );
|
||||
button.configure( this.googlePayConfig, this.transactionInfo );
|
||||
button.init();
|
||||
}
|
||||
} catch ( error ) {
|
||||
console.error( 'Error during initialization:', error );
|
||||
|
|
|
@ -103,7 +103,7 @@ class GooglePayPreviewButton extends PreviewButton {
|
|||
null
|
||||
);
|
||||
|
||||
const button = new GooglepayButton(
|
||||
const button = GooglepayButton.createButton(
|
||||
'preview',
|
||||
null,
|
||||
buttonConfig,
|
||||
|
@ -111,7 +111,8 @@ class GooglePayPreviewButton extends PreviewButton {
|
|||
contextHandler
|
||||
);
|
||||
|
||||
button.init( this.apiConfig, null );
|
||||
button.configure( this.apiConfig, null );
|
||||
button.init();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue