@funnelsgrove/payments 0.1.48 → 0.1.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/dist/components/shared/SharedStripeCheckoutDialog.d.ts +4 -1
- package/dist/components/shared/SharedStripeCheckoutDialog.js +8 -1
- package/dist/components/shared/SharedStripeCheckoutV2Dialog.d.ts +2 -1
- package/dist/components/shared/SharedStripeCheckoutV2Dialog.js +301 -6
- package/dist/providers/stripe/ApplePaySubscriptionCheckoutSlot.d.ts +4 -2
- package/dist/providers/stripe/ApplePaySubscriptionCheckoutSlot.js +26 -2
- package/dist/providers/stripe/WalletSubscriptionCheckoutSlot.d.ts +5 -3
- package/dist/providers/stripe/WalletSubscriptionCheckoutSlot.js +47 -13
- package/dist/providers/stripe/useStripeSubscriptionCheckoutSession.d.ts +8 -4
- package/dist/providers/stripe/useStripeSubscriptionCheckoutSession.js +17 -7
- package/dist/testing/walletCheckoutSmoke.d.ts +1 -1
- package/dist/testing/walletCheckoutSmoke.js +22 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,13 +22,17 @@ Use these for new subscription paywalls:
|
|
|
22
22
|
- `WalletSubscriptionCheckoutSlot`
|
|
23
23
|
- `trackPaidStripeSubscriptionCheckoutCompleted`
|
|
24
24
|
|
|
25
|
+
Use these for new one-time paywall plans:
|
|
26
|
+
|
|
27
|
+
- `createStripePaymentIntent`
|
|
28
|
+
- `SharedStripeCheckoutV2Dialog` with `checkoutMode="payment_intent"`
|
|
29
|
+
|
|
25
30
|
Use `chargeStripeOneClickPayment` for post-checkout one-click upsells when the shared client helper fits the funnel. It delegates to `funnelSdkService.chargeOneClickPayment`.
|
|
26
31
|
|
|
27
32
|
## Compatibility-Only Surfaces
|
|
28
33
|
|
|
29
34
|
Keep these exports available for saved drafts, old published artifacts, and controlled migrations. Do not use them for new subscription checkout work:
|
|
30
35
|
|
|
31
|
-
- `createStripePaymentIntent`
|
|
32
36
|
- `SharedStripeCheckoutDialog`
|
|
33
37
|
- `ApplePaySubscribeButton`
|
|
34
38
|
- `GooglePaySubscribeButton`
|
|
@@ -64,7 +68,7 @@ When a live funnel still uses one of these, migrate the funnel deliberately with
|
|
|
64
68
|
- `services/planCatalog.service`: plan resolution and selection helpers.
|
|
65
69
|
- `services/runtimeBillingPlanCatalog.service`: test/live runtime catalog selection.
|
|
66
70
|
- `services/paywallOffer.service`: timed discount and display-plan helpers.
|
|
67
|
-
- `services/stripe.service`: Stripe loader, checkout-session, hosted checkout, one-click, and
|
|
71
|
+
- `services/stripe.service`: Stripe loader, checkout-session, hosted checkout, one-click, and one-time PaymentIntent clients.
|
|
68
72
|
- `providers/*`: provider-neutral checkout state and Stripe subscription checkout slots.
|
|
69
73
|
- `components/shared/*`: plan selector, checkout dialogs, Express Checkout wrappers, wallet placeholders, and trust assets.
|
|
70
74
|
- `testing/walletCheckoutSmoke`: wallet checkout smoke assertions.
|
|
@@ -74,7 +78,9 @@ When a live funnel still uses one of these, migrate the funnel deliberately with
|
|
|
74
78
|
- Keep provider-specific implementation under `src/providers/<provider>`.
|
|
75
79
|
- Stripe owns real card fields and wallet controls. Local wallet buttons are placeholders until Stripe confirms availability.
|
|
76
80
|
- Wallet unavailable state must fall back to card/manual checkout or disappear.
|
|
77
|
-
- Do not
|
|
81
|
+
- Do not count checkout intent until the visitor taps or confirms a visible checkout CTA.
|
|
82
|
+
- Wallet slots may create render-only Checkout Sessions on mount so Apple Pay and Google Pay render before the visitor taps. These sessions must use `checkoutStartSource: 'wallet_render'`; trusted server `checkout_started` analytics ignores that source.
|
|
83
|
+
- Funnel paywalls should style wallet buttons through the shared slot API: `className` for the Stripe button/placeholder, `slotClassName` for the outer slot, `appearance` for Stripe Elements appearance, and `options` for Stripe Express Checkout options.
|
|
78
84
|
- Keep discount math reusable here, but keep offer activation timing in funnel code.
|
|
79
85
|
- Checkout metadata must avoid sensitive raw query params and use `@funnelsgrove/analytics` metadata helpers.
|
|
80
86
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import type { Stripe } from '@stripe/stripe-js';
|
|
3
|
+
import { type StripeSubscriptionCheckoutAnalyticsContext } from '../../services/checkoutCompletionAnalytics.service.js';
|
|
3
4
|
export type SharedStripeCheckoutSummaryRow = {
|
|
4
5
|
id: string;
|
|
5
6
|
label: string;
|
|
@@ -8,6 +9,8 @@ export type SharedStripeCheckoutSummaryRow = {
|
|
|
8
9
|
};
|
|
9
10
|
export type SharedStripeCheckoutDialogProps = {
|
|
10
11
|
amountCents: number;
|
|
12
|
+
checkoutAnalytics?: StripeSubscriptionCheckoutAnalyticsContext | null;
|
|
13
|
+
checkoutSessionId?: string | null;
|
|
11
14
|
clientSecret: string;
|
|
12
15
|
closeAriaLabel: string;
|
|
13
16
|
customerEmailEditable?: boolean;
|
|
@@ -41,4 +44,4 @@ export type SharedStripeCheckoutDialogProps = {
|
|
|
41
44
|
};
|
|
42
45
|
export declare function useApplePayQrFallbackAllowed(): boolean;
|
|
43
46
|
export declare function useApplePayExpressCheckoutAllowed(): boolean;
|
|
44
|
-
export declare function SharedStripeCheckoutDialog({ clientSecret, onClose, stripePromise, ...props }: SharedStripeCheckoutDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
47
|
+
export declare function SharedStripeCheckoutDialog({ checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, ...props }: SharedStripeCheckoutDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -16,6 +16,7 @@ import { CardCvcElement, CardExpiryElement, CardNumberElement, Elements, useElem
|
|
|
16
16
|
import { ApplePaySubscribeButton } from './ApplePaySubscribeButton.js';
|
|
17
17
|
import { PaymentBrandMark, SecurityLockIcon, StripeWordmark, } from './CheckoutBrandAssets.js';
|
|
18
18
|
import { StripeExpressCheckoutButton } from './StripeExpressCheckoutButton.js';
|
|
19
|
+
import { trackStripeSubscriptionCheckoutStarted, } from '../../services/checkoutCompletionAnalytics.service.js';
|
|
19
20
|
const isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
20
21
|
const defaultPaymentMethodLabels = ['Visa', 'Mastercard', 'PayPal', 'G Pay', 'Apple Pay'];
|
|
21
22
|
const normalizeBillingName = (input) => {
|
|
@@ -244,7 +245,13 @@ function SharedStripeCheckoutForm({ amountCents, clientSecret, closeAriaLabel, c
|
|
|
244
245
|
} }) })] })] })] }), fieldError ? _jsx("p", { className: 'shared-stripe-checkout-error', children: fieldError }) : null, _jsx("button", { type: 'submit', className: 'shared-stripe-checkout-submit', disabled: !canSubmit, children: submitting ? processingLabel : submitLabel }), _jsxs("div", { className: 'shared-stripe-checkout-trust', children: [_jsxs("p", { className: 'shared-stripe-checkout-secure', children: [_jsx(SecurityLockIcon, { className: 'shared-stripe-checkout-secure-icon' }), _jsx("span", { children: secureLabel })] }), _jsxs("p", { className: 'shared-stripe-checkout-powered', children: [poweredByText ? _jsx("span", { children: poweredByText }) : null, showsStripeWordmark ? (_jsx(StripeWordmark, { className: 'shared-stripe-checkout-powered-mark' })) : null] })] }), paymentMethodLabels.length > 0 ? (_jsx("div", { className: 'shared-stripe-checkout-brands', "aria-hidden": 'true', children: paymentMethodLabels.map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'shared-stripe-checkout-brand' }, label))) })) : null, legalNotice ? (_jsx("div", { className: 'shared-stripe-checkout-legal', children: legalNotice })) : null, renewalNotice ? (_jsx("div", { className: 'shared-stripe-checkout-renewal', children: renewalNotice })) : null] })] }));
|
|
245
246
|
}
|
|
246
247
|
export function SharedStripeCheckoutDialog(_a) {
|
|
247
|
-
var { clientSecret, onClose, stripePromise } = _a, props = __rest(_a, ["clientSecret", "onClose", "stripePromise"]);
|
|
248
|
+
var { checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise } = _a, props = __rest(_a, ["checkoutAnalytics", "checkoutSessionId", "clientSecret", "onClose", "stripePromise"]);
|
|
249
|
+
useEffect(() => {
|
|
250
|
+
if (!checkoutAnalytics) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
void trackStripeSubscriptionCheckoutStarted(Object.assign({ checkoutSessionId }, checkoutAnalytics));
|
|
254
|
+
}, [checkoutAnalytics, checkoutSessionId, clientSecret]);
|
|
248
255
|
useEffect(() => {
|
|
249
256
|
const handleKeyDown = (event) => {
|
|
250
257
|
if (event.key === 'Escape') {
|
|
@@ -5,6 +5,7 @@ export type SharedStripeCheckoutV2DialogProps = {
|
|
|
5
5
|
buttonColor: string;
|
|
6
6
|
cardSubmitLabel: string;
|
|
7
7
|
checkoutAnalytics?: StripeSubscriptionCheckoutAnalyticsContext | null;
|
|
8
|
+
checkoutMode?: 'checkout_session' | 'payment_intent';
|
|
8
9
|
checkoutSessionId?: string | null;
|
|
9
10
|
clientSecret: string;
|
|
10
11
|
closeAriaLabel: string;
|
|
@@ -63,5 +64,5 @@ export type SharedCheckoutSpecialOfferDialogProps = {
|
|
|
63
64
|
themeColor: string;
|
|
64
65
|
title: string;
|
|
65
66
|
};
|
|
66
|
-
export declare function SharedStripeCheckoutV2Dialog({ checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries, ...props }: SharedStripeCheckoutV2DialogProps): import("react/jsx-runtime").JSX.Element;
|
|
67
|
+
export declare function SharedStripeCheckoutV2Dialog({ checkoutAnalytics, checkoutMode, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries, ...props }: SharedStripeCheckoutV2DialogProps): import("react/jsx-runtime").JSX.Element;
|
|
67
68
|
export declare function SharedCheckoutSpecialOfferDialog({ buttonColor, buttonLabel, description, discountLabel, imageAlt, imageSrc, onAccept, themeColor, title, }: SharedCheckoutSpecialOfferDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -12,8 +12,10 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
12
12
|
};
|
|
13
13
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
14
14
|
import { useEffect, useMemo, useState, } from 'react';
|
|
15
|
+
import { Elements, PaymentElement as PaymentIntentPaymentElement, useElements, useStripe, } from '@stripe/react-stripe-js';
|
|
15
16
|
import { CheckoutProvider, PaymentElement, useCheckout, } from '@stripe/react-stripe-js/checkout';
|
|
16
17
|
import { PaymentBrandMark, SecurityLockIcon } from './CheckoutBrandAssets.js';
|
|
18
|
+
import { StripeExpressCheckoutButton } from './StripeExpressCheckoutButton.js';
|
|
17
19
|
import { StripeCheckoutExpressCheckoutButton } from './StripeCheckoutExpressCheckoutButton.js';
|
|
18
20
|
import { getUnsupportedCheckoutCountryMessage, normalizeSupportedCheckoutCountries, } from './checkoutCountries.js';
|
|
19
21
|
import { isInactiveCheckoutSessionError } from '../../providers/stripe/useStripeSubscriptionCheckoutSession.js';
|
|
@@ -59,7 +61,24 @@ function getFriendlyCardErrorMessage(error) {
|
|
|
59
61
|
? error.message
|
|
60
62
|
: 'Payment failed. Please review your card details and try again.';
|
|
61
63
|
}
|
|
62
|
-
|
|
64
|
+
const normalizeBillingName = (input) => {
|
|
65
|
+
var _a, _b, _c;
|
|
66
|
+
const normalizedName = (_a = input.name) === null || _a === void 0 ? void 0 : _a.trim();
|
|
67
|
+
if (normalizedName) {
|
|
68
|
+
return normalizedName;
|
|
69
|
+
}
|
|
70
|
+
const normalizedEmail = (_b = input.email) === null || _b === void 0 ? void 0 : _b.trim();
|
|
71
|
+
if (normalizedEmail) {
|
|
72
|
+
const localPart = (_c = normalizedEmail
|
|
73
|
+
.split('@')[0]) === null || _c === void 0 ? void 0 : _c.replace(/[._-]+/g, ' ').trim();
|
|
74
|
+
if (localPart) {
|
|
75
|
+
return localPart;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return 'Customer';
|
|
79
|
+
};
|
|
80
|
+
const isSuccessfulIntentStatus = (status) => status === 'succeeded' || status === 'processing' || status === 'requires_capture';
|
|
81
|
+
function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, cardSubmitLabel, closeAriaLabel, countdownLabel, checkoutAnalytics, checkoutSessionId, customerEmail, customerEmailEditable = false, customerEmailLabel = 'Email', customerEmailPlaceholder = 'Enter your email', customerEmailInvalidMessage = 'Enter a valid email address.', customerName, discountAmountLabel, discountLabel, discountPercent, initialWalletAvailable, onClose, onCustomerEmailChange, onCustomerEmailCommit, onError, onInactiveCheckoutSession, onPaymentInfoSubmitted, onSuccess, paymentMethodLabels = defaultPaymentMethodLabels, promoActive, processingLabel, promoCode, promoCodeLabel, remainingSeconds, returnUrl, savedLabel, secureLabel, satisfactionLabel, satisfactionPercent, summaryLabel, supportedCountries, themeColor, title, totalLabel, totalValue, unsupportedCountryMessage, walletButtonLabel, originalPriceLabel, originalPriceValue, }) {
|
|
63
82
|
const checkoutState = useCheckout();
|
|
64
83
|
const walletPaymentMethods = usePlatformWalletPaymentMethods();
|
|
65
84
|
const [selectedMethod, setSelectedMethod] = useState('wallet');
|
|
@@ -306,10 +325,272 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
306
325
|
onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(event.target.value);
|
|
307
326
|
} }) })] }), _jsx(PaymentElement, { options: paymentElementOptions, onChange: handlePaymentElementChange }), fixedBillingCountry && fixedBillingCountryLabel ? (_jsxs("label", { className: 'shared-checkout-v2-country-field', children: [_jsx("span", { className: 'shared-checkout-v2-country-label', children: "Country" }), _jsx("span", { className: 'shared-checkout-v2-country-control', children: _jsx("select", { "aria-label": 'Country', className: 'shared-checkout-v2-country-select', value: fixedBillingCountry, onChange: () => setBillingCountry(fixedBillingCountry), children: _jsx("option", { value: fixedBillingCountry, children: fixedBillingCountryLabel }) }) })] })) : null] }), visibleError ? _jsx("p", { className: 'shared-checkout-v2-error', children: visibleError }) : null, _jsxs("button", { type: 'submit', className: 'shared-checkout-v2-card-submit', disabled: submitting, children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-card-submit-icon' }), submitting ? processingLabel : cardSubmitLabel] }), _jsx("div", { className: 'shared-checkout-v2-card-brands', "aria-hidden": 'true', children: cardBrandLabels.map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'shared-checkout-v2-card-brand' }, label))) }), _jsxs("p", { className: 'shared-checkout-v2-secure-pill shared-checkout-v2-secure-pill--card', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] })] })] })] }));
|
|
308
327
|
}
|
|
309
|
-
|
|
310
|
-
|
|
328
|
+
function SharedStripeCheckoutV2PaymentIntentForm({ amountCents, buttonColor, cardSubmitLabel, closeAriaLabel, countdownLabel, customerEmail, customerEmailEditable = false, customerEmailLabel = 'Email', customerEmailPlaceholder = 'Enter your email', customerEmailInvalidMessage = 'Enter a valid email address.', customerName, discountAmountLabel, discountLabel, discountPercent, initialWalletAvailable, onClose, onCustomerEmailChange, onCustomerEmailCommit, onError, onPaymentInfoSubmitted, onSuccess, paymentMethodLabels = defaultPaymentMethodLabels, promoActive, processingLabel, promoCode, promoCodeLabel, remainingSeconds, returnUrl, savedLabel, secureLabel, satisfactionLabel, satisfactionPercent, summaryLabel, supportedCountries, themeColor, title, totalLabel, totalValue, unsupportedCountryMessage, walletButtonLabel, originalPriceLabel, originalPriceValue, }) {
|
|
329
|
+
const stripe = useStripe();
|
|
330
|
+
const elements = useElements();
|
|
331
|
+
const walletPaymentMethods = usePlatformWalletPaymentMethods();
|
|
332
|
+
const [selectedMethod, setSelectedMethod] = useState('wallet');
|
|
333
|
+
const [walletAvailable, setWalletAvailable] = useState(initialWalletAvailable !== null && initialWalletAvailable !== void 0 ? initialWalletAvailable : null);
|
|
334
|
+
const effectiveWalletAvailable = initialWalletAvailable === true && walletAvailable !== false
|
|
335
|
+
? true
|
|
336
|
+
: walletAvailable;
|
|
337
|
+
const [submitting, setSubmitting] = useState(false);
|
|
338
|
+
const [error, setError] = useState(null);
|
|
339
|
+
const [billingCountry, setBillingCountry] = useState(null);
|
|
340
|
+
const initialCustomerEmail = (customerEmail === null || customerEmail === void 0 ? void 0 : customerEmail.trim()) || '';
|
|
341
|
+
const [emailDraft, setEmailDraft] = useState(initialCustomerEmail);
|
|
311
342
|
const normalizedSupportedCountries = useMemo(() => normalizeSupportedCheckoutCountries(supportedCountries), [supportedCountries]);
|
|
312
343
|
const fixedBillingCountry = getFixedSupportedBillingCountry(normalizedSupportedCountries);
|
|
344
|
+
const fixedBillingCountryLabel = fixedBillingCountry
|
|
345
|
+
? getCheckoutCountryLabel(fixedBillingCountry)
|
|
346
|
+
: null;
|
|
347
|
+
const cardBrandLabels = useMemo(() => paymentMethodLabels.length > 0 ? paymentMethodLabels : defaultPaymentMethodLabels, [paymentMethodLabels]);
|
|
348
|
+
const normalizedPromoCode = promoCode.trim();
|
|
349
|
+
const showPromo = promoActive !== null && promoActive !== void 0 ? promoActive : (discountPercent > 0 && normalizedPromoCode.length > 0);
|
|
350
|
+
const countdownValue = formatCountdown(remainingSeconds);
|
|
351
|
+
const resolvedCustomerEmail = customerEmailEditable
|
|
352
|
+
? emailDraft.trim() || initialCustomerEmail
|
|
353
|
+
: initialCustomerEmail;
|
|
354
|
+
const emailFieldClassName = [
|
|
355
|
+
'shared-checkout-v2-email-field',
|
|
356
|
+
customerEmailEditable ? '' : 'is-disabled',
|
|
357
|
+
]
|
|
358
|
+
.filter(Boolean)
|
|
359
|
+
.join(' ');
|
|
360
|
+
const checkoutStyle = {
|
|
361
|
+
'--shared-checkout-v2-theme-color': themeColor,
|
|
362
|
+
'--shared-checkout-v2-button-color': buttonColor,
|
|
363
|
+
};
|
|
364
|
+
const expressCheckoutSummaryLabel = (summaryLabel === null || summaryLabel === void 0 ? void 0 : summaryLabel.trim()) || discountLabel || title;
|
|
365
|
+
const walletAriaLabel = walletPaymentMethods
|
|
366
|
+
.map((method) => method === 'applePay' ? walletButtonLabel : 'Google Pay')
|
|
367
|
+
.join(' / ');
|
|
368
|
+
const showWalletMethod = effectiveWalletAvailable !== false && walletPaymentMethods.length > 0;
|
|
369
|
+
const effectiveSelectedMethod = showWalletMethod && selectedMethod === 'wallet' ? 'wallet' : 'card';
|
|
370
|
+
const expressCheckoutOptions = useMemo(() => {
|
|
371
|
+
return {
|
|
372
|
+
buttonHeight: 55,
|
|
373
|
+
buttonTheme: {
|
|
374
|
+
applePay: 'black',
|
|
375
|
+
googlePay: 'black',
|
|
376
|
+
},
|
|
377
|
+
buttonType: {
|
|
378
|
+
applePay: 'buy',
|
|
379
|
+
googlePay: 'buy',
|
|
380
|
+
},
|
|
381
|
+
layout: {
|
|
382
|
+
maxColumns: 1,
|
|
383
|
+
maxRows: 2,
|
|
384
|
+
overflow: 'auto',
|
|
385
|
+
},
|
|
386
|
+
lineItems: [
|
|
387
|
+
{
|
|
388
|
+
name: expressCheckoutSummaryLabel,
|
|
389
|
+
amount: amountCents,
|
|
390
|
+
},
|
|
391
|
+
],
|
|
392
|
+
paymentMethodOrder: getStripeWalletPaymentMethodOrder(walletPaymentMethods),
|
|
393
|
+
paymentMethods: {
|
|
394
|
+
amazonPay: 'never',
|
|
395
|
+
applePay: walletPaymentMethods.includes('applePay') ? 'always' : 'never',
|
|
396
|
+
googlePay: walletPaymentMethods.includes('googlePay') ? 'always' : 'never',
|
|
397
|
+
klarna: 'never',
|
|
398
|
+
link: 'never',
|
|
399
|
+
paypal: 'never',
|
|
400
|
+
},
|
|
401
|
+
};
|
|
402
|
+
}, [amountCents, expressCheckoutSummaryLabel, walletPaymentMethods]);
|
|
403
|
+
const paymentElementOptions = useMemo(() => {
|
|
404
|
+
return Object.assign(Object.assign({ fields: {
|
|
405
|
+
billingDetails: {
|
|
406
|
+
name: 'never',
|
|
407
|
+
email: 'never',
|
|
408
|
+
address: {
|
|
409
|
+
country: fixedBillingCountry ? 'never' : 'auto',
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
} }, (fixedBillingCountry
|
|
413
|
+
? {
|
|
414
|
+
defaultValues: {
|
|
415
|
+
billingDetails: {
|
|
416
|
+
address: {
|
|
417
|
+
country: fixedBillingCountry,
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
}
|
|
422
|
+
: {})), { layout: 'tabs', wallets: {
|
|
423
|
+
applePay: 'never',
|
|
424
|
+
googlePay: 'never',
|
|
425
|
+
link: 'never',
|
|
426
|
+
} });
|
|
427
|
+
}, [fixedBillingCountry]);
|
|
428
|
+
const setSharedError = (message) => {
|
|
429
|
+
setError(message);
|
|
430
|
+
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
431
|
+
};
|
|
432
|
+
const selectWalletMethod = () => {
|
|
433
|
+
if (showWalletMethod) {
|
|
434
|
+
setSelectedMethod('wallet');
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
const selectCardMethod = () => setSelectedMethod('card');
|
|
438
|
+
const handleWalletAvailabilityChange = (available) => {
|
|
439
|
+
setWalletAvailable(available);
|
|
440
|
+
if (!available && selectedMethod === 'wallet') {
|
|
441
|
+
setSelectedMethod('card');
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
const getBillingCountryError = (country) => getUnsupportedCheckoutCountryMessage({
|
|
445
|
+
billingCountry: country,
|
|
446
|
+
message: unsupportedCountryMessage,
|
|
447
|
+
supportedCountries: normalizedSupportedCountries,
|
|
448
|
+
});
|
|
449
|
+
const handlePaymentElementChange = (event) => {
|
|
450
|
+
var _a, _b;
|
|
451
|
+
setBillingCountry((_b = (_a = event.value.billingDetails) === null || _a === void 0 ? void 0 : _a.address.country) !== null && _b !== void 0 ? _b : fixedBillingCountry);
|
|
452
|
+
};
|
|
453
|
+
const trackCheckoutSuccess = async () => {
|
|
454
|
+
await (onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess());
|
|
455
|
+
};
|
|
456
|
+
useEffect(() => {
|
|
457
|
+
if (effectiveSelectedMethod !== 'card' || typeof window === 'undefined') {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
const resizeTimer = window.setTimeout(() => {
|
|
461
|
+
window.dispatchEvent(new Event('resize'));
|
|
462
|
+
}, 0);
|
|
463
|
+
return () => window.clearTimeout(resizeTimer);
|
|
464
|
+
}, [effectiveSelectedMethod]);
|
|
465
|
+
const commitCustomerEmail = async (normalizedEmail) => {
|
|
466
|
+
if (!customerEmailEditable || !onCustomerEmailCommit) {
|
|
467
|
+
return normalizedEmail;
|
|
468
|
+
}
|
|
469
|
+
const committedEmail = await onCustomerEmailCommit(normalizedEmail);
|
|
470
|
+
const nextEmail = typeof committedEmail === 'string' && committedEmail.trim()
|
|
471
|
+
? committedEmail.trim()
|
|
472
|
+
: normalizedEmail;
|
|
473
|
+
setEmailDraft(nextEmail);
|
|
474
|
+
onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(nextEmail);
|
|
475
|
+
return nextEmail;
|
|
476
|
+
};
|
|
477
|
+
const commitEmailDraftIfValid = (value) => {
|
|
478
|
+
const normalizedEmail = value.trim();
|
|
479
|
+
if (!customerEmailEditable || !onCustomerEmailCommit) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
if (!normalizedEmail || !isValidEmail(normalizedEmail)) {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
void commitCustomerEmail(normalizedEmail).catch((commitError) => {
|
|
486
|
+
setSharedError(getFriendlyCardErrorMessage(commitError));
|
|
487
|
+
});
|
|
488
|
+
};
|
|
489
|
+
const ensureCustomerEmail = async () => {
|
|
490
|
+
const normalizedEmail = resolvedCustomerEmail.trim();
|
|
491
|
+
if (!normalizedEmail || !isValidEmail(normalizedEmail)) {
|
|
492
|
+
setSharedError(customerEmailInvalidMessage);
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
return commitCustomerEmail(normalizedEmail);
|
|
496
|
+
};
|
|
497
|
+
const handleSubmit = async (event) => {
|
|
498
|
+
var _a;
|
|
499
|
+
event.preventDefault();
|
|
500
|
+
if (!stripe || !elements || submitting) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const billingCountryError = getBillingCountryError(billingCountry !== null && billingCountry !== void 0 ? billingCountry : fixedBillingCountry);
|
|
504
|
+
if (billingCountryError) {
|
|
505
|
+
setSharedError(billingCountryError);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
setSubmitting(true);
|
|
509
|
+
setSharedError(null);
|
|
510
|
+
try {
|
|
511
|
+
const syncedEmail = await ensureCustomerEmail();
|
|
512
|
+
if (!syncedEmail) {
|
|
513
|
+
setSubmitting(false);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const submitResult = await elements.submit();
|
|
517
|
+
if (submitResult.error) {
|
|
518
|
+
setSharedError(submitResult.error.message || 'Payment form is not ready yet.');
|
|
519
|
+
setSubmitting(false);
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
await (onPaymentInfoSubmitted === null || onPaymentInfoSubmitted === void 0 ? void 0 : onPaymentInfoSubmitted());
|
|
523
|
+
const result = await stripe.confirmPayment({
|
|
524
|
+
elements,
|
|
525
|
+
confirmParams: {
|
|
526
|
+
payment_method_data: {
|
|
527
|
+
billing_details: {
|
|
528
|
+
email: syncedEmail || undefined,
|
|
529
|
+
name: normalizeBillingName({
|
|
530
|
+
email: syncedEmail,
|
|
531
|
+
name: customerName,
|
|
532
|
+
}),
|
|
533
|
+
},
|
|
534
|
+
},
|
|
535
|
+
return_url: returnUrl,
|
|
536
|
+
},
|
|
537
|
+
redirect: 'if_required',
|
|
538
|
+
});
|
|
539
|
+
if (result.error) {
|
|
540
|
+
const message = result.error.message || 'Payment failed.';
|
|
541
|
+
setSharedError(message);
|
|
542
|
+
setSubmitting(false);
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
if (typeof window !== 'undefined' &&
|
|
546
|
+
isSuccessfulIntentStatus((_a = result.paymentIntent) === null || _a === void 0 ? void 0 : _a.status)) {
|
|
547
|
+
await trackCheckoutSuccess();
|
|
548
|
+
window.location.assign(returnUrl);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
setSubmitting(false);
|
|
552
|
+
}
|
|
553
|
+
catch (submitError) {
|
|
554
|
+
setSharedError(getFriendlyCardErrorMessage(submitError));
|
|
555
|
+
setSubmitting(false);
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
const visibleError = error;
|
|
559
|
+
return (_jsxs("div", { className: 'shared-checkout-v2-shell', style: checkoutStyle, children: [_jsxs("header", { className: 'shared-checkout-v2-header', children: [_jsx("button", { type: 'button', className: 'shared-checkout-v2-close', onClick: onClose, "aria-label": closeAriaLabel, children: _jsx("span", { "aria-hidden": 'true' }) }), _jsx("h2", { id: 'shared-checkout-v2-title', children: title })] }), _jsxs("section", { className: 'shared-checkout-v2-summary', children: [showPromo ? (_jsxs("p", { className: 'shared-checkout-v2-countdown', children: [discountPercent, "% ", countdownLabel, " ", countdownValue, " min"] })) : null, _jsxs("p", { className: 'shared-checkout-v2-satisfaction', children: [_jsx("strong", { children: satisfactionPercent }), " ", satisfactionLabel] }), showPromo ? (_jsxs("div", { className: 'shared-checkout-v2-price-stack', children: [_jsxs("div", { className: 'shared-checkout-v2-price-row is-muted', children: [_jsx("span", { children: originalPriceLabel }), _jsx("span", { className: 'shared-checkout-v2-strike', children: originalPriceValue })] }), _jsxs("div", { className: 'shared-checkout-v2-price-row is-discount', children: [_jsx("strong", { children: discountLabel }), _jsx("strong", { children: discountAmountLabel })] }), _jsxs("div", { className: 'shared-checkout-v2-promo', children: [_jsx("span", { children: promoCodeLabel }), _jsx("strong", { children: normalizedPromoCode })] })] })) : null, _jsxs("div", { className: [
|
|
560
|
+
'shared-checkout-v2-total',
|
|
561
|
+
showPromo ? '' : 'is-plain',
|
|
562
|
+
]
|
|
563
|
+
.filter(Boolean)
|
|
564
|
+
.join(' '), children: [_jsx("span", { children: totalLabel }), _jsxs("strong", { children: [_jsx("svg", { viewBox: '0 0 24 24', "aria-hidden": 'true', children: _jsx("path", { d: 'M20.6 13.4 12.4 21.6a2.2 2.2 0 0 1-3.1 0L2.4 14.7a2.2 2.2 0 0 1-.6-1.6V5.4a2 2 0 0 1 2-2h7.7a2.2 2.2 0 0 1 1.6.6l7.5 7.5a1.4 1.4 0 0 1 0 1.9ZM7.2 8.1a1.2 1.2 0 1 0 0-2.4 1.2 1.2 0 0 0 0 2.4Z' }) }), totalValue] })] }), showPromo ? (_jsxs("p", { className: 'shared-checkout-v2-saved', children: [_jsx("span", { "aria-hidden": 'true', children: "\uD83D\uDD25" }), savedLabel] })) : null] }), _jsxs("form", { className: 'shared-checkout-v2-payment', onSubmit: (event) => void handleSubmit(event), children: [showWalletMethod ? (_jsxs("div", { className: 'shared-checkout-v2-methods', role: 'tablist', "aria-label": 'Payment method', children: [_jsxs("button", { type: 'button', className: [
|
|
565
|
+
'shared-checkout-v2-method',
|
|
566
|
+
effectiveSelectedMethod === 'wallet' ? 'is-selected' : '',
|
|
567
|
+
]
|
|
568
|
+
.filter(Boolean)
|
|
569
|
+
.join(' '), onClick: selectWalletMethod, role: 'tab', "aria-selected": effectiveSelectedMethod === 'wallet', children: [_jsxs("span", { className: 'shared-checkout-v2-tab-wallets', "aria-hidden": 'true', children: [walletPaymentMethods.includes('applePay') ? (_jsx(PaymentBrandMark, { label: 'Apple Pay', className: 'shared-checkout-v2-tab-wallet' })) : null, walletPaymentMethods.includes('googlePay') ? (_jsx(PaymentBrandMark, { label: 'Google Pay', className: 'shared-checkout-v2-tab-wallet' })) : null] }), _jsx("span", { className: 'shared-checkout-v2-sr-only', children: walletAriaLabel })] }), _jsxs("button", { type: 'button', className: [
|
|
570
|
+
'shared-checkout-v2-method',
|
|
571
|
+
effectiveSelectedMethod === 'card' ? 'is-selected' : '',
|
|
572
|
+
]
|
|
573
|
+
.filter(Boolean)
|
|
574
|
+
.join(' '), onClick: selectCardMethod, role: 'tab', "aria-selected": effectiveSelectedMethod === 'card', children: [_jsx("strong", { children: "Credit card" }), _jsx("span", { className: 'shared-checkout-v2-tab-brands', "aria-hidden": 'true', children: cardBrandLabels.slice(0, 4).map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'shared-checkout-v2-tab-brand' }, label))) })] })] })) : null, _jsxs("div", { hidden: effectiveSelectedMethod !== 'wallet', className: [
|
|
575
|
+
'shared-checkout-v2-wallet-panel',
|
|
576
|
+
effectiveSelectedMethod === 'wallet' ? 'is-visible' : '',
|
|
577
|
+
]
|
|
578
|
+
.filter(Boolean)
|
|
579
|
+
.join(' '), children: [_jsxs("p", { className: 'shared-checkout-v2-secure-pill', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] }), _jsxs("div", { className: 'shared-checkout-v2-wallet-shell', "aria-label": walletAriaLabel, children: [_jsx(StripeExpressCheckoutButton, { amountCents: amountCents, availabilityPaymentMethods: walletPaymentMethods, beforeConfirm: ensureCustomerEmail, className: 'shared-checkout-v2-express-buttons', customerEmail: resolvedCustomerEmail, customerName: customerName, initialAvailable: initialWalletAvailable, keepInitialAvailableOnReady: initialWalletAvailable === true, onAvailabilityChange: handleWalletAvailabilityChange, onError: setSharedError, onPaymentInfoSubmitted: onPaymentInfoSubmitted, onSuccess: trackCheckoutSuccess, options: expressCheckoutOptions, returnUrl: returnUrl, summaryLabel: expressCheckoutSummaryLabel }), _jsx("span", { className: 'shared-checkout-v2-sr-only', children: walletAriaLabel })] })] }), _jsxs("div", { hidden: effectiveSelectedMethod !== 'card', className: [
|
|
580
|
+
'shared-checkout-v2-card-panel',
|
|
581
|
+
effectiveSelectedMethod === 'card' ? 'is-visible' : '',
|
|
582
|
+
]
|
|
583
|
+
.filter(Boolean)
|
|
584
|
+
.join(' '), children: [_jsxs("div", { className: 'shared-checkout-v2-card-box', children: [_jsxs("label", { className: emailFieldClassName, children: [_jsx("span", { className: 'shared-checkout-v2-email-label', children: customerEmailLabel }), _jsx("span", { className: 'shared-checkout-v2-email-control', children: _jsx("input", { type: 'email', autoComplete: 'email', className: 'shared-checkout-v2-email-input', disabled: !customerEmailEditable, inputMode: 'email', readOnly: !customerEmailEditable, value: customerEmailEditable ? emailDraft : initialCustomerEmail, placeholder: customerEmailPlaceholder, onBlur: (event) => commitEmailDraftIfValid(event.currentTarget.value), onChange: (event) => {
|
|
585
|
+
if (!customerEmailEditable) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
setEmailDraft(event.target.value);
|
|
589
|
+
onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(event.target.value);
|
|
590
|
+
} }) })] }), _jsx(PaymentIntentPaymentElement, { options: paymentElementOptions, onChange: handlePaymentElementChange }), fixedBillingCountry && fixedBillingCountryLabel ? (_jsxs("label", { className: 'shared-checkout-v2-country-field', children: [_jsx("span", { className: 'shared-checkout-v2-country-label', children: "Country" }), _jsx("span", { className: 'shared-checkout-v2-country-control', children: _jsx("select", { "aria-label": 'Country', className: 'shared-checkout-v2-country-select', value: fixedBillingCountry, onChange: () => setBillingCountry(fixedBillingCountry), children: _jsx("option", { value: fixedBillingCountry, children: fixedBillingCountryLabel }) }) })] })) : null] }), visibleError ? _jsx("p", { className: 'shared-checkout-v2-error', children: visibleError }) : null, _jsxs("button", { type: 'submit', className: 'shared-checkout-v2-card-submit', disabled: submitting, children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-card-submit-icon' }), submitting ? processingLabel : cardSubmitLabel] }), _jsx("div", { className: 'shared-checkout-v2-card-brands', "aria-hidden": 'true', children: cardBrandLabels.map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'shared-checkout-v2-card-brand' }, label))) }), _jsxs("p", { className: 'shared-checkout-v2-secure-pill shared-checkout-v2-secure-pill--card', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] })] })] })] }));
|
|
591
|
+
}
|
|
592
|
+
function CheckoutSessionProvider({ children, clientSecret, fixedBillingCountry, stripePromise, }) {
|
|
593
|
+
const providerChildren = children;
|
|
313
594
|
const checkoutProviderOptions = useMemo(() => (Object.assign(Object.assign({ clientSecret }, (fixedBillingCountry
|
|
314
595
|
? {
|
|
315
596
|
defaultValues: {
|
|
@@ -323,12 +604,26 @@ export function SharedStripeCheckoutV2Dialog(_a) {
|
|
|
323
604
|
: {})), { elementsOptions: {
|
|
324
605
|
appearance: stripeCheckoutV2Appearance,
|
|
325
606
|
} })), [clientSecret, fixedBillingCountry]);
|
|
607
|
+
return (_jsx(CheckoutProvider, { stripe: stripePromise, options: checkoutProviderOptions, children: providerChildren }, clientSecret));
|
|
608
|
+
}
|
|
609
|
+
function PaymentIntentProvider({ children, clientSecret, stripePromise, }) {
|
|
610
|
+
const providerChildren = children;
|
|
611
|
+
const elementsOptions = useMemo(() => ({
|
|
612
|
+
clientSecret,
|
|
613
|
+
appearance: stripeCheckoutV2Appearance,
|
|
614
|
+
}), [clientSecret]);
|
|
615
|
+
return (_jsx(Elements, { stripe: stripePromise, options: elementsOptions, children: providerChildren }, clientSecret));
|
|
616
|
+
}
|
|
617
|
+
export function SharedStripeCheckoutV2Dialog(_a) {
|
|
618
|
+
var { checkoutAnalytics, checkoutMode = 'checkout_session', checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries } = _a, props = __rest(_a, ["checkoutAnalytics", "checkoutMode", "checkoutSessionId", "clientSecret", "onClose", "stripePromise", "supportedCountries"]);
|
|
619
|
+
const normalizedSupportedCountries = useMemo(() => normalizeSupportedCheckoutCountries(supportedCountries), [supportedCountries]);
|
|
620
|
+
const fixedBillingCountry = getFixedSupportedBillingCountry(normalizedSupportedCountries);
|
|
326
621
|
useEffect(() => {
|
|
327
|
-
if (!checkoutAnalytics) {
|
|
622
|
+
if (checkoutMode !== 'checkout_session' || !checkoutAnalytics) {
|
|
328
623
|
return;
|
|
329
624
|
}
|
|
330
625
|
void trackStripeSubscriptionCheckoutStarted(Object.assign({ checkoutSessionId }, checkoutAnalytics));
|
|
331
|
-
}, [checkoutAnalytics, checkoutSessionId, clientSecret]);
|
|
626
|
+
}, [checkoutAnalytics, checkoutMode, checkoutSessionId, clientSecret]);
|
|
332
627
|
useEffect(() => {
|
|
333
628
|
const handleKeyDown = (event) => {
|
|
334
629
|
if (event.key === 'Escape') {
|
|
@@ -338,7 +633,7 @@ export function SharedStripeCheckoutV2Dialog(_a) {
|
|
|
338
633
|
window.addEventListener('keydown', handleKeyDown);
|
|
339
634
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
340
635
|
}, [onClose]);
|
|
341
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { className: 'shared-checkout-v2-overlay', children: _jsx("div", { className: 'shared-checkout-v2-dialog', role: 'dialog', "aria-modal": 'true', "aria-labelledby": 'shared-checkout-v2-title', children: _jsx(
|
|
636
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: 'shared-checkout-v2-overlay', children: _jsx("div", { className: 'shared-checkout-v2-dialog', role: 'dialog', "aria-modal": 'true', "aria-labelledby": 'shared-checkout-v2-title', children: checkoutMode === 'payment_intent' ? (_jsx(PaymentIntentProvider, { clientSecret: clientSecret, stripePromise: stripePromise, children: _jsx(SharedStripeCheckoutV2PaymentIntentForm, Object.assign({}, props, { clientSecret: clientSecret, onClose: onClose, supportedCountries: normalizedSupportedCountries })) })) : (_jsx(CheckoutSessionProvider, { clientSecret: clientSecret, fixedBillingCountry: fixedBillingCountry, stripePromise: stripePromise, children: _jsx(SharedStripeCheckoutV2CheckoutSessionForm, Object.assign({}, props, { checkoutAnalytics: checkoutAnalytics, checkoutSessionId: checkoutSessionId, clientSecret: clientSecret, onClose: onClose, supportedCountries: normalizedSupportedCountries })) })) }) }), _jsx("style", { children: sharedStripeCheckoutV2Styles })] }));
|
|
342
637
|
}
|
|
343
638
|
function SharedCheckoutSpecialOfferGift({ discountLabel, imageAlt, imageSrc, }) {
|
|
344
639
|
if (imageSrc) {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { StripeCheckoutExpressCheckoutElementOptions } from '@stripe/stripe-js';
|
|
1
2
|
import { type WalletSubscriptionCheckoutSlotProps } from './WalletSubscriptionCheckoutSlot.js';
|
|
2
|
-
export type ApplePaySubscriptionCheckoutSlotProps = Omit<WalletSubscriptionCheckoutSlotProps, 'availabilityPaymentMethod' | 'expressCheckoutAllowed' | 'placeholderLabel' | 'renderPlaceholder' | 'renderPreparingPlaceholder'> & {
|
|
3
|
+
export type ApplePaySubscriptionCheckoutSlotProps = Omit<WalletSubscriptionCheckoutSlotProps, 'availabilityPaymentMethod' | 'expressCheckoutAllowed' | 'options' | 'placeholderLabel' | 'renderPlaceholder' | 'renderPreparingPlaceholder'> & {
|
|
4
|
+
options?: Partial<StripeCheckoutExpressCheckoutElementOptions>;
|
|
3
5
|
placeholderLabel?: string;
|
|
4
6
|
};
|
|
5
|
-
export declare function ApplePaySubscriptionCheckoutSlot({ placeholderLabel, ...slotProps }: ApplePaySubscriptionCheckoutSlotProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare function ApplePaySubscriptionCheckoutSlot({ options, placeholderLabel, ...slotProps }: ApplePaySubscriptionCheckoutSlotProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -13,7 +13,31 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
13
13
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
14
|
import { ApplePaySubscribeButton } from '../../components/shared/ApplePaySubscribeButton.js';
|
|
15
15
|
import { WalletSubscriptionCheckoutLoadingPlaceholder, WalletSubscriptionCheckoutSlot, } from './WalletSubscriptionCheckoutSlot.js';
|
|
16
|
+
const applePayExpressCheckoutOptions = {
|
|
17
|
+
buttonHeight: 55,
|
|
18
|
+
buttonTheme: {
|
|
19
|
+
applePay: 'black',
|
|
20
|
+
},
|
|
21
|
+
buttonType: {
|
|
22
|
+
applePay: 'subscribe',
|
|
23
|
+
},
|
|
24
|
+
layout: {
|
|
25
|
+
maxColumns: 1,
|
|
26
|
+
maxRows: 1,
|
|
27
|
+
overflow: 'auto',
|
|
28
|
+
},
|
|
29
|
+
paymentMethodOrder: ['apple_pay'],
|
|
30
|
+
paymentMethods: {
|
|
31
|
+
amazonPay: 'never',
|
|
32
|
+
applePay: 'always',
|
|
33
|
+
googlePay: 'never',
|
|
34
|
+
klarna: 'never',
|
|
35
|
+
link: 'never',
|
|
36
|
+
paypal: 'never',
|
|
37
|
+
},
|
|
38
|
+
};
|
|
16
39
|
export function ApplePaySubscriptionCheckoutSlot(_a) {
|
|
17
|
-
var
|
|
18
|
-
|
|
40
|
+
var _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
41
|
+
var { options, placeholderLabel = 'Subscribe with Apple Pay' } = _a, slotProps = __rest(_a, ["options", "placeholderLabel"]);
|
|
42
|
+
return (_jsx(WalletSubscriptionCheckoutSlot, Object.assign({}, slotProps, { availabilityPaymentMethod: 'applePay', options: Object.assign(Object.assign(Object.assign({}, applePayExpressCheckoutOptions), (options !== null && options !== void 0 ? options : {})), { buttonTheme: Object.assign(Object.assign({}, ((_b = applePayExpressCheckoutOptions.buttonTheme) !== null && _b !== void 0 ? _b : {})), ((_c = options === null || options === void 0 ? void 0 : options.buttonTheme) !== null && _c !== void 0 ? _c : {})), buttonType: Object.assign(Object.assign({}, ((_d = applePayExpressCheckoutOptions.buttonType) !== null && _d !== void 0 ? _d : {})), ((_e = options === null || options === void 0 ? void 0 : options.buttonType) !== null && _e !== void 0 ? _e : {})), layout: Object.assign(Object.assign({}, ((_f = applePayExpressCheckoutOptions.layout) !== null && _f !== void 0 ? _f : {})), ((_g = options === null || options === void 0 ? void 0 : options.layout) !== null && _g !== void 0 ? _g : {})), paymentMethods: Object.assign(Object.assign({}, ((_h = applePayExpressCheckoutOptions.paymentMethods) !== null && _h !== void 0 ? _h : {})), ((_j = options === null || options === void 0 ? void 0 : options.paymentMethods) !== null && _j !== void 0 ? _j : {})), paymentMethodOrder: (_k = options === null || options === void 0 ? void 0 : options.paymentMethodOrder) !== null && _k !== void 0 ? _k : applePayExpressCheckoutOptions.paymentMethodOrder }), placeholderLabel: placeholderLabel, renderPreparingPlaceholder: (placeholderProps) => (_jsx(WalletSubscriptionCheckoutLoadingPlaceholder, Object.assign({}, placeholderProps, { label: 'Loading Apple Pay' }))), renderPlaceholder: (placeholderProps) => (_jsx(ApplePaySubscribeButton, Object.assign({}, placeholderProps))) })));
|
|
19
43
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
-
import type { AvailablePaymentMethods, StripeCheckoutExpressCheckoutElementOptions } from '@stripe/stripe-js';
|
|
3
|
-
import type
|
|
2
|
+
import type { Appearance, AvailablePaymentMethods, StripeCheckoutExpressCheckoutElementOptions } from '@stripe/stripe-js';
|
|
3
|
+
import { type StripeSubscriptionCheckoutAnalyticsContext } from '../../services/checkoutCompletionAnalytics.service.js';
|
|
4
4
|
import { type StripeSubscriptionCheckoutSession } from './useStripeSubscriptionCheckoutSession.js';
|
|
5
5
|
export type WalletSubscriptionCheckoutRenderStateInput = {
|
|
6
6
|
expressCheckoutAllowed: boolean;
|
|
@@ -27,6 +27,7 @@ export type WalletSubscriptionCheckoutSlotProps = {
|
|
|
27
27
|
availabilityPaymentMethod: keyof AvailablePaymentMethods;
|
|
28
28
|
beforeConfirm?: () => Promise<string | null>;
|
|
29
29
|
checkoutAnalytics?: StripeSubscriptionCheckoutAnalyticsContext | null;
|
|
30
|
+
appearance?: Appearance;
|
|
30
31
|
className?: string;
|
|
31
32
|
customerEmail?: string | null;
|
|
32
33
|
customerName?: string | null;
|
|
@@ -44,9 +45,10 @@ export type WalletSubscriptionCheckoutSlotProps = {
|
|
|
44
45
|
renderPlaceholder: (props: WalletPlaceholderButtonProps) => ReactNode;
|
|
45
46
|
returnUrl: string;
|
|
46
47
|
session: StripeSubscriptionCheckoutSession;
|
|
48
|
+
slotClassName?: string;
|
|
47
49
|
summaryLabel: string;
|
|
48
50
|
suspended?: boolean;
|
|
49
51
|
};
|
|
50
52
|
export declare function WalletSubscriptionCheckoutLoadingPlaceholder({ className, label, }: Pick<WalletPlaceholderButtonProps, 'className' | 'label'>): import("react/jsx-runtime").JSX.Element;
|
|
51
|
-
export declare function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymentMethod, beforeConfirm, checkoutAnalytics, className, customerEmail, customerName, disabled, expressCheckoutAllowed, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, onUnavailableClick, options, placeholderLabel, renderPreparingPlaceholder, renderPlaceholder, returnUrl, session, summaryLabel, suspended, }: WalletSubscriptionCheckoutSlotProps): import("react/jsx-runtime").JSX.Element;
|
|
53
|
+
export declare function WalletSubscriptionCheckoutSlot({ amountCents, appearance, availabilityPaymentMethod, beforeConfirm, checkoutAnalytics, className, customerEmail, customerName, disabled, expressCheckoutAllowed, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, onUnavailableClick, options, placeholderLabel, renderPreparingPlaceholder, renderPlaceholder, returnUrl, session, slotClassName, summaryLabel, suspended, }: WalletSubscriptionCheckoutSlotProps): import("react/jsx-runtime").JSX.Element;
|
|
52
54
|
export {};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
4
|
import { StripeExpressCheckoutElement } from '../../components/shared/StripeExpressCheckoutElement.js';
|
|
5
|
+
import { trackStripeSubscriptionCheckoutStarted, } from '../../services/checkoutCompletionAnalytics.service.js';
|
|
5
6
|
import { isInactiveCheckoutSessionError, } from './useStripeSubscriptionCheckoutSession.js';
|
|
6
7
|
export function getWalletSubscriptionCheckoutRenderState({ expressCheckoutAllowed, hasActiveClientSecret, hasStripePromise, suspended, walletAvailable, walletPreparing, }) {
|
|
7
8
|
const shouldRenderExpressCheckout = !suspended &&
|
|
@@ -27,12 +28,14 @@ export function WalletSubscriptionCheckoutLoadingPlaceholder({ className, label,
|
|
|
27
28
|
.filter(Boolean)
|
|
28
29
|
.join(' '), "aria-label": label, role: 'status', children: [_jsx("span", { className: 'wallet-subscription-checkout-slot__loading-bar' }), _jsx("style", { children: walletSubscriptionCheckoutLoadingPlaceholderStyles })] }));
|
|
29
30
|
}
|
|
30
|
-
export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymentMethod, beforeConfirm, checkoutAnalytics, className, customerEmail, customerName, disabled = false, expressCheckoutAllowed = true, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, onUnavailableClick, options, placeholderLabel, renderPreparingPlaceholder, renderPlaceholder, returnUrl, session, summaryLabel, suspended = false, }) {
|
|
31
|
+
export function WalletSubscriptionCheckoutSlot({ amountCents, appearance, availabilityPaymentMethod, beforeConfirm, checkoutAnalytics, className, customerEmail, customerName, disabled = false, expressCheckoutAllowed = true, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, onUnavailableClick, options, placeholderLabel, renderPreparingPlaceholder, renderPlaceholder, returnUrl, session, slotClassName, summaryLabel, suspended = false, }) {
|
|
31
32
|
const [walletAvailability, setWalletAvailability] = useState({
|
|
32
33
|
available: null,
|
|
33
34
|
intentKey: session.intentKey,
|
|
34
35
|
});
|
|
35
|
-
const
|
|
36
|
+
const [walletCheckoutStartedAfterClickIntentKey, setWalletCheckoutStartedAfterClickIntentKey] = useState(null);
|
|
37
|
+
const autoWalletPreparationIntentKeyRef = useRef(null);
|
|
38
|
+
const walletCheckoutStartedAfterClickSessionIdRef = useRef(null);
|
|
36
39
|
const slotDisabled = disabled || !session.configured;
|
|
37
40
|
const walletAvailable = walletAvailability.intentKey === session.intentKey
|
|
38
41
|
? walletAvailability.available
|
|
@@ -70,35 +73,61 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
70
73
|
suspended ||
|
|
71
74
|
!expressCheckoutAllowed ||
|
|
72
75
|
walletAvailable === false ||
|
|
76
|
+
session.loading.wallet ||
|
|
73
77
|
session.activeClientSecret) {
|
|
74
78
|
return;
|
|
75
79
|
}
|
|
76
|
-
|
|
77
|
-
if (autoWalletAttemptedIntentKeyRef.current === requestKey) {
|
|
80
|
+
if (autoWalletPreparationIntentKeyRef.current === session.intentKey) {
|
|
78
81
|
return;
|
|
79
82
|
}
|
|
80
|
-
|
|
81
|
-
void
|
|
82
|
-
|
|
83
|
+
autoWalletPreparationIntentKeyRef.current = session.intentKey;
|
|
84
|
+
void session
|
|
85
|
+
.prepareWalletCheckout({
|
|
86
|
+
checkoutStartSource: 'wallet_render',
|
|
87
|
+
})
|
|
88
|
+
.then((readyClientSecret) => {
|
|
83
89
|
if (!readyClientSecret) {
|
|
84
|
-
reportWalletPreparationFailure(
|
|
90
|
+
reportWalletPreparationFailure(session.intentKey);
|
|
85
91
|
}
|
|
86
|
-
})
|
|
92
|
+
});
|
|
87
93
|
}, [
|
|
88
94
|
expressCheckoutAllowed,
|
|
89
95
|
reportWalletPreparationFailure,
|
|
90
|
-
session,
|
|
96
|
+
session.activeClientSecret,
|
|
97
|
+
session.intentKey,
|
|
98
|
+
session.loading.wallet,
|
|
99
|
+
session.prepareWalletCheckout,
|
|
91
100
|
slotDisabled,
|
|
92
101
|
suspended,
|
|
93
102
|
walletAvailable,
|
|
94
103
|
]);
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!walletCheckoutStartedAfterClickIntentKey ||
|
|
106
|
+
walletCheckoutStartedAfterClickIntentKey !== session.intentKey ||
|
|
107
|
+
!session.checkoutSessionId) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (!checkoutAnalytics ||
|
|
111
|
+
walletCheckoutStartedAfterClickSessionIdRef.current === session.checkoutSessionId) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
walletCheckoutStartedAfterClickSessionIdRef.current = session.checkoutSessionId;
|
|
115
|
+
void trackStripeSubscriptionCheckoutStarted(Object.assign({ checkoutSessionId: session.checkoutSessionId }, checkoutAnalytics));
|
|
116
|
+
}, [
|
|
117
|
+
checkoutAnalytics,
|
|
118
|
+
session.checkoutSessionId,
|
|
119
|
+
session.intentKey,
|
|
120
|
+
walletCheckoutStartedAfterClickIntentKey,
|
|
121
|
+
]);
|
|
95
122
|
const handleError = (message) => {
|
|
96
123
|
if (isInactiveCheckoutSessionError(message)) {
|
|
97
124
|
setWalletAvailability({
|
|
98
125
|
available: null,
|
|
99
126
|
intentKey: session.intentKey,
|
|
100
127
|
});
|
|
101
|
-
void session.restartWalletCheckout(
|
|
128
|
+
void session.restartWalletCheckout({
|
|
129
|
+
checkoutStartSource: 'wallet_render',
|
|
130
|
+
});
|
|
102
131
|
return;
|
|
103
132
|
}
|
|
104
133
|
session.setError(message);
|
|
@@ -115,8 +144,12 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
115
144
|
await (onUnavailableClick === null || onUnavailableClick === void 0 ? void 0 : onUnavailableClick());
|
|
116
145
|
return;
|
|
117
146
|
}
|
|
118
|
-
|
|
147
|
+
setWalletCheckoutStartedAfterClickIntentKey(session.intentKey);
|
|
148
|
+
const readyClientSecret = await session.prepareWalletCheckout({
|
|
149
|
+
checkoutStartSource: 'wallet_render',
|
|
150
|
+
});
|
|
119
151
|
if (!readyClientSecret) {
|
|
152
|
+
setWalletCheckoutStartedAfterClickIntentKey(null);
|
|
120
153
|
reportWalletPreparationFailure(session.intentKey);
|
|
121
154
|
}
|
|
122
155
|
};
|
|
@@ -125,13 +158,14 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
125
158
|
: renderPlaceholder;
|
|
126
159
|
return (_jsxs(_Fragment, { children: [shouldRenderPlaceholder || shouldRenderExpressCheckout ? (_jsxs("div", { className: [
|
|
127
160
|
'wallet-subscription-checkout-slot',
|
|
161
|
+
slotClassName !== null && slotClassName !== void 0 ? slotClassName : '',
|
|
128
162
|
placeholderIsPreparing ? 'is-loading' : '',
|
|
129
163
|
shouldRenderExpressCheckout ? 'has-express-checkout' : '',
|
|
130
164
|
]
|
|
131
165
|
.filter(Boolean)
|
|
132
166
|
.join(' '), "aria-busy": placeholderIsPreparing || undefined, children: [shouldRenderExpressCheckout &&
|
|
133
167
|
session.activeClientSecret &&
|
|
134
|
-
session.stripePromise ? (_jsx(StripeExpressCheckoutElement, { amountCents: amountCents, availabilityPaymentMethods: [availabilityPaymentMethod], beforeConfirm: beforeConfirm, checkoutAnalytics: checkoutAnalytics, checkoutSessionId: session.checkoutSessionId, className: className, clientSecret: session.activeClientSecret, customerEmail: customerEmail, customerName: customerName, onAvailabilityChange: handleAvailabilityChange, onCancel: onCancel, onError: handleError, onPaymentInfoSubmitted: onPaymentInfoSubmitted, onSuccess: onSuccess, options: options, returnUrl: returnUrl, serverUpdateKey: serverUpdateKey, stripePromise: session.stripePromise, summaryLabel: summaryLabel, onServerUpdate: session.updateCheckoutSessionPlan })) : null, shouldRenderPlaceholder ? (_jsx("div", { className: 'wallet-subscription-checkout-slot__placeholder', children: placeholderRenderer({
|
|
168
|
+
session.stripePromise ? (_jsx(StripeExpressCheckoutElement, { amountCents: amountCents, appearance: appearance, availabilityPaymentMethods: [availabilityPaymentMethod], beforeConfirm: beforeConfirm, checkoutAnalytics: checkoutAnalytics, checkoutSessionId: session.checkoutSessionId, className: className, clientSecret: session.activeClientSecret, customerEmail: customerEmail, customerName: customerName, onAvailabilityChange: handleAvailabilityChange, onCancel: onCancel, onError: handleError, onPaymentInfoSubmitted: onPaymentInfoSubmitted, onSuccess: onSuccess, options: options, returnUrl: returnUrl, serverUpdateKey: serverUpdateKey, stripePromise: session.stripePromise, summaryLabel: summaryLabel, onServerUpdate: session.updateCheckoutSessionPlan })) : null, shouldRenderPlaceholder ? (_jsx("div", { className: 'wallet-subscription-checkout-slot__placeholder', children: placeholderRenderer({
|
|
135
169
|
className,
|
|
136
170
|
disabled: slotDisabled,
|
|
137
171
|
label: placeholderLabel,
|
|
@@ -16,6 +16,10 @@ export type StripeSubscriptionCheckoutSessionInput = {
|
|
|
16
16
|
runtimeConfig?: StripeRuntimeConfigOverrides;
|
|
17
17
|
userId?: string | null;
|
|
18
18
|
};
|
|
19
|
+
export type StripeSubscriptionCheckoutPreparationOptions = {
|
|
20
|
+
checkoutStartSource?: 'card_click' | 'wallet_click' | 'wallet_render' | (string & {});
|
|
21
|
+
forceNew?: boolean;
|
|
22
|
+
};
|
|
19
23
|
export type StripeSubscriptionCheckoutSession = {
|
|
20
24
|
activeClientSecret: string | null;
|
|
21
25
|
activePlanKey: string | null;
|
|
@@ -24,12 +28,12 @@ export type StripeSubscriptionCheckoutSession = {
|
|
|
24
28
|
error: string | null;
|
|
25
29
|
intentKey: string;
|
|
26
30
|
loading: CheckoutPreparationLoading;
|
|
27
|
-
prepareCardCheckout: () => Promise<string | null>;
|
|
28
|
-
prepareWalletCheckout: () => Promise<string | null>;
|
|
31
|
+
prepareCardCheckout: (options?: StripeSubscriptionCheckoutPreparationOptions) => Promise<string | null>;
|
|
32
|
+
prepareWalletCheckout: (options?: StripeSubscriptionCheckoutPreparationOptions) => Promise<string | null>;
|
|
29
33
|
provider: 'stripe';
|
|
30
34
|
reset: () => void;
|
|
31
|
-
restartCardCheckout: () => Promise<string | null>;
|
|
32
|
-
restartWalletCheckout: () => Promise<string | null>;
|
|
35
|
+
restartCardCheckout: (options?: StripeSubscriptionCheckoutPreparationOptions) => Promise<string | null>;
|
|
36
|
+
restartWalletCheckout: (options?: StripeSubscriptionCheckoutPreparationOptions) => Promise<string | null>;
|
|
33
37
|
planKey: string;
|
|
34
38
|
setError: (message: string | null) => void;
|
|
35
39
|
stripePromise: Promise<Stripe | null> | null;
|
|
@@ -10,6 +10,14 @@ const getFriendlyStripeCheckoutError = (error) => {
|
|
|
10
10
|
};
|
|
11
11
|
const normalizeRuntimeConfigValue = (value) => (value === null || value === void 0 ? void 0 : value.trim()) || '';
|
|
12
12
|
const useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
|
|
13
|
+
const buildCheckoutPreparationAnalyticsMetadata = (analyticsMetadata, options = {}) => {
|
|
14
|
+
var _a;
|
|
15
|
+
const checkoutStartSource = (_a = options.checkoutStartSource) === null || _a === void 0 ? void 0 : _a.trim();
|
|
16
|
+
if (!checkoutStartSource) {
|
|
17
|
+
return analyticsMetadata;
|
|
18
|
+
}
|
|
19
|
+
return Object.assign(Object.assign({}, (analyticsMetadata !== null && analyticsMetadata !== void 0 ? analyticsMetadata : {})), { checkoutStartSource });
|
|
20
|
+
};
|
|
13
21
|
export function buildStripeSubscriptionCheckoutIntentKey({ checkoutMode, couponId, customerEmail, returnUrl, runtimeConfig, userId, }) {
|
|
14
22
|
const runtimeConfigSignature = [
|
|
15
23
|
normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.apiBaseUrl),
|
|
@@ -110,8 +118,9 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
110
118
|
? current
|
|
111
119
|
: Object.assign(Object.assign({}, current), { [source]: value }));
|
|
112
120
|
}, []);
|
|
113
|
-
const createCheckoutSubscription = useCallback(async (
|
|
121
|
+
const createCheckoutSubscription = useCallback(async (options = {}) => {
|
|
114
122
|
var _a;
|
|
123
|
+
const forceNew = options.forceNew === true;
|
|
115
124
|
if (!configured || !plan || !displayPlan) {
|
|
116
125
|
return null;
|
|
117
126
|
}
|
|
@@ -133,7 +142,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
133
142
|
try {
|
|
134
143
|
const response = await createStripeSubscriptionCheckout({
|
|
135
144
|
plan,
|
|
136
|
-
analyticsMetadata: analyticsMetadataRef.current,
|
|
145
|
+
analyticsMetadata: buildCheckoutPreparationAnalyticsMetadata(analyticsMetadataRef.current, options),
|
|
137
146
|
couponId,
|
|
138
147
|
customerEmail,
|
|
139
148
|
returnUrl,
|
|
@@ -192,6 +201,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
192
201
|
userId,
|
|
193
202
|
]);
|
|
194
203
|
const prepareCheckout = useCallback(async (source, options = {}) => {
|
|
204
|
+
var _a;
|
|
195
205
|
if (!configured || !plan || !displayPlan) {
|
|
196
206
|
return null;
|
|
197
207
|
}
|
|
@@ -201,7 +211,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
201
211
|
setSourceLoading(source, true);
|
|
202
212
|
setError(null);
|
|
203
213
|
try {
|
|
204
|
-
return await createCheckoutSubscription(options.
|
|
214
|
+
return await createCheckoutSubscription(Object.assign(Object.assign({}, options), { checkoutStartSource: (_a = options.checkoutStartSource) !== null && _a !== void 0 ? _a : (source === 'wallet' ? 'wallet_render' : 'card_click') }));
|
|
205
215
|
}
|
|
206
216
|
finally {
|
|
207
217
|
setSourceLoading(source, false);
|
|
@@ -215,10 +225,10 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
215
225
|
setError,
|
|
216
226
|
setSourceLoading,
|
|
217
227
|
]);
|
|
218
|
-
const prepareCardCheckout = useCallback(() => prepareCheckout('card'), [prepareCheckout]);
|
|
219
|
-
const prepareWalletCheckout = useCallback(() => prepareCheckout('wallet'), [prepareCheckout]);
|
|
220
|
-
const restartCardCheckout = useCallback(() => prepareCheckout('card', { forceNew: true }), [prepareCheckout]);
|
|
221
|
-
const restartWalletCheckout = useCallback(() => prepareCheckout('wallet', { forceNew: true }), [prepareCheckout]);
|
|
228
|
+
const prepareCardCheckout = useCallback((options = {}) => prepareCheckout('card', options), [prepareCheckout]);
|
|
229
|
+
const prepareWalletCheckout = useCallback((options = {}) => prepareCheckout('wallet', options), [prepareCheckout]);
|
|
230
|
+
const restartCardCheckout = useCallback((options = {}) => prepareCheckout('card', Object.assign(Object.assign({}, options), { forceNew: true })), [prepareCheckout]);
|
|
231
|
+
const restartWalletCheckout = useCallback((options = {}) => prepareCheckout('wallet', Object.assign(Object.assign({}, options), { forceNew: true })), [prepareCheckout]);
|
|
222
232
|
const updateCheckoutSessionPlan = useCallback(async () => {
|
|
223
233
|
if (!configured || !plan || !displayPlan || !activeCheckoutSessionId) {
|
|
224
234
|
return false;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type WalletCheckoutSmokeProfileId = 'mobile-safari' | 'mobile-chrome';
|
|
1
|
+
export type WalletCheckoutSmokeProfileId = 'mobile-safari' | 'mobile-chrome' | 'instagram-ios' | 'instagram-android';
|
|
2
2
|
export type WalletCheckoutSmokeProfile = {
|
|
3
3
|
id: WalletCheckoutSmokeProfileId;
|
|
4
4
|
name: string;
|
|
@@ -22,6 +22,28 @@ export function buildWalletCheckoutSmokeProfiles() {
|
|
|
22
22
|
isMobile: true,
|
|
23
23
|
},
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
id: 'instagram-ios',
|
|
27
|
+
name: 'Instagram iOS in-app browser',
|
|
28
|
+
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Instagram 333.0.0.36.109 (iPhone16,2; iOS 17_5; en_US; en-US; scale=3.00; 1290x2796; 579418012)',
|
|
29
|
+
viewport: {
|
|
30
|
+
width: 390,
|
|
31
|
+
height: 844,
|
|
32
|
+
hasTouch: true,
|
|
33
|
+
isMobile: true,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'instagram-android',
|
|
38
|
+
name: 'Instagram Android in-app browser',
|
|
39
|
+
userAgent: 'Mozilla/5.0 (Linux; Android 14; Pixel 8 Build/AP2A.240605.024; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/126.0.0.0 Mobile Safari/537.36 Instagram 333.0.0.39.92 Android (34/14; 420dpi; 1080x2400; Google/google; Pixel 8; shiba; shiba; en_US; 579418012)',
|
|
40
|
+
viewport: {
|
|
41
|
+
width: 412,
|
|
42
|
+
height: 915,
|
|
43
|
+
hasTouch: true,
|
|
44
|
+
isMobile: true,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
25
47
|
];
|
|
26
48
|
}
|
|
27
49
|
export function evaluateWalletCheckoutSmokeSnapshot(snapshot) {
|