@funnelsgrove/payments 0.1.50 → 0.1.51
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/README.md
CHANGED
|
@@ -24,8 +24,8 @@ Use these for new subscription paywalls:
|
|
|
24
24
|
|
|
25
25
|
Use these for new one-time paywall plans:
|
|
26
26
|
|
|
27
|
-
- `
|
|
28
|
-
- `SharedStripeCheckoutV2Dialog`
|
|
27
|
+
- `createStripeOneTimeCheckout`
|
|
28
|
+
- `SharedStripeCheckoutV2Dialog`
|
|
29
29
|
|
|
30
30
|
Use `chargeStripeOneClickPayment` for post-checkout one-click upsells when the shared client helper fits the funnel. It delegates to `funnelSdkService.chargeOneClickPayment`.
|
|
31
31
|
|
|
@@ -33,6 +33,7 @@ Use `chargeStripeOneClickPayment` for post-checkout one-click upsells when the s
|
|
|
33
33
|
|
|
34
34
|
Keep these exports available for saved drafts, old published artifacts, and controlled migrations. Do not use them for new subscription checkout work:
|
|
35
35
|
|
|
36
|
+
- `createStripePaymentIntent`
|
|
36
37
|
- `SharedStripeCheckoutDialog`
|
|
37
38
|
- `ApplePaySubscribeButton`
|
|
38
39
|
- `GooglePaySubscribeButton`
|
|
@@ -68,7 +69,7 @@ When a live funnel still uses one of these, migrate the funnel deliberately with
|
|
|
68
69
|
- `services/planCatalog.service`: plan resolution and selection helpers.
|
|
69
70
|
- `services/runtimeBillingPlanCatalog.service`: test/live runtime catalog selection.
|
|
70
71
|
- `services/paywallOffer.service`: timed discount and display-plan helpers.
|
|
71
|
-
- `services/stripe.service`: Stripe loader,
|
|
72
|
+
- `services/stripe.service`: Stripe loader, Checkout Session, hosted checkout, one-click, one-time Checkout Session clients, and deprecated PaymentIntent compatibility clients.
|
|
72
73
|
- `providers/*`: provider-neutral checkout state and Stripe subscription checkout slots.
|
|
73
74
|
- `components/shared/*`: plan selector, checkout dialogs, Express Checkout wrappers, wallet placeholders, and trust assets.
|
|
74
75
|
- `testing/walletCheckoutSmoke`: wallet checkout smoke assertions.
|
|
@@ -5,7 +5,6 @@ export type SharedStripeCheckoutV2DialogProps = {
|
|
|
5
5
|
buttonColor: string;
|
|
6
6
|
cardSubmitLabel: string;
|
|
7
7
|
checkoutAnalytics?: StripeSubscriptionCheckoutAnalyticsContext | null;
|
|
8
|
-
checkoutMode?: 'checkout_session' | 'payment_intent';
|
|
9
8
|
checkoutSessionId?: string | null;
|
|
10
9
|
clientSecret: string;
|
|
11
10
|
closeAriaLabel: string;
|
|
@@ -64,5 +63,5 @@ export type SharedCheckoutSpecialOfferDialogProps = {
|
|
|
64
63
|
themeColor: string;
|
|
65
64
|
title: string;
|
|
66
65
|
};
|
|
67
|
-
export declare function SharedStripeCheckoutV2Dialog({ checkoutAnalytics,
|
|
66
|
+
export declare function SharedStripeCheckoutV2Dialog({ checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries, ...props }: SharedStripeCheckoutV2DialogProps): import("react/jsx-runtime").JSX.Element;
|
|
68
67
|
export declare function SharedCheckoutSpecialOfferDialog({ buttonColor, buttonLabel, description, discountLabel, imageAlt, imageSrc, onAccept, themeColor, title, }: SharedCheckoutSpecialOfferDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -12,10 +12,8 @@ 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 { Elements, PaymentElement as PaymentIntentPaymentElement, useElements, useStripe, } from '@stripe/react-stripe-js';
|
|
16
15
|
import { CheckoutProvider, PaymentElement, useCheckout, } from '@stripe/react-stripe-js/checkout';
|
|
17
16
|
import { PaymentBrandMark, SecurityLockIcon } from './CheckoutBrandAssets.js';
|
|
18
|
-
import { StripeExpressCheckoutButton } from './StripeExpressCheckoutButton.js';
|
|
19
17
|
import { StripeCheckoutExpressCheckoutButton } from './StripeCheckoutExpressCheckoutButton.js';
|
|
20
18
|
import { getUnsupportedCheckoutCountryMessage, normalizeSupportedCheckoutCountries, } from './checkoutCountries.js';
|
|
21
19
|
import { isInactiveCheckoutSessionError } from '../../providers/stripe/useStripeSubscriptionCheckoutSession.js';
|
|
@@ -61,23 +59,6 @@ function getFriendlyCardErrorMessage(error) {
|
|
|
61
59
|
? error.message
|
|
62
60
|
: 'Payment failed. Please review your card details and try again.';
|
|
63
61
|
}
|
|
64
|
-
const normalizeBillingName = (input) => {
|
|
65
|
-
var _a, _b, _c;
|
|
66
|
-
const normalizedName = (_a = input.name) === null || _a === void 0 ? void 0 : _a.trim();
|
|
67
|
-
if (normalizedName) {
|
|
68
|
-
return normalizedName;
|
|
69
|
-
}
|
|
70
|
-
const normalizedEmail = (_b = input.email) === null || _b === void 0 ? void 0 : _b.trim();
|
|
71
|
-
if (normalizedEmail) {
|
|
72
|
-
const localPart = (_c = normalizedEmail
|
|
73
|
-
.split('@')[0]) === null || _c === void 0 ? void 0 : _c.replace(/[._-]+/g, ' ').trim();
|
|
74
|
-
if (localPart) {
|
|
75
|
-
return localPart;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return 'Customer';
|
|
79
|
-
};
|
|
80
|
-
const isSuccessfulIntentStatus = (status) => status === 'succeeded' || status === 'processing' || status === 'requires_capture';
|
|
81
62
|
function SharedStripeCheckoutV2CheckoutSessionForm({ 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, }) {
|
|
82
63
|
const checkoutState = useCheckout();
|
|
83
64
|
const walletPaymentMethods = usePlatformWalletPaymentMethods();
|
|
@@ -325,270 +306,6 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
|
|
|
325
306
|
onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(event.target.value);
|
|
326
307
|
} }) })] }), _jsx(PaymentElement, { options: paymentElementOptions, onChange: handlePaymentElementChange }), fixedBillingCountry && fixedBillingCountryLabel ? (_jsxs("label", { className: 'shared-checkout-v2-country-field', children: [_jsx("span", { className: 'shared-checkout-v2-country-label', children: "Country" }), _jsx("span", { className: 'shared-checkout-v2-country-control', children: _jsx("select", { "aria-label": 'Country', className: 'shared-checkout-v2-country-select', value: fixedBillingCountry, onChange: () => setBillingCountry(fixedBillingCountry), children: _jsx("option", { value: fixedBillingCountry, children: fixedBillingCountryLabel }) }) })] })) : null] }), 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] })] })] })] }));
|
|
327
308
|
}
|
|
328
|
-
function SharedStripeCheckoutV2PaymentIntentForm({ amountCents, buttonColor, cardSubmitLabel, closeAriaLabel, countdownLabel, customerEmail, customerEmailEditable = false, customerEmailLabel = 'Email', customerEmailPlaceholder = 'Enter your email', customerEmailInvalidMessage = 'Enter a valid email address.', customerName, discountAmountLabel, discountLabel, discountPercent, initialWalletAvailable, onClose, onCustomerEmailChange, onCustomerEmailCommit, onError, onPaymentInfoSubmitted, onSuccess, paymentMethodLabels = defaultPaymentMethodLabels, promoActive, processingLabel, promoCode, promoCodeLabel, remainingSeconds, returnUrl, savedLabel, secureLabel, satisfactionLabel, satisfactionPercent, summaryLabel, supportedCountries, themeColor, title, totalLabel, totalValue, unsupportedCountryMessage, walletButtonLabel, originalPriceLabel, originalPriceValue, }) {
|
|
329
|
-
const stripe = useStripe();
|
|
330
|
-
const elements = useElements();
|
|
331
|
-
const walletPaymentMethods = usePlatformWalletPaymentMethods();
|
|
332
|
-
const [selectedMethod, setSelectedMethod] = useState('wallet');
|
|
333
|
-
const [walletAvailable, setWalletAvailable] = useState(initialWalletAvailable !== null && initialWalletAvailable !== void 0 ? initialWalletAvailable : null);
|
|
334
|
-
const effectiveWalletAvailable = initialWalletAvailable === true && walletAvailable !== false
|
|
335
|
-
? true
|
|
336
|
-
: walletAvailable;
|
|
337
|
-
const [submitting, setSubmitting] = useState(false);
|
|
338
|
-
const [error, setError] = useState(null);
|
|
339
|
-
const [billingCountry, setBillingCountry] = useState(null);
|
|
340
|
-
const initialCustomerEmail = (customerEmail === null || customerEmail === void 0 ? void 0 : customerEmail.trim()) || '';
|
|
341
|
-
const [emailDraft, setEmailDraft] = useState(initialCustomerEmail);
|
|
342
|
-
const normalizedSupportedCountries = useMemo(() => normalizeSupportedCheckoutCountries(supportedCountries), [supportedCountries]);
|
|
343
|
-
const fixedBillingCountry = getFixedSupportedBillingCountry(normalizedSupportedCountries);
|
|
344
|
-
const fixedBillingCountryLabel = fixedBillingCountry
|
|
345
|
-
? getCheckoutCountryLabel(fixedBillingCountry)
|
|
346
|
-
: null;
|
|
347
|
-
const cardBrandLabels = useMemo(() => paymentMethodLabels.length > 0 ? paymentMethodLabels : defaultPaymentMethodLabels, [paymentMethodLabels]);
|
|
348
|
-
const normalizedPromoCode = promoCode.trim();
|
|
349
|
-
const showPromo = promoActive !== null && promoActive !== void 0 ? promoActive : (discountPercent > 0 && normalizedPromoCode.length > 0);
|
|
350
|
-
const countdownValue = formatCountdown(remainingSeconds);
|
|
351
|
-
const resolvedCustomerEmail = customerEmailEditable
|
|
352
|
-
? emailDraft.trim() || initialCustomerEmail
|
|
353
|
-
: initialCustomerEmail;
|
|
354
|
-
const emailFieldClassName = [
|
|
355
|
-
'shared-checkout-v2-email-field',
|
|
356
|
-
customerEmailEditable ? '' : 'is-disabled',
|
|
357
|
-
]
|
|
358
|
-
.filter(Boolean)
|
|
359
|
-
.join(' ');
|
|
360
|
-
const checkoutStyle = {
|
|
361
|
-
'--shared-checkout-v2-theme-color': themeColor,
|
|
362
|
-
'--shared-checkout-v2-button-color': buttonColor,
|
|
363
|
-
};
|
|
364
|
-
const expressCheckoutSummaryLabel = (summaryLabel === null || summaryLabel === void 0 ? void 0 : summaryLabel.trim()) || discountLabel || title;
|
|
365
|
-
const walletAriaLabel = walletPaymentMethods
|
|
366
|
-
.map((method) => method === 'applePay' ? walletButtonLabel : 'Google Pay')
|
|
367
|
-
.join(' / ');
|
|
368
|
-
const showWalletMethod = effectiveWalletAvailable !== false && walletPaymentMethods.length > 0;
|
|
369
|
-
const effectiveSelectedMethod = showWalletMethod && selectedMethod === 'wallet' ? 'wallet' : 'card';
|
|
370
|
-
const expressCheckoutOptions = useMemo(() => {
|
|
371
|
-
return {
|
|
372
|
-
buttonHeight: 55,
|
|
373
|
-
buttonTheme: {
|
|
374
|
-
applePay: 'black',
|
|
375
|
-
googlePay: 'black',
|
|
376
|
-
},
|
|
377
|
-
buttonType: {
|
|
378
|
-
applePay: 'buy',
|
|
379
|
-
googlePay: 'buy',
|
|
380
|
-
},
|
|
381
|
-
layout: {
|
|
382
|
-
maxColumns: 1,
|
|
383
|
-
maxRows: 2,
|
|
384
|
-
overflow: 'auto',
|
|
385
|
-
},
|
|
386
|
-
lineItems: [
|
|
387
|
-
{
|
|
388
|
-
name: expressCheckoutSummaryLabel,
|
|
389
|
-
amount: amountCents,
|
|
390
|
-
},
|
|
391
|
-
],
|
|
392
|
-
paymentMethodOrder: getStripeWalletPaymentMethodOrder(walletPaymentMethods),
|
|
393
|
-
paymentMethods: {
|
|
394
|
-
amazonPay: 'never',
|
|
395
|
-
applePay: walletPaymentMethods.includes('applePay') ? 'always' : 'never',
|
|
396
|
-
googlePay: walletPaymentMethods.includes('googlePay') ? 'always' : 'never',
|
|
397
|
-
klarna: 'never',
|
|
398
|
-
link: 'never',
|
|
399
|
-
paypal: 'never',
|
|
400
|
-
},
|
|
401
|
-
};
|
|
402
|
-
}, [amountCents, expressCheckoutSummaryLabel, walletPaymentMethods]);
|
|
403
|
-
const paymentElementOptions = useMemo(() => {
|
|
404
|
-
return Object.assign(Object.assign({ fields: {
|
|
405
|
-
billingDetails: {
|
|
406
|
-
name: 'never',
|
|
407
|
-
email: 'never',
|
|
408
|
-
address: {
|
|
409
|
-
country: fixedBillingCountry ? 'never' : 'auto',
|
|
410
|
-
},
|
|
411
|
-
},
|
|
412
|
-
} }, (fixedBillingCountry
|
|
413
|
-
? {
|
|
414
|
-
defaultValues: {
|
|
415
|
-
billingDetails: {
|
|
416
|
-
address: {
|
|
417
|
-
country: fixedBillingCountry,
|
|
418
|
-
},
|
|
419
|
-
},
|
|
420
|
-
},
|
|
421
|
-
}
|
|
422
|
-
: {})), { layout: 'tabs', wallets: {
|
|
423
|
-
applePay: 'never',
|
|
424
|
-
googlePay: 'never',
|
|
425
|
-
link: 'never',
|
|
426
|
-
} });
|
|
427
|
-
}, [fixedBillingCountry]);
|
|
428
|
-
const setSharedError = (message) => {
|
|
429
|
-
setError(message);
|
|
430
|
-
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
431
|
-
};
|
|
432
|
-
const selectWalletMethod = () => {
|
|
433
|
-
if (showWalletMethod) {
|
|
434
|
-
setSelectedMethod('wallet');
|
|
435
|
-
}
|
|
436
|
-
};
|
|
437
|
-
const selectCardMethod = () => setSelectedMethod('card');
|
|
438
|
-
const handleWalletAvailabilityChange = (available) => {
|
|
439
|
-
setWalletAvailable(available);
|
|
440
|
-
if (!available && selectedMethod === 'wallet') {
|
|
441
|
-
setSelectedMethod('card');
|
|
442
|
-
}
|
|
443
|
-
};
|
|
444
|
-
const getBillingCountryError = (country) => getUnsupportedCheckoutCountryMessage({
|
|
445
|
-
billingCountry: country,
|
|
446
|
-
message: unsupportedCountryMessage,
|
|
447
|
-
supportedCountries: normalizedSupportedCountries,
|
|
448
|
-
});
|
|
449
|
-
const handlePaymentElementChange = (event) => {
|
|
450
|
-
var _a, _b;
|
|
451
|
-
setBillingCountry((_b = (_a = event.value.billingDetails) === null || _a === void 0 ? void 0 : _a.address.country) !== null && _b !== void 0 ? _b : fixedBillingCountry);
|
|
452
|
-
};
|
|
453
|
-
const trackCheckoutSuccess = async () => {
|
|
454
|
-
await (onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess());
|
|
455
|
-
};
|
|
456
|
-
useEffect(() => {
|
|
457
|
-
if (effectiveSelectedMethod !== 'card' || typeof window === 'undefined') {
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
const resizeTimer = window.setTimeout(() => {
|
|
461
|
-
window.dispatchEvent(new Event('resize'));
|
|
462
|
-
}, 0);
|
|
463
|
-
return () => window.clearTimeout(resizeTimer);
|
|
464
|
-
}, [effectiveSelectedMethod]);
|
|
465
|
-
const commitCustomerEmail = async (normalizedEmail) => {
|
|
466
|
-
if (!customerEmailEditable || !onCustomerEmailCommit) {
|
|
467
|
-
return normalizedEmail;
|
|
468
|
-
}
|
|
469
|
-
const committedEmail = await onCustomerEmailCommit(normalizedEmail);
|
|
470
|
-
const nextEmail = typeof committedEmail === 'string' && committedEmail.trim()
|
|
471
|
-
? committedEmail.trim()
|
|
472
|
-
: normalizedEmail;
|
|
473
|
-
setEmailDraft(nextEmail);
|
|
474
|
-
onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(nextEmail);
|
|
475
|
-
return nextEmail;
|
|
476
|
-
};
|
|
477
|
-
const commitEmailDraftIfValid = (value) => {
|
|
478
|
-
const normalizedEmail = value.trim();
|
|
479
|
-
if (!customerEmailEditable || !onCustomerEmailCommit) {
|
|
480
|
-
return;
|
|
481
|
-
}
|
|
482
|
-
if (!normalizedEmail || !isValidEmail(normalizedEmail)) {
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
void commitCustomerEmail(normalizedEmail).catch((commitError) => {
|
|
486
|
-
setSharedError(getFriendlyCardErrorMessage(commitError));
|
|
487
|
-
});
|
|
488
|
-
};
|
|
489
|
-
const ensureCustomerEmail = async () => {
|
|
490
|
-
const normalizedEmail = resolvedCustomerEmail.trim();
|
|
491
|
-
if (!normalizedEmail || !isValidEmail(normalizedEmail)) {
|
|
492
|
-
setSharedError(customerEmailInvalidMessage);
|
|
493
|
-
return null;
|
|
494
|
-
}
|
|
495
|
-
return commitCustomerEmail(normalizedEmail);
|
|
496
|
-
};
|
|
497
|
-
const handleSubmit = async (event) => {
|
|
498
|
-
var _a;
|
|
499
|
-
event.preventDefault();
|
|
500
|
-
if (!stripe || !elements || submitting) {
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
|
-
const billingCountryError = getBillingCountryError(billingCountry !== null && billingCountry !== void 0 ? billingCountry : fixedBillingCountry);
|
|
504
|
-
if (billingCountryError) {
|
|
505
|
-
setSharedError(billingCountryError);
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
setSubmitting(true);
|
|
509
|
-
setSharedError(null);
|
|
510
|
-
try {
|
|
511
|
-
const syncedEmail = await ensureCustomerEmail();
|
|
512
|
-
if (!syncedEmail) {
|
|
513
|
-
setSubmitting(false);
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
const submitResult = await elements.submit();
|
|
517
|
-
if (submitResult.error) {
|
|
518
|
-
setSharedError(submitResult.error.message || 'Payment form is not ready yet.');
|
|
519
|
-
setSubmitting(false);
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
await (onPaymentInfoSubmitted === null || onPaymentInfoSubmitted === void 0 ? void 0 : onPaymentInfoSubmitted());
|
|
523
|
-
const result = await stripe.confirmPayment({
|
|
524
|
-
elements,
|
|
525
|
-
confirmParams: {
|
|
526
|
-
payment_method_data: {
|
|
527
|
-
billing_details: {
|
|
528
|
-
email: syncedEmail || undefined,
|
|
529
|
-
name: normalizeBillingName({
|
|
530
|
-
email: syncedEmail,
|
|
531
|
-
name: customerName,
|
|
532
|
-
}),
|
|
533
|
-
},
|
|
534
|
-
},
|
|
535
|
-
return_url: returnUrl,
|
|
536
|
-
},
|
|
537
|
-
redirect: 'if_required',
|
|
538
|
-
});
|
|
539
|
-
if (result.error) {
|
|
540
|
-
const message = result.error.message || 'Payment failed.';
|
|
541
|
-
setSharedError(message);
|
|
542
|
-
setSubmitting(false);
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
if (typeof window !== 'undefined' &&
|
|
546
|
-
isSuccessfulIntentStatus((_a = result.paymentIntent) === null || _a === void 0 ? void 0 : _a.status)) {
|
|
547
|
-
await trackCheckoutSuccess();
|
|
548
|
-
window.location.assign(returnUrl);
|
|
549
|
-
return;
|
|
550
|
-
}
|
|
551
|
-
setSubmitting(false);
|
|
552
|
-
}
|
|
553
|
-
catch (submitError) {
|
|
554
|
-
setSharedError(getFriendlyCardErrorMessage(submitError));
|
|
555
|
-
setSubmitting(false);
|
|
556
|
-
}
|
|
557
|
-
};
|
|
558
|
-
const visibleError = error;
|
|
559
|
-
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: [
|
|
560
|
-
'shared-checkout-v2-total',
|
|
561
|
-
showPromo ? '' : 'is-plain',
|
|
562
|
-
]
|
|
563
|
-
.filter(Boolean)
|
|
564
|
-
.join(' '), children: [_jsx("span", { children: totalLabel }), _jsxs("strong", { children: [_jsx("svg", { viewBox: '0 0 24 24', "aria-hidden": 'true', children: _jsx("path", { d: 'M20.6 13.4 12.4 21.6a2.2 2.2 0 0 1-3.1 0L2.4 14.7a2.2 2.2 0 0 1-.6-1.6V5.4a2 2 0 0 1 2-2h7.7a2.2 2.2 0 0 1 1.6.6l7.5 7.5a1.4 1.4 0 0 1 0 1.9ZM7.2 8.1a1.2 1.2 0 1 0 0-2.4 1.2 1.2 0 0 0 0 2.4Z' }) }), totalValue] })] }), showPromo ? (_jsxs("p", { className: 'shared-checkout-v2-saved', children: [_jsx("span", { "aria-hidden": 'true', children: "\uD83D\uDD25" }), savedLabel] })) : null] }), _jsxs("form", { className: 'shared-checkout-v2-payment', onSubmit: (event) => void handleSubmit(event), children: [showWalletMethod ? (_jsxs("div", { className: 'shared-checkout-v2-methods', role: 'tablist', "aria-label": 'Payment method', children: [_jsxs("button", { type: 'button', className: [
|
|
565
|
-
'shared-checkout-v2-method',
|
|
566
|
-
effectiveSelectedMethod === 'wallet' ? 'is-selected' : '',
|
|
567
|
-
]
|
|
568
|
-
.filter(Boolean)
|
|
569
|
-
.join(' '), onClick: selectWalletMethod, role: 'tab', "aria-selected": effectiveSelectedMethod === 'wallet', children: [_jsxs("span", { className: 'shared-checkout-v2-tab-wallets', "aria-hidden": 'true', children: [walletPaymentMethods.includes('applePay') ? (_jsx(PaymentBrandMark, { label: 'Apple Pay', className: 'shared-checkout-v2-tab-wallet' })) : null, walletPaymentMethods.includes('googlePay') ? (_jsx(PaymentBrandMark, { label: 'Google Pay', className: 'shared-checkout-v2-tab-wallet' })) : null] }), _jsx("span", { className: 'shared-checkout-v2-sr-only', children: walletAriaLabel })] }), _jsxs("button", { type: 'button', className: [
|
|
570
|
-
'shared-checkout-v2-method',
|
|
571
|
-
effectiveSelectedMethod === 'card' ? 'is-selected' : '',
|
|
572
|
-
]
|
|
573
|
-
.filter(Boolean)
|
|
574
|
-
.join(' '), onClick: selectCardMethod, role: 'tab', "aria-selected": effectiveSelectedMethod === 'card', children: [_jsx("strong", { children: "Credit card" }), _jsx("span", { className: 'shared-checkout-v2-tab-brands', "aria-hidden": 'true', children: cardBrandLabels.slice(0, 4).map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'shared-checkout-v2-tab-brand' }, label))) })] })] })) : null, _jsxs("div", { hidden: effectiveSelectedMethod !== 'wallet', className: [
|
|
575
|
-
'shared-checkout-v2-wallet-panel',
|
|
576
|
-
effectiveSelectedMethod === 'wallet' ? 'is-visible' : '',
|
|
577
|
-
]
|
|
578
|
-
.filter(Boolean)
|
|
579
|
-
.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, 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: [
|
|
580
|
-
'shared-checkout-v2-card-panel',
|
|
581
|
-
effectiveSelectedMethod === 'card' ? 'is-visible' : '',
|
|
582
|
-
]
|
|
583
|
-
.filter(Boolean)
|
|
584
|
-
.join(' '), children: [_jsxs("div", { className: 'shared-checkout-v2-card-box', children: [_jsxs("label", { className: emailFieldClassName, children: [_jsx("span", { className: 'shared-checkout-v2-email-label', children: customerEmailLabel }), _jsx("span", { className: 'shared-checkout-v2-email-control', children: _jsx("input", { type: 'email', autoComplete: 'email', className: 'shared-checkout-v2-email-input', disabled: !customerEmailEditable, inputMode: 'email', readOnly: !customerEmailEditable, value: customerEmailEditable ? emailDraft : initialCustomerEmail, placeholder: customerEmailPlaceholder, onBlur: (event) => commitEmailDraftIfValid(event.currentTarget.value), onChange: (event) => {
|
|
585
|
-
if (!customerEmailEditable) {
|
|
586
|
-
return;
|
|
587
|
-
}
|
|
588
|
-
setEmailDraft(event.target.value);
|
|
589
|
-
onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(event.target.value);
|
|
590
|
-
} }) })] }), _jsx(PaymentIntentPaymentElement, { options: paymentElementOptions, onChange: handlePaymentElementChange }), fixedBillingCountry && fixedBillingCountryLabel ? (_jsxs("label", { className: 'shared-checkout-v2-country-field', children: [_jsx("span", { className: 'shared-checkout-v2-country-label', children: "Country" }), _jsx("span", { className: 'shared-checkout-v2-country-control', children: _jsx("select", { "aria-label": 'Country', className: 'shared-checkout-v2-country-select', value: fixedBillingCountry, onChange: () => setBillingCountry(fixedBillingCountry), children: _jsx("option", { value: fixedBillingCountry, children: fixedBillingCountryLabel }) }) })] })) : null] }), 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] })] })] })] }));
|
|
591
|
-
}
|
|
592
309
|
function CheckoutSessionProvider({ children, clientSecret, fixedBillingCountry, stripePromise, }) {
|
|
593
310
|
const providerChildren = children;
|
|
594
311
|
const checkoutProviderOptions = useMemo(() => (Object.assign(Object.assign({ clientSecret }, (fixedBillingCountry
|
|
@@ -606,24 +323,16 @@ function CheckoutSessionProvider({ children, clientSecret, fixedBillingCountry,
|
|
|
606
323
|
} })), [clientSecret, fixedBillingCountry]);
|
|
607
324
|
return (_jsx(CheckoutProvider, { stripe: stripePromise, options: checkoutProviderOptions, children: providerChildren }, clientSecret));
|
|
608
325
|
}
|
|
609
|
-
function PaymentIntentProvider({ children, clientSecret, stripePromise, }) {
|
|
610
|
-
const providerChildren = children;
|
|
611
|
-
const elementsOptions = useMemo(() => ({
|
|
612
|
-
clientSecret,
|
|
613
|
-
appearance: stripeCheckoutV2Appearance,
|
|
614
|
-
}), [clientSecret]);
|
|
615
|
-
return (_jsx(Elements, { stripe: stripePromise, options: elementsOptions, children: providerChildren }, clientSecret));
|
|
616
|
-
}
|
|
617
326
|
export function SharedStripeCheckoutV2Dialog(_a) {
|
|
618
|
-
var { checkoutAnalytics,
|
|
327
|
+
var { checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries } = _a, props = __rest(_a, ["checkoutAnalytics", "checkoutSessionId", "clientSecret", "onClose", "stripePromise", "supportedCountries"]);
|
|
619
328
|
const normalizedSupportedCountries = useMemo(() => normalizeSupportedCheckoutCountries(supportedCountries), [supportedCountries]);
|
|
620
329
|
const fixedBillingCountry = getFixedSupportedBillingCountry(normalizedSupportedCountries);
|
|
621
330
|
useEffect(() => {
|
|
622
|
-
if (
|
|
331
|
+
if (!checkoutAnalytics) {
|
|
623
332
|
return;
|
|
624
333
|
}
|
|
625
334
|
void trackStripeSubscriptionCheckoutStarted(Object.assign({ checkoutSessionId }, checkoutAnalytics));
|
|
626
|
-
}, [checkoutAnalytics,
|
|
335
|
+
}, [checkoutAnalytics, checkoutSessionId, clientSecret]);
|
|
627
336
|
useEffect(() => {
|
|
628
337
|
const handleKeyDown = (event) => {
|
|
629
338
|
if (event.key === 'Escape') {
|
|
@@ -633,7 +342,7 @@ export function SharedStripeCheckoutV2Dialog(_a) {
|
|
|
633
342
|
window.addEventListener('keydown', handleKeyDown);
|
|
634
343
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
635
344
|
}, [onClose]);
|
|
636
|
-
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:
|
|
345
|
+
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(CheckoutSessionProvider, { clientSecret: clientSecret, fixedBillingCountry: fixedBillingCountry, stripePromise: stripePromise, children: _jsx(SharedStripeCheckoutV2CheckoutSessionForm, Object.assign({}, props, { checkoutAnalytics: checkoutAnalytics, checkoutSessionId: checkoutSessionId, clientSecret: clientSecret, onClose: onClose, supportedCountries: normalizedSupportedCountries })) }) }) }), _jsx("style", { children: sharedStripeCheckoutV2Styles })] }));
|
|
637
346
|
}
|
|
638
347
|
function SharedCheckoutSpecialOfferGift({ discountLabel, imageAlt, imageSrc, }) {
|
|
639
348
|
if (imageSrc) {
|
|
@@ -60,6 +60,26 @@ type CreatePaymentIntentResponse = {
|
|
|
60
60
|
stripePublishableKey?: string;
|
|
61
61
|
environment?: 'test' | 'live';
|
|
62
62
|
};
|
|
63
|
+
type CreateOneTimeCheckoutInput = {
|
|
64
|
+
plan: CheckoutSessionPlanInput;
|
|
65
|
+
couponId?: string | null;
|
|
66
|
+
analyticsMetadata?: Record<string, unknown> | null;
|
|
67
|
+
customerEmail?: string | null;
|
|
68
|
+
returnUrl: string;
|
|
69
|
+
user_id?: string | null;
|
|
70
|
+
environment?: RuntimeMode;
|
|
71
|
+
runtimeConfig?: StripeRuntimeConfigOverrides;
|
|
72
|
+
};
|
|
73
|
+
type CreateOneTimeCheckoutResponse = {
|
|
74
|
+
clientSecret: string;
|
|
75
|
+
checkoutSessionId?: string;
|
|
76
|
+
stripePublishableKey?: string;
|
|
77
|
+
environment?: 'test' | 'live';
|
|
78
|
+
};
|
|
79
|
+
export declare function createStripeOneTimeCheckout(input: CreateOneTimeCheckoutInput): Promise<CreateOneTimeCheckoutResponse>;
|
|
80
|
+
/**
|
|
81
|
+
* @deprecated Use createStripeOneTimeCheckout for one-time paywall checkout.
|
|
82
|
+
*/
|
|
63
83
|
export declare function createStripePaymentIntent(input: CreatePaymentIntentInput): Promise<CreatePaymentIntentResponse>;
|
|
64
84
|
type ChargeOneClickPaymentInput = {
|
|
65
85
|
planId: string;
|
|
@@ -531,6 +531,26 @@ const normalizeCheckoutAnalyticsMetadata = (metadata, plan) => {
|
|
|
531
531
|
}
|
|
532
532
|
return Object.assign(Object.assign({}, (normalized !== null && normalized !== void 0 ? normalized : {})), { analyticsPurchaseValue });
|
|
533
533
|
};
|
|
534
|
+
export async function createStripeOneTimeCheckout(input) {
|
|
535
|
+
var _a, _b, _c, _d, _e;
|
|
536
|
+
return funnelSdkService.createOneTimeCheckout({
|
|
537
|
+
planId: getPaywallPlanSelectionValue(input.plan),
|
|
538
|
+
providerPlanId: ((_a = input.plan.providerPlanId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
|
|
539
|
+
title: input.plan.title,
|
|
540
|
+
description: ((_b = input.plan.description) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
|
|
541
|
+
amountCents: input.plan.amountCents,
|
|
542
|
+
couponId: ((_c = input.couponId) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
|
|
543
|
+
analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
|
|
544
|
+
customerEmail: ((_d = input.customerEmail) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
|
|
545
|
+
returnUrl: input.returnUrl,
|
|
546
|
+
userId: ((_e = input.user_id) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
|
|
547
|
+
environment: input.environment,
|
|
548
|
+
runtimeConfig: input.runtimeConfig,
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* @deprecated Use createStripeOneTimeCheckout for one-time paywall checkout.
|
|
553
|
+
*/
|
|
534
554
|
export async function createStripePaymentIntent(input) {
|
|
535
555
|
var _a, _b;
|
|
536
556
|
return funnelSdkService.createOneTimePaymentIntent({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@funnelsgrove/payments",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.51",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@funnelsgrove/analytics": "^0.1.28",
|
|
31
|
-
"@funnelsgrove/runtime": "^0.1.
|
|
31
|
+
"@funnelsgrove/runtime": "^0.1.54",
|
|
32
32
|
"@stripe/react-stripe-js": "^5.6.0",
|
|
33
33
|
"@stripe/stripe-js": "^8.7.0",
|
|
34
34
|
"react": "19.2.3",
|