@funnelsgrove/payments 0.1.12 → 0.1.14
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/dist/components/shared/SharedStripeCheckoutV2Dialog.d.ts +1 -0
- package/dist/components/shared/SharedStripeCheckoutV2Dialog.js +85 -48
- package/dist/providers/stripe/ApplePaySubscriptionCheckoutSlot.js +1 -3
- package/dist/providers/stripe/WalletSubscriptionCheckoutSlot.d.ts +1 -1
- package/dist/providers/stripe/WalletSubscriptionCheckoutSlot.js +10 -1
- package/dist/providers/stripe/useStripeSubscriptionCheckoutSession.d.ts +3 -0
- package/dist/providers/stripe/useStripeSubscriptionCheckoutSession.js +45 -16
- package/package.json +1 -1
|
@@ -21,6 +21,7 @@ export type SharedStripeCheckoutV2DialogProps = {
|
|
|
21
21
|
onCustomerEmailChange?: (value: string) => void;
|
|
22
22
|
onCustomerEmailCommit?: (email: string) => Promise<string | null | void>;
|
|
23
23
|
onError?: (message: string | null) => void;
|
|
24
|
+
onInactiveCheckoutSession?: () => void;
|
|
24
25
|
onSuccess?: () => void;
|
|
25
26
|
paymentMethodLabels?: readonly string[];
|
|
26
27
|
paypalButtonLabel: string;
|
|
@@ -15,8 +15,29 @@ import { useEffect, useMemo, useState, } from 'react';
|
|
|
15
15
|
import { CheckoutProvider, PaymentElement, useCheckout, } from '@stripe/react-stripe-js/checkout';
|
|
16
16
|
import { PaymentBrandMark, SecurityLockIcon } from './CheckoutBrandAssets.js';
|
|
17
17
|
import { StripeCheckoutExpressCheckoutButton } from './StripeCheckoutExpressCheckoutButton.js';
|
|
18
|
+
import { isInactiveCheckoutSessionError } from '../../providers/stripe/useStripeSubscriptionCheckoutSession.js';
|
|
18
19
|
import { getStripeWalletPaymentMethodOrder, usePlatformWalletPaymentMethods, } from './walletPlatform.js';
|
|
19
20
|
const defaultPaymentMethodLabels = ['Visa', 'Mastercard', 'Maestro', 'Discover'];
|
|
21
|
+
const stripeCheckoutV2Appearance = {
|
|
22
|
+
labels: 'above',
|
|
23
|
+
inputs: 'spaced',
|
|
24
|
+
variables: {
|
|
25
|
+
borderRadius: '0px',
|
|
26
|
+
colorBackground: '#fff',
|
|
27
|
+
colorText: '#303136',
|
|
28
|
+
colorTextPlaceholder: '#8c909a',
|
|
29
|
+
gridColumnSpacing: '12px',
|
|
30
|
+
gridRowSpacing: '14px',
|
|
31
|
+
spacingUnit: '5px',
|
|
32
|
+
},
|
|
33
|
+
rules: {
|
|
34
|
+
'.Label': {
|
|
35
|
+
paddingLeft: '14px',
|
|
36
|
+
paddingRight: '14px',
|
|
37
|
+
marginBottom: '6px',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
20
41
|
const isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
21
42
|
const formatCountdown = (remainingSeconds) => {
|
|
22
43
|
const normalizedSeconds = Number.isFinite(remainingSeconds)
|
|
@@ -31,7 +52,7 @@ function getFriendlyCardErrorMessage(error) {
|
|
|
31
52
|
? error.message
|
|
32
53
|
: 'Payment failed. Please review your card details and try again.';
|
|
33
54
|
}
|
|
34
|
-
function SharedStripeCheckoutV2Form({ 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, onSuccess, paymentMethodLabels = defaultPaymentMethodLabels, promoActive, processingLabel, promoCode, promoCodeLabel, remainingSeconds, returnUrl, savedLabel, secureLabel, satisfactionLabel, satisfactionPercent, summaryLabel, themeColor, title, totalLabel, totalValue, walletButtonLabel, originalPriceLabel, originalPriceValue, }) {
|
|
55
|
+
function SharedStripeCheckoutV2Form({ 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, onInactiveCheckoutSession, onSuccess, paymentMethodLabels = defaultPaymentMethodLabels, promoActive, processingLabel, promoCode, promoCodeLabel, remainingSeconds, returnUrl, savedLabel, secureLabel, satisfactionLabel, satisfactionPercent, summaryLabel, themeColor, title, totalLabel, totalValue, walletButtonLabel, originalPriceLabel, originalPriceValue, }) {
|
|
35
56
|
const checkoutState = useCheckout();
|
|
36
57
|
const walletPaymentMethods = usePlatformWalletPaymentMethods();
|
|
37
58
|
const [selectedMethod, setSelectedMethod] = useState('wallet');
|
|
@@ -112,7 +133,15 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
112
133
|
},
|
|
113
134
|
};
|
|
114
135
|
}, []);
|
|
136
|
+
const handleInactiveCheckoutSession = () => {
|
|
137
|
+
setError(null);
|
|
138
|
+
onInactiveCheckoutSession === null || onInactiveCheckoutSession === void 0 ? void 0 : onInactiveCheckoutSession();
|
|
139
|
+
};
|
|
115
140
|
const setSharedError = (message) => {
|
|
141
|
+
if (isInactiveCheckoutSessionError(message)) {
|
|
142
|
+
handleInactiveCheckoutSession();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
116
145
|
setError(message);
|
|
117
146
|
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
118
147
|
};
|
|
@@ -128,11 +157,6 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
128
157
|
setSelectedMethod('card');
|
|
129
158
|
}
|
|
130
159
|
};
|
|
131
|
-
useEffect(() => {
|
|
132
|
-
if (!customerEmailEditable) {
|
|
133
|
-
setEmailDraft(initialCustomerEmail);
|
|
134
|
-
}
|
|
135
|
-
}, [customerEmailEditable, initialCustomerEmail]);
|
|
136
160
|
useEffect(() => {
|
|
137
161
|
if (effectiveSelectedMethod !== 'card' || typeof window === 'undefined') {
|
|
138
162
|
return;
|
|
@@ -184,7 +208,8 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
184
208
|
returnUrl,
|
|
185
209
|
});
|
|
186
210
|
if (result.type === 'error') {
|
|
187
|
-
|
|
211
|
+
const message = result.error.message || 'Payment failed.';
|
|
212
|
+
setSharedError(message);
|
|
188
213
|
setSubmitting(false);
|
|
189
214
|
return;
|
|
190
215
|
}
|
|
@@ -206,22 +231,17 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
206
231
|
showPromo ? '' : 'is-plain',
|
|
207
232
|
]
|
|
208
233
|
.filter(Boolean)
|
|
209
|
-
.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: [_jsxs("div", { className: [
|
|
210
|
-
'shared-checkout-v2-methods',
|
|
211
|
-
showWalletMethod ? '' : 'has-card-only',
|
|
212
|
-
]
|
|
213
|
-
.filter(Boolean)
|
|
214
|
-
.join(' '), role: 'tablist', "aria-label": 'Payment method', children: [showWalletMethod ? (_jsxs("button", { type: 'button', className: [
|
|
234
|
+
.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: [
|
|
215
235
|
'shared-checkout-v2-method',
|
|
216
236
|
effectiveSelectedMethod === 'wallet' ? 'is-selected' : '',
|
|
217
237
|
]
|
|
218
238
|
.filter(Boolean)
|
|
219
|
-
.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 })] })
|
|
239
|
+
.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: [
|
|
220
240
|
'shared-checkout-v2-method',
|
|
221
241
|
effectiveSelectedMethod === 'card' ? 'is-selected' : '',
|
|
222
242
|
]
|
|
223
243
|
.filter(Boolean)
|
|
224
|
-
.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))) })] })] }), _jsxs("div", { hidden: effectiveSelectedMethod !== 'wallet', className: [
|
|
244
|
+
.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: [
|
|
225
245
|
'shared-checkout-v2-wallet-panel',
|
|
226
246
|
effectiveSelectedMethod === 'wallet' ? 'is-visible' : '',
|
|
227
247
|
]
|
|
@@ -231,16 +251,22 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
231
251
|
effectiveSelectedMethod === 'card' ? 'is-visible' : '',
|
|
232
252
|
]
|
|
233
253
|
.filter(Boolean)
|
|
234
|
-
.join(' '), children: [_jsxs("div", { className: 'shared-checkout-v2-card-box', children: [_jsxs("label", { className: emailFieldClassName, children: [_jsx("span", { children: customerEmailLabel }), _jsx("input", { type: 'email', autoComplete: 'email', className: 'shared-checkout-v2-email-input', disabled: !customerEmailEditable, inputMode: 'email', readOnly: !customerEmailEditable, value: emailDraft, placeholder: customerEmailPlaceholder, onChange: (event) => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
254
|
+
.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, onChange: (event) => {
|
|
255
|
+
if (!customerEmailEditable) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
setEmailDraft(event.target.value);
|
|
259
|
+
onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(event.target.value);
|
|
260
|
+
} }) })] }), _jsx(PaymentElement, { options: paymentElementOptions })] }), 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] })] })] })] }));
|
|
241
261
|
}
|
|
242
262
|
export function SharedStripeCheckoutV2Dialog(_a) {
|
|
243
263
|
var { clientSecret, onClose, stripePromise } = _a, props = __rest(_a, ["clientSecret", "onClose", "stripePromise"]);
|
|
264
|
+
const checkoutProviderOptions = useMemo(() => ({
|
|
265
|
+
clientSecret,
|
|
266
|
+
elementsOptions: {
|
|
267
|
+
appearance: stripeCheckoutV2Appearance,
|
|
268
|
+
},
|
|
269
|
+
}), [clientSecret]);
|
|
244
270
|
useEffect(() => {
|
|
245
271
|
const handleKeyDown = (event) => {
|
|
246
272
|
if (event.key === 'Escape') {
|
|
@@ -250,9 +276,7 @@ export function SharedStripeCheckoutV2Dialog(_a) {
|
|
|
250
276
|
window.addEventListener('keydown', handleKeyDown);
|
|
251
277
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
252
278
|
}, [onClose]);
|
|
253
|
-
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(CheckoutProvider, { stripe: stripePromise, options: {
|
|
254
|
-
clientSecret,
|
|
255
|
-
}, children: _jsx(SharedStripeCheckoutV2Form, Object.assign({}, props, { clientSecret: clientSecret, onClose: onClose })) }) }) }), _jsx("style", { children: sharedStripeCheckoutV2Styles })] }));
|
|
279
|
+
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(CheckoutProvider, { stripe: stripePromise, options: checkoutProviderOptions, children: _jsx(SharedStripeCheckoutV2Form, Object.assign({}, props, { clientSecret: clientSecret, onClose: onClose })) }, clientSecret) }) }), _jsx("style", { children: sharedStripeCheckoutV2Styles })] }));
|
|
256
280
|
}
|
|
257
281
|
function SharedCheckoutSpecialOfferGift({ discountLabel, imageAlt, imageSrc, }) {
|
|
258
282
|
if (imageSrc) {
|
|
@@ -522,11 +546,6 @@ const sharedStripeCheckoutV2Styles = `
|
|
|
522
546
|
gap: 42px;
|
|
523
547
|
}
|
|
524
548
|
|
|
525
|
-
.shared-checkout-v2-methods.has-card-only {
|
|
526
|
-
grid-template-columns: minmax(0, 1fr);
|
|
527
|
-
gap: 0;
|
|
528
|
-
}
|
|
529
|
-
|
|
530
549
|
.shared-checkout-v2-method {
|
|
531
550
|
min-width: 0;
|
|
532
551
|
min-height: 74px;
|
|
@@ -648,9 +667,9 @@ const sharedStripeCheckoutV2Styles = `
|
|
|
648
667
|
.shared-checkout-v2-card-panel {
|
|
649
668
|
position: relative;
|
|
650
669
|
gap: 10px;
|
|
651
|
-
margin-
|
|
670
|
+
margin-inline: -17px;
|
|
652
671
|
background: #f2f2f3;
|
|
653
|
-
padding: 16px
|
|
672
|
+
padding: 16px 32px 92px;
|
|
654
673
|
}
|
|
655
674
|
|
|
656
675
|
.shared-checkout-v2-wallet-panel.is-visible,
|
|
@@ -668,36 +687,54 @@ const sharedStripeCheckoutV2Styles = `
|
|
|
668
687
|
}
|
|
669
688
|
|
|
670
689
|
.shared-checkout-v2-email-field {
|
|
671
|
-
min-height: 64px;
|
|
672
690
|
box-sizing: border-box;
|
|
673
691
|
display: flex;
|
|
674
692
|
flex-direction: column;
|
|
675
|
-
|
|
693
|
+
gap: 7px;
|
|
676
694
|
border: 0;
|
|
677
|
-
border-bottom: 1px solid #dadde4;
|
|
678
695
|
border-radius: 0;
|
|
679
|
-
background:
|
|
680
|
-
|
|
681
|
-
|
|
696
|
+
background: transparent;
|
|
697
|
+
margin-bottom: 14px;
|
|
698
|
+
padding: 0;
|
|
699
|
+
color: #303136;
|
|
682
700
|
font-size: 14px;
|
|
683
|
-
font-weight:
|
|
684
|
-
line-height: 1;
|
|
701
|
+
font-weight: 400;
|
|
702
|
+
line-height: 1.2;
|
|
685
703
|
}
|
|
686
704
|
|
|
687
705
|
.shared-checkout-v2-email-field.is-disabled {
|
|
688
706
|
cursor: default;
|
|
689
707
|
}
|
|
690
708
|
|
|
709
|
+
.shared-checkout-v2-email-label {
|
|
710
|
+
padding: 0 14px;
|
|
711
|
+
color: #303136;
|
|
712
|
+
font-size: 14px;
|
|
713
|
+
font-weight: 400;
|
|
714
|
+
line-height: 1.2;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
.shared-checkout-v2-email-control {
|
|
718
|
+
min-height: 50px;
|
|
719
|
+
box-sizing: border-box;
|
|
720
|
+
display: flex;
|
|
721
|
+
align-items: center;
|
|
722
|
+
border: 1px solid #dedede;
|
|
723
|
+
background: #fff;
|
|
724
|
+
box-shadow: 0 1px 2px rgb(16 24 40 / 8%);
|
|
725
|
+
padding: 0 14px;
|
|
726
|
+
}
|
|
727
|
+
|
|
691
728
|
.shared-checkout-v2-email-input {
|
|
692
729
|
width: 100%;
|
|
693
|
-
min-height:
|
|
730
|
+
min-height: 48px;
|
|
694
731
|
box-sizing: border-box;
|
|
695
732
|
border: 0;
|
|
696
733
|
background: transparent;
|
|
697
734
|
padding: 0;
|
|
698
735
|
color: #303136;
|
|
699
736
|
font: inherit;
|
|
700
|
-
font-size:
|
|
737
|
+
font-size: 18px;
|
|
701
738
|
font-weight: 400;
|
|
702
739
|
line-height: 1.2;
|
|
703
740
|
outline: none;
|
|
@@ -714,11 +751,11 @@ const sharedStripeCheckoutV2Styles = `
|
|
|
714
751
|
}
|
|
715
752
|
|
|
716
753
|
.shared-checkout-v2-card-box {
|
|
717
|
-
overflow:
|
|
718
|
-
border:
|
|
754
|
+
overflow: visible;
|
|
755
|
+
border: 0;
|
|
719
756
|
border-radius: 6px;
|
|
720
|
-
background:
|
|
721
|
-
box-shadow:
|
|
757
|
+
background: transparent;
|
|
758
|
+
box-shadow: none;
|
|
722
759
|
}
|
|
723
760
|
|
|
724
761
|
.shared-checkout-v2-error {
|
|
@@ -773,7 +810,7 @@ const sharedStripeCheckoutV2Styles = `
|
|
|
773
810
|
.shared-checkout-v2-secure-pill--card {
|
|
774
811
|
position: absolute;
|
|
775
812
|
left: 50%;
|
|
776
|
-
bottom:
|
|
813
|
+
bottom: 16px;
|
|
777
814
|
transform: translateX(-50%);
|
|
778
815
|
white-space: nowrap;
|
|
779
816
|
}
|
|
@@ -908,7 +945,7 @@ const sharedStripeCheckoutV2Styles = `
|
|
|
908
945
|
}
|
|
909
946
|
|
|
910
947
|
.shared-checkout-v2-card-panel {
|
|
911
|
-
padding-inline:
|
|
948
|
+
padding-inline: 32px;
|
|
912
949
|
}
|
|
913
950
|
}
|
|
914
951
|
`;
|
|
@@ -12,10 +12,8 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
12
12
|
};
|
|
13
13
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
14
|
import { ApplePaySubscribeButton } from '../../components/shared/ApplePaySubscribeButton.js';
|
|
15
|
-
import { useApplePayExpressCheckoutAllowed } from '../../components/shared/SharedStripeCheckoutDialog.js';
|
|
16
15
|
import { WalletSubscriptionCheckoutLoadingPlaceholder, WalletSubscriptionCheckoutSlot, } from './WalletSubscriptionCheckoutSlot.js';
|
|
17
16
|
export function ApplePaySubscriptionCheckoutSlot(_a) {
|
|
18
17
|
var { placeholderLabel = 'Subscribe with Apple Pay' } = _a, slotProps = __rest(_a, ["placeholderLabel"]);
|
|
19
|
-
|
|
20
|
-
return (_jsx(WalletSubscriptionCheckoutSlot, Object.assign({}, slotProps, { availabilityPaymentMethod: 'applePay', expressCheckoutAllowed: allowApplePayExpressCheckout, placeholderLabel: placeholderLabel, renderPreparingPlaceholder: (placeholderProps) => (_jsx(WalletSubscriptionCheckoutLoadingPlaceholder, Object.assign({}, placeholderProps, { label: 'Loading Apple Pay' }))), renderPlaceholder: (placeholderProps) => (_jsx(ApplePaySubscribeButton, Object.assign({}, placeholderProps))) })));
|
|
18
|
+
return (_jsx(WalletSubscriptionCheckoutSlot, Object.assign({}, slotProps, { availabilityPaymentMethod: 'applePay', placeholderLabel: placeholderLabel, renderPreparingPlaceholder: (placeholderProps) => (_jsx(WalletSubscriptionCheckoutLoadingPlaceholder, Object.assign({}, placeholderProps, { label: 'Loading Apple Pay' }))), renderPlaceholder: (placeholderProps) => (_jsx(ApplePaySubscribeButton, Object.assign({}, placeholderProps))) })));
|
|
21
19
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import type { AvailablePaymentMethods, StripeCheckoutExpressCheckoutElementOptions } from '@stripe/stripe-js';
|
|
3
|
-
import type
|
|
3
|
+
import { type StripeSubscriptionCheckoutSession } from './useStripeSubscriptionCheckoutSession.js';
|
|
4
4
|
type WalletPlaceholderButtonProps = {
|
|
5
5
|
className?: string;
|
|
6
6
|
disabled: boolean;
|
|
@@ -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 { isInactiveCheckoutSessionError, } from './useStripeSubscriptionCheckoutSession.js';
|
|
5
6
|
export function WalletSubscriptionCheckoutLoadingPlaceholder({ className, label, }) {
|
|
6
7
|
return (_jsxs("div", { className: [
|
|
7
8
|
'wallet-subscription-checkout-slot__loading',
|
|
@@ -65,6 +66,14 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
65
66
|
walletAvailable,
|
|
66
67
|
]);
|
|
67
68
|
const handleError = (message) => {
|
|
69
|
+
if (isInactiveCheckoutSessionError(message)) {
|
|
70
|
+
setWalletAvailability({
|
|
71
|
+
available: null,
|
|
72
|
+
intentKey: session.intentKey,
|
|
73
|
+
});
|
|
74
|
+
void session.restartWalletCheckout();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
68
77
|
session.setError(message);
|
|
69
78
|
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
70
79
|
};
|
|
@@ -96,7 +105,7 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
96
105
|
.filter(Boolean)
|
|
97
106
|
.join(' '), "aria-busy": placeholderIsPreparing || undefined, children: [shouldRenderExpressCheckout &&
|
|
98
107
|
session.activeClientSecret &&
|
|
99
|
-
session.stripePromise ? (_jsx(StripeExpressCheckoutElement, { amountCents: amountCents, availabilityPaymentMethods: [availabilityPaymentMethod], beforeConfirm: beforeConfirm, className: className, clientSecret: session.activeClientSecret, customerEmail: customerEmail, customerName: customerName, onAvailabilityChange: handleAvailabilityChange, onError: handleError, onSuccess: onSuccess, options: options, returnUrl: returnUrl, stripePromise: session.stripePromise, summaryLabel: summaryLabel })) : null, shouldRenderPlaceholder ? (_jsx("div", { className: 'wallet-subscription-checkout-slot__placeholder', children: (renderPreparingPlaceholder !== null && renderPreparingPlaceholder !== void 0 ? renderPreparingPlaceholder : renderPlaceholder)({
|
|
108
|
+
session.stripePromise ? (_jsx(StripeExpressCheckoutElement, { amountCents: amountCents, availabilityPaymentMethods: [availabilityPaymentMethod], beforeConfirm: beforeConfirm, className: className, clientSecret: session.activeClientSecret, customerEmail: customerEmail, customerName: customerName, onAvailabilityChange: handleAvailabilityChange, onError: handleError, onSuccess: onSuccess, options: options, returnUrl: returnUrl, stripePromise: session.stripePromise, summaryLabel: summaryLabel }, session.activeClientSecret)) : null, shouldRenderPlaceholder ? (_jsx("div", { className: 'wallet-subscription-checkout-slot__placeholder', children: (renderPreparingPlaceholder !== null && renderPreparingPlaceholder !== void 0 ? renderPreparingPlaceholder : renderPlaceholder)({
|
|
100
109
|
className,
|
|
101
110
|
disabled: slotDisabled,
|
|
102
111
|
label: placeholderLabel,
|
|
@@ -25,7 +25,10 @@ export type StripeSubscriptionCheckoutSession = {
|
|
|
25
25
|
prepareWalletCheckout: () => Promise<string | null>;
|
|
26
26
|
provider: 'stripe';
|
|
27
27
|
reset: () => void;
|
|
28
|
+
restartCardCheckout: () => Promise<string | null>;
|
|
29
|
+
restartWalletCheckout: () => Promise<string | null>;
|
|
28
30
|
setError: (message: string | null) => void;
|
|
29
31
|
stripePromise: Promise<Stripe | null> | null;
|
|
30
32
|
};
|
|
33
|
+
export declare function isInactiveCheckoutSessionError(message?: string | null): boolean;
|
|
31
34
|
export declare function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, customerEmail, displayPlan, enabled, onError, plan, returnUrl, runtimeConfig, userId, }: StripeSubscriptionCheckoutSessionInput): StripeSubscriptionCheckoutSession;
|
|
@@ -9,6 +9,10 @@ const getFriendlyStripeCheckoutError = (error) => {
|
|
|
9
9
|
: message;
|
|
10
10
|
};
|
|
11
11
|
const normalizeRuntimeConfigValue = (value) => (value === null || value === void 0 ? void 0 : value.trim()) || '';
|
|
12
|
+
export function isInactiveCheckoutSessionError(message) {
|
|
13
|
+
var _a;
|
|
14
|
+
return /\bcheckout session\b.*\bno longer active\b/i.test((_a = message === null || message === void 0 ? void 0 : message.trim()) !== null && _a !== void 0 ? _a : '');
|
|
15
|
+
}
|
|
12
16
|
export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, customerEmail, displayPlan, enabled = true, onError, plan, returnUrl, runtimeConfig, userId, }) {
|
|
13
17
|
var _a, _b, _c, _d;
|
|
14
18
|
const [clientSecret, setClientSecret] = useState(null);
|
|
@@ -17,6 +21,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, c
|
|
|
17
21
|
const [loading, setLoading] = useState(createEmptyCheckoutPreparationLoading);
|
|
18
22
|
const [runtimeStripePublishableKey, setRuntimeStripePublishableKey] = useState(null);
|
|
19
23
|
const creatingIntentRef = useRef(null);
|
|
24
|
+
const requestIdRef = useRef(0);
|
|
20
25
|
const runtimeConfigSignature = [
|
|
21
26
|
normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.apiBaseUrl),
|
|
22
27
|
normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelId),
|
|
@@ -39,18 +44,28 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, c
|
|
|
39
44
|
].join('|');
|
|
40
45
|
const activeClientSecret = clientSecretIntentKey === intentKey ? clientSecret : null;
|
|
41
46
|
const stripePromise = useMemo(() => getStripePromise(checkoutMode, runtimeStripePublishableKey), [checkoutMode, runtimeStripePublishableKey]);
|
|
47
|
+
const clearActiveCheckoutSession = useCallback(() => {
|
|
48
|
+
requestIdRef.current += 1;
|
|
49
|
+
creatingIntentRef.current = null;
|
|
50
|
+
setClientSecret(null);
|
|
51
|
+
setClientSecretIntentKey(null);
|
|
52
|
+
}, []);
|
|
42
53
|
const setError = useCallback((message) => {
|
|
54
|
+
if (isInactiveCheckoutSessionError(message)) {
|
|
55
|
+
clearActiveCheckoutSession();
|
|
56
|
+
setErrorState(null);
|
|
57
|
+
onError === null || onError === void 0 ? void 0 : onError(null);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
43
60
|
setErrorState(message);
|
|
44
61
|
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
45
|
-
}, [onError]);
|
|
62
|
+
}, [clearActiveCheckoutSession, onError]);
|
|
46
63
|
const reset = useCallback(() => {
|
|
47
|
-
|
|
48
|
-
setClientSecret(null);
|
|
49
|
-
setClientSecretIntentKey(null);
|
|
64
|
+
clearActiveCheckoutSession();
|
|
50
65
|
setLoading(createEmptyCheckoutPreparationLoading());
|
|
51
66
|
setRuntimeStripePublishableKey(null);
|
|
52
67
|
setError(null);
|
|
53
|
-
}, [setError]);
|
|
68
|
+
}, [clearActiveCheckoutSession, setError]);
|
|
54
69
|
useEffect(() => {
|
|
55
70
|
reset();
|
|
56
71
|
}, [intentKey, reset]);
|
|
@@ -59,20 +74,25 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, c
|
|
|
59
74
|
? current
|
|
60
75
|
: Object.assign(Object.assign({}, current), { [source]: value }));
|
|
61
76
|
}, []);
|
|
62
|
-
const createCheckoutSubscription = useCallback(async () => {
|
|
77
|
+
const createCheckoutSubscription = useCallback(async (forceNew = false) => {
|
|
63
78
|
var _a;
|
|
64
79
|
if (!configured || !plan || !displayPlan) {
|
|
65
80
|
return null;
|
|
66
81
|
}
|
|
67
|
-
if (activeClientSecret) {
|
|
82
|
+
if (!forceNew && activeClientSecret) {
|
|
68
83
|
return activeClientSecret;
|
|
69
84
|
}
|
|
70
|
-
if (((_a = creatingIntentRef.current) === null || _a === void 0 ? void 0 : _a.key) === intentKey) {
|
|
85
|
+
if (!forceNew && ((_a = creatingIntentRef.current) === null || _a === void 0 ? void 0 : _a.key) === intentKey) {
|
|
71
86
|
return creatingIntentRef.current.promise;
|
|
72
87
|
}
|
|
88
|
+
if (forceNew) {
|
|
89
|
+
clearActiveCheckoutSession();
|
|
90
|
+
}
|
|
73
91
|
const requestKey = intentKey;
|
|
92
|
+
const requestId = requestIdRef.current + 1;
|
|
93
|
+
requestIdRef.current = requestId;
|
|
74
94
|
const subscriptionRequest = (async () => {
|
|
75
|
-
var _a, _b, _c, _d;
|
|
95
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
76
96
|
try {
|
|
77
97
|
const response = await createStripeSubscriptionCheckout({
|
|
78
98
|
plan,
|
|
@@ -83,10 +103,11 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, c
|
|
|
83
103
|
environment: checkoutMode,
|
|
84
104
|
runtimeConfig,
|
|
85
105
|
});
|
|
86
|
-
if (((_a = creatingIntentRef.current) === null || _a === void 0 ? void 0 : _a.key) !== requestKey
|
|
106
|
+
if (((_a = creatingIntentRef.current) === null || _a === void 0 ? void 0 : _a.key) !== requestKey ||
|
|
107
|
+
((_b = creatingIntentRef.current) === null || _b === void 0 ? void 0 : _b.id) !== requestId) {
|
|
87
108
|
return response.clientSecret;
|
|
88
109
|
}
|
|
89
|
-
const publishableKey = (
|
|
110
|
+
const publishableKey = (_c = response.stripePublishableKey) === null || _c === void 0 ? void 0 : _c.trim();
|
|
90
111
|
if (publishableKey) {
|
|
91
112
|
setRuntimeStripePublishableKey(publishableKey);
|
|
92
113
|
}
|
|
@@ -95,18 +116,21 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, c
|
|
|
95
116
|
return response.clientSecret;
|
|
96
117
|
}
|
|
97
118
|
catch (subscriptionError) {
|
|
98
|
-
if (((
|
|
119
|
+
if (((_d = creatingIntentRef.current) === null || _d === void 0 ? void 0 : _d.key) === requestKey &&
|
|
120
|
+
((_e = creatingIntentRef.current) === null || _e === void 0 ? void 0 : _e.id) === requestId) {
|
|
99
121
|
setError(getFriendlyStripeCheckoutError(subscriptionError));
|
|
100
122
|
}
|
|
101
123
|
return null;
|
|
102
124
|
}
|
|
103
125
|
finally {
|
|
104
|
-
if (((
|
|
126
|
+
if (((_f = creatingIntentRef.current) === null || _f === void 0 ? void 0 : _f.key) === requestKey &&
|
|
127
|
+
((_g = creatingIntentRef.current) === null || _g === void 0 ? void 0 : _g.id) === requestId) {
|
|
105
128
|
creatingIntentRef.current = null;
|
|
106
129
|
}
|
|
107
130
|
}
|
|
108
131
|
})();
|
|
109
132
|
creatingIntentRef.current = {
|
|
133
|
+
id: requestId,
|
|
110
134
|
key: requestKey,
|
|
111
135
|
promise: subscriptionRequest,
|
|
112
136
|
};
|
|
@@ -114,6 +138,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, c
|
|
|
114
138
|
}, [
|
|
115
139
|
activeClientSecret,
|
|
116
140
|
checkoutMode,
|
|
141
|
+
clearActiveCheckoutSession,
|
|
117
142
|
configured,
|
|
118
143
|
couponId,
|
|
119
144
|
customerEmail,
|
|
@@ -125,17 +150,17 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, c
|
|
|
125
150
|
setError,
|
|
126
151
|
userId,
|
|
127
152
|
]);
|
|
128
|
-
const prepareCheckout = useCallback(async (source) => {
|
|
153
|
+
const prepareCheckout = useCallback(async (source, options = {}) => {
|
|
129
154
|
if (!configured || !plan || !displayPlan) {
|
|
130
155
|
return null;
|
|
131
156
|
}
|
|
132
|
-
if (activeClientSecret) {
|
|
157
|
+
if (!options.forceNew && activeClientSecret) {
|
|
133
158
|
return activeClientSecret;
|
|
134
159
|
}
|
|
135
160
|
setSourceLoading(source, true);
|
|
136
161
|
setError(null);
|
|
137
162
|
try {
|
|
138
|
-
return await createCheckoutSubscription();
|
|
163
|
+
return await createCheckoutSubscription(options.forceNew === true);
|
|
139
164
|
}
|
|
140
165
|
finally {
|
|
141
166
|
setSourceLoading(source, false);
|
|
@@ -151,6 +176,8 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, c
|
|
|
151
176
|
]);
|
|
152
177
|
const prepareCardCheckout = useCallback(() => prepareCheckout('card'), [prepareCheckout]);
|
|
153
178
|
const prepareWalletCheckout = useCallback(() => prepareCheckout('wallet'), [prepareCheckout]);
|
|
179
|
+
const restartCardCheckout = useCallback(() => prepareCheckout('card', { forceNew: true }), [prepareCheckout]);
|
|
180
|
+
const restartWalletCheckout = useCallback(() => prepareCheckout('wallet', { forceNew: true }), [prepareCheckout]);
|
|
154
181
|
return {
|
|
155
182
|
activeClientSecret,
|
|
156
183
|
configured,
|
|
@@ -161,6 +188,8 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, c
|
|
|
161
188
|
prepareWalletCheckout,
|
|
162
189
|
provider: 'stripe',
|
|
163
190
|
reset,
|
|
191
|
+
restartCardCheckout,
|
|
192
|
+
restartWalletCheckout,
|
|
164
193
|
setError,
|
|
165
194
|
stripePromise,
|
|
166
195
|
};
|