Merge pull request #2414 from woocommerce/PCP-2645-when-selecting-google-pay-as-a-payment-option-in-safari-a-developer-error-is-displayed

Google Pay: Fix the incorrect popup triggering (2645)
This commit is contained in:
Emili Castells 2024-07-23 12:57:00 +02:00 committed by GitHub
commit 2e44e11dbe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 113 additions and 59 deletions

View file

@ -1,4 +1,3 @@
import ContextHandlerFactory from './Context/ContextHandlerFactory';
import { setVisible } from '../../../ppcp-button/resources/js/modules/Helper/Hiding';
import { setEnabled } from '../../../ppcp-button/resources/js/modules/Helper/ButtonDisabler';
import widgetBuilder from '../../../ppcp-button/resources/js/modules/Renderer/WidgetBuilder';
@ -6,7 +5,13 @@ import UpdatePaymentData from './Helper/UpdatePaymentData';
import { apmButtonsInit } from '../../../ppcp-button/resources/js/modules/Helper/ApmButtons';
class GooglepayButton {
constructor( context, externalHandler, buttonConfig, ppcpConfig ) {
constructor(
context,
externalHandler,
buttonConfig,
ppcpConfig,
contextHandler
) {
apmButtonsInit( ppcpConfig );
this.isInitialized = false;
@ -15,16 +20,10 @@ class GooglepayButton {
this.externalHandler = externalHandler;
this.buttonConfig = buttonConfig;
this.ppcpConfig = ppcpConfig;
this.contextHandler = contextHandler;
this.paymentsClient = null;
this.contextHandler = ContextHandlerFactory.create(
this.context,
this.buttonConfig,
this.ppcpConfig,
this.externalHandler
);
this.log = function () {
if ( this.buttonConfig.is_debug ) {
//console.log('[GooglePayButton]', ...arguments);
@ -32,7 +31,7 @@ class GooglepayButton {
};
}
init( config ) {
init( config, transactionInfo ) {
if ( this.isInitialized ) {
return;
}
@ -47,6 +46,7 @@ class GooglepayButton {
}
this.googlePayConfig = config;
this.transactionInfo = transactionInfo;
this.allowedPaymentMethods = config.allowedPaymentMethods;
this.baseCardPaymentMethod = this.allowedPaymentMethods[ 0 ];
@ -109,7 +109,7 @@ class GooglepayButton {
}
this.isInitialized = false;
this.init( this.googlePayConfig );
this.init( this.googlePayConfig, this.transactionInfo );
}
validateConfig() {
@ -289,10 +289,11 @@ class GooglepayButton {
/**
* Show Google Pay payment sheet when Google Pay payment button is clicked
*/
async onButtonClick() {
onButtonClick() {
this.log( 'onButtonClick', this.context );
const paymentDataRequest = await this.paymentDataRequest();
const paymentDataRequest = this.paymentDataRequest();
this.log(
'onButtonClick: paymentDataRequest',
paymentDataRequest,
@ -304,7 +305,7 @@ class GooglepayButton {
this.paymentsClient.loadPaymentData( paymentDataRequest );
}
async paymentDataRequest() {
paymentDataRequest() {
const baseRequest = {
apiVersion: 2,
apiVersionMinor: 0,
@ -314,8 +315,7 @@ class GooglepayButton {
const paymentDataRequest = Object.assign( {}, baseRequest );
paymentDataRequest.allowedPaymentMethods =
googlePayConfig.allowedPaymentMethods;
paymentDataRequest.transactionInfo =
await this.contextHandler.transactionInfo();
paymentDataRequest.transactionInfo = this.transactionInfo;
paymentDataRequest.merchantInfo = googlePayConfig.merchantInfo;
if (
@ -354,43 +354,51 @@ class GooglepayButton {
this.log( 'paymentData', paymentData );
return new Promise( async ( resolve, reject ) => {
const paymentDataRequestUpdate = {};
try {
const paymentDataRequestUpdate = {};
const updatedData = await new UpdatePaymentData(
this.buttonConfig.ajax.update_payment_data
).update( paymentData );
const transactionInfo = await this.contextHandler.transactionInfo();
const updatedData = await new UpdatePaymentData(
this.buttonConfig.ajax.update_payment_data
).update( paymentData );
const transactionInfo = this.transactionInfo;
this.log( 'onPaymentDataChanged:updatedData', updatedData );
this.log( 'onPaymentDataChanged:transactionInfo', transactionInfo );
this.log( 'onPaymentDataChanged:updatedData', updatedData );
this.log(
'onPaymentDataChanged:transactionInfo',
transactionInfo
);
updatedData.country_code = transactionInfo.countryCode;
updatedData.currency_code = transactionInfo.currencyCode;
updatedData.total_str = transactionInfo.totalPrice;
updatedData.country_code = transactionInfo.countryCode;
updatedData.currency_code = transactionInfo.currencyCode;
updatedData.total_str = transactionInfo.totalPrice;
// Handle unserviceable address.
if ( ! updatedData.shipping_options?.shippingOptions?.length ) {
paymentDataRequestUpdate.error =
this.unserviceableShippingAddressError();
resolve( paymentDataRequestUpdate );
return;
}
switch ( paymentData.callbackTrigger ) {
case 'INITIALIZE':
case 'SHIPPING_ADDRESS':
paymentDataRequestUpdate.newShippingOptionParameters =
updatedData.shipping_options;
paymentDataRequestUpdate.newTransactionInfo =
this.calculateNewTransactionInfo( updatedData );
break;
case 'SHIPPING_OPTION':
paymentDataRequestUpdate.newTransactionInfo =
this.calculateNewTransactionInfo( updatedData );
break;
}
// Handle unserviceable address.
if ( ! updatedData.shipping_options?.shippingOptions?.length ) {
paymentDataRequestUpdate.error =
this.unserviceableShippingAddressError();
resolve( paymentDataRequestUpdate );
return;
} catch ( error ) {
console.error( 'Error during onPaymentDataChanged:', error );
reject( error );
}
switch ( paymentData.callbackTrigger ) {
case 'INITIALIZE':
case 'SHIPPING_ADDRESS':
paymentDataRequestUpdate.newShippingOptionParameters =
updatedData.shipping_options;
paymentDataRequestUpdate.newTransactionInfo =
this.calculateNewTransactionInfo( updatedData );
break;
case 'SHIPPING_OPTION':
paymentDataRequestUpdate.newTransactionInfo =
this.calculateNewTransactionInfo( updatedData );
break;
}
resolve( paymentDataRequestUpdate );
} );
}

View file

@ -1,39 +1,76 @@
import buttonModuleWatcher from '../../../ppcp-button/resources/js/modules/ButtonModuleWatcher';
import GooglepayButton from './GooglepayButton';
import ContextHandlerFactory from './Context/ContextHandlerFactory';
class GooglepayManager {
constructor( buttonConfig, ppcpConfig ) {
this.buttonConfig = buttonConfig;
this.ppcpConfig = ppcpConfig;
this.googlePayConfig = null;
this.transactionInfo = null;
this.contextHandler = null;
this.buttons = [];
buttonModuleWatcher.watchContextBootstrap( ( bootstrap ) => {
buttonModuleWatcher.watchContextBootstrap( async ( bootstrap ) => {
this.contextHandler = ContextHandlerFactory.create(
bootstrap.context,
buttonConfig,
ppcpConfig,
bootstrap.handler
);
const button = new GooglepayButton(
bootstrap.context,
bootstrap.handler,
buttonConfig,
ppcpConfig
ppcpConfig,
this.contextHandler
);
this.buttons.push( button );
if ( this.googlePayConfig ) {
button.init( this.googlePayConfig );
// Initialize button only if googlePayConfig and transactionInfo are already fetched.
if ( this.googlePayConfig && this.transactionInfo ) {
button.init( this.googlePayConfig, this.transactionInfo );
} else {
await this.init();
if ( this.googlePayConfig && this.transactionInfo ) {
button.init( this.googlePayConfig, this.transactionInfo );
}
}
} );
}
init() {
( async () => {
// Gets GooglePay configuration of the PayPal merchant.
this.googlePayConfig = await paypal.Googlepay().config();
async init() {
try {
if ( ! this.googlePayConfig ) {
// Gets GooglePay configuration of the PayPal merchant.
this.googlePayConfig = await paypal.Googlepay().config();
}
if ( ! this.transactionInfo ) {
this.transactionInfo = await this.fetchTransactionInfo();
}
for ( const button of this.buttons ) {
button.init( this.googlePayConfig );
button.init( this.googlePayConfig, this.transactionInfo );
}
} )();
} catch ( error ) {
console.error( 'Error during initialization:', error );
}
}
async fetchTransactionInfo() {
try {
if ( ! this.contextHandler ) {
throw new Error( 'ContextHandler is not initialized' );
}
return await this.contextHandler.transactionInfo();
} catch ( error ) {
console.error( 'Error fetching transaction info:', error );
throw error;
}
}
reinit() {

View file

@ -1,6 +1,7 @@
import GooglepayButton from './GooglepayButton';
import PreviewButton from '../../../ppcp-button/resources/js/modules/Renderer/PreviewButton';
import PreviewButtonManager from '../../../ppcp-button/resources/js/modules/Renderer/PreviewButtonManager';
import ContextHandlerFactory from './Context/ContextHandlerFactory';
/**
* Accessor that creates and returns a single PreviewButtonManager instance.
@ -95,14 +96,22 @@ class GooglePayPreviewButton extends PreviewButton {
}
createButton( buttonConfig ) {
const contextHandler = ContextHandlerFactory.create(
'preview',
buttonConfig,
this.ppcpConfig,
null
);
const button = new GooglepayButton(
'preview',
null,
buttonConfig,
this.ppcpConfig
this.ppcpConfig,
contextHandler
);
button.init( this.apiConfig );
button.init( this.apiConfig, null );
}
/**