@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.
@@ -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 { CardCvcElement, CardExpiryElement, CardNumberElement, Elements, useElements, useStripe, } from '@stripe/react-stripe-js';
15
+ import { CheckoutProvider, PaymentElement, useCheckout, } from '@stripe/react-stripe-js/checkout';
16
16
  import { PaymentBrandMark, SecurityLockIcon } from './CheckoutBrandAssets.js';
17
- import { StripeExpressCheckoutButton } from './StripeExpressCheckoutButton.js';
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, clientSecret, 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, }) {
83
- const stripe = useStripe();
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 (!stripe || !elements) {
202
- setSharedError('Payment form is not ready yet.');
203
- return;
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 stripe.confirmCardPayment(clientSecret, {
219
- payment_method: {
220
- card: cardNumberElement,
221
- billing_details: {
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 || cardNumberError || cardExpiryError || cardCvcError;
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(StripeExpressCheckoutButton, { amountCents: amountCents, availabilityPaymentMethods: walletPaymentMethods, beforeConfirm: ensureCustomerEmail, className: 'shared-checkout-v2-express-buttons', customerEmail: resolvedCustomerEmail, customerName: customerName, initialAvailable: initialWalletAvailable, keepInitialAvailableOnReady: initialWalletAvailable === true, onAvailabilityChange: handleWalletAvailabilityChange, onError: setSharedError, onSuccess: onSuccess, options: expressCheckoutOptions, returnUrl: returnUrl, summaryLabel: expressCheckoutSummaryLabel }), _jsx("span", { className: 'shared-checkout-v2-sr-only', children: walletAriaLabel })] })] }), _jsxs("div", { hidden: effectiveSelectedMethod !== 'card', className: [
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, _jsxs("div", { className: 'shared-checkout-v2-card-box', children: [_jsx("div", { className: 'shared-checkout-v2-card-number', children: _jsx(CardNumberElement, { options: cardNumberElementOptions, onChange: (event) => {
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(Elements, { stripe: stripePromise, options: {
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 StripeExpressCheckoutButtonProps } from './StripeExpressCheckoutButton.js';
3
- export type StripeExpressCheckoutElementProps = StripeExpressCheckoutButtonProps & {
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 { Elements } from '@stripe/react-stripe-js';
15
- import { StripeExpressCheckoutButton, } from './StripeExpressCheckoutButton.js';
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(Elements, { stripe: stripePromise, options: Object.assign({ clientSecret }, (appearance ? { appearance } : {})), children: _jsx(StripeExpressCheckoutButton, Object.assign({}, buttonProps)) }));
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 { StripeExpressCheckoutElementOptions } from '@stripe/stripe-js';
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?: StripeExpressCheckoutElementOptions;
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;
@@ -21,7 +21,6 @@ const googlePayExpressCheckoutOptions = {
21
21
  buttonType: {
22
22
  googlePay: 'subscribe',
23
23
  },
24
- emailRequired: true,
25
24
  layout: {
26
25
  maxColumns: 1,
27
26
  maxRows: 1,
@@ -1,5 +1,5 @@
1
1
  import { type ReactNode } from 'react';
2
- import type { AvailablePaymentMethods, StripeExpressCheckoutElementOptions } from '@stripe/stripe-js';
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?: StripeExpressCheckoutElementOptions;
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
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnelsgrove/payments",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "main": "./dist/index.js",