Skip to content

Commit bc3e4d3

Browse files
Merge pull request #3054 from bigcommerce/bcp-button-app-switch
feat(payment): PAYPAL-5723 add bcp button app switch
2 parents 9469eb4 + c51d10e commit bc3e4d3

File tree

4 files changed

+87
-7
lines changed

4 files changed

+87
-7
lines changed

packages/bigcommerce-payments-integration/src/bigcommerce-payments-types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ export interface BigCommercePaymentsInitializationData {
263263
shouldRenderFields?: boolean;
264264
shouldRunAcceleratedCheckout?: boolean;
265265
paymentButtonStyles?: Record<string, PayPalButtonStyleOptions>;
266+
isAppSwitchEnabled?: boolean;
266267
}
267268

268269
/**
@@ -357,6 +358,8 @@ export interface BigCommercePaymentsButtons {
357358
render(id: string): void;
358359
close(): void;
359360
isEligible(): boolean;
361+
hasReturned?(): boolean;
362+
resume?(): void;
360363
}
361364

362365
export interface BigCommercePaymentsButtonsOptions {

packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-button-strategy.spec.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,57 @@ describe('BigCommercePaymentsButtonStrategy', () => {
441441
expect(bigCommercePaymentsSdkRenderMock).toHaveBeenCalled();
442442
});
443443

444+
it('render button with appSwitch flag', async () => {
445+
jest.spyOn(
446+
paymentIntegrationService.getState(),
447+
'getPaymentMethodOrThrow',
448+
).mockReturnValue({
449+
...paymentMethod,
450+
initializationData: {
451+
...paymentMethod.initializationData,
452+
isAppSwitchEnabled: true,
453+
},
454+
});
455+
456+
await strategy.initialize(initializationOptions);
457+
458+
expect(paypalSdk.Buttons).toHaveBeenCalledWith({
459+
appSwitchWhenAvailable: true,
460+
fundingSource: paypalSdk.FUNDING.PAYPAL,
461+
style: bigCommercePaymentsOptions.style,
462+
createOrder: expect.any(Function),
463+
onApprove: expect.any(Function),
464+
});
465+
});
466+
467+
it('calls resume when appSwitch enabled and returned from app', async () => {
468+
jest.spyOn(
469+
paymentIntegrationService.getState(),
470+
'getPaymentMethodOrThrow',
471+
).mockReturnValue({
472+
...paymentMethod,
473+
initializationData: {
474+
...paymentMethod.initializationData,
475+
isAppSwitchEnabled: true,
476+
},
477+
});
478+
479+
const resumeMock = jest.fn();
480+
const bigCommercePaymentsSdkRenderMock = jest.fn();
481+
482+
jest.spyOn(paypalSdk, 'Buttons').mockImplementation(() => ({
483+
close: jest.fn(),
484+
isEligible: jest.fn(() => true),
485+
render: bigCommercePaymentsSdkRenderMock,
486+
hasReturned: jest.fn(() => true),
487+
resume: resumeMock,
488+
}));
489+
490+
await strategy.initialize(initializationOptions);
491+
492+
expect(resumeMock).toHaveBeenCalled();
493+
});
494+
444495
it('does not render PayPal button if it is not eligible', async () => {
445496
const bigCommercePaymentsSdkRenderMock = jest.fn();
446497

packages/bigcommerce-payments-integration/src/bigcommerce-payments/bigcommerce-payments-button-strategy.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export default class BigCommercePaymentsButtonStrategy implements CheckoutButton
8888
false,
8989
);
9090

91-
this.renderButton(containerId, methodId, bigcommerce_payments);
91+
this.renderButton(containerId, methodId, bigcommerce_payments, isBuyNowFlow);
9292
}
9393

9494
deinitialize(): Promise<void> {
@@ -99,6 +99,7 @@ export default class BigCommercePaymentsButtonStrategy implements CheckoutButton
9999
containerId: string,
100100
methodId: string,
101101
bigcommerce_payments: BigCommercePaymentsButtonInitializeOptions,
102+
isBuyNowFlow?: boolean,
102103
): void {
103104
const { buyNowInitializeOptions, style, onComplete, onEligibilityFailure } =
104105
bigcommerce_payments;
@@ -107,9 +108,14 @@ export default class BigCommercePaymentsButtonStrategy implements CheckoutButton
107108
const state = this.paymentIntegrationService.getState();
108109
const paymentMethod =
109110
state.getPaymentMethodOrThrow<BigCommercePaymentsInitializationData>(methodId);
110-
const { isHostedCheckoutEnabled } = paymentMethod.initializationData || {};
111+
const { isHostedCheckoutEnabled, isAppSwitchEnabled } =
112+
paymentMethod.initializationData || {};
111113

112114
const defaultCallbacks = {
115+
...(!isBuyNowFlow &&
116+
this.isPaypalCommerceAppSwitchEnabled(methodId) && {
117+
appSwitchWhenAvailable: true,
118+
}),
113119
createOrder: () =>
114120
this.bigCommercePaymentsIntegrationService.createOrder('bigcommerce_payments'),
115121
onApprove: ({ orderID }: ApproveCallbackPayload) =>
@@ -122,10 +128,12 @@ export default class BigCommercePaymentsButtonStrategy implements CheckoutButton
122128
};
123129

124130
const hostedCheckoutCallbacks = {
125-
onShippingAddressChange: (data: ShippingAddressChangeCallbackPayload) =>
126-
this.onShippingAddressChange(data),
127-
onShippingOptionsChange: (data: ShippingOptionChangeCallbackPayload) =>
128-
this.onShippingOptionsChange(data),
131+
...(!isAppSwitchEnabled && {
132+
onShippingAddressChange: (data: ShippingAddressChangeCallbackPayload) =>
133+
this.onShippingAddressChange(data),
134+
onShippingOptionsChange: (data: ShippingOptionChangeCallbackPayload) =>
135+
this.onShippingOptionsChange(data),
136+
}),
129137
onApprove: (data: ApproveCallbackPayload, actions: ApproveCallbackActions) =>
130138
this.onHostedCheckoutApprove(data, actions, methodId, onComplete),
131139
};
@@ -141,7 +149,11 @@ export default class BigCommercePaymentsButtonStrategy implements CheckoutButton
141149
const paypalButton = paypalSdk.Buttons(buttonRenderOptions);
142150

143151
if (paypalButton.isEligible()) {
144-
paypalButton.render(`#${containerId}`);
152+
if (paypalButton.hasReturned?.() && this.isPaypalCommerceAppSwitchEnabled(methodId)) {
153+
paypalButton.resume?.();
154+
} else {
155+
paypalButton.render(`#${containerId}`);
156+
}
145157
} else if (onEligibilityFailure && typeof onEligibilityFailure === 'function') {
146158
onEligibilityFailure();
147159
} else {
@@ -259,4 +271,17 @@ export default class BigCommercePaymentsButtonStrategy implements CheckoutButton
259271
throw error;
260272
}
261273
}
274+
275+
/**
276+
*
277+
* PayPal AppSwitch enabling handling
278+
*
279+
*/
280+
private isPaypalCommerceAppSwitchEnabled(methodId: string): boolean {
281+
const state = this.paymentIntegrationService.getState();
282+
const paymentMethod =
283+
state.getPaymentMethodOrThrow<BigCommercePaymentsInitializationData>(methodId);
284+
285+
return paymentMethod.initializationData?.isAppSwitchEnabled ?? false;
286+
}
262287
}

packages/bigcommerce-payments-integration/src/mocks/get-bigcommerce-payments-payment-method.mock.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export default function getBigCommercePaymentsPaymentMethod(): PaymentMethod {
7272
},
7373
},
7474
],
75+
isAppSwitchEnabled: false,
7576
},
7677
skipRedirectConfirmationAlert: false,
7778
type: 'PAYMENT_TYPE_API',

0 commit comments

Comments
 (0)