From 98ee1e049dc9c037cf8333881e3b5f8370742237 Mon Sep 17 00:00:00 2001 From: bc-yaroslav-zhmutskyi Date: Mon, 3 Nov 2025 20:51:53 +0200 Subject: [PATCH 1/2] feat(payment): test appswitch bcp --- .../src/bigcommerce-payments-types.ts | 3 ++ .../bigcommerce-payments-button-strategy.ts | 37 +++++++++++++++--- .../bigcommerce-payments-customer-strategy.ts | 39 +++++++++++++++---- ...igcommerce-payments-payment-method.mock.ts | 1 + 4 files changed, 67 insertions(+), 13 deletions(-) diff --git a/packages/bigcommerce-payments-integration/src/bigcommerce-payments-types.ts b/packages/bigcommerce-payments-integration/src/bigcommerce-payments-types.ts index 156268d04f..3e2d47bedc 100644 --- a/packages/bigcommerce-payments-integration/src/bigcommerce-payments-types.ts +++ b/packages/bigcommerce-payments-integration/src/bigcommerce-payments-types.ts @@ -263,6 +263,7 @@ export interface BigCommercePaymentsInitializationData { shouldRenderFields?: boolean; shouldRunAcceleratedCheckout?: boolean; paymentButtonStyles?: Record; + isAppSwitchEnabled?: boolean; } /** @@ -357,6 +358,8 @@ export interface BigCommercePaymentsButtons { render(id: string): void; close(): void; isEligible(): boolean; + hasReturned?(): boolean; + resume?(): void; } export interface BigCommercePaymentsButtonsOptions { diff --git a/packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-button-strategy.ts b/packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-button-strategy.ts index b74c93c601..2d789eed07 100644 --- a/packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-button-strategy.ts +++ b/packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-button-strategy.ts @@ -99,6 +99,7 @@ export default class BigCommercePaymentsButtonStrategy implements CheckoutButton containerId: string, methodId: string, bigcommerce_payments: BigCommercePaymentsButtonInitializeOptions, + isBuyNowFlow?: boolean, ): void { const { buyNowInitializeOptions, style, onComplete, onEligibilityFailure } = bigcommerce_payments; @@ -107,9 +108,14 @@ export default class BigCommercePaymentsButtonStrategy implements CheckoutButton const state = this.paymentIntegrationService.getState(); const paymentMethod = state.getPaymentMethodOrThrow(methodId); - const { isHostedCheckoutEnabled } = paymentMethod.initializationData || {}; + const { isHostedCheckoutEnabled, isAppSwitchEnabled = true } = + paymentMethod.initializationData || {}; const defaultCallbacks = { + ...(!isBuyNowFlow && + this.isPaypalCommerceAppSwitchEnabled(methodId) && { + appSwitchWhenAvailable: true, + }), createOrder: () => this.bigCommercePaymentsIntegrationService.createOrder('bigcommerce_payments'), onApprove: ({ orderID }: ApproveCallbackPayload) => @@ -122,10 +128,12 @@ export default class BigCommercePaymentsButtonStrategy implements CheckoutButton }; const hostedCheckoutCallbacks = { - onShippingAddressChange: (data: ShippingAddressChangeCallbackPayload) => - this.onShippingAddressChange(data), - onShippingOptionsChange: (data: ShippingOptionChangeCallbackPayload) => - this.onShippingOptionsChange(data), + ...(!isAppSwitchEnabled && { + onShippingAddressChange: (data: ShippingAddressChangeCallbackPayload) => + this.onShippingAddressChange(data), + onShippingOptionsChange: (data: ShippingOptionChangeCallbackPayload) => + this.onShippingOptionsChange(data), + }), onApprove: (data: ApproveCallbackPayload, actions: ApproveCallbackActions) => this.onHostedCheckoutApprove(data, actions, methodId, onComplete), }; @@ -141,7 +149,11 @@ export default class BigCommercePaymentsButtonStrategy implements CheckoutButton const paypalButton = paypalSdk.Buttons(buttonRenderOptions); if (paypalButton.isEligible()) { - paypalButton.render(`#${containerId}`); + if (paypalButton.hasReturned?.() && this.isPaypalCommerceAppSwitchEnabled(methodId)) { + paypalButton.resume?.(); + } else { + paypalButton.render(`#${containerId}`); + } } else if (onEligibilityFailure && typeof onEligibilityFailure === 'function') { onEligibilityFailure(); } else { @@ -259,4 +271,17 @@ export default class BigCommercePaymentsButtonStrategy implements CheckoutButton throw error; } } + + /** + * + * PayPal AppSwitch enabling handling + * + */ + private isPaypalCommerceAppSwitchEnabled(methodId: string): boolean { + const state = this.paymentIntegrationService.getState(); + const paymentMethod = + state.getPaymentMethodOrThrow(methodId); + + return paymentMethod.initializationData?.isAppSwitchEnabled ?? true; + } } diff --git a/packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-customer-strategy.ts b/packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-customer-strategy.ts index d8bdfaede1..d2fb2fdcc4 100644 --- a/packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-customer-strategy.ts +++ b/packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-customer-strategy.ts @@ -119,11 +119,17 @@ export default class BigCommercePaymentsCustomerStrategy implements CustomerStra const state = this.paymentIntegrationService.getState(); const paymentMethod = state.getPaymentMethodOrThrow(methodId); - const { isHostedCheckoutEnabled, paymentButtonStyles } = - paymentMethod.initializationData || {}; + const { + isHostedCheckoutEnabled, + paymentButtonStyles, + isAppSwitchEnabled = true, + } = paymentMethod.initializationData || {}; const { checkoutTopButtonStyles } = paymentButtonStyles || {}; const defaultCallbacks = { + ...(this.isPaypalCommerceAppSwitchEnabled(methodId) && { + appSwitchWhenAvailable: true, + }), createOrder: () => this.bigCommercePaymentsIntegrationService.createOrder('bigcommerce_payments'), onApprove: ({ orderID }: ApproveCallbackPayload) => @@ -132,10 +138,12 @@ export default class BigCommercePaymentsCustomerStrategy implements CustomerStra }; const hostedCheckoutCallbacks = { - onShippingAddressChange: (data: ShippingAddressChangeCallbackPayload) => - this.onShippingAddressChange(data), - onShippingOptionsChange: (data: ShippingOptionChangeCallbackPayload) => - this.onShippingOptionsChange(data), + ...(!isAppSwitchEnabled && { + onShippingAddressChange: (data: ShippingAddressChangeCallbackPayload) => + this.onShippingAddressChange(data), + onShippingOptionsChange: (data: ShippingOptionChangeCallbackPayload) => + this.onShippingOptionsChange(data), + }), onApprove: (data: ApproveCallbackPayload, actions: ApproveCallbackActions) => this.onHostedCheckoutApprove(data, actions, methodId, onComplete), }; @@ -153,7 +161,11 @@ export default class BigCommercePaymentsCustomerStrategy implements CustomerStra const paypalButton = paypalSdk.Buttons(buttonRenderOptions); if (paypalButton.isEligible()) { - paypalButton.render(`#${container}`); + if (paypalButton.hasReturned?.() && this.isPaypalCommerceAppSwitchEnabled(methodId)) { + paypalButton.resume?.(); + } else { + paypalButton.render(`#${container}`); + } } else { this.bigCommercePaymentsIntegrationService.removeElement(container); } @@ -249,4 +261,17 @@ export default class BigCommercePaymentsCustomerStrategy implements CustomerStra throw error; } } + + /** + * + * PayPal AppSwitch enabling handling + * + */ + private isPaypalCommerceAppSwitchEnabled(methodId: string): boolean { + const state = this.paymentIntegrationService.getState(); + const paymentMethod = + state.getPaymentMethodOrThrow(methodId); + + return paymentMethod.initializationData?.isAppSwitchEnabled ?? true; + } } diff --git a/packages/bigcommerce-payments-integration/src/mocks/get-bigcommerce-payments-payment-method.mock.ts b/packages/bigcommerce-payments-integration/src/mocks/get-bigcommerce-payments-payment-method.mock.ts index 28fdde375b..38bde10573 100644 --- a/packages/bigcommerce-payments-integration/src/mocks/get-bigcommerce-payments-payment-method.mock.ts +++ b/packages/bigcommerce-payments-integration/src/mocks/get-bigcommerce-payments-payment-method.mock.ts @@ -72,6 +72,7 @@ export default function getBigCommercePaymentsPaymentMethod(): PaymentMethod { }, }, ], + isAppSwitchEnabled: false, }, skipRedirectConfirmationAlert: false, type: 'PAYMENT_TYPE_API', From aa3e29be31274d85d40b5b8e170ee48959669c2f Mon Sep 17 00:00:00 2001 From: bc-yaroslav-zhmutskyi Date: Mon, 3 Nov 2025 20:58:37 +0200 Subject: [PATCH 2/2] refactor(payment): add buy now flow --- .../bigcommerce-payments-button-strategy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-button-strategy.ts b/packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-button-strategy.ts index 2d789eed07..b1c534f3f2 100644 --- a/packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-button-strategy.ts +++ b/packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-button-strategy.ts @@ -88,7 +88,7 @@ export default class BigCommercePaymentsButtonStrategy implements CheckoutButton false, ); - this.renderButton(containerId, methodId, bigcommerce_payments); + this.renderButton(containerId, methodId, bigcommerce_payments, isBuyNowFlow); } deinitialize(): Promise {