@funnelsgrove/payments 0.1.43 → 0.1.45

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.
@@ -42,10 +42,12 @@ export type SharedStripeCheckoutV2DialogProps = {
42
42
  satisfactionPercent: string;
43
43
  stripePromise: Promise<Stripe | null>;
44
44
  summaryLabel?: string;
45
+ supportedCountries?: readonly string[];
45
46
  themeColor: string;
46
47
  title: string;
47
48
  totalLabel: string;
48
49
  totalValue: string;
50
+ unsupportedCountryMessage?: string;
49
51
  walletButtonLabel: string;
50
52
  originalPriceLabel: string;
51
53
  originalPriceValue: string;
@@ -61,5 +63,5 @@ export type SharedCheckoutSpecialOfferDialogProps = {
61
63
  themeColor: string;
62
64
  title: string;
63
65
  };
64
- export declare function SharedStripeCheckoutV2Dialog({ checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, ...props }: SharedStripeCheckoutV2DialogProps): import("react/jsx-runtime").JSX.Element;
66
+ export declare function SharedStripeCheckoutV2Dialog({ checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries, ...props }: SharedStripeCheckoutV2DialogProps): import("react/jsx-runtime").JSX.Element;
65
67
  export declare function SharedCheckoutSpecialOfferDialog({ buttonColor, buttonLabel, description, discountLabel, imageAlt, imageSrc, onAccept, themeColor, title, }: SharedCheckoutSpecialOfferDialogProps): import("react/jsx-runtime").JSX.Element;
@@ -15,6 +15,7 @@ import { useEffect, useMemo, useState, } from 'react';
15
15
  import { CheckoutProvider, PaymentElement, useCheckout, } from '@stripe/react-stripe-js/checkout';
16
16
  import { PaymentBrandMark, SecurityLockIcon } from './CheckoutBrandAssets.js';
17
17
  import { StripeCheckoutExpressCheckoutButton } from './StripeCheckoutExpressCheckoutButton.js';
18
+ import { getUnsupportedCheckoutCountryMessage, normalizeSupportedCheckoutCountries, } from './checkoutCountries.js';
18
19
  import { isInactiveCheckoutSessionError } from '../../providers/stripe/useStripeSubscriptionCheckoutSession.js';
19
20
  import { getStripeWalletPaymentMethodOrder, usePlatformWalletPaymentMethods, } from './walletPlatform.js';
20
21
  import { trackPaidStripeSubscriptionCheckoutCompleted, trackStripeSubscriptionCheckoutStarted, } from '../../services/checkoutCompletionAnalytics.service.js';
@@ -48,12 +49,13 @@ const formatCountdown = (remainingSeconds) => {
48
49
  const seconds = normalizedSeconds % 60;
49
50
  return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
50
51
  };
52
+ const getFixedSupportedBillingCountry = (supportedCountries) => supportedCountries.length === 1 ? supportedCountries[0] : null;
51
53
  function getFriendlyCardErrorMessage(error) {
52
54
  return error instanceof Error && error.message
53
55
  ? error.message
54
56
  : 'Payment failed. Please review your card details and try again.';
55
57
  }
56
- function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel, closeAriaLabel, countdownLabel, checkoutAnalytics, checkoutSessionId, customerEmail, customerEmailEditable = false, customerEmailLabel = 'Email', customerEmailPlaceholder = 'Enter your email', customerEmailInvalidMessage = 'Enter a valid email address.', customerName, discountAmountLabel, discountLabel, discountPercent, initialWalletAvailable, onClose, onCustomerEmailChange, onCustomerEmailCommit, onError, onInactiveCheckoutSession, onPaymentInfoSubmitted, onSuccess, paymentMethodLabels = defaultPaymentMethodLabels, promoActive, processingLabel, promoCode, promoCodeLabel, remainingSeconds, returnUrl, savedLabel, secureLabel, satisfactionLabel, satisfactionPercent, summaryLabel, themeColor, title, totalLabel, totalValue, walletButtonLabel, originalPriceLabel, originalPriceValue, }) {
58
+ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel, closeAriaLabel, countdownLabel, checkoutAnalytics, checkoutSessionId, customerEmail, customerEmailEditable = false, customerEmailLabel = 'Email', customerEmailPlaceholder = 'Enter your email', customerEmailInvalidMessage = 'Enter a valid email address.', customerName, discountAmountLabel, discountLabel, discountPercent, initialWalletAvailable, onClose, onCustomerEmailChange, onCustomerEmailCommit, onError, onInactiveCheckoutSession, onPaymentInfoSubmitted, onSuccess, paymentMethodLabels = defaultPaymentMethodLabels, promoActive, processingLabel, promoCode, promoCodeLabel, remainingSeconds, returnUrl, savedLabel, secureLabel, satisfactionLabel, satisfactionPercent, summaryLabel, supportedCountries, themeColor, title, totalLabel, totalValue, unsupportedCountryMessage, walletButtonLabel, originalPriceLabel, originalPriceValue, }) {
57
59
  const checkoutState = useCheckout();
58
60
  const walletPaymentMethods = usePlatformWalletPaymentMethods();
59
61
  const [selectedMethod, setSelectedMethod] = useState('wallet');
@@ -63,8 +65,11 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
63
65
  : walletAvailable;
64
66
  const [submitting, setSubmitting] = useState(false);
65
67
  const [error, setError] = useState(null);
68
+ const [billingCountry, setBillingCountry] = useState(null);
66
69
  const initialCustomerEmail = (customerEmail === null || customerEmail === void 0 ? void 0 : customerEmail.trim()) || '';
67
70
  const [emailDraft, setEmailDraft] = useState(initialCustomerEmail);
71
+ const normalizedSupportedCountries = useMemo(() => normalizeSupportedCheckoutCountries(supportedCountries), [supportedCountries]);
72
+ const fixedBillingCountry = getFixedSupportedBillingCountry(normalizedSupportedCountries);
68
73
  const cardBrandLabels = useMemo(() => paymentMethodLabels.length > 0 ? paymentMethodLabels : defaultPaymentMethodLabels, [paymentMethodLabels]);
69
74
  const normalizedPromoCode = promoCode.trim();
70
75
  const showPromo = promoActive !== null && promoActive !== void 0 ? promoActive : (discountPercent > 0 && normalizedPromoCode.length > 0);
@@ -122,7 +127,7 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
122
127
  name: 'never',
123
128
  email: 'never',
124
129
  address: {
125
- country: 'auto',
130
+ country: fixedBillingCountry ? 'never' : 'auto',
126
131
  },
127
132
  },
128
133
  },
@@ -133,7 +138,7 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
133
138
  link: 'never',
134
139
  },
135
140
  };
136
- }, []);
141
+ }, [fixedBillingCountry]);
137
142
  const handleInactiveCheckoutSession = () => {
138
143
  setError(null);
139
144
  onInactiveCheckoutSession === null || onInactiveCheckoutSession === void 0 ? void 0 : onInactiveCheckoutSession();
@@ -158,6 +163,15 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
158
163
  setSelectedMethod('card');
159
164
  }
160
165
  };
166
+ const getBillingCountryError = (country) => getUnsupportedCheckoutCountryMessage({
167
+ billingCountry: country,
168
+ message: unsupportedCountryMessage,
169
+ supportedCountries: normalizedSupportedCountries,
170
+ });
171
+ const handlePaymentElementChange = (event) => {
172
+ var _a, _b;
173
+ setBillingCountry((_b = (_a = event.value.billingDetails) === null || _a === void 0 ? void 0 : _a.address.country) !== null && _b !== void 0 ? _b : fixedBillingCountry);
174
+ };
161
175
  const trackCheckoutSuccess = async () => {
162
176
  if (checkoutAnalytics) {
163
177
  await trackPaidStripeSubscriptionCheckoutCompleted(Object.assign({ checkoutSessionId }, checkoutAnalytics));
@@ -210,6 +224,11 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
210
224
  if (submitting) {
211
225
  return;
212
226
  }
227
+ const billingCountryError = getBillingCountryError(billingCountry !== null && billingCountry !== void 0 ? billingCountry : fixedBillingCountry);
228
+ if (billingCountryError) {
229
+ setSharedError(billingCountryError);
230
+ return;
231
+ }
213
232
  if (checkoutState.type !== 'success') {
214
233
  setSharedError(checkoutState.type === 'error'
215
234
  ? checkoutState.error.message
@@ -267,7 +286,7 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
267
286
  effectiveSelectedMethod === 'wallet' ? 'is-visible' : '',
268
287
  ]
269
288
  .filter(Boolean)
270
- .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', confirmEmail: false, customerEmail: resolvedCustomerEmail, customerName: customerName, initialAvailable: initialWalletAvailable, keepInitialAvailableOnReady: initialWalletAvailable === true, onAvailabilityChange: handleWalletAvailabilityChange, onError: setSharedError, onPaymentInfoSubmitted: onPaymentInfoSubmitted, onSuccess: trackCheckoutSuccess, options: expressCheckoutOptions, returnUrl: returnUrl, summaryLabel: expressCheckoutSummaryLabel }), _jsx("span", { className: 'shared-checkout-v2-sr-only', children: walletAriaLabel })] })] }), _jsxs("div", { hidden: effectiveSelectedMethod !== 'card', className: [
289
+ .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', confirmEmail: false, customerEmail: resolvedCustomerEmail, customerName: customerName, initialAvailable: initialWalletAvailable, keepInitialAvailableOnReady: initialWalletAvailable === true, onAvailabilityChange: handleWalletAvailabilityChange, onError: setSharedError, onPaymentInfoSubmitted: onPaymentInfoSubmitted, onSuccess: trackCheckoutSuccess, options: expressCheckoutOptions, returnUrl: returnUrl, summaryLabel: expressCheckoutSummaryLabel, supportedCountries: normalizedSupportedCountries, unsupportedCountryMessage: unsupportedCountryMessage }), _jsx("span", { className: 'shared-checkout-v2-sr-only', children: walletAriaLabel })] })] }), _jsxs("div", { hidden: effectiveSelectedMethod !== 'card', className: [
271
290
  'shared-checkout-v2-card-panel',
272
291
  effectiveSelectedMethod === 'card' ? 'is-visible' : '',
273
292
  ]
@@ -278,16 +297,25 @@ function SharedStripeCheckoutV2Form({ amountCents, buttonColor, cardSubmitLabel,
278
297
  }
279
298
  setEmailDraft(event.target.value);
280
299
  onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(event.target.value);
281
- } }) })] }), _jsx(PaymentElement, { options: paymentElementOptions })] }), visibleError ? _jsx("p", { className: 'shared-checkout-v2-error', children: visibleError }) : null, _jsxs("button", { type: 'submit', className: 'shared-checkout-v2-card-submit', disabled: submitting, children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-card-submit-icon' }), submitting ? processingLabel : cardSubmitLabel] }), _jsx("div", { className: 'shared-checkout-v2-card-brands', "aria-hidden": 'true', children: cardBrandLabels.map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'shared-checkout-v2-card-brand' }, label))) }), _jsxs("p", { className: 'shared-checkout-v2-secure-pill shared-checkout-v2-secure-pill--card', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] })] })] })] }));
300
+ } }) })] }), _jsx(PaymentElement, { options: paymentElementOptions, onChange: handlePaymentElementChange })] }), visibleError ? _jsx("p", { className: 'shared-checkout-v2-error', children: visibleError }) : null, _jsxs("button", { type: 'submit', className: 'shared-checkout-v2-card-submit', disabled: submitting, children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-card-submit-icon' }), submitting ? processingLabel : cardSubmitLabel] }), _jsx("div", { className: 'shared-checkout-v2-card-brands', "aria-hidden": 'true', children: cardBrandLabels.map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'shared-checkout-v2-card-brand' }, label))) }), _jsxs("p", { className: 'shared-checkout-v2-secure-pill shared-checkout-v2-secure-pill--card', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] })] })] })] }));
282
301
  }
283
302
  export function SharedStripeCheckoutV2Dialog(_a) {
284
- var { checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise } = _a, props = __rest(_a, ["checkoutAnalytics", "checkoutSessionId", "clientSecret", "onClose", "stripePromise"]);
285
- const checkoutProviderOptions = useMemo(() => ({
286
- clientSecret,
287
- elementsOptions: {
303
+ var { checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries } = _a, props = __rest(_a, ["checkoutAnalytics", "checkoutSessionId", "clientSecret", "onClose", "stripePromise", "supportedCountries"]);
304
+ const normalizedSupportedCountries = useMemo(() => normalizeSupportedCheckoutCountries(supportedCountries), [supportedCountries]);
305
+ const fixedBillingCountry = getFixedSupportedBillingCountry(normalizedSupportedCountries);
306
+ const checkoutProviderOptions = useMemo(() => (Object.assign(Object.assign({ clientSecret }, (fixedBillingCountry
307
+ ? {
308
+ defaultValues: {
309
+ billingAddress: {
310
+ address: {
311
+ country: fixedBillingCountry,
312
+ },
313
+ },
314
+ },
315
+ }
316
+ : {})), { elementsOptions: {
288
317
  appearance: stripeCheckoutV2Appearance,
289
- },
290
- }), [clientSecret]);
318
+ } })), [clientSecret, fixedBillingCountry]);
291
319
  useEffect(() => {
292
320
  if (!checkoutAnalytics) {
293
321
  return;
@@ -303,7 +331,7 @@ export function SharedStripeCheckoutV2Dialog(_a) {
303
331
  window.addEventListener('keydown', handleKeyDown);
304
332
  return () => window.removeEventListener('keydown', handleKeyDown);
305
333
  }, [onClose]);
306
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: 'shared-checkout-v2-overlay', children: _jsx("div", { className: 'shared-checkout-v2-dialog', role: 'dialog', "aria-modal": 'true', "aria-labelledby": 'shared-checkout-v2-title', children: _jsx(CheckoutProvider, { stripe: stripePromise, options: checkoutProviderOptions, children: _jsx(SharedStripeCheckoutV2Form, Object.assign({}, props, { checkoutAnalytics: checkoutAnalytics, checkoutSessionId: checkoutSessionId, clientSecret: clientSecret, onClose: onClose })) }, clientSecret) }) }), _jsx("style", { children: sharedStripeCheckoutV2Styles })] }));
334
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: 'shared-checkout-v2-overlay', children: _jsx("div", { className: 'shared-checkout-v2-dialog', role: 'dialog', "aria-modal": 'true', "aria-labelledby": 'shared-checkout-v2-title', children: _jsx(CheckoutProvider, { stripe: stripePromise, options: checkoutProviderOptions, children: _jsx(SharedStripeCheckoutV2Form, Object.assign({}, props, { checkoutAnalytics: checkoutAnalytics, checkoutSessionId: checkoutSessionId, clientSecret: clientSecret, onClose: onClose, supportedCountries: normalizedSupportedCountries })) }, clientSecret) }) }), _jsx("style", { children: sharedStripeCheckoutV2Styles })] }));
307
335
  }
308
336
  function SharedCheckoutSpecialOfferGift({ discountLabel, imageAlt, imageSrc, }) {
309
337
  if (imageSrc) {
@@ -16,11 +16,13 @@ export type StripeCheckoutExpressCheckoutButtonProps = {
16
16
  initialAvailable?: boolean | null;
17
17
  keepInitialAvailableOnReady?: boolean;
18
18
  serverUpdateKey?: string | null;
19
+ supportedCountries?: readonly string[];
19
20
  onServerUpdate?: () => Promise<boolean>;
20
21
  onAvailabilityChange?: (available: boolean) => void;
21
22
  onCancel?: () => void;
22
23
  onError?: (message: string | null) => void;
23
24
  onPaymentInfoSubmitted?: () => void | Promise<void>;
24
25
  onSuccess?: () => void | Promise<void>;
26
+ unsupportedCountryMessage?: string;
25
27
  };
26
- export declare function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAnalytics, checkoutSessionId, returnUrl, confirmEmail, customerEmail, className, options, availabilityPaymentMethods, initialAvailable, keepInitialAvailableOnReady, serverUpdateKey, onServerUpdate, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, }: StripeCheckoutExpressCheckoutButtonProps): import("react/jsx-runtime").JSX.Element;
28
+ export declare function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAnalytics, checkoutSessionId, returnUrl, confirmEmail, customerEmail, className, options, availabilityPaymentMethods, initialAvailable, keepInitialAvailableOnReady, serverUpdateKey, supportedCountries, onServerUpdate, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, unsupportedCountryMessage, }: StripeCheckoutExpressCheckoutButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -3,6 +3,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { ExpressCheckoutElement, useCheckout, } from '@stripe/react-stripe-js/checkout';
5
5
  import { trackPaidStripeSubscriptionCheckoutCompleted, trackStripeSubscriptionCheckoutStarted, } from '../../services/checkoutCompletionAnalytics.service.js';
6
+ import { getUnsupportedCheckoutCountryMessage, normalizeSupportedCheckoutCountries, } from './checkoutCountries.js';
6
7
  const ExpressCheckoutElementWithCancel = ExpressCheckoutElement;
7
8
  const buildDefaultOptions = () => ({
8
9
  buttonHeight: 55,
@@ -27,7 +28,7 @@ const buildDefaultOptions = () => ({
27
28
  paypal: 'never',
28
29
  },
29
30
  });
30
- export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAnalytics, checkoutSessionId, returnUrl, confirmEmail = true, customerEmail, className, options, availabilityPaymentMethods = ['applePay'], initialAvailable, keepInitialAvailableOnReady = false, serverUpdateKey, onServerUpdate, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, }) {
31
+ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAnalytics, checkoutSessionId, returnUrl, confirmEmail = true, customerEmail, className, options, availabilityPaymentMethods = ['applePay'], initialAvailable, keepInitialAvailableOnReady = false, serverUpdateKey, supportedCountries, onServerUpdate, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, unsupportedCountryMessage, }) {
31
32
  const checkoutState = useCheckout();
32
33
  const appliedServerUpdateKeyRef = useRef('');
33
34
  const serverUpdatePromiseRef = useRef(null);
@@ -37,6 +38,7 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
37
38
  ? true
38
39
  : walletAvailable;
39
40
  const baseOptions = useMemo(() => buildDefaultOptions(), []);
41
+ const normalizedSupportedCountries = useMemo(() => normalizeSupportedCheckoutCountries(supportedCountries), [supportedCountries]);
40
42
  const resolvedOptions = useMemo(() => {
41
43
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
42
44
  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 });
@@ -94,6 +96,7 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
94
96
  await (onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess());
95
97
  };
96
98
  const handleConfirm = async (event) => {
99
+ var _a, _b, _c;
97
100
  if (checkoutState.type !== 'success') {
98
101
  const message = checkoutState.type === 'error'
99
102
  ? checkoutState.error.message
@@ -103,6 +106,16 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
103
106
  return;
104
107
  }
105
108
  onError === null || onError === void 0 ? void 0 : onError(null);
109
+ const unsupportedCountryError = getUnsupportedCheckoutCountryMessage({
110
+ billingCountry: (_c = (_b = (_a = event.billingDetails) === null || _a === void 0 ? void 0 : _a.address) === null || _b === void 0 ? void 0 : _b.country) !== null && _c !== void 0 ? _c : null,
111
+ message: unsupportedCountryMessage,
112
+ supportedCountries: normalizedSupportedCountries,
113
+ });
114
+ if (unsupportedCountryError) {
115
+ onError === null || onError === void 0 ? void 0 : onError(unsupportedCountryError);
116
+ event.paymentFailed({ reason: 'invalid_billing_address', message: unsupportedCountryError });
117
+ return;
118
+ }
106
119
  const updated = await ensureServerUpdated();
107
120
  if (!updated) {
108
121
  const message = 'Unable to update checkout session.';
@@ -0,0 +1,7 @@
1
+ export declare const defaultUnsupportedCheckoutCountryMessage = "Payment is not available for the selected billing country.";
2
+ export declare function normalizeSupportedCheckoutCountries(countries?: readonly string[] | null): string[];
3
+ export declare function getUnsupportedCheckoutCountryMessage({ billingCountry, message, supportedCountries, }: {
4
+ billingCountry?: string | null;
5
+ message?: string;
6
+ supportedCountries: readonly string[];
7
+ }): string | null;
@@ -0,0 +1,25 @@
1
+ export const defaultUnsupportedCheckoutCountryMessage = 'Payment is not available for the selected billing country.';
2
+ const normalizeCheckoutCountryCode = (countryCode) => {
3
+ const normalizedCountryCode = (countryCode === null || countryCode === void 0 ? void 0 : countryCode.trim().toUpperCase()) || '';
4
+ return /^[A-Z]{2}$/.test(normalizedCountryCode) ? normalizedCountryCode : null;
5
+ };
6
+ export function normalizeSupportedCheckoutCountries(countries) {
7
+ const normalizedCountries = new Set();
8
+ for (const country of countries !== null && countries !== void 0 ? countries : []) {
9
+ const normalizedCountry = normalizeCheckoutCountryCode(country);
10
+ if (normalizedCountry) {
11
+ normalizedCountries.add(normalizedCountry);
12
+ }
13
+ }
14
+ return Array.from(normalizedCountries);
15
+ }
16
+ export function getUnsupportedCheckoutCountryMessage({ billingCountry, message = defaultUnsupportedCheckoutCountryMessage, supportedCountries, }) {
17
+ if (supportedCountries.length === 0) {
18
+ return null;
19
+ }
20
+ const normalizedBillingCountry = normalizeCheckoutCountryCode(billingCountry);
21
+ if (!normalizedBillingCountry) {
22
+ return null;
23
+ }
24
+ return supportedCountries.includes(normalizedBillingCountry) ? null : message;
25
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnelsgrove/payments",
3
- "version": "0.1.43",
3
+ "version": "0.1.45",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "main": "./dist/index.js",