@funnelsgrove/payments 0.1.7 → 0.1.8
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 -99
- 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]);
|
|
@@ -141,6 +89,16 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
141
89
|
},
|
|
142
90
|
};
|
|
143
91
|
}, [walletPaymentMethods]);
|
|
92
|
+
const paymentElementOptions = useMemo(() => {
|
|
93
|
+
return {
|
|
94
|
+
layout: 'tabs',
|
|
95
|
+
wallets: {
|
|
96
|
+
applePay: 'never',
|
|
97
|
+
googlePay: 'never',
|
|
98
|
+
link: 'auto',
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}, []);
|
|
144
102
|
const setSharedError = (message) => {
|
|
145
103
|
setError(message);
|
|
146
104
|
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
@@ -183,28 +141,15 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
183
141
|
onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(nextEmail);
|
|
184
142
|
return nextEmail;
|
|
185
143
|
};
|
|
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
144
|
const handleSubmit = async (event) => {
|
|
196
|
-
var _a;
|
|
197
145
|
event.preventDefault();
|
|
198
146
|
if (submitting) {
|
|
199
147
|
return;
|
|
200
148
|
}
|
|
201
|
-
if (
|
|
202
|
-
setSharedError(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const cardNumberElement = elements.getElement(CardNumberElement);
|
|
206
|
-
if (!cardNumberElement) {
|
|
207
|
-
setSharedError('Payment form is not ready yet.');
|
|
149
|
+
if (checkoutState.type !== 'success') {
|
|
150
|
+
setSharedError(checkoutState.type === 'error'
|
|
151
|
+
? checkoutState.error.message
|
|
152
|
+
: 'Payment form is not ready yet.');
|
|
208
153
|
return;
|
|
209
154
|
}
|
|
210
155
|
setSubmitting(true);
|
|
@@ -215,27 +160,17 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
215
160
|
setSubmitting(false);
|
|
216
161
|
return;
|
|
217
162
|
}
|
|
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,
|
|
163
|
+
const result = await checkoutState.checkout.confirm({
|
|
164
|
+
email: syncedEmail || undefined,
|
|
165
|
+
redirect: 'if_required',
|
|
166
|
+
returnUrl,
|
|
231
167
|
});
|
|
232
|
-
if (result.error) {
|
|
168
|
+
if (result.type === 'error') {
|
|
233
169
|
setSharedError(result.error.message || 'Payment failed.');
|
|
234
170
|
setSubmitting(false);
|
|
235
171
|
return;
|
|
236
172
|
}
|
|
237
|
-
if (typeof window !== 'undefined'
|
|
238
|
-
isSuccessfulIntentStatus((_a = result.paymentIntent) === null || _a === void 0 ? void 0 : _a.status)) {
|
|
173
|
+
if (typeof window !== 'undefined') {
|
|
239
174
|
onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess();
|
|
240
175
|
window.location.assign(returnUrl);
|
|
241
176
|
return;
|
|
@@ -247,7 +182,7 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
247
182
|
setSubmitting(false);
|
|
248
183
|
}
|
|
249
184
|
};
|
|
250
|
-
const visibleError = error
|
|
185
|
+
const visibleError = error;
|
|
251
186
|
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
187
|
'shared-checkout-v2-total',
|
|
253
188
|
showPromo ? '' : 'is-plain',
|
|
@@ -273,7 +208,7 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
273
208
|
effectiveSelectedMethod === 'wallet' ? 'is-visible' : '',
|
|
274
209
|
]
|
|
275
210
|
.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(
|
|
211
|
+
.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
212
|
'shared-checkout-v2-card-panel',
|
|
278
213
|
effectiveSelectedMethod === 'card' ? 'is-visible' : '',
|
|
279
214
|
]
|
|
@@ -281,13 +216,7 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
|
|
|
281
216
|
.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
217
|
setEmailDraft(event.target.value);
|
|
283
218
|
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] })] })] })] }));
|
|
219
|
+
} })] })) : 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
220
|
}
|
|
292
221
|
export function SharedStripeCheckoutV2Dialog(_a) {
|
|
293
222
|
var { clientSecret, onClose, stripePromise } = _a, props = __rest(_a, ["clientSecret", "onClose", "stripePromise"]);
|
|
@@ -300,7 +229,7 @@ export function SharedStripeCheckoutV2Dialog(_a) {
|
|
|
300
229
|
window.addEventListener('keydown', handleKeyDown);
|
|
301
230
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
302
231
|
}, [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(
|
|
232
|
+
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
233
|
clientSecret,
|
|
305
234
|
}, children: _jsx(SharedStripeCheckoutV2Form, Object.assign({}, props, { clientSecret: clientSecret, onClose: onClose })) }) }) }), _jsx("style", { children: sharedStripeCheckoutV2Styles })] }));
|
|
306
235
|
}
|
|
@@ -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
|
}),
|