@funnelsgrove/payments 0.1.29 → 0.1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/billing.config.d.ts +1 -0
- package/dist/providers/stripe/WalletSubscriptionCheckoutSlot.d.ts +13 -0
- package/dist/providers/stripe/WalletSubscriptionCheckoutSlot.js +23 -10
- package/dist/providers/stripe/useStripeSubscriptionCheckoutSession.d.ts +5 -0
- package/dist/providers/stripe/useStripeSubscriptionCheckoutSession.js +35 -15
- package/dist/services/stripe.service.d.ts +1 -0
- package/dist/services/stripe.service.js +13 -0
- package/package.json +1 -1
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import type { AvailablePaymentMethods, StripeCheckoutExpressCheckoutElementOptions } from '@stripe/stripe-js';
|
|
3
3
|
import { type StripeSubscriptionCheckoutSession } from './useStripeSubscriptionCheckoutSession.js';
|
|
4
|
+
export type WalletSubscriptionCheckoutRenderStateInput = {
|
|
5
|
+
expressCheckoutAllowed: boolean;
|
|
6
|
+
hasActiveClientSecret: boolean;
|
|
7
|
+
hasStripePromise: boolean;
|
|
8
|
+
suspended: boolean;
|
|
9
|
+
walletAvailable: boolean | null;
|
|
10
|
+
};
|
|
11
|
+
export type WalletSubscriptionCheckoutRenderState = {
|
|
12
|
+
placeholderIsPreparing: boolean;
|
|
13
|
+
shouldRenderExpressCheckout: boolean;
|
|
14
|
+
shouldRenderPlaceholder: boolean;
|
|
15
|
+
};
|
|
16
|
+
export declare function getWalletSubscriptionCheckoutRenderState({ expressCheckoutAllowed, hasActiveClientSecret, hasStripePromise, suspended, walletAvailable, }: WalletSubscriptionCheckoutRenderStateInput): WalletSubscriptionCheckoutRenderState;
|
|
4
17
|
type WalletPlaceholderButtonProps = {
|
|
5
18
|
className?: string;
|
|
6
19
|
disabled: boolean;
|
|
@@ -3,6 +3,22 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
4
|
import { StripeExpressCheckoutElement } from '../../components/shared/StripeExpressCheckoutElement.js';
|
|
5
5
|
import { isInactiveCheckoutSessionError, } from './useStripeSubscriptionCheckoutSession.js';
|
|
6
|
+
export function getWalletSubscriptionCheckoutRenderState({ expressCheckoutAllowed, hasActiveClientSecret, hasStripePromise, suspended, walletAvailable, }) {
|
|
7
|
+
const shouldRenderExpressCheckout = !suspended &&
|
|
8
|
+
expressCheckoutAllowed &&
|
|
9
|
+
walletAvailable !== false &&
|
|
10
|
+
hasActiveClientSecret &&
|
|
11
|
+
hasStripePromise;
|
|
12
|
+
const shouldRenderPlaceholder = !shouldRenderExpressCheckout &&
|
|
13
|
+
!suspended &&
|
|
14
|
+
expressCheckoutAllowed &&
|
|
15
|
+
walletAvailable === null;
|
|
16
|
+
return {
|
|
17
|
+
placeholderIsPreparing: shouldRenderPlaceholder,
|
|
18
|
+
shouldRenderExpressCheckout,
|
|
19
|
+
shouldRenderPlaceholder,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
6
22
|
export function WalletSubscriptionCheckoutLoadingPlaceholder({ className, label, }) {
|
|
7
23
|
return (_jsxs("div", { className: [
|
|
8
24
|
'wallet-subscription-checkout-slot__loading',
|
|
@@ -21,16 +37,13 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
21
37
|
const walletAvailable = walletAvailability.intentKey === session.intentKey
|
|
22
38
|
? walletAvailability.available
|
|
23
39
|
: null;
|
|
24
|
-
const shouldRenderExpressCheckout =
|
|
25
|
-
expressCheckoutAllowed
|
|
26
|
-
|
|
27
|
-
Boolean(session.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
expressCheckoutAllowed &&
|
|
32
|
-
walletAvailable === null;
|
|
33
|
-
const placeholderIsPreparing = shouldRenderPlaceholder;
|
|
40
|
+
const { placeholderIsPreparing, shouldRenderExpressCheckout, shouldRenderPlaceholder, } = getWalletSubscriptionCheckoutRenderState({
|
|
41
|
+
expressCheckoutAllowed,
|
|
42
|
+
hasActiveClientSecret: Boolean(session.activeClientSecret),
|
|
43
|
+
hasStripePromise: Boolean(session.stripePromise),
|
|
44
|
+
suspended,
|
|
45
|
+
walletAvailable,
|
|
46
|
+
});
|
|
34
47
|
const serverUpdateKey = session.activeClientSecret &&
|
|
35
48
|
session.checkoutSessionId &&
|
|
36
49
|
session.activePlanKey !== session.planKey
|
|
@@ -35,5 +35,10 @@ export type StripeSubscriptionCheckoutSession = {
|
|
|
35
35
|
stripePromise: Promise<Stripe | null> | null;
|
|
36
36
|
updateCheckoutSessionPlan: () => Promise<boolean>;
|
|
37
37
|
};
|
|
38
|
+
export type StripeSubscriptionCheckoutIntentKeyInput = Pick<StripeSubscriptionCheckoutSessionInput, 'checkoutMode' | 'couponId' | 'customerEmail' | 'returnUrl' | 'runtimeConfig' | 'userId'> & {
|
|
39
|
+
analyticsMetadata?: Record<string, unknown> | null;
|
|
40
|
+
};
|
|
41
|
+
export declare function buildStripeSubscriptionCheckoutIntentKey({ checkoutMode, couponId, customerEmail, returnUrl, runtimeConfig, userId, }: StripeSubscriptionCheckoutIntentKeyInput): string;
|
|
42
|
+
export declare function shouldResetStripeSubscriptionCheckoutSessionForIntentKey(previousIntentKey: string | null, nextIntentKey: string): boolean;
|
|
38
43
|
export declare function isInactiveCheckoutSessionError(message?: string | null): boolean;
|
|
39
44
|
export declare function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMetadata, couponId, customerEmail, displayPlan, enabled, onError, plan, returnUrl, runtimeConfig, userId, }: StripeSubscriptionCheckoutSessionInput): StripeSubscriptionCheckoutSession;
|
|
@@ -9,6 +9,28 @@ const getFriendlyStripeCheckoutError = (error) => {
|
|
|
9
9
|
: message;
|
|
10
10
|
};
|
|
11
11
|
const normalizeRuntimeConfigValue = (value) => (value === null || value === void 0 ? void 0 : value.trim()) || '';
|
|
12
|
+
export function buildStripeSubscriptionCheckoutIntentKey({ checkoutMode, couponId, customerEmail, returnUrl, runtimeConfig, userId, }) {
|
|
13
|
+
const runtimeConfigSignature = [
|
|
14
|
+
normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.apiBaseUrl),
|
|
15
|
+
normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelId),
|
|
16
|
+
normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelVersionId),
|
|
17
|
+
normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey),
|
|
18
|
+
].join('|');
|
|
19
|
+
const customerEmailSignature = normalizeRuntimeConfigValue(customerEmail);
|
|
20
|
+
const userIdSignature = normalizeRuntimeConfigValue(userId);
|
|
21
|
+
return [
|
|
22
|
+
'stripe',
|
|
23
|
+
checkoutMode,
|
|
24
|
+
runtimeConfigSignature,
|
|
25
|
+
customerEmailSignature,
|
|
26
|
+
userIdSignature,
|
|
27
|
+
(couponId === null || couponId === void 0 ? void 0 : couponId.trim()) || '',
|
|
28
|
+
returnUrl.trim(),
|
|
29
|
+
].join('|');
|
|
30
|
+
}
|
|
31
|
+
export function shouldResetStripeSubscriptionCheckoutSessionForIntentKey(previousIntentKey, nextIntentKey) {
|
|
32
|
+
return previousIntentKey !== null && previousIntentKey !== nextIntentKey;
|
|
33
|
+
}
|
|
12
34
|
export function isInactiveCheckoutSessionError(message) {
|
|
13
35
|
var _a;
|
|
14
36
|
return /\bcheckout session\b.*\bno longer active\b/i.test((_a = message === null || message === void 0 ? void 0 : message.trim()) !== null && _a !== void 0 ? _a : '');
|
|
@@ -24,24 +46,17 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
24
46
|
const [runtimeStripePublishableKey, setRuntimeStripePublishableKey] = useState(null);
|
|
25
47
|
const creatingIntentRef = useRef(null);
|
|
26
48
|
const requestIdRef = useRef(0);
|
|
27
|
-
const runtimeConfigSignature = [
|
|
28
|
-
normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.apiBaseUrl),
|
|
29
|
-
normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelId),
|
|
30
|
-
normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelVersionId),
|
|
31
|
-
normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey),
|
|
32
|
-
].join('|');
|
|
33
|
-
const analyticsMetadataSignature = JSON.stringify(analyticsMetadata !== null && analyticsMetadata !== void 0 ? analyticsMetadata : {});
|
|
34
49
|
const configured = enabled &&
|
|
35
50
|
(isStripeConfigured(checkoutMode) ||
|
|
36
51
|
Boolean(normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey)));
|
|
37
|
-
const intentKey =
|
|
38
|
-
'stripe',
|
|
52
|
+
const intentKey = buildStripeSubscriptionCheckoutIntentKey({
|
|
39
53
|
checkoutMode,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
couponId,
|
|
55
|
+
customerEmail,
|
|
56
|
+
returnUrl,
|
|
57
|
+
runtimeConfig,
|
|
58
|
+
userId,
|
|
59
|
+
});
|
|
45
60
|
const planKey = [
|
|
46
61
|
(_a = plan === null || plan === void 0 ? void 0 : plan.id) !== null && _a !== void 0 ? _a : '',
|
|
47
62
|
(_b = plan === null || plan === void 0 ? void 0 : plan.providerPlanId) !== null && _b !== void 0 ? _b : '',
|
|
@@ -53,6 +68,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
53
68
|
const activeCheckoutSessionId = clientSecretIntentKey === intentKey ? checkoutSessionId : null;
|
|
54
69
|
const activePlanKey = clientSecretIntentKey === intentKey ? clientSecretPlanKey : null;
|
|
55
70
|
const stripePromise = useMemo(() => getStripePromise(checkoutMode, runtimeStripePublishableKey), [checkoutMode, runtimeStripePublishableKey]);
|
|
71
|
+
const previousIntentKeyRef = useRef(intentKey);
|
|
56
72
|
const clearActiveCheckoutSession = useCallback(() => {
|
|
57
73
|
requestIdRef.current += 1;
|
|
58
74
|
creatingIntentRef.current = null;
|
|
@@ -78,7 +94,11 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
78
94
|
setError(null);
|
|
79
95
|
}, [clearActiveCheckoutSession, setError]);
|
|
80
96
|
useEffect(() => {
|
|
81
|
-
|
|
97
|
+
const previousIntentKey = previousIntentKeyRef.current;
|
|
98
|
+
previousIntentKeyRef.current = intentKey;
|
|
99
|
+
if (shouldResetStripeSubscriptionCheckoutSessionForIntentKey(previousIntentKey, intentKey)) {
|
|
100
|
+
reset();
|
|
101
|
+
}
|
|
82
102
|
}, [intentKey, reset]);
|
|
83
103
|
const setSourceLoading = useCallback((source, value) => {
|
|
84
104
|
setLoading((current) => current[source] === value
|
|
@@ -14,6 +14,7 @@ export type PaywallPlan = {
|
|
|
14
14
|
perDayAmount: string;
|
|
15
15
|
perDayLabel: string;
|
|
16
16
|
amountCents: number;
|
|
17
|
+
analyticsPurchaseValue?: number;
|
|
17
18
|
comparison?: BillingFallbackPlanConfig['comparison'];
|
|
18
19
|
checkoutOriginalAmountCents?: number;
|
|
19
20
|
checkoutSummaryLabel?: string;
|
|
@@ -68,6 +68,17 @@ const asPositiveIntOrNull = (value) => {
|
|
|
68
68
|
}
|
|
69
69
|
return Math.round(numeric);
|
|
70
70
|
};
|
|
71
|
+
const asNonNegativeNumberOrNull = (value) => {
|
|
72
|
+
const numeric = typeof value === 'number'
|
|
73
|
+
? value
|
|
74
|
+
: typeof value === 'string' && value.trim()
|
|
75
|
+
? Number(value.trim())
|
|
76
|
+
: null;
|
|
77
|
+
if (numeric === null || !Number.isFinite(numeric) || numeric < 0) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return Math.round(numeric * 100) / 100;
|
|
81
|
+
};
|
|
71
82
|
const asBillingPlanIntervalOrNull = (value) => {
|
|
72
83
|
var _a;
|
|
73
84
|
const normalized = (_a = asTrimmedStringOrNull(value)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
@@ -230,6 +241,7 @@ const toRemoteProjectBillingPlan = (rawPlan) => {
|
|
|
230
241
|
};
|
|
231
242
|
};
|
|
232
243
|
const toPlanFromRemoteProjectPlan = (rawPlan, options, planIdOverride) => {
|
|
244
|
+
var _a;
|
|
233
245
|
const planId = (planIdOverride === null || planIdOverride === void 0 ? void 0 : planIdOverride.trim()) || rawPlan.id || rawPlan.key || rawPlan.providerPlanId;
|
|
234
246
|
if (!planId) {
|
|
235
247
|
return null;
|
|
@@ -266,6 +278,7 @@ const toPlanFromRemoteProjectPlan = (rawPlan, options, planIdOverride) => {
|
|
|
266
278
|
perDayAmount,
|
|
267
279
|
perDayLabel: 'per day',
|
|
268
280
|
amountCents: amountMinor,
|
|
281
|
+
analyticsPurchaseValue: (_a = asNonNegativeNumberOrNull(metadata.analyticsPurchaseValue)) !== null && _a !== void 0 ? _a : undefined,
|
|
269
282
|
comparison: intervalDays
|
|
270
283
|
? {
|
|
271
284
|
perDay: `${perDayAmount}/day`,
|