@funnelsgrove/payments 0.1.7 → 0.1.9
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.js +28 -100
- package/dist/components/shared/StripeCheckoutExpressCheckoutButton.d.ts +18 -0
- package/dist/components/shared/StripeCheckoutExpressCheckoutButton.js +116 -0
- package/dist/components/shared/StripeExpressCheckoutElement.d.ts +2 -2
- package/dist/components/shared/StripeExpressCheckoutElement.js +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/providers/stripe/GooglePaySubscriptionCheckoutSlot.d.ts +2 -2
- package/dist/providers/stripe/GooglePaySubscriptionCheckoutSlot.js +0 -1
- package/dist/providers/stripe/WalletSubscriptionCheckoutSlot.d.ts +2 -2
- package/dist/providers/stripe/useStripeSubscriptionCheckoutSession.d.ts +2 -1
- package/dist/providers/stripe/useStripeSubscriptionCheckoutSession.js +4 -1
- package/dist/services/stripe.service.d.ts +2 -0
- package/dist/services/stripe.service.js +1 -0
- package/package.json +1 -1
|
@@ -12,31 +12,12 @@ 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 {
|
|
15
|
+
import { CheckoutProvider, PaymentElement, useCheckout, } from '@stripe/react-stripe-js/checkout';
|
|
16
16
|
import { PaymentBrandMark, SecurityLockIcon } from './CheckoutBrandAssets.js';
|
|
17
|
-
import {
|
|
17
|
+
import { StripeCheckoutExpressCheckoutButton } from './StripeCheckoutExpressCheckoutButton.js';
|
|
18
18
|
import { getStripeWalletPaymentMethodOrder, usePlatformWalletPaymentMethods, } from './walletPlatform.js';
|
|
19
19
|
const defaultPaymentMethodLabels = ['Visa', 'Mastercard', 'Maestro', 'Discover'];
|
|
20
20
|
const isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
21
|
-
const normalizeBillingName = (input) => {
|
|
22
|
-
var _a, _b, _c, _d;
|
|
23
|
-
const normalizedName = ((_a = input.name) === null || _a === void 0 ? void 0 : _a.trim()) || ((_b = input.fallback) === null || _b === void 0 ? void 0 : _b.trim());
|
|
24
|
-
if (normalizedName) {
|
|
25
|
-
return normalizedName;
|
|
26
|
-
}
|
|
27
|
-
const normalizedEmail = (_c = input.email) === null || _c === void 0 ? void 0 : _c.trim();
|
|
28
|
-
if (normalizedEmail) {
|
|
29
|
-
const localPart = (_d = normalizedEmail
|
|
30
|
-
.split('@')[0]) === null || _d === void 0 ? void 0 : _d.replace(/[._-]+/g, ' ').trim();
|
|
31
|
-
if (localPart) {
|
|
32
|
-
return localPart;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return 'Customer';
|
|
36
|
-
};
|
|
37
|
-
const isSuccessfulIntentStatus = (status) => {
|
|
38
|
-
return status === 'succeeded' || status === 'processing' || status === 'requires_capture';
|
|
39
|
-
};
|
|
40
21
|
const formatCountdown = (remainingSeconds) => {
|
|
41
22
|
const normalizedSeconds = Number.isFinite(remainingSeconds)
|
|
42
23
|
? Math.max(0, Math.floor(remainingSeconds))
|
|
@@ -45,43 +26,13 @@ const formatCountdown = (remainingSeconds) => {
|
|
|
45
26
|
const seconds = normalizedSeconds % 60;
|
|
46
27
|
return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
|
47
28
|
};
|
|
48
|
-
const stripeCardElementStyle = {
|
|
49
|
-
base: {
|
|
50
|
-
color: '#303136',
|
|
51
|
-
fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
52
|
-
fontSize: '18px',
|
|
53
|
-
fontSmoothing: 'antialiased',
|
|
54
|
-
fontWeight: '500',
|
|
55
|
-
'::placeholder': {
|
|
56
|
-
color: '#8c909a',
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
invalid: {
|
|
60
|
-
color: '#ff2544',
|
|
61
|
-
iconColor: '#ff2544',
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
|
-
const cardNumberElementOptions = {
|
|
65
|
-
placeholder: 'Credit or Debit Card Number',
|
|
66
|
-
showIcon: false,
|
|
67
|
-
style: stripeCardElementStyle,
|
|
68
|
-
};
|
|
69
|
-
const cardExpiryElementOptions = {
|
|
70
|
-
placeholder: 'Expiry Date',
|
|
71
|
-
style: stripeCardElementStyle,
|
|
72
|
-
};
|
|
73
|
-
const cardCvcElementOptions = {
|
|
74
|
-
placeholder: 'CVV/CVC',
|
|
75
|
-
style: stripeCardElementStyle,
|
|
76
|
-
};
|
|
77
29
|
function getFriendlyCardErrorMessage(error) {
|
|
78
30
|
return error instanceof Error && error.message
|
|
79
31
|
? error.message
|
|
80
32
|
: 'Payment failed. Please review your card details and try again.';
|
|
81
33
|
}
|
|
82
|
-
function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
83
|
-
const
|
|
84
|
-
const elements = useElements();
|
|
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, nameOnCardPlaceholder = 'Name on card', 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, }) {
|
|
35
|
+
const checkoutState = useCheckout();
|
|
85
36
|
const walletPaymentMethods = usePlatformWalletPaymentMethods();
|
|
86
37
|
const [selectedMethod, setSelectedMethod] = useState('wallet');
|
|
87
38
|
const [walletAvailable, setWalletAvailable] = useState(initialWalletAvailable !== null && initialWalletAvailable !== void 0 ? initialWalletAvailable : null);
|
|
@@ -90,9 +41,6 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
90
41
|
: walletAvailable;
|
|
91
42
|
const [submitting, setSubmitting] = useState(false);
|
|
92
43
|
const [error, setError] = useState(null);
|
|
93
|
-
const [cardNumberError, setCardNumberError] = useState(null);
|
|
94
|
-
const [cardExpiryError, setCardExpiryError] = useState(null);
|
|
95
|
-
const [cardCvcError, setCardCvcError] = useState(null);
|
|
96
44
|
const [emailDraft, setEmailDraft] = useState((customerEmail === null || customerEmail === void 0 ? void 0 : customerEmail.trim()) || '');
|
|
97
45
|
const [nameOnCard, setNameOnCard] = useState((customerName === null || customerName === void 0 ? void 0 : customerName.trim()) || '');
|
|
98
46
|
const cardBrandLabels = useMemo(() => paymentMethodLabels.length > 0 ? paymentMethodLabels : defaultPaymentMethodLabels, [paymentMethodLabels]);
|
|
@@ -124,7 +72,6 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
124
72
|
applePay: 'subscribe',
|
|
125
73
|
googlePay: 'subscribe',
|
|
126
74
|
},
|
|
127
|
-
emailRequired: true,
|
|
128
75
|
layout: {
|
|
129
76
|
maxColumns: 1,
|
|
130
77
|
maxRows: 2,
|
|
@@ -141,6 +88,16 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
141
88
|
},
|
|
142
89
|
};
|
|
143
90
|
}, [walletPaymentMethods]);
|
|
91
|
+
const paymentElementOptions = useMemo(() => {
|
|
92
|
+
return {
|
|
93
|
+
layout: 'tabs',
|
|
94
|
+
wallets: {
|
|
95
|
+
applePay: 'never',
|
|
96
|
+
googlePay: 'never',
|
|
97
|
+
link: 'auto',
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}, []);
|
|
144
101
|
const setSharedError = (message) => {
|
|
145
102
|
setError(message);
|
|
146
103
|
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
@@ -183,28 +140,15 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
183
140
|
onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(nextEmail);
|
|
184
141
|
return nextEmail;
|
|
185
142
|
};
|
|
186
|
-
const handleFieldError = (event, setFieldError) => {
|
|
187
|
-
var _a, _b, _c;
|
|
188
|
-
setFieldError((_b = (_a = event.error) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : null);
|
|
189
|
-
if ((_c = event.error) === null || _c === void 0 ? void 0 : _c.message) {
|
|
190
|
-
setSharedError(event.error.message);
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
setSharedError(null);
|
|
194
|
-
};
|
|
195
143
|
const handleSubmit = async (event) => {
|
|
196
|
-
var _a;
|
|
197
144
|
event.preventDefault();
|
|
198
145
|
if (submitting) {
|
|
199
146
|
return;
|
|
200
147
|
}
|
|
201
|
-
if (
|
|
202
|
-
setSharedError(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const cardNumberElement = elements.getElement(CardNumberElement);
|
|
206
|
-
if (!cardNumberElement) {
|
|
207
|
-
setSharedError('Payment form is not ready yet.');
|
|
148
|
+
if (checkoutState.type !== 'success') {
|
|
149
|
+
setSharedError(checkoutState.type === 'error'
|
|
150
|
+
? checkoutState.error.message
|
|
151
|
+
: 'Payment form is not ready yet.');
|
|
208
152
|
return;
|
|
209
153
|
}
|
|
210
154
|
setSubmitting(true);
|
|
@@ -215,27 +159,17 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
215
159
|
setSubmitting(false);
|
|
216
160
|
return;
|
|
217
161
|
}
|
|
218
|
-
const result = await
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
email: syncedEmail || undefined,
|
|
223
|
-
name: normalizeBillingName({
|
|
224
|
-
email: syncedEmail,
|
|
225
|
-
name: customerName,
|
|
226
|
-
fallback: nameOnCard,
|
|
227
|
-
}),
|
|
228
|
-
},
|
|
229
|
-
},
|
|
230
|
-
return_url: returnUrl,
|
|
162
|
+
const result = await checkoutState.checkout.confirm({
|
|
163
|
+
email: syncedEmail || undefined,
|
|
164
|
+
redirect: 'if_required',
|
|
165
|
+
returnUrl,
|
|
231
166
|
});
|
|
232
|
-
if (result.error) {
|
|
167
|
+
if (result.type === 'error') {
|
|
233
168
|
setSharedError(result.error.message || 'Payment failed.');
|
|
234
169
|
setSubmitting(false);
|
|
235
170
|
return;
|
|
236
171
|
}
|
|
237
|
-
if (typeof window !== 'undefined'
|
|
238
|
-
isSuccessfulIntentStatus((_a = result.paymentIntent) === null || _a === void 0 ? void 0 : _a.status)) {
|
|
172
|
+
if (typeof window !== 'undefined') {
|
|
239
173
|
onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess();
|
|
240
174
|
window.location.assign(returnUrl);
|
|
241
175
|
return;
|
|
@@ -247,7 +181,7 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
247
181
|
setSubmitting(false);
|
|
248
182
|
}
|
|
249
183
|
};
|
|
250
|
-
const visibleError = error
|
|
184
|
+
const visibleError = error;
|
|
251
185
|
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: [
|
|
252
186
|
'shared-checkout-v2-total',
|
|
253
187
|
showPromo ? '' : 'is-plain',
|
|
@@ -273,7 +207,7 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
273
207
|
effectiveSelectedMethod === 'wallet' ? 'is-visible' : '',
|
|
274
208
|
]
|
|
275
209
|
.filter(Boolean)
|
|
276
|
-
.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(
|
|
210
|
+
.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(StripeCheckoutExpressCheckoutButton, { 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, onSuccess: onSuccess, options: expressCheckoutOptions, returnUrl: returnUrl, summaryLabel: expressCheckoutSummaryLabel }), _jsx("span", { className: 'shared-checkout-v2-sr-only', children: walletAriaLabel })] })] }), _jsxs("div", { hidden: effectiveSelectedMethod !== 'card', className: [
|
|
277
211
|
'shared-checkout-v2-card-panel',
|
|
278
212
|
effectiveSelectedMethod === 'card' ? 'is-visible' : '',
|
|
279
213
|
]
|
|
@@ -281,13 +215,7 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
281
215
|
.join(' '), children: [customerEmailEditable ? (_jsxs("label", { className: 'shared-checkout-v2-email-field', children: [_jsx("span", { children: customerEmailLabel }), _jsx("input", { type: 'email', autoComplete: 'email', className: 'shared-checkout-v2-email-input', inputMode: 'email', value: emailDraft, placeholder: customerEmailPlaceholder, onChange: (event) => {
|
|
282
216
|
setEmailDraft(event.target.value);
|
|
283
217
|
onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(event.target.value);
|
|
284
|
-
} })] })) : null,
|
|
285
|
-
handleFieldError(event, setCardNumberError);
|
|
286
|
-
} }) }), _jsxs("div", { className: 'shared-checkout-v2-card-row', children: [_jsx("div", { className: 'shared-checkout-v2-card-half', children: _jsx(CardExpiryElement, { options: cardExpiryElementOptions, onChange: (event) => {
|
|
287
|
-
handleFieldError(event, setCardExpiryError);
|
|
288
|
-
} }) }), _jsxs("div", { className: 'shared-checkout-v2-card-half shared-checkout-v2-card-half--cvc', children: [_jsx(CardCvcElement, { options: cardCvcElementOptions, onChange: (event) => {
|
|
289
|
-
handleFieldError(event, setCardCvcError);
|
|
290
|
-
} }), _jsx("span", { className: 'shared-checkout-v2-cvc-info', "aria-hidden": 'true', children: "i" })] })] })] }), _jsx("input", { type: 'text', autoComplete: 'cc-name', className: 'shared-checkout-v2-name-input', value: nameOnCard, placeholder: nameOnCardPlaceholder, onChange: (event) => setNameOnCard(event.target.value) }), 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', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] })] })] })] }));
|
|
218
|
+
} })] })) : null, _jsx("div", { className: 'shared-checkout-v2-card-box', children: _jsx(PaymentElement, { options: paymentElementOptions }) }), _jsx("input", { type: 'text', autoComplete: 'cc-name', className: 'shared-checkout-v2-name-input', value: nameOnCard, placeholder: nameOnCardPlaceholder, onChange: (event) => setNameOnCard(event.target.value) }), 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', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] })] })] })] }));
|
|
291
219
|
}
|
|
292
220
|
export function SharedStripeCheckoutV2Dialog(_a) {
|
|
293
221
|
var { clientSecret, onClose, stripePromise } = _a, props = __rest(_a, ["clientSecret", "onClose", "stripePromise"]);
|
|
@@ -300,7 +228,7 @@ export function SharedStripeCheckoutV2Dialog(_a) {
|
|
|
300
228
|
window.addEventListener('keydown', handleKeyDown);
|
|
301
229
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
302
230
|
}, [onClose]);
|
|
303
|
-
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(
|
|
231
|
+
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: {
|
|
304
232
|
clientSecret,
|
|
305
233
|
}, children: _jsx(SharedStripeCheckoutV2Form, Object.assign({}, props, { clientSecret: clientSecret, onClose: onClose })) }) }) }), _jsx("style", { children: sharedStripeCheckoutV2Styles })] }));
|
|
306
234
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AvailablePaymentMethods, StripeCheckoutExpressCheckoutElementOptions } from '@stripe/stripe-js';
|
|
2
|
+
export type StripeCheckoutExpressCheckoutButtonProps = {
|
|
3
|
+
amountCents: number;
|
|
4
|
+
beforeConfirm?: () => Promise<string | null>;
|
|
5
|
+
summaryLabel: string;
|
|
6
|
+
returnUrl: string;
|
|
7
|
+
customerEmail?: string | null;
|
|
8
|
+
customerName?: string | null;
|
|
9
|
+
className?: string;
|
|
10
|
+
options?: Partial<StripeCheckoutExpressCheckoutElementOptions>;
|
|
11
|
+
availabilityPaymentMethods?: readonly (keyof AvailablePaymentMethods)[];
|
|
12
|
+
initialAvailable?: boolean | null;
|
|
13
|
+
keepInitialAvailableOnReady?: boolean;
|
|
14
|
+
onAvailabilityChange?: (available: boolean) => void;
|
|
15
|
+
onError?: (message: string | null) => void;
|
|
16
|
+
onSuccess?: () => void;
|
|
17
|
+
};
|
|
18
|
+
export declare function StripeCheckoutExpressCheckoutButton({ beforeConfirm, returnUrl, customerEmail, className, options, availabilityPaymentMethods, initialAvailable, keepInitialAvailableOnReady, onAvailabilityChange, onError, onSuccess, }: StripeCheckoutExpressCheckoutButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo, useState } from 'react';
|
|
4
|
+
import { ExpressCheckoutElement, useCheckout, } from '@stripe/react-stripe-js/checkout';
|
|
5
|
+
const buildDefaultOptions = () => ({
|
|
6
|
+
buttonHeight: 55,
|
|
7
|
+
buttonTheme: {
|
|
8
|
+
applePay: 'black',
|
|
9
|
+
},
|
|
10
|
+
buttonType: {
|
|
11
|
+
applePay: 'subscribe',
|
|
12
|
+
},
|
|
13
|
+
layout: {
|
|
14
|
+
maxColumns: 1,
|
|
15
|
+
maxRows: 1,
|
|
16
|
+
overflow: 'auto',
|
|
17
|
+
},
|
|
18
|
+
paymentMethodOrder: ['apple_pay'],
|
|
19
|
+
paymentMethods: {
|
|
20
|
+
amazonPay: 'never',
|
|
21
|
+
applePay: 'always',
|
|
22
|
+
googlePay: 'never',
|
|
23
|
+
klarna: 'never',
|
|
24
|
+
link: 'never',
|
|
25
|
+
paypal: 'never',
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, returnUrl, customerEmail, className, options, availabilityPaymentMethods = ['applePay'], initialAvailable, keepInitialAvailableOnReady = false, onAvailabilityChange, onError, onSuccess, }) {
|
|
29
|
+
const checkoutState = useCheckout();
|
|
30
|
+
const [walletAvailable, setWalletAvailable] = useState(initialAvailable !== null && initialAvailable !== void 0 ? initialAvailable : null);
|
|
31
|
+
const effectiveWalletAvailable = initialAvailable === true && walletAvailable !== false
|
|
32
|
+
? true
|
|
33
|
+
: walletAvailable;
|
|
34
|
+
const baseOptions = useMemo(() => buildDefaultOptions(), []);
|
|
35
|
+
const resolvedOptions = useMemo(() => {
|
|
36
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
37
|
+
return Object.assign(Object.assign(Object.assign({}, baseOptions), (options !== null && options !== void 0 ? options : {})), { buttonTheme: Object.assign(Object.assign({}, ((_a = baseOptions.buttonTheme) !== null && _a !== void 0 ? _a : {})), ((_b = options === null || options === void 0 ? void 0 : options.buttonTheme) !== null && _b !== void 0 ? _b : {})), buttonType: Object.assign(Object.assign({}, ((_c = baseOptions.buttonType) !== null && _c !== void 0 ? _c : {})), ((_d = options === null || options === void 0 ? void 0 : options.buttonType) !== null && _d !== void 0 ? _d : {})), layout: Object.assign(Object.assign({}, ((_e = baseOptions.layout) !== null && _e !== void 0 ? _e : {})), ((_f = options === null || options === void 0 ? void 0 : options.layout) !== null && _f !== void 0 ? _f : {})), paymentMethods: Object.assign(Object.assign({}, ((_g = baseOptions.paymentMethods) !== null && _g !== void 0 ? _g : {})), ((_h = options === null || options === void 0 ? void 0 : options.paymentMethods) !== null && _h !== void 0 ? _h : {})), paymentMethodOrder: (_j = options === null || options === void 0 ? void 0 : options.paymentMethodOrder) !== null && _j !== void 0 ? _j : baseOptions.paymentMethodOrder });
|
|
38
|
+
}, [baseOptions, options]);
|
|
39
|
+
const handleConfirm = async (event) => {
|
|
40
|
+
if (checkoutState.type !== 'success') {
|
|
41
|
+
const message = checkoutState.type === 'error'
|
|
42
|
+
? checkoutState.error.message
|
|
43
|
+
: 'Wallet checkout is not ready yet.';
|
|
44
|
+
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
45
|
+
event.paymentFailed({ reason: 'fail', message });
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
onError === null || onError === void 0 ? void 0 : onError(null);
|
|
49
|
+
let preparedCustomerEmail = (customerEmail === null || customerEmail === void 0 ? void 0 : customerEmail.trim()) || null;
|
|
50
|
+
if (beforeConfirm) {
|
|
51
|
+
try {
|
|
52
|
+
preparedCustomerEmail = await beforeConfirm();
|
|
53
|
+
}
|
|
54
|
+
catch (confirmError) {
|
|
55
|
+
const message = confirmError instanceof Error && confirmError.message
|
|
56
|
+
? confirmError.message
|
|
57
|
+
: 'Unable to prepare wallet checkout.';
|
|
58
|
+
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
59
|
+
event.paymentFailed({ reason: 'invalid_payment_data', message });
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (beforeConfirm && !preparedCustomerEmail) {
|
|
64
|
+
const message = 'Email is required to continue.';
|
|
65
|
+
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
66
|
+
event.paymentFailed({ reason: 'invalid_payment_data', message });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const result = await checkoutState.checkout.confirm({
|
|
70
|
+
email: preparedCustomerEmail || (customerEmail === null || customerEmail === void 0 ? void 0 : customerEmail.trim()) || undefined,
|
|
71
|
+
expressCheckoutConfirmEvent: event,
|
|
72
|
+
redirect: 'if_required',
|
|
73
|
+
returnUrl,
|
|
74
|
+
});
|
|
75
|
+
if (result.type === 'error') {
|
|
76
|
+
const message = result.error.message || 'Wallet checkout failed.';
|
|
77
|
+
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
78
|
+
event.paymentFailed({ reason: 'fail', message });
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
onError === null || onError === void 0 ? void 0 : onError(null);
|
|
82
|
+
if (typeof window !== 'undefined') {
|
|
83
|
+
onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess();
|
|
84
|
+
window.location.assign(returnUrl);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: [
|
|
88
|
+
'stripe-express-checkout-button',
|
|
89
|
+
className !== null && className !== void 0 ? className : '',
|
|
90
|
+
effectiveWalletAvailable === false ? 'is-hidden' : '',
|
|
91
|
+
]
|
|
92
|
+
.filter(Boolean)
|
|
93
|
+
.join(' '), children: _jsx(ExpressCheckoutElement, { options: resolvedOptions, onConfirm: (event) => void handleConfirm(event), onLoadError: ({ error }) => {
|
|
94
|
+
setWalletAvailable(false);
|
|
95
|
+
onAvailabilityChange === null || onAvailabilityChange === void 0 ? void 0 : onAvailabilityChange(false);
|
|
96
|
+
onError === null || onError === void 0 ? void 0 : onError(error.message || 'Unable to load wallet checkout.');
|
|
97
|
+
}, onReady: ({ availablePaymentMethods: availablePaymentMethodsMap }) => {
|
|
98
|
+
const available = Boolean(availabilityPaymentMethods.some((paymentMethod) => availablePaymentMethodsMap === null || availablePaymentMethodsMap === void 0 ? void 0 : availablePaymentMethodsMap[paymentMethod]));
|
|
99
|
+
const resolvedAvailable = available || (keepInitialAvailableOnReady && initialAvailable === true);
|
|
100
|
+
setWalletAvailable(resolvedAvailable);
|
|
101
|
+
onAvailabilityChange === null || onAvailabilityChange === void 0 ? void 0 : onAvailabilityChange(resolvedAvailable);
|
|
102
|
+
if (resolvedAvailable) {
|
|
103
|
+
onError === null || onError === void 0 ? void 0 : onError(null);
|
|
104
|
+
}
|
|
105
|
+
} }) }), _jsx("style", { children: stripeExpressCheckoutButtonStyles })] }));
|
|
106
|
+
}
|
|
107
|
+
const stripeExpressCheckoutButtonStyles = `
|
|
108
|
+
.stripe-express-checkout-button {
|
|
109
|
+
width: 100%;
|
|
110
|
+
min-height: 55px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.stripe-express-checkout-button.is-hidden {
|
|
114
|
+
display: none;
|
|
115
|
+
}
|
|
116
|
+
`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Appearance, Stripe } from '@stripe/stripe-js';
|
|
2
|
-
import { type
|
|
3
|
-
export type StripeExpressCheckoutElementProps =
|
|
2
|
+
import { type StripeCheckoutExpressCheckoutButtonProps } from './StripeCheckoutExpressCheckoutButton.js';
|
|
3
|
+
export type StripeExpressCheckoutElementProps = StripeCheckoutExpressCheckoutButtonProps & {
|
|
4
4
|
appearance?: Appearance;
|
|
5
5
|
clientSecret: string;
|
|
6
6
|
stripePromise: Promise<Stripe | null>;
|
|
@@ -11,9 +11,9 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
return t;
|
|
12
12
|
};
|
|
13
13
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
14
|
+
import { CheckoutProvider } from '@stripe/react-stripe-js/checkout';
|
|
15
|
+
import { StripeCheckoutExpressCheckoutButton, } from './StripeCheckoutExpressCheckoutButton.js';
|
|
16
16
|
export function StripeExpressCheckoutElement(_a) {
|
|
17
17
|
var { appearance, clientSecret, stripePromise } = _a, buttonProps = __rest(_a, ["appearance", "clientSecret", "stripePromise"]);
|
|
18
|
-
return (_jsx(
|
|
18
|
+
return (_jsx(CheckoutProvider, { stripe: stripePromise, options: Object.assign({ clientSecret }, (appearance ? { elementsOptions: { appearance } } : {})), children: _jsx(StripeCheckoutExpressCheckoutButton, Object.assign({}, buttonProps)) }));
|
|
19
19
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export * from './components/shared/SharedStripeCheckoutDialog.js';
|
|
|
15
15
|
export * from './components/shared/SharedStripeCheckoutV2Dialog.js';
|
|
16
16
|
export * from './components/shared/ApplePaySubscribeButton.js';
|
|
17
17
|
export * from './components/shared/GooglePaySubscribeButton.js';
|
|
18
|
+
export * from './components/shared/StripeCheckoutExpressCheckoutButton.js';
|
|
18
19
|
export * from './components/shared/StripeExpressCheckoutButton.js';
|
|
19
20
|
export * from './components/shared/StripeExpressCheckoutElement.js';
|
|
20
21
|
export * from './components/shared/StripePlanSelector.js';
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ export * from './components/shared/SharedStripeCheckoutDialog.js';
|
|
|
15
15
|
export * from './components/shared/SharedStripeCheckoutV2Dialog.js';
|
|
16
16
|
export * from './components/shared/ApplePaySubscribeButton.js';
|
|
17
17
|
export * from './components/shared/GooglePaySubscribeButton.js';
|
|
18
|
+
export * from './components/shared/StripeCheckoutExpressCheckoutButton.js';
|
|
18
19
|
export * from './components/shared/StripeExpressCheckoutButton.js';
|
|
19
20
|
export * from './components/shared/StripeExpressCheckoutElement.js';
|
|
20
21
|
export * from './components/shared/StripePlanSelector.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StripeCheckoutExpressCheckoutElementOptions } from '@stripe/stripe-js';
|
|
2
2
|
import { type WalletSubscriptionCheckoutSlotProps } from './WalletSubscriptionCheckoutSlot.js';
|
|
3
3
|
export type GooglePaySubscriptionCheckoutSlotProps = Omit<WalletSubscriptionCheckoutSlotProps, 'availabilityPaymentMethod' | 'options' | 'placeholderLabel' | 'renderPlaceholder' | 'renderPreparingPlaceholder'> & {
|
|
4
|
-
options?:
|
|
4
|
+
options?: Partial<StripeCheckoutExpressCheckoutElementOptions>;
|
|
5
5
|
placeholderLabel?: string;
|
|
6
6
|
};
|
|
7
7
|
export declare function GooglePaySubscriptionCheckoutSlot({ options, placeholderLabel, ...slotProps }: GooglePaySubscriptionCheckoutSlotProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
-
import type { AvailablePaymentMethods,
|
|
2
|
+
import type { AvailablePaymentMethods, StripeCheckoutExpressCheckoutElementOptions } from '@stripe/stripe-js';
|
|
3
3
|
import type { StripeSubscriptionCheckoutSession } from './useStripeSubscriptionCheckoutSession.js';
|
|
4
4
|
type WalletPlaceholderButtonProps = {
|
|
5
5
|
className?: string;
|
|
@@ -20,7 +20,7 @@ export type WalletSubscriptionCheckoutSlotProps = {
|
|
|
20
20
|
onError?: (message: string | null) => void;
|
|
21
21
|
onSuccess?: () => void;
|
|
22
22
|
onUnavailableClick?: () => Promise<void> | void;
|
|
23
|
-
options?:
|
|
23
|
+
options?: Partial<StripeCheckoutExpressCheckoutElementOptions>;
|
|
24
24
|
placeholderLabel: string;
|
|
25
25
|
renderPreparingPlaceholder?: (props: WalletPlaceholderButtonProps) => ReactNode;
|
|
26
26
|
renderPlaceholder: (props: WalletPlaceholderButtonProps) => ReactNode;
|
|
@@ -11,6 +11,7 @@ export type StripeSubscriptionCheckoutSessionInput = {
|
|
|
11
11
|
enabled?: boolean;
|
|
12
12
|
onError?: (message: string | null) => void;
|
|
13
13
|
plan?: PaywallPlan | null;
|
|
14
|
+
returnUrl: string;
|
|
14
15
|
runtimeConfig?: StripeRuntimeConfigOverrides;
|
|
15
16
|
userId?: string | null;
|
|
16
17
|
};
|
|
@@ -27,4 +28,4 @@ export type StripeSubscriptionCheckoutSession = {
|
|
|
27
28
|
setError: (message: string | null) => void;
|
|
28
29
|
stripePromise: Promise<Stripe | null> | null;
|
|
29
30
|
};
|
|
30
|
-
export declare function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, customerEmail, displayPlan, enabled, onError, plan, runtimeConfig, userId, }: StripeSubscriptionCheckoutSessionInput): StripeSubscriptionCheckoutSession;
|
|
31
|
+
export declare function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, customerEmail, displayPlan, enabled, onError, plan, returnUrl, runtimeConfig, userId, }: StripeSubscriptionCheckoutSessionInput): StripeSubscriptionCheckoutSession;
|
|
@@ -9,7 +9,7 @@ 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 useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, customerEmail, displayPlan, enabled = true, onError, plan, runtimeConfig, userId, }) {
|
|
12
|
+
export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, customerEmail, displayPlan, enabled = true, onError, plan, returnUrl, runtimeConfig, userId, }) {
|
|
13
13
|
var _a, _b, _c, _d;
|
|
14
14
|
const [clientSecret, setClientSecret] = useState(null);
|
|
15
15
|
const [clientSecretIntentKey, setClientSecretIntentKey] = useState(null);
|
|
@@ -35,6 +35,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, c
|
|
|
35
35
|
(_c = displayPlan === null || displayPlan === void 0 ? void 0 : displayPlan.id) !== null && _c !== void 0 ? _c : '',
|
|
36
36
|
(_d = displayPlan === null || displayPlan === void 0 ? void 0 : displayPlan.amountCents) !== null && _d !== void 0 ? _d : '',
|
|
37
37
|
(couponId === null || couponId === void 0 ? void 0 : couponId.trim()) || '',
|
|
38
|
+
returnUrl.trim(),
|
|
38
39
|
].join('|');
|
|
39
40
|
const activeClientSecret = clientSecretIntentKey === intentKey ? clientSecret : null;
|
|
40
41
|
const stripePromise = useMemo(() => getStripePromise(checkoutMode, runtimeStripePublishableKey), [checkoutMode, runtimeStripePublishableKey]);
|
|
@@ -77,6 +78,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, c
|
|
|
77
78
|
plan,
|
|
78
79
|
couponId,
|
|
79
80
|
customerEmail,
|
|
81
|
+
returnUrl,
|
|
80
82
|
user_id: userId,
|
|
81
83
|
environment: checkoutMode,
|
|
82
84
|
runtimeConfig,
|
|
@@ -118,6 +120,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, couponId, c
|
|
|
118
120
|
displayPlan,
|
|
119
121
|
intentKey,
|
|
120
122
|
plan,
|
|
123
|
+
returnUrl,
|
|
121
124
|
runtimeConfig,
|
|
122
125
|
setError,
|
|
123
126
|
userId,
|
|
@@ -68,12 +68,14 @@ type CreateSubscriptionCheckoutInput = {
|
|
|
68
68
|
plan: CheckoutSessionPlanInput;
|
|
69
69
|
couponId?: string | null;
|
|
70
70
|
customerEmail?: string | null;
|
|
71
|
+
returnUrl: string;
|
|
71
72
|
user_id?: string | null;
|
|
72
73
|
environment?: RuntimeMode;
|
|
73
74
|
runtimeConfig?: StripeRuntimeConfigOverrides;
|
|
74
75
|
};
|
|
75
76
|
type CreateSubscriptionCheckoutResponse = {
|
|
76
77
|
clientSecret: string;
|
|
78
|
+
checkoutSessionId?: string;
|
|
77
79
|
subscriptionId?: string;
|
|
78
80
|
stripePublishableKey?: string;
|
|
79
81
|
environment?: 'test' | 'live';
|
|
@@ -577,6 +577,7 @@ export async function createStripeSubscriptionCheckout(input) {
|
|
|
577
577
|
billingIntervalCount: recurring.intervalCount,
|
|
578
578
|
couponId: ((_c = input.couponId) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
|
|
579
579
|
customerEmail: ((_d = input.customerEmail) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
|
|
580
|
+
returnUrl: input.returnUrl,
|
|
580
581
|
user_id: ((_e = input.user_id) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
|
|
581
582
|
environment: input.environment || undefined,
|
|
582
583
|
}),
|