@funnelsgrove/payments 0.11.2 → 0.11.3
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
|
@@ -108,11 +108,11 @@ Funnels should call `resolvePublishedBillingRuntime` once at their runtime-provi
|
|
|
108
108
|
- Stripe owns real card fields and wallet controls. Local wallet buttons are placeholders until Stripe confirms availability.
|
|
109
109
|
- Keep `planId` as the funnel plan key and send Stripe's price id only as `providerPlanId`; the API uses both fields to resolve the active test/live offer mapping.
|
|
110
110
|
- Wallet unavailable state must fall back to card/manual checkout or disappear.
|
|
111
|
-
- Count `checkout_started` only at shared UI boundaries: when a shared card dialog opens or when Stripe reports Apple Pay / Google Pay intent. Checkout Sessions use confirmation as a fallback because Stripe omits their click callback.
|
|
111
|
+
- Count `checkout_started` only at shared UI boundaries: when a shared card dialog opens or when Stripe reports Apple Pay / Google Pay intent. Checkout Sessions use confirmation or cancellation as a fallback because Stripe omits their click callback. Cancellation recovers the start with `checkout_start_source: wallet_cancel`; its timestamp is dismissal time, not wallet-open time. Closing the browser before either callback is still unobservable. Cancel has no payment-method field, so the method is included only when the element enables exactly one method.
|
|
112
112
|
- Pass `checkoutAnalytics` to every current shared dialog and wallet surface. The package then owns `checkout_started`, `add_payment_info`, and verified `checkout_completed`, all deduplicated by the actual Checkout Session.
|
|
113
113
|
- Call funnel lifecycle `completeStep` only from the shared checkout `onSuccess` callback. Payment-info submission is not step completion.
|
|
114
114
|
- Wallet slots may create render-only Checkout Sessions on mount so Apple Pay and Google Pay render before the visitor taps. Session creation is technical preparation and must never emit `checkout_started`.
|
|
115
|
-
- Shared checkout analytics deduplicates `checkout_started` by Checkout Session id. Wallet confirmation may retry the start signal when the click callback is unavailable, without creating a duplicate.
|
|
115
|
+
- Shared checkout analytics deduplicates `checkout_started` by Checkout Session id. Wallet confirmation and cancellation may retry the start signal when the click callback is unavailable, without creating a duplicate. Cancellation never emits payment-info or purchase completion events.
|
|
116
116
|
- Do not call `publicAnalyticsSdk.trackCheckoutStarted`, `trackPaymentInfoSubmitted`, or `trackCheckoutCompleted` directly from funnel checkout components.
|
|
117
117
|
- Funnel paywalls should style wallet buttons through the shared slot API: `className` for the Stripe button/placeholder, `slotClassName` for the outer slot, `appearance` for Stripe Elements appearance, and `options` for Stripe Express Checkout options.
|
|
118
118
|
- Keep discount math reusable here, but keep offer activation timing in funnel code.
|
|
@@ -95,16 +95,18 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
|
|
|
95
95
|
}
|
|
96
96
|
await (onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess());
|
|
97
97
|
};
|
|
98
|
-
const queueCheckoutStarted = (paymentMethod) => {
|
|
98
|
+
const queueCheckoutStarted = (paymentMethod, checkoutStartSource = 'wallet_click') => {
|
|
99
99
|
if (!checkoutAnalytics) {
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
102
|
-
queueStripeSubscriptionCheckoutStarted(Object.assign(Object.assign({}, checkoutAnalytics), { checkoutSessionId,
|
|
102
|
+
queueStripeSubscriptionCheckoutStarted(Object.assign(Object.assign({}, checkoutAnalytics), { checkoutSessionId,
|
|
103
|
+
checkoutStartSource,
|
|
104
|
+
paymentMethod }));
|
|
103
105
|
};
|
|
104
106
|
const handleConfirm = async (event) => {
|
|
105
107
|
var _a, _b, _c;
|
|
106
108
|
// Checkout Sessions omits the Express Checkout onClick callback. Confirmation
|
|
107
|
-
//
|
|
109
|
+
// and cancellation are the reliable wallet-intent boundaries for this provider.
|
|
108
110
|
// Session-based analytics deduplication keeps this idempotent if onClick fires.
|
|
109
111
|
queueCheckoutStarted(event.expressPaymentType);
|
|
110
112
|
if (checkoutState.type !== 'success') {
|
|
@@ -176,13 +178,22 @@ export function StripeCheckoutExpressCheckoutButton({ beforeConfirm, checkoutAna
|
|
|
176
178
|
queueCheckoutStarted(event.expressPaymentType);
|
|
177
179
|
event.resolve();
|
|
178
180
|
};
|
|
181
|
+
const handleCancel = () => {
|
|
182
|
+
var _a;
|
|
183
|
+
// Dismissal proves the wallet was opened, even when Stripe omitted onClick.
|
|
184
|
+
// Cancel has no method field; only single-method placements can identify it.
|
|
185
|
+
const enabledMethods = Object.entries((_a = resolvedOptions.paymentMethods) !== null && _a !== void 0 ? _a : {})
|
|
186
|
+
.filter(([, availability]) => availability !== 'never');
|
|
187
|
+
queueCheckoutStarted(enabledMethods.length === 1 ? enabledMethods[0][0] : undefined, 'wallet_cancel');
|
|
188
|
+
onCancel === null || onCancel === void 0 ? void 0 : onCancel();
|
|
189
|
+
};
|
|
179
190
|
return (_jsxs(_Fragment, { children: [_jsx("div", { className: [
|
|
180
191
|
'stripe-express-checkout-button',
|
|
181
192
|
className !== null && className !== void 0 ? className : '',
|
|
182
193
|
effectiveWalletAvailable === false ? 'is-hidden' : '',
|
|
183
194
|
]
|
|
184
195
|
.filter(Boolean)
|
|
185
|
-
.join(' '), children: _jsx(ExpressCheckoutElementWithCancel, { options: resolvedOptions, onCancel:
|
|
196
|
+
.join(' '), children: _jsx(ExpressCheckoutElementWithCancel, { options: resolvedOptions, onCancel: handleCancel, onClick: handleClick, onConfirm: (event) => void handleConfirm(event), onLoadError: ({ error }) => {
|
|
186
197
|
setWalletAvailable(false);
|
|
187
198
|
onAvailabilityChange === null || onAvailabilityChange === void 0 ? void 0 : onAvailabilityChange(false);
|
|
188
199
|
onError === null || onError === void 0 ? void 0 : onError(error.message || 'Unable to load wallet checkout.');
|
|
@@ -12,7 +12,7 @@ export type StripeSubscriptionCheckoutAnalyticsContext = {
|
|
|
12
12
|
};
|
|
13
13
|
export type TrackStripeSubscriptionCheckoutStartedInput = StripeSubscriptionCheckoutAnalyticsContext & {
|
|
14
14
|
checkoutSessionId?: string | null;
|
|
15
|
-
checkoutStartSource?: 'card_form_open' | 'wallet_click';
|
|
15
|
+
checkoutStartSource?: 'card_form_open' | 'wallet_click' | 'wallet_cancel';
|
|
16
16
|
paymentMethod?: unknown;
|
|
17
17
|
};
|
|
18
18
|
export type TrackPaidStripeSubscriptionCheckoutCompletedInput = StripeSubscriptionCheckoutAnalyticsContext & {
|