@funnelsgrove/payments 0.1.56 → 0.1.58
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 +12 -4
- package/dist/config/billing.config.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/providers/stripe/ApplePaySubscriptionCheckoutSlot.d.ts +5 -0
- package/dist/providers/stripe/ApplePaySubscriptionCheckoutSlot.js +5 -0
- package/dist/providers/stripe/GooglePaySubscriptionCheckoutSlot.d.ts +5 -0
- package/dist/providers/stripe/GooglePaySubscriptionCheckoutSlot.js +5 -0
- package/dist/providers/stripe/StripeSubscriptionWalletSurface.d.ts +82 -0
- package/dist/providers/stripe/StripeSubscriptionWalletSurface.js +188 -0
- package/dist/providers/stripe/WalletSubscriptionCheckoutSlot.d.ts +5 -0
- package/dist/providers/stripe/WalletSubscriptionCheckoutSlot.js +5 -0
- package/dist/services/stripe.service.d.ts +2 -1
- package/dist/services/stripe.service.js +32 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,13 +13,17 @@ Read this file before editing checkout code. Deeper implementation docs:
|
|
|
13
13
|
|
|
14
14
|
## Current Checkout Path
|
|
15
15
|
|
|
16
|
+
Render every visible wallet placement with `StripeSubscriptionWalletSurface`. It is the normal current path for Apple Pay and Google Pay:
|
|
17
|
+
|
|
18
|
+
- Each surface owns one private Checkout Session per simultaneously visible wallet placement, isolated by its own `surfaceId`.
|
|
19
|
+
- Simultaneously visible placements may use the same plan and coupon; nothing is shared because each surface keeps its own session.
|
|
20
|
+
- When the selected plan changes, the surface updates the existing Checkout Session in place without changing `surfaceId`, React `key`, `clientSecret`, `CheckoutProvider`, or the Express Checkout iframe.
|
|
21
|
+
|
|
16
22
|
Use these for new subscription paywalls:
|
|
17
23
|
|
|
24
|
+
- `StripeSubscriptionWalletSurface`
|
|
18
25
|
- `useStripeSubscriptionCheckoutSession`
|
|
19
26
|
- `SharedStripeCheckoutV2Dialog`
|
|
20
|
-
- `ApplePaySubscriptionCheckoutSlot`
|
|
21
|
-
- `GooglePaySubscriptionCheckoutSlot`
|
|
22
|
-
- `WalletSubscriptionCheckoutSlot`
|
|
23
27
|
- `trackPaidStripeSubscriptionCheckoutCompleted`
|
|
24
28
|
|
|
25
29
|
Use these for new one-time paywall plans:
|
|
@@ -29,6 +33,10 @@ Use these for new one-time paywall plans:
|
|
|
29
33
|
|
|
30
34
|
Use `chargeStripeOneClickPayment` for post-checkout one-click upsells when the shared client helper fits the funnel. It delegates to `funnelSdkService.chargeOneClickPayment`.
|
|
31
35
|
|
|
36
|
+
## Advanced Wallet Primitives
|
|
37
|
+
|
|
38
|
+
`ApplePaySubscriptionCheckoutSlot`, `GooglePaySubscriptionCheckoutSlot`, and `WalletSubscriptionCheckoutSlot` stay exported and runtime-compatible. They are backward-compatible advanced low-level primitives: reach for them only when a placement needs wiring `StripeSubscriptionWalletSurface` does not cover. Never share one `useStripeSubscriptionCheckoutSession` result across placements; give each visible placement its own session.
|
|
39
|
+
|
|
32
40
|
## Compatibility-Only Surfaces
|
|
33
41
|
|
|
34
42
|
Keep these exports available for saved drafts, old published artifacts, and controlled migrations. Do not use them for new subscription checkout work:
|
|
@@ -70,7 +78,7 @@ When a live funnel still uses one of these, migrate the funnel deliberately with
|
|
|
70
78
|
- `services/runtimeBillingPlanCatalog.service`: test/live runtime catalog selection.
|
|
71
79
|
- `services/paywallOffer.service`: timed discount and display-plan helpers.
|
|
72
80
|
- `services/stripe.service`: Stripe loader, Checkout Session, hosted checkout, one-click, one-time Checkout Session clients, and deprecated PaymentIntent compatibility clients.
|
|
73
|
-
- `providers/*`: provider-neutral checkout state and Stripe subscription checkout slots.
|
|
81
|
+
- `providers/*`: provider-neutral checkout state, the Stripe subscription wallet surface, and Stripe subscription checkout slots.
|
|
74
82
|
- `components/shared/*`: plan selector, checkout dialogs, Express Checkout wrappers, wallet placeholders, and trust assets.
|
|
75
83
|
- `testing/walletCheckoutSmoke`: wallet checkout smoke assertions.
|
|
76
84
|
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from './providers/stripe/useStripeOneTimeCheckoutSession.js';
|
|
|
14
14
|
export * from './providers/stripe/WalletSubscriptionCheckoutSlot.js';
|
|
15
15
|
export * from './providers/stripe/ApplePaySubscriptionCheckoutSlot.js';
|
|
16
16
|
export * from './providers/stripe/GooglePaySubscriptionCheckoutSlot.js';
|
|
17
|
+
export * from './providers/stripe/StripeSubscriptionWalletSurface.js';
|
|
17
18
|
export { ManageSubscriptionScreen, type ManageSubscriptionContent, type ManageSubscriptionScreenProps, } from './components/ManageSubscriptionScreen.js';
|
|
18
19
|
export * from './components/shared/SharedStripeCheckoutV2Dialog.js';
|
|
19
20
|
export * from './components/shared/StripeExpressCheckoutElement.js';
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ export * from './providers/stripe/useStripeOneTimeCheckoutSession.js';
|
|
|
17
17
|
export * from './providers/stripe/WalletSubscriptionCheckoutSlot.js';
|
|
18
18
|
export * from './providers/stripe/ApplePaySubscriptionCheckoutSlot.js';
|
|
19
19
|
export * from './providers/stripe/GooglePaySubscriptionCheckoutSlot.js';
|
|
20
|
+
export * from './providers/stripe/StripeSubscriptionWalletSurface.js';
|
|
20
21
|
// Shared checkout and subscription-management UI.
|
|
21
22
|
export { ManageSubscriptionScreen, } from './components/ManageSubscriptionScreen.js';
|
|
22
23
|
export * from './components/shared/SharedStripeCheckoutV2Dialog.js';
|
|
@@ -4,4 +4,9 @@ export type ApplePaySubscriptionCheckoutSlotProps = Omit<WalletSubscriptionCheck
|
|
|
4
4
|
options?: Partial<StripeCheckoutExpressCheckoutElementOptions>;
|
|
5
5
|
placeholderLabel?: string;
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Prefer StripeSubscriptionWalletSurface for visible wallet placements. This slot stays
|
|
9
|
+
* exported and runtime-compatible as an advanced low-level primitive; its checkout session must
|
|
10
|
+
* never be shared across placements.
|
|
11
|
+
*/
|
|
7
12
|
export declare function ApplePaySubscriptionCheckoutSlot({ options, placeholderLabel, ...slotProps }: ApplePaySubscriptionCheckoutSlotProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -36,6 +36,11 @@ const applePayExpressCheckoutOptions = {
|
|
|
36
36
|
paypal: 'never',
|
|
37
37
|
},
|
|
38
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* @deprecated Prefer StripeSubscriptionWalletSurface for visible wallet placements. This slot stays
|
|
41
|
+
* exported and runtime-compatible as an advanced low-level primitive; its checkout session must
|
|
42
|
+
* never be shared across placements.
|
|
43
|
+
*/
|
|
39
44
|
export function ApplePaySubscriptionCheckoutSlot(_a) {
|
|
40
45
|
var _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
41
46
|
var { options, placeholderLabel = 'Subscribe with Apple Pay' } = _a, slotProps = __rest(_a, ["options", "placeholderLabel"]);
|
|
@@ -4,4 +4,9 @@ export type GooglePaySubscriptionCheckoutSlotProps = Omit<WalletSubscriptionChec
|
|
|
4
4
|
options?: Partial<StripeCheckoutExpressCheckoutElementOptions>;
|
|
5
5
|
placeholderLabel?: string;
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Prefer StripeSubscriptionWalletSurface for visible wallet placements. This slot stays
|
|
9
|
+
* exported and runtime-compatible as an advanced low-level primitive; its checkout session must
|
|
10
|
+
* never be shared across placements.
|
|
11
|
+
*/
|
|
7
12
|
export declare function GooglePaySubscriptionCheckoutSlot({ options, placeholderLabel, ...slotProps }: GooglePaySubscriptionCheckoutSlotProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -36,6 +36,11 @@ const googlePayExpressCheckoutOptions = {
|
|
|
36
36
|
paypal: 'never',
|
|
37
37
|
},
|
|
38
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* @deprecated Prefer StripeSubscriptionWalletSurface for visible wallet placements. This slot stays
|
|
41
|
+
* exported and runtime-compatible as an advanced low-level primitive; its checkout session must
|
|
42
|
+
* never be shared across placements.
|
|
43
|
+
*/
|
|
39
44
|
export function GooglePaySubscriptionCheckoutSlot(_a) {
|
|
40
45
|
var _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
41
46
|
var { options, placeholderLabel = 'Subscribe with Google Pay' } = _a, slotProps = __rest(_a, ["options", "placeholderLabel"]);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { Appearance, StripeCheckoutExpressCheckoutElementOptions } from '@stripe/stripe-js';
|
|
3
|
+
import { type PlatformWalletPaymentMethod } from '../../components/shared/walletPlatform.js';
|
|
4
|
+
import type { StripeSubscriptionCheckoutAnalyticsContext } from '../../services/checkoutCompletionAnalytics.service.js';
|
|
5
|
+
import { type StripeSubscriptionCheckoutSessionInput } from './useStripeSubscriptionCheckoutSession.js';
|
|
6
|
+
export type StripeSubscriptionWalletSurfaceCheckoutInput = Omit<StripeSubscriptionCheckoutSessionInput, 'onError'> & {
|
|
7
|
+
customerName?: string | null;
|
|
8
|
+
};
|
|
9
|
+
export type StripeSubscriptionWalletSurfaceAvailability = {
|
|
10
|
+
anyAvailable: boolean;
|
|
11
|
+
methods: Partial<Record<PlatformWalletPaymentMethod, boolean>>;
|
|
12
|
+
resolved: boolean;
|
|
13
|
+
};
|
|
14
|
+
export type StripeSubscriptionWalletSurfaceAvailabilityState = {
|
|
15
|
+
intentKey: string;
|
|
16
|
+
methods: Partial<Record<PlatformWalletPaymentMethod, boolean>>;
|
|
17
|
+
};
|
|
18
|
+
export type StripeSubscriptionWalletSurfaceErrorContext = {
|
|
19
|
+
paymentMethod?: PlatformWalletPaymentMethod;
|
|
20
|
+
surfaceId: string;
|
|
21
|
+
};
|
|
22
|
+
export type StripeSubscriptionWalletSurfaceErrorEmission = {
|
|
23
|
+
context: StripeSubscriptionWalletSurfaceErrorContext;
|
|
24
|
+
errorState: StripeSubscriptionWalletSurfaceErrorState;
|
|
25
|
+
message: string | null;
|
|
26
|
+
};
|
|
27
|
+
export type StripeSubscriptionWalletSurfaceErrorState = {
|
|
28
|
+
methodMessages: Partial<Record<PlatformWalletPaymentMethod, string>>;
|
|
29
|
+
surfaceMessage: string | null;
|
|
30
|
+
};
|
|
31
|
+
export type StripeSubscriptionWalletSurfaceRenderStateInput = {
|
|
32
|
+
anyAvailable: boolean;
|
|
33
|
+
configured: boolean;
|
|
34
|
+
paymentMethodCount: number;
|
|
35
|
+
resolved: boolean;
|
|
36
|
+
suspended: boolean;
|
|
37
|
+
};
|
|
38
|
+
export declare function buildStripeSubscriptionWalletSurfaceAnalyticsMetadata(analyticsMetadata: Record<string, unknown> | null | undefined, surfaceId: string): Record<string, unknown>;
|
|
39
|
+
export declare function buildStripeSubscriptionWalletSurfaceCheckoutAnalytics(checkoutAnalytics: StripeSubscriptionCheckoutAnalyticsContext | null | undefined, surfaceId: string): StripeSubscriptionCheckoutAnalyticsContext | null;
|
|
40
|
+
export declare function normalizeStripeSubscriptionWalletSurfaceMethods(paymentMethods: readonly PlatformWalletPaymentMethod[]): PlatformWalletPaymentMethod[];
|
|
41
|
+
export declare function getStripeSubscriptionWalletSurfaceVisibleMethods(paymentMethods: readonly PlatformWalletPaymentMethod[], methods: Partial<Record<PlatformWalletPaymentMethod, boolean>>): PlatformWalletPaymentMethod[];
|
|
42
|
+
export declare function getStripeSubscriptionWalletSurfaceMethodAvailability(state: StripeSubscriptionWalletSurfaceAvailabilityState, intentKey: string): Partial<Record<PlatformWalletPaymentMethod, boolean>>;
|
|
43
|
+
export declare function applyStripeSubscriptionWalletSurfaceMethodAvailability(state: StripeSubscriptionWalletSurfaceAvailabilityState, intentKey: string, method: PlatformWalletPaymentMethod, available: boolean): StripeSubscriptionWalletSurfaceAvailabilityState;
|
|
44
|
+
export declare function buildStripeSubscriptionWalletSurfaceAvailability(paymentMethods: readonly PlatformWalletPaymentMethod[], methods: Partial<Record<PlatformWalletPaymentMethod, boolean>>): StripeSubscriptionWalletSurfaceAvailability;
|
|
45
|
+
export declare function shouldRenderStripeSubscriptionWalletSurface({ anyAvailable, configured, paymentMethodCount, resolved, suspended, }: StripeSubscriptionWalletSurfaceRenderStateInput): boolean;
|
|
46
|
+
export declare function resolveStripeSubscriptionWalletSurfaceError({ errorState, message, paymentMethod, surfaceId, }: {
|
|
47
|
+
errorState: StripeSubscriptionWalletSurfaceErrorState;
|
|
48
|
+
message: string | null;
|
|
49
|
+
paymentMethod?: PlatformWalletPaymentMethod;
|
|
50
|
+
surfaceId: string;
|
|
51
|
+
}): StripeSubscriptionWalletSurfaceErrorEmission | null;
|
|
52
|
+
export type StripeSubscriptionWalletSurfaceProps = {
|
|
53
|
+
amountCents: number;
|
|
54
|
+
appearance?: Appearance;
|
|
55
|
+
applePayOptions?: Partial<StripeCheckoutExpressCheckoutElementOptions>;
|
|
56
|
+
applePayPlaceholderLabel?: string;
|
|
57
|
+
beforeConfirm?: () => Promise<string | null>;
|
|
58
|
+
checkout: StripeSubscriptionWalletSurfaceCheckoutInput;
|
|
59
|
+
checkoutAnalytics?: StripeSubscriptionCheckoutAnalyticsContext | null;
|
|
60
|
+
className?: string;
|
|
61
|
+
containerClassName?: string;
|
|
62
|
+
disabled?: boolean;
|
|
63
|
+
googlePayOptions?: Partial<StripeCheckoutExpressCheckoutElementOptions>;
|
|
64
|
+
googlePayPlaceholderLabel?: string;
|
|
65
|
+
onAvailabilityChange?: (availability: StripeSubscriptionWalletSurfaceAvailability) => void;
|
|
66
|
+
onCancel?: () => void;
|
|
67
|
+
onError?: (message: string | null, context: StripeSubscriptionWalletSurfaceErrorContext) => void;
|
|
68
|
+
onPaymentInfoSubmitted?: () => void | Promise<void>;
|
|
69
|
+
onSuccess?: () => void | Promise<void>;
|
|
70
|
+
onUnavailableClick?: () => Promise<void> | void;
|
|
71
|
+
paymentMethods?: readonly PlatformWalletPaymentMethod[];
|
|
72
|
+
renderHeader?: (props: {
|
|
73
|
+
availability: StripeSubscriptionWalletSurfaceAvailability;
|
|
74
|
+
}) => ReactNode;
|
|
75
|
+
resolveMethodClassName?: (method: PlatformWalletPaymentMethod) => string | undefined;
|
|
76
|
+
resolveMethodWrapperClassName?: (method: PlatformWalletPaymentMethod) => string | undefined;
|
|
77
|
+
slotClassName?: string;
|
|
78
|
+
summaryLabel: string;
|
|
79
|
+
surfaceId: string;
|
|
80
|
+
suspended?: boolean;
|
|
81
|
+
};
|
|
82
|
+
export declare function StripeSubscriptionWalletSurface({ amountCents, appearance, applePayOptions, applePayPlaceholderLabel, beforeConfirm, checkout, checkoutAnalytics, className, containerClassName, disabled, googlePayOptions, googlePayPlaceholderLabel, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, onUnavailableClick, paymentMethods, renderHeader, resolveMethodClassName, resolveMethodWrapperClassName, slotClassName, summaryLabel, surfaceId, suspended, }: StripeSubscriptionWalletSurfaceProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
15
|
+
import { usePlatformWalletPaymentMethods, } from '../../components/shared/walletPlatform.js';
|
|
16
|
+
import { ApplePaySubscriptionCheckoutSlot } from './ApplePaySubscriptionCheckoutSlot.js';
|
|
17
|
+
import { GooglePaySubscriptionCheckoutSlot } from './GooglePaySubscriptionCheckoutSlot.js';
|
|
18
|
+
import { useStripeSubscriptionCheckoutSession, } from './useStripeSubscriptionCheckoutSession.js';
|
|
19
|
+
export function buildStripeSubscriptionWalletSurfaceAnalyticsMetadata(analyticsMetadata, surfaceId) {
|
|
20
|
+
return Object.assign(Object.assign({}, (analyticsMetadata !== null && analyticsMetadata !== void 0 ? analyticsMetadata : {})), { checkoutSurfaceId: surfaceId });
|
|
21
|
+
}
|
|
22
|
+
export function buildStripeSubscriptionWalletSurfaceCheckoutAnalytics(checkoutAnalytics, surfaceId) {
|
|
23
|
+
if (!checkoutAnalytics) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return Object.assign(Object.assign({}, checkoutAnalytics), { metadata: buildStripeSubscriptionWalletSurfaceAnalyticsMetadata(checkoutAnalytics.metadata, surfaceId) });
|
|
27
|
+
}
|
|
28
|
+
export function normalizeStripeSubscriptionWalletSurfaceMethods(paymentMethods) {
|
|
29
|
+
return paymentMethods.filter((method, index) => paymentMethods.indexOf(method) === index);
|
|
30
|
+
}
|
|
31
|
+
export function getStripeSubscriptionWalletSurfaceVisibleMethods(paymentMethods, methods) {
|
|
32
|
+
return paymentMethods.filter((method) => methods[method] !== false);
|
|
33
|
+
}
|
|
34
|
+
export function getStripeSubscriptionWalletSurfaceMethodAvailability(state, intentKey) {
|
|
35
|
+
return state.intentKey === intentKey ? state.methods : {};
|
|
36
|
+
}
|
|
37
|
+
export function applyStripeSubscriptionWalletSurfaceMethodAvailability(state, intentKey, method, available) {
|
|
38
|
+
return {
|
|
39
|
+
intentKey,
|
|
40
|
+
methods: Object.assign(Object.assign({}, getStripeSubscriptionWalletSurfaceMethodAvailability(state, intentKey)), { [method]: available }),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function buildStripeSubscriptionWalletSurfaceAvailability(paymentMethods, methods) {
|
|
44
|
+
const reportedMethods = paymentMethods.filter((method) => typeof methods[method] === 'boolean');
|
|
45
|
+
return {
|
|
46
|
+
anyAvailable: reportedMethods.some((method) => methods[method] === true),
|
|
47
|
+
methods: reportedMethods.reduce((current, method) => (Object.assign(Object.assign({}, current), { [method]: methods[method] === true })), {}),
|
|
48
|
+
resolved: reportedMethods.length === paymentMethods.length,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function shouldRenderStripeSubscriptionWalletSurface({ anyAvailable, configured, paymentMethodCount, resolved, suspended, }) {
|
|
52
|
+
return configured && !suspended && paymentMethodCount > 0 && (!resolved || anyAvailable);
|
|
53
|
+
}
|
|
54
|
+
export function resolveStripeSubscriptionWalletSurfaceError({ errorState, message, paymentMethod, surfaceId, }) {
|
|
55
|
+
if (paymentMethod && errorState.methodMessages[paymentMethod] === message) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
if (!paymentMethod) {
|
|
59
|
+
const methodMessages = Object.values(errorState.methodMessages);
|
|
60
|
+
if (message === null) {
|
|
61
|
+
if (errorState.surfaceMessage === null && methodMessages.length === 0) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else if (errorState.surfaceMessage === message || methodMessages.includes(message)) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const nextErrorState = message === null
|
|
70
|
+
? { methodMessages: {}, surfaceMessage: null }
|
|
71
|
+
: paymentMethod
|
|
72
|
+
? Object.assign(Object.assign({}, errorState), { methodMessages: Object.assign(Object.assign({}, errorState.methodMessages), { [paymentMethod]: message }) }) : Object.assign(Object.assign({}, errorState), { surfaceMessage: message });
|
|
73
|
+
return {
|
|
74
|
+
context: Object.assign(Object.assign({}, (paymentMethod ? { paymentMethod } : {})), { surfaceId }),
|
|
75
|
+
errorState: nextErrorState,
|
|
76
|
+
message,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// Availability identity used to notify consumers only when the aggregate actually changed.
|
|
80
|
+
function buildAvailabilitySignature(availability) {
|
|
81
|
+
return [
|
|
82
|
+
availability.resolved ? 'resolved' : 'unresolved',
|
|
83
|
+
availability.anyAvailable ? 'available' : 'unavailable',
|
|
84
|
+
Object.entries(availability.methods)
|
|
85
|
+
.map(([method, available]) => `${method}:${available ? '1' : '0'}`)
|
|
86
|
+
.sort()
|
|
87
|
+
.join(','),
|
|
88
|
+
].join('|');
|
|
89
|
+
}
|
|
90
|
+
export function StripeSubscriptionWalletSurface({ amountCents, appearance, applePayOptions, applePayPlaceholderLabel, beforeConfirm, checkout, checkoutAnalytics, className, containerClassName, disabled, googlePayOptions, googlePayPlaceholderLabel, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, onUnavailableClick, paymentMethods, renderHeader, resolveMethodClassName, resolveMethodWrapperClassName, slotClassName, summaryLabel, surfaceId, suspended = false, }) {
|
|
91
|
+
var _a;
|
|
92
|
+
const platformWalletPaymentMethods = usePlatformWalletPaymentMethods();
|
|
93
|
+
const walletPaymentMethods = normalizeStripeSubscriptionWalletSurfaceMethods(paymentMethods !== null && paymentMethods !== void 0 ? paymentMethods : platformWalletPaymentMethods);
|
|
94
|
+
const normalizedSurfaceId = surfaceId.trim();
|
|
95
|
+
const { customerName } = checkout, checkoutSessionInput = __rest(checkout, ["customerName"]);
|
|
96
|
+
const surfaceAnalyticsMetadata = useMemo(() => buildStripeSubscriptionWalletSurfaceAnalyticsMetadata(checkout.analyticsMetadata, normalizedSurfaceId), [checkout.analyticsMetadata, normalizedSurfaceId]);
|
|
97
|
+
const session = useStripeSubscriptionCheckoutSession(Object.assign(Object.assign({}, checkoutSessionInput), { analyticsMetadata: surfaceAnalyticsMetadata }));
|
|
98
|
+
const surfaceCheckoutAnalytics = useMemo(() => buildStripeSubscriptionWalletSurfaceCheckoutAnalytics(checkoutAnalytics, normalizedSurfaceId), [checkoutAnalytics, normalizedSurfaceId]);
|
|
99
|
+
const [availabilityState, setAvailabilityState] = useState({
|
|
100
|
+
intentKey: session.intentKey,
|
|
101
|
+
methods: {},
|
|
102
|
+
});
|
|
103
|
+
const availability = buildStripeSubscriptionWalletSurfaceAvailability(walletPaymentMethods, getStripeSubscriptionWalletSurfaceMethodAvailability(availabilityState, session.intentKey));
|
|
104
|
+
const availabilitySignature = buildAvailabilitySignature(availability);
|
|
105
|
+
const reportedAvailabilitySignatureRef = useRef(null);
|
|
106
|
+
const errorStateRef = useRef({
|
|
107
|
+
methodMessages: {},
|
|
108
|
+
surfaceMessage: null,
|
|
109
|
+
});
|
|
110
|
+
const emitError = useCallback((message, paymentMethod) => {
|
|
111
|
+
const emission = resolveStripeSubscriptionWalletSurfaceError({
|
|
112
|
+
errorState: errorStateRef.current,
|
|
113
|
+
message,
|
|
114
|
+
paymentMethod,
|
|
115
|
+
surfaceId: normalizedSurfaceId,
|
|
116
|
+
});
|
|
117
|
+
if (!emission) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
errorStateRef.current = emission.errorState;
|
|
121
|
+
onError === null || onError === void 0 ? void 0 : onError(emission.message, emission.context);
|
|
122
|
+
}, [normalizedSurfaceId, onError]);
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
if (reportedAvailabilitySignatureRef.current === availabilitySignature) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
reportedAvailabilitySignatureRef.current = availabilitySignature;
|
|
128
|
+
onAvailabilityChange === null || onAvailabilityChange === void 0 ? void 0 : onAvailabilityChange(availability);
|
|
129
|
+
}, [availability, availabilitySignature, onAvailabilityChange]);
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
emitError(session.error);
|
|
132
|
+
}, [emitError, session.error]);
|
|
133
|
+
const renderWalletMethod = (method) => {
|
|
134
|
+
var _a;
|
|
135
|
+
const slotProps = {
|
|
136
|
+
amountCents,
|
|
137
|
+
appearance,
|
|
138
|
+
beforeConfirm,
|
|
139
|
+
checkoutAnalytics: surfaceCheckoutAnalytics,
|
|
140
|
+
className: (_a = resolveMethodClassName === null || resolveMethodClassName === void 0 ? void 0 : resolveMethodClassName(method)) !== null && _a !== void 0 ? _a : className,
|
|
141
|
+
customerEmail: checkout.customerEmail,
|
|
142
|
+
customerName,
|
|
143
|
+
disabled,
|
|
144
|
+
onAvailabilityChange: (available) => setAvailabilityState((current) => applyStripeSubscriptionWalletSurfaceMethodAvailability(current, session.intentKey, method, available)),
|
|
145
|
+
onCancel,
|
|
146
|
+
onError: (message) => emitError(message, method),
|
|
147
|
+
onPaymentInfoSubmitted,
|
|
148
|
+
onSuccess,
|
|
149
|
+
onUnavailableClick,
|
|
150
|
+
returnUrl: checkout.returnUrl,
|
|
151
|
+
session,
|
|
152
|
+
slotClassName,
|
|
153
|
+
summaryLabel,
|
|
154
|
+
};
|
|
155
|
+
if (method === 'applePay') {
|
|
156
|
+
return (_jsx(ApplePaySubscriptionCheckoutSlot, Object.assign({}, slotProps, { options: applePayOptions, placeholderLabel: applePayPlaceholderLabel })));
|
|
157
|
+
}
|
|
158
|
+
if (method === 'googlePay') {
|
|
159
|
+
return (_jsx(GooglePaySubscriptionCheckoutSlot, Object.assign({}, slotProps, { options: googlePayOptions, placeholderLabel: googlePayPlaceholderLabel })));
|
|
160
|
+
}
|
|
161
|
+
return null;
|
|
162
|
+
};
|
|
163
|
+
const visibleWalletPaymentMethods = getStripeSubscriptionWalletSurfaceVisibleMethods(walletPaymentMethods, availability.methods);
|
|
164
|
+
const shouldRenderSurface = shouldRenderStripeSubscriptionWalletSurface({
|
|
165
|
+
anyAvailable: availability.anyAvailable,
|
|
166
|
+
configured: session.configured,
|
|
167
|
+
paymentMethodCount: walletPaymentMethods.length,
|
|
168
|
+
resolved: availability.resolved,
|
|
169
|
+
suspended,
|
|
170
|
+
});
|
|
171
|
+
if (!shouldRenderSurface) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
return (_jsxs("div", { className: [
|
|
175
|
+
'stripe-subscription-wallet-surface',
|
|
176
|
+
containerClassName !== null && containerClassName !== void 0 ? containerClassName : '',
|
|
177
|
+
]
|
|
178
|
+
.filter(Boolean)
|
|
179
|
+
.join(' '), "data-wallet-surface-id": normalizedSurfaceId, children: [(_a = renderHeader === null || renderHeader === void 0 ? void 0 : renderHeader({ availability })) !== null && _a !== void 0 ? _a : null, visibleWalletPaymentMethods.map((method) => {
|
|
180
|
+
var _a;
|
|
181
|
+
return (_jsx("div", { className: [
|
|
182
|
+
'stripe-subscription-wallet-surface__method',
|
|
183
|
+
(_a = resolveMethodWrapperClassName === null || resolveMethodWrapperClassName === void 0 ? void 0 : resolveMethodWrapperClassName(method)) !== null && _a !== void 0 ? _a : '',
|
|
184
|
+
]
|
|
185
|
+
.filter(Boolean)
|
|
186
|
+
.join(' '), "data-wallet-payment-method": method, children: renderWalletMethod(method) }, method));
|
|
187
|
+
})] }));
|
|
188
|
+
}
|
|
@@ -50,5 +50,10 @@ export type WalletSubscriptionCheckoutSlotProps = {
|
|
|
50
50
|
suspended?: boolean;
|
|
51
51
|
};
|
|
52
52
|
export declare function WalletSubscriptionCheckoutLoadingPlaceholder({ className, label, }: Pick<WalletPlaceholderButtonProps, 'className' | 'label'>): import("react/jsx-runtime").JSX.Element;
|
|
53
|
+
/**
|
|
54
|
+
* @deprecated Prefer StripeSubscriptionWalletSurface for visible wallet placements. This slot stays
|
|
55
|
+
* exported and runtime-compatible as an advanced low-level primitive; its checkout session must
|
|
56
|
+
* never be shared across placements.
|
|
57
|
+
*/
|
|
53
58
|
export declare function WalletSubscriptionCheckoutSlot({ amountCents, appearance, availabilityPaymentMethod, beforeConfirm, checkoutAnalytics, className, customerEmail, customerName, disabled, expressCheckoutAllowed, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, onUnavailableClick, options, placeholderLabel, renderPreparingPlaceholder, renderPlaceholder, returnUrl, session, slotClassName, summaryLabel, suspended, }: WalletSubscriptionCheckoutSlotProps): import("react/jsx-runtime").JSX.Element;
|
|
54
59
|
export {};
|
|
@@ -29,6 +29,11 @@ export function WalletSubscriptionCheckoutLoadingPlaceholder({ className, label,
|
|
|
29
29
|
.filter(Boolean)
|
|
30
30
|
.join(' '), "aria-label": label, role: 'status', children: [_jsx("span", { className: 'wallet-subscription-checkout-slot__loading-bar' }), _jsx("style", { children: walletSubscriptionCheckoutLoadingPlaceholderStyles })] }));
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* @deprecated Prefer StripeSubscriptionWalletSurface for visible wallet placements. This slot stays
|
|
34
|
+
* exported and runtime-compatible as an advanced low-level primitive; its checkout session must
|
|
35
|
+
* never be shared across placements.
|
|
36
|
+
*/
|
|
32
37
|
export function WalletSubscriptionCheckoutSlot({ amountCents, appearance, availabilityPaymentMethod, beforeConfirm, checkoutAnalytics, className, customerEmail, customerName, disabled = false, expressCheckoutAllowed = true, onAvailabilityChange, onCancel, onError, onPaymentInfoSubmitted, onSuccess, onUnavailableClick, options, placeholderLabel, renderPreparingPlaceholder, renderPlaceholder, returnUrl, session, slotClassName, summaryLabel, suspended = false, }) {
|
|
33
38
|
const [walletAvailability, setWalletAvailability] = useState({
|
|
34
39
|
available: null,
|
|
@@ -5,6 +5,7 @@ import type { RuntimeMode } from '@funnelsgrove/runtime';
|
|
|
5
5
|
import { type RemoteProjectBillingPlan } from './planCatalog.service.js';
|
|
6
6
|
export type PaywallPlan = {
|
|
7
7
|
id: string;
|
|
8
|
+
offerSetKey?: string;
|
|
8
9
|
title: string;
|
|
9
10
|
description?: string;
|
|
10
11
|
providerPlanId?: string;
|
|
@@ -45,7 +46,7 @@ export declare function resolvePaywallPlansFromProjectPlans(projectPlans: readon
|
|
|
45
46
|
export declare function getPaywallPlans(mode: RuntimeMode, planCatalog?: BillingPlanInputCatalog | readonly BillingFallbackPlanConfig[], options?: PaywallPlanResolutionOptions): Promise<readonly PaywallPlan[]>;
|
|
46
47
|
export declare function isStripeConfigured(mode: RuntimeMode): boolean;
|
|
47
48
|
export declare function getStripePromise(_mode: RuntimeMode, runtimePublishableKey?: string | null): Promise<Stripe | null> | null;
|
|
48
|
-
type CheckoutSessionPlanInput = Pick<PaywallPlan, 'amountCents' | 'analyticsPurchaseValue' | 'billingInterval' | 'billingIntervalCount' | 'description' | 'id' | 'providerPlanId' | 'title' | 'followUpProviderPlanId' | 'followUpPlanTitle' | 'followUpBillingInterval' | 'followUpBillingIntervalCount' | 'introIterations'>;
|
|
49
|
+
type CheckoutSessionPlanInput = Pick<PaywallPlan, 'amountCents' | 'analyticsPurchaseValue' | 'billingInterval' | 'billingIntervalCount' | 'description' | 'id' | 'providerPlanId' | 'title' | 'followUpProviderPlanId' | 'followUpPlanTitle' | 'followUpBillingInterval' | 'followUpBillingIntervalCount' | 'introIterations' | 'offerSetKey'>;
|
|
49
50
|
type CheckoutPlanRecurringConfig = {
|
|
50
51
|
interval: BillingPlanInterval;
|
|
51
52
|
intervalCount: number;
|
|
@@ -537,18 +537,19 @@ const normalizeCheckoutAnalyticsMetadata = (metadata, plan) => {
|
|
|
537
537
|
return Object.assign(Object.assign({}, (normalized !== null && normalized !== void 0 ? normalized : {})), { analyticsPurchaseValue });
|
|
538
538
|
};
|
|
539
539
|
export async function createStripeOneTimeCheckout(input) {
|
|
540
|
-
var _a, _b, _c, _d, _e;
|
|
540
|
+
var _a, _b, _c, _d, _e, _f;
|
|
541
541
|
return funnelSdkService.createOneTimeCheckout({
|
|
542
|
+
offerSetKey: ((_a = input.plan.offerSetKey) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
|
|
542
543
|
planId: getPaywallPlanSelectionValue(input.plan),
|
|
543
|
-
providerPlanId: ((
|
|
544
|
+
providerPlanId: ((_b = input.plan.providerPlanId) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
|
|
544
545
|
title: input.plan.title,
|
|
545
|
-
description: ((
|
|
546
|
+
description: ((_c = input.plan.description) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
|
|
546
547
|
amountCents: input.plan.amountCents,
|
|
547
|
-
couponId: ((
|
|
548
|
+
couponId: ((_d = input.couponId) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
|
|
548
549
|
analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
|
|
549
|
-
customerEmail: ((
|
|
550
|
+
customerEmail: ((_e = input.customerEmail) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
|
|
550
551
|
returnUrl: input.returnUrl,
|
|
551
|
-
userId: ((
|
|
552
|
+
userId: ((_f = input.user_id) === null || _f === void 0 ? void 0 : _f.trim()) || undefined,
|
|
552
553
|
environment: input.environment,
|
|
553
554
|
runtimeConfig: input.runtimeConfig,
|
|
554
555
|
});
|
|
@@ -584,57 +585,59 @@ export async function chargeStripeOneClickPayment(input) {
|
|
|
584
585
|
});
|
|
585
586
|
}
|
|
586
587
|
export async function createStripeSubscriptionCheckout(input) {
|
|
587
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
588
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
588
589
|
const recurring = resolveCheckoutPlanRecurringConfig(input.plan);
|
|
589
590
|
if (!recurring) {
|
|
590
591
|
throw new Error('Unable to resolve the recurring interval for the selected plan');
|
|
591
592
|
}
|
|
592
593
|
return funnelSdkService.createSubscriptionCheckout({
|
|
594
|
+
offerSetKey: ((_a = input.plan.offerSetKey) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
|
|
593
595
|
planId: getPaywallPlanSelectionValue(input.plan),
|
|
594
|
-
providerPlanId: ((
|
|
596
|
+
providerPlanId: ((_b = input.plan.providerPlanId) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
|
|
595
597
|
title: input.plan.title,
|
|
596
|
-
description: ((
|
|
598
|
+
description: ((_c = input.plan.description) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
|
|
597
599
|
amountCents: input.plan.amountCents,
|
|
598
600
|
billingInterval: recurring.interval,
|
|
599
601
|
billingIntervalCount: recurring.intervalCount,
|
|
600
|
-
followUpProviderPlanId: ((
|
|
601
|
-
followUpPlanTitle: ((
|
|
602
|
+
followUpProviderPlanId: ((_d = input.plan.followUpProviderPlanId) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
|
|
603
|
+
followUpPlanTitle: ((_e = input.plan.followUpPlanTitle) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
|
|
602
604
|
followUpBillingInterval: input.plan.followUpBillingInterval,
|
|
603
605
|
followUpBillingIntervalCount: input.plan.followUpBillingIntervalCount,
|
|
604
606
|
introIterations: input.plan.introIterations,
|
|
605
|
-
couponId: ((
|
|
607
|
+
couponId: ((_f = input.couponId) === null || _f === void 0 ? void 0 : _f.trim()) || undefined,
|
|
606
608
|
analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
|
|
607
|
-
customerEmail: ((
|
|
609
|
+
customerEmail: ((_g = input.customerEmail) === null || _g === void 0 ? void 0 : _g.trim()) || undefined,
|
|
608
610
|
returnUrl: input.returnUrl,
|
|
609
|
-
userId: ((
|
|
611
|
+
userId: ((_h = input.user_id) === null || _h === void 0 ? void 0 : _h.trim()) || undefined,
|
|
610
612
|
environment: input.environment,
|
|
611
613
|
runtimeConfig: input.runtimeConfig,
|
|
612
614
|
});
|
|
613
615
|
}
|
|
614
616
|
export async function updateStripeSubscriptionCheckoutPlan(input) {
|
|
615
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
617
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
616
618
|
const recurring = resolveCheckoutPlanRecurringConfig(input.plan);
|
|
617
619
|
if (!recurring) {
|
|
618
620
|
throw new Error('Unable to resolve the recurring interval for the selected plan');
|
|
619
621
|
}
|
|
620
622
|
return funnelSdkService.updateSubscriptionCheckoutPlan({
|
|
621
623
|
checkoutSessionId: input.checkoutSessionId.trim(),
|
|
624
|
+
offerSetKey: ((_a = input.plan.offerSetKey) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
|
|
622
625
|
planId: getPaywallPlanSelectionValue(input.plan),
|
|
623
|
-
providerPlanId: ((
|
|
626
|
+
providerPlanId: ((_b = input.plan.providerPlanId) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
|
|
624
627
|
title: input.plan.title,
|
|
625
|
-
description: ((
|
|
628
|
+
description: ((_c = input.plan.description) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
|
|
626
629
|
amountCents: input.plan.amountCents,
|
|
627
630
|
billingInterval: recurring.interval,
|
|
628
631
|
billingIntervalCount: recurring.intervalCount,
|
|
629
|
-
followUpProviderPlanId: ((
|
|
630
|
-
followUpPlanTitle: ((
|
|
632
|
+
followUpProviderPlanId: ((_d = input.plan.followUpProviderPlanId) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
|
|
633
|
+
followUpPlanTitle: ((_e = input.plan.followUpPlanTitle) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
|
|
631
634
|
followUpBillingInterval: input.plan.followUpBillingInterval,
|
|
632
635
|
followUpBillingIntervalCount: input.plan.followUpBillingIntervalCount,
|
|
633
636
|
introIterations: input.plan.introIterations,
|
|
634
|
-
couponId: ((
|
|
637
|
+
couponId: ((_f = input.couponId) === null || _f === void 0 ? void 0 : _f.trim()) || undefined,
|
|
635
638
|
analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
|
|
636
|
-
customerEmail: ((
|
|
637
|
-
userId: ((
|
|
639
|
+
customerEmail: ((_g = input.customerEmail) === null || _g === void 0 ? void 0 : _g.trim()) || undefined,
|
|
640
|
+
userId: ((_h = input.user_id) === null || _h === void 0 ? void 0 : _h.trim()) || undefined,
|
|
638
641
|
environment: input.environment,
|
|
639
642
|
runtimeConfig: input.runtimeConfig,
|
|
640
643
|
});
|
|
@@ -651,25 +654,26 @@ export async function verifyStripeSubscriptionCheckoutPayment(input) {
|
|
|
651
654
|
});
|
|
652
655
|
}
|
|
653
656
|
export async function createStripeCheckoutSession(input) {
|
|
654
|
-
var _a, _b, _c, _d, _e;
|
|
657
|
+
var _a, _b, _c, _d, _e, _f;
|
|
655
658
|
const recurring = resolveCheckoutPlanRecurringConfig(input.plan);
|
|
656
659
|
if (!recurring) {
|
|
657
660
|
throw new Error('Unable to resolve the recurring interval for the selected plan');
|
|
658
661
|
}
|
|
659
662
|
return funnelSdkService.createHostedCheckoutSession({
|
|
663
|
+
offerSetKey: ((_a = input.plan.offerSetKey) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
|
|
660
664
|
planId: getPaywallPlanSelectionValue(input.plan),
|
|
661
|
-
providerPlanId: ((
|
|
665
|
+
providerPlanId: ((_b = input.plan.providerPlanId) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
|
|
662
666
|
title: input.plan.title,
|
|
663
|
-
description: ((
|
|
667
|
+
description: ((_c = input.plan.description) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
|
|
664
668
|
amountCents: input.plan.amountCents,
|
|
665
669
|
billingInterval: recurring.interval,
|
|
666
670
|
billingIntervalCount: recurring.intervalCount,
|
|
667
|
-
couponId: ((
|
|
671
|
+
couponId: ((_d = input.couponId) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
|
|
668
672
|
analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
|
|
669
673
|
successUrl: input.successUrl,
|
|
670
674
|
cancelUrl: input.cancelUrl,
|
|
671
|
-
customerEmail: ((
|
|
672
|
-
userId: ((
|
|
675
|
+
customerEmail: ((_e = input.customerEmail) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
|
|
676
|
+
userId: ((_f = input.user_id) === null || _f === void 0 ? void 0 : _f.trim()) || undefined,
|
|
673
677
|
environment: input.environment,
|
|
674
678
|
runtimeConfig: input.runtimeConfig,
|
|
675
679
|
});
|