Skip to content

Commit 23a5b24

Browse files
feat(payment): PAYPAL-5717 Added AppSwitch to PPCP button strategy
1 parent 9119954 commit 23a5b24

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

packages/paypal-commerce-integration/src/paypal-commerce-types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@ export interface PayPalCommerceButtons {
360360
render(id: string): void;
361361
close(): void;
362362
isEligible(): boolean;
363+
hasReturned?(): boolean;
364+
resume?(): void;
363365
}
364366

365367
export interface PayPalCommerceButtonsOptions {
@@ -607,6 +609,7 @@ export interface PayPalCreateOrderRequestBody extends HostedInstrument, VaultedI
607609
metadataId?: string;
608610
setupToken?: boolean;
609611
fastlaneToken?: string;
612+
userAgent?: string;
610613
}
611614

612615
export enum PayPalOrderStatus {

packages/paypal-commerce-integration/src/paypal-commerce/paypal-commerce-button-strategy.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ describe('PayPalCommerceButtonStrategy', () => {
371371
await strategy.initialize(initializationOptions);
372372

373373
expect(paypalSdk.Buttons).toHaveBeenCalledWith({
374+
appSwitchWhenAvailable: true,
374375
fundingSource: paypalSdk.FUNDING.PAYPAL,
375376
style: paypalCommerceOptions.style,
376377
createOrder: expect.any(Function),
@@ -382,6 +383,7 @@ describe('PayPalCommerceButtonStrategy', () => {
382383
await strategy.initialize(buyNowInitializationOptions);
383384

384385
expect(paypalSdk.Buttons).toHaveBeenCalledWith({
386+
appSwitchWhenAvailable: true,
385387
fundingSource: paypalSdk.FUNDING.PAYPAL,
386388
style: paypalCommerceOptions.style,
387389
createOrder: expect.any(Function),
@@ -408,6 +410,7 @@ describe('PayPalCommerceButtonStrategy', () => {
408410
await strategy.initialize(initializationOptions);
409411

410412
expect(paypalSdk.Buttons).toHaveBeenCalledWith({
413+
appSwitchWhenAvailable: true,
411414
fundingSource: paypalSdk.FUNDING.PAYPAL,
412415
style: paypalCommerceOptions.style,
413416
createOrder: expect.any(Function),
@@ -492,6 +495,9 @@ describe('PayPalCommerceButtonStrategy', () => {
492495

493496
expect(paypalCommerceIntegrationService.createOrder).toHaveBeenCalledWith(
494497
'paypalcommerce',
498+
{
499+
userAgent: 'Mozilla/5.0 (darwin) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/16.7.0',
500+
},
495501
);
496502
});
497503
});

packages/paypal-commerce-integration/src/paypal-commerce/paypal-commerce-button-strategy.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
import PayPalCommerceButtonInitializeOptions, {
2222
WithPayPalCommerceButtonInitializeOptions,
2323
} from './paypal-commerce-button-initialize-options';
24+
import { isExperimentEnabled } from '@bigcommerce/checkout-sdk/utility';
2425

2526
export default class PayPalCommerceButtonStrategy implements CheckoutButtonStrategy {
2627
constructor(
@@ -96,6 +97,7 @@ export default class PayPalCommerceButtonStrategy implements CheckoutButtonStrat
9697
paypalcommerce: PayPalCommerceButtonInitializeOptions,
9798
): void {
9899
const { buyNowInitializeOptions, style, onComplete, onEligibilityFailure } = paypalcommerce;
100+
const userAgent = navigator.userAgent;
99101

100102
const paypalSdk = this.paypalCommerceIntegrationService.getPayPalSdkOrThrow();
101103
const state = this.paymentIntegrationService.getState();
@@ -104,7 +106,11 @@ export default class PayPalCommerceButtonStrategy implements CheckoutButtonStrat
104106
const { isHostedCheckoutEnabled } = paymentMethod.initializationData || {};
105107

106108
const defaultCallbacks = {
107-
createOrder: () => this.paypalCommerceIntegrationService.createOrder('paypalcommerce'),
109+
...(this.isPaypalCommerceAppSwitchEnabled() && { appSwitchWhenAvailable: true }),
110+
createOrder: () => this.paypalCommerceIntegrationService.createOrder(
111+
'paypalcommerce',
112+
...(this.isPaypalCommerceAppSwitchEnabled() ? [{ userAgent: userAgent }] : [])
113+
),
108114
onApprove: ({ orderID }: ApproveCallbackPayload) =>
109115
this.paypalCommerceIntegrationService.tokenizePayment(methodId, orderID),
110116
};
@@ -134,7 +140,14 @@ export default class PayPalCommerceButtonStrategy implements CheckoutButtonStrat
134140
const paypalButton = paypalSdk.Buttons(buttonRenderOptions);
135141

136142
if (paypalButton.isEligible()) {
137-
paypalButton.render(`#${containerId}`);
143+
if (
144+
paypalButton.hasReturned?.() &&
145+
this.isPaypalCommerceAppSwitchEnabled()
146+
) {
147+
paypalButton.resume?.();
148+
} else {
149+
paypalButton.render(`#${containerId}`);
150+
}
138151
} else if (onEligibilityFailure && typeof onEligibilityFailure === 'function') {
139152
onEligibilityFailure();
140153
} else {
@@ -250,4 +263,16 @@ export default class PayPalCommerceButtonStrategy implements CheckoutButtonStrat
250263
throw error;
251264
}
252265
}
266+
267+
/**
268+
*
269+
* PayPal AppSwitch experiments handling
270+
*
271+
*/
272+
private isPaypalCommerceAppSwitchEnabled(): boolean {
273+
const state = this.paymentIntegrationService.getState();
274+
const features = state.getStoreConfigOrThrow().checkoutSettings.features;
275+
276+
return isExperimentEnabled(features, 'PAYPAL-5716.app_switch_functionality');
277+
}
253278
}

0 commit comments

Comments
 (0)