@funnelsgrove/payments 0.1.4 → 0.1.6
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
|
@@ -40,11 +40,11 @@ Shared billing and checkout helpers for funnels.
|
|
|
40
40
|
- the `StripeExpressCheckoutElement` wrapper, which keeps `Elements` provider ownership inside this package so catalog funnels with their own dependency installs do not pass Stripe promises across duplicate local Stripe type copies
|
|
41
41
|
- `src/providers/paymentProvider.types.ts` for provider-neutral checkout preparation state and provider ids
|
|
42
42
|
- `src/providers/stripe/useStripeSubscriptionCheckoutSession.ts` for Stripe SDK initialization, publishable-key resolution, subscription client-secret preparation, card/wallet loading state, and friendly checkout errors
|
|
43
|
-
- `src/providers/stripe/ApplePaySubscriptionCheckoutSlot.tsx` and `src/providers/stripe/GooglePaySubscriptionCheckoutSlot.tsx` for
|
|
43
|
+
- `src/providers/stripe/ApplePaySubscriptionCheckoutSlot.tsx` and `src/providers/stripe/GooglePaySubscriptionCheckoutSlot.tsx` for wallet shells that prepare Stripe Express Checkout on load, keep the loading placeholder clickable, and let Stripe's real wallet controls sit above the placeholder as soon as they mount
|
|
44
44
|
- Stripe subscription checkout sessions reuse the active client secret across card checkout and paywall wallet checkout for the same intent key, so opening the embedded checkout after a paywall wallet button is ready does not create a second subscription session.
|
|
45
45
|
- Stripe Express Checkout elements must stay mounted and measurable until Stripe reports availability; only hide the container after `onReady` or `onLoadError` reports that the requested wallet method is unavailable.
|
|
46
46
|
- Shared checkout dialogs must switch to card checkout when Stripe reports no requested wallet availability, so an unavailable Apple Pay or Google Pay shell never leaves a fake wallet tab blocking the card form.
|
|
47
|
-
- Wallet slots should
|
|
47
|
+
- Wallet slots should not leave disabled grey placeholder shells blocking the paywall. While availability is unknown, the placeholder can sit behind Stripe's real wallet element; after Stripe reports unavailable or preparation cannot create a client secret, the placeholder must disappear instead of opening a card checkout under wallet branding.
|
|
48
48
|
- Checkout v2 owns only real Stripe Elements for card and wallet collection: Stripe controls the card-field placeholders, Stripe's `ExpressCheckoutElement` controls Apple Pay / Google Pay availability, desktop web can expose both wallet icons, and mobile narrows to Apple Pay on iOS or Google Pay on Android.
|
|
49
49
|
- Checkout v2 can receive a paywall-confirmed wallet availability hint and seed its wallet tab from that state, letting a checkout reopen keep Apple Pay or Google Pay visible while its own Express Checkout element remounts against the same client secret.
|
|
50
50
|
- Checkout v2 renders the wallet tab icons from the active platform wallet list and keeps Apple Pay / Google Pay marks large enough to read inside the tab.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
4
|
import { StripeExpressCheckoutElement } from '../../components/shared/StripeExpressCheckoutElement.js';
|
|
5
5
|
export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymentMethod, beforeConfirm, className, customerEmail, customerName, disabled = false, expressCheckoutAllowed = true, onAvailabilityChange, onError, onSuccess, onUnavailableClick, options, placeholderLabel, renderPlaceholder, returnUrl, session, summaryLabel, suspended = false, }) {
|
|
6
6
|
const [walletAvailability, setWalletAvailability] = useState({
|
|
@@ -12,12 +12,23 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
12
12
|
const walletAvailable = walletAvailability.intentKey === session.intentKey
|
|
13
13
|
? walletAvailability.available
|
|
14
14
|
: null;
|
|
15
|
-
const shouldRenderPlaceholder = !suspended && expressCheckoutAllowed && walletAvailable === null;
|
|
16
15
|
const shouldRenderExpressCheckout = !suspended &&
|
|
17
16
|
expressCheckoutAllowed &&
|
|
18
17
|
walletAvailable !== false &&
|
|
19
18
|
Boolean(session.activeClientSecret) &&
|
|
20
19
|
Boolean(session.stripePromise);
|
|
20
|
+
const shouldRenderPlaceholder = !shouldRenderExpressCheckout &&
|
|
21
|
+
!suspended &&
|
|
22
|
+
expressCheckoutAllowed &&
|
|
23
|
+
walletAvailable === null;
|
|
24
|
+
const placeholderIsPreparing = shouldRenderPlaceholder;
|
|
25
|
+
const markWalletUnavailable = useCallback((intentKey) => {
|
|
26
|
+
setWalletAvailability({
|
|
27
|
+
available: false,
|
|
28
|
+
intentKey,
|
|
29
|
+
});
|
|
30
|
+
onAvailabilityChange === null || onAvailabilityChange === void 0 ? void 0 : onAvailabilityChange(false);
|
|
31
|
+
}, [onAvailabilityChange]);
|
|
21
32
|
useEffect(() => {
|
|
22
33
|
if (slotDisabled ||
|
|
23
34
|
suspended ||
|
|
@@ -31,9 +42,15 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
31
42
|
return;
|
|
32
43
|
}
|
|
33
44
|
autoWalletAttemptedIntentKeyRef.current = requestKey;
|
|
34
|
-
void
|
|
45
|
+
void (async () => {
|
|
46
|
+
const readyClientSecret = await session.prepareWalletCheckout();
|
|
47
|
+
if (!readyClientSecret) {
|
|
48
|
+
markWalletUnavailable(requestKey);
|
|
49
|
+
}
|
|
50
|
+
})();
|
|
35
51
|
}, [
|
|
36
52
|
expressCheckoutAllowed,
|
|
53
|
+
markWalletUnavailable,
|
|
37
54
|
session,
|
|
38
55
|
slotDisabled,
|
|
39
56
|
suspended,
|
|
@@ -58,18 +75,22 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
58
75
|
await (onUnavailableClick === null || onUnavailableClick === void 0 ? void 0 : onUnavailableClick());
|
|
59
76
|
return;
|
|
60
77
|
}
|
|
61
|
-
await session.prepareWalletCheckout();
|
|
78
|
+
const readyClientSecret = await session.prepareWalletCheckout();
|
|
79
|
+
if (!readyClientSecret) {
|
|
80
|
+
markWalletUnavailable(session.intentKey);
|
|
81
|
+
}
|
|
62
82
|
};
|
|
63
83
|
return (_jsxs(_Fragment, { children: [shouldRenderPlaceholder || shouldRenderExpressCheckout ? (_jsxs("div", { className: [
|
|
64
84
|
'wallet-subscription-checkout-slot',
|
|
65
|
-
|
|
85
|
+
placeholderIsPreparing ? 'is-loading' : '',
|
|
86
|
+
shouldRenderExpressCheckout ? 'has-express-checkout' : '',
|
|
66
87
|
]
|
|
67
88
|
.filter(Boolean)
|
|
68
|
-
.join(' '), "aria-busy":
|
|
89
|
+
.join(' '), "aria-busy": placeholderIsPreparing || undefined, children: [shouldRenderExpressCheckout &&
|
|
69
90
|
session.activeClientSecret &&
|
|
70
91
|
session.stripePromise ? (_jsx(StripeExpressCheckoutElement, { amountCents: amountCents, availabilityPaymentMethods: [availabilityPaymentMethod], beforeConfirm: beforeConfirm, className: className, clientSecret: session.activeClientSecret, customerEmail: customerEmail, customerName: customerName, onAvailabilityChange: handleAvailabilityChange, onError: handleError, onSuccess: onSuccess, options: options, returnUrl: returnUrl, stripePromise: session.stripePromise, summaryLabel: summaryLabel })) : null, shouldRenderPlaceholder ? (_jsx("div", { className: 'wallet-subscription-checkout-slot__placeholder', children: renderPlaceholder({
|
|
71
92
|
className,
|
|
72
|
-
disabled:
|
|
93
|
+
disabled: slotDisabled,
|
|
73
94
|
label: placeholderLabel,
|
|
74
95
|
onClick: () => void handlePlaceholderClick(),
|
|
75
96
|
}) })) : null] })) : null, _jsx("style", { children: walletSubscriptionCheckoutSlotStyles })] }));
|
|
@@ -81,6 +102,11 @@ const walletSubscriptionCheckoutSlotStyles = `
|
|
|
81
102
|
min-height: var(--wallet-subscription-checkout-slot-min-height, 64px);
|
|
82
103
|
}
|
|
83
104
|
|
|
105
|
+
.wallet-subscription-checkout-slot .stripe-express-checkout-button {
|
|
106
|
+
position: relative;
|
|
107
|
+
z-index: 2;
|
|
108
|
+
}
|
|
109
|
+
|
|
84
110
|
.wallet-subscription-checkout-slot__placeholder {
|
|
85
111
|
position: absolute;
|
|
86
112
|
inset: 0;
|