diff --git a/src/button-angular/README.md b/src/button-angular/README.md index fb0bdd5c..1590c148 100644 --- a/src/button-angular/README.md +++ b/src/button-angular/README.md @@ -184,6 +184,7 @@ integrating Google Pay into your website.

Invoked when the Google Pay button is clicked, before the payment sheet is displayed.

Display of the payment sheet can be prevented by calling event.preventDefault().

+

It is possible to return Promise with a boolean value from the click handler to delay showing the payment sheet or even prevent it, by returning false. Return true to let the regular behavior continue.

diff --git a/src/button-element/README.md b/src/button-element/README.md index 9197c2e2..47a7413a 100644 --- a/src/button-element/README.md +++ b/src/button-element/README.md @@ -285,6 +285,7 @@ integrating Google Pay into your website.

Invoked when the Google Pay button is clicked, before the payment sheet is displayed.

Display of the payment sheet can be prevented by calling event.preventDefault().

+

It is possible to return Promise with a boolean value from the click handler to delay showing the payment sheet or even prevent it, by returning false. Return true to let the regular behavior continue.

diff --git a/src/button-react/README.md b/src/button-react/README.md index 43cd8f66..8f574be1 100644 --- a/src/button-react/README.md +++ b/src/button-react/README.md @@ -201,6 +201,7 @@ integrating Google Pay into your website.

Invoked when the Google Pay button is clicked, before the payment sheet is displayed.

Display of the payment sheet can be prevented by calling event.preventDefault().

+

It is possible to return Promise with a boolean value from the click handler to delay showing the payment sheet or even prevent it, by returning false. Return true to let the regular behavior continue.

diff --git a/src/lib/button-manager.test.ts b/src/lib/button-manager.test.ts index b411d72a..0f1b2cb9 100644 --- a/src/lib/button-manager.test.ts +++ b/src/lib/button-manager.test.ts @@ -799,4 +799,30 @@ describe('Events', () => { expect(loadPaymentDataSpy).not.toBeCalled(); }); + + it('does not call onLoadPaymentData when onClick returns a Promise with false', async () => { + manager.configure({ + ...defaults, + onClick: _ => Promise.resolve(false), + onLoadPaymentData: loadPaymentDataSpy, + }); + + const event = new Event('click', { cancelable: true }); + await manager.handleClick(event); + + expect(loadPaymentDataSpy).not.toBeCalled(); + }); + + it('calls onLoadPaymentData when onClick returns a Promise with true', async () => { + manager.configure({ + ...defaults, + onClick: _ => Promise.resolve(true), + onLoadPaymentData: loadPaymentDataSpy, + }); + + const event = new Event('click', { cancelable: true }); + await manager.handleClick(event); + + expect(loadPaymentDataSpy).toBeCalled(); + }); }); diff --git a/src/lib/button-manager.ts b/src/lib/button-manager.ts index 5cc2a0b9..4e5d08ce 100644 --- a/src/lib/button-manager.ts +++ b/src/lib/button-manager.ts @@ -34,7 +34,7 @@ export interface Config { onCancel?: (reason: google.payments.api.PaymentsError) => void; onError?: (error: Error | google.payments.api.PaymentsError) => void; onReadyToPayChange?: (result: ReadyToPayChangeResponse) => void; - onClick?: (event: Event) => void; + onClick?: (event: Event) => void | Promise; buttonType?: google.payments.api.ButtonType; buttonColor?: google.payments.api.ButtonColor; buttonRadius?: number; @@ -270,9 +270,9 @@ export class ButtonManager { try { readyToPay = await this.client.isReadyToPay(this.createIsReadyToPayRequest(this.config)); showButton = - (readyToPay.result && !this.config.existingPaymentMethodRequired) - || (readyToPay.result && readyToPay.paymentMethodPresent && this.config.existingPaymentMethodRequired) - || false; + (readyToPay.result && !this.config.existingPaymentMethodRequired) || + (readyToPay.result && readyToPay.paymentMethodPresent && this.config.existingPaymentMethodRequired) || + false; } catch (err) { if (this.config.onError) { this.config.onError(err as Error); @@ -333,11 +333,17 @@ export class ButtonManager { const request = this.createLoadPaymentDataRequest(config); try { + let shouldProceed: boolean | null = null; + if (config.onClick) { - config.onClick(event); + const onClickResult = await config.onClick(event); + + if (typeof onClickResult === 'boolean') { + shouldProceed = onClickResult; + } } - if (event.defaultPrevented) { + if (event.defaultPrevented || shouldProceed === false) { return; }