@appfunnel-dev/sdk 0.4.0 → 0.6.0
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/chunk-BUF5FDKC.cjs +1303 -0
- package/dist/chunk-BUF5FDKC.cjs.map +1 -0
- package/dist/chunk-E6KSJ5UI.js +1299 -0
- package/dist/chunk-E6KSJ5UI.js.map +1 -0
- package/dist/index.cjs +413 -313
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -14
- package/dist/index.d.ts +65 -14
- package/dist/index.js +392 -300
- package/dist/index.js.map +1 -1
- package/dist/internal-BlgQ9C2d.d.cts +515 -0
- package/dist/internal-BlgQ9C2d.d.ts +515 -0
- package/dist/internal.cjs +5 -1196
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +2 -204
- package/dist/internal.d.ts +2 -204
- package/dist/internal.js +1 -1199
- package/dist/internal.js.map +1 -1
- package/package.json +1 -1
- package/dist/types-ChorYUCl.d.cts +0 -255
- package/dist/types-ChorYUCl.d.ts +0 -255
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { useFunnelContext } from './chunk-E6KSJ5UI.js';
|
|
2
|
+
export { FunnelProvider, registerIntegration } from './chunk-E6KSJ5UI.js';
|
|
3
|
+
import { forwardRef, useState, useRef, useEffect, useCallback, useImperativeHandle, useMemo, useSyncExternalStore } from 'react';
|
|
3
4
|
import { loadStripe } from '@stripe/stripe-js';
|
|
4
|
-
import {
|
|
5
|
+
import { useStripe, useElements, PaymentElement, EmbeddedCheckoutProvider, EmbeddedCheckout, Elements } from '@stripe/react-stripe-js';
|
|
6
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
7
|
|
|
6
8
|
// src/config.ts
|
|
7
9
|
function defineConfig(config) {
|
|
@@ -10,23 +12,11 @@ function defineConfig(config) {
|
|
|
10
12
|
function definePage(definition) {
|
|
11
13
|
return definition;
|
|
12
14
|
}
|
|
13
|
-
function registerIntegration(id, loader) {
|
|
14
|
-
}
|
|
15
|
-
var FunnelContext = createContext(null);
|
|
16
|
-
function useFunnelContext() {
|
|
17
|
-
const ctx = useContext(FunnelContext);
|
|
18
|
-
if (!ctx) {
|
|
19
|
-
throw new Error("useFunnelContext must be used within a <FunnelProvider>");
|
|
20
|
-
}
|
|
21
|
-
return ctx;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// src/hooks/useVariable.ts
|
|
25
15
|
function useVariable(id) {
|
|
26
16
|
const { variableStore } = useFunnelContext();
|
|
27
17
|
const subscribe = useCallback(
|
|
28
|
-
(callback) => variableStore.subscribe(callback),
|
|
29
|
-
[variableStore]
|
|
18
|
+
(callback) => variableStore.subscribe(callback, { keys: [id] }),
|
|
19
|
+
[variableStore, id]
|
|
30
20
|
);
|
|
31
21
|
const getSnapshot = useCallback(
|
|
32
22
|
() => variableStore.get(id),
|
|
@@ -52,9 +42,9 @@ function useVariables() {
|
|
|
52
42
|
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
53
43
|
}
|
|
54
44
|
function useUser() {
|
|
55
|
-
const { variableStore
|
|
45
|
+
const { variableStore } = useFunnelContext();
|
|
56
46
|
const subscribe = useCallback(
|
|
57
|
-
(cb) => variableStore.subscribe(cb),
|
|
47
|
+
(cb) => variableStore.subscribe(cb, { prefix: "user." }),
|
|
58
48
|
[variableStore]
|
|
59
49
|
);
|
|
60
50
|
const getSnapshot = useCallback(
|
|
@@ -71,7 +61,6 @@ function useUser() {
|
|
|
71
61
|
dateOfBirth: variables["user.dateOfBirth"] || "",
|
|
72
62
|
setEmail(email) {
|
|
73
63
|
variableStore.set("user.email", email);
|
|
74
|
-
tracker.identify(email);
|
|
75
64
|
},
|
|
76
65
|
setName(name) {
|
|
77
66
|
variableStore.set("user.name", name);
|
|
@@ -80,15 +69,15 @@ function useUser() {
|
|
|
80
69
|
variableStore.set("user.dateOfBirth", dateOfBirth);
|
|
81
70
|
}
|
|
82
71
|
}),
|
|
83
|
-
[variables, variableStore
|
|
72
|
+
[variables, variableStore]
|
|
84
73
|
);
|
|
85
74
|
}
|
|
86
75
|
function useUserProperty(field) {
|
|
87
76
|
const { variableStore } = useFunnelContext();
|
|
88
77
|
const key = `user.${field}`;
|
|
89
78
|
const subscribe = useCallback(
|
|
90
|
-
(cb) => variableStore.subscribe(cb),
|
|
91
|
-
[variableStore]
|
|
79
|
+
(cb) => variableStore.subscribe(cb, { keys: [key] }),
|
|
80
|
+
[variableStore, key]
|
|
92
81
|
);
|
|
93
82
|
const getSnapshot = useCallback(
|
|
94
83
|
() => variableStore.get(key) || "",
|
|
@@ -105,8 +94,8 @@ function useResponse(key) {
|
|
|
105
94
|
const { variableStore } = useFunnelContext();
|
|
106
95
|
const prefixedKey = `answers.${key}`;
|
|
107
96
|
const subscribe = useCallback(
|
|
108
|
-
(cb) => variableStore.subscribe(cb),
|
|
109
|
-
[variableStore]
|
|
97
|
+
(cb) => variableStore.subscribe(cb, { keys: [prefixedKey] }),
|
|
98
|
+
[variableStore, prefixedKey]
|
|
110
99
|
);
|
|
111
100
|
const getSnapshot = useCallback(
|
|
112
101
|
() => variableStore.get(prefixedKey),
|
|
@@ -122,7 +111,7 @@ function useResponse(key) {
|
|
|
122
111
|
function useResponses() {
|
|
123
112
|
const { variableStore } = useFunnelContext();
|
|
124
113
|
const subscribe = useCallback(
|
|
125
|
-
(cb) => variableStore.subscribe(cb),
|
|
114
|
+
(cb) => variableStore.subscribe(cb, { prefix: "answers." }),
|
|
126
115
|
[variableStore]
|
|
127
116
|
);
|
|
128
117
|
const getSnapshot = useCallback(
|
|
@@ -143,7 +132,7 @@ function useResponses() {
|
|
|
143
132
|
function useQueryParams() {
|
|
144
133
|
const { variableStore } = useFunnelContext();
|
|
145
134
|
const subscribe = useCallback(
|
|
146
|
-
(cb) => variableStore.subscribe(cb),
|
|
135
|
+
(cb) => variableStore.subscribe(cb, { prefix: "query." }),
|
|
147
136
|
[variableStore]
|
|
148
137
|
);
|
|
149
138
|
const getSnapshot = useCallback(
|
|
@@ -165,8 +154,8 @@ function useQueryParam(key) {
|
|
|
165
154
|
const { variableStore } = useFunnelContext();
|
|
166
155
|
const prefixedKey = `query.${key}`;
|
|
167
156
|
const subscribe = useCallback(
|
|
168
|
-
(cb) => variableStore.subscribe(cb),
|
|
169
|
-
[variableStore]
|
|
157
|
+
(cb) => variableStore.subscribe(cb, { keys: [prefixedKey] }),
|
|
158
|
+
[variableStore, prefixedKey]
|
|
170
159
|
);
|
|
171
160
|
const getSnapshot = useCallback(
|
|
172
161
|
() => variableStore.get(prefixedKey) || "",
|
|
@@ -178,8 +167,8 @@ function useData(key) {
|
|
|
178
167
|
const { variableStore } = useFunnelContext();
|
|
179
168
|
const prefixedKey = `data.${key}`;
|
|
180
169
|
const subscribe = useCallback(
|
|
181
|
-
(cb) => variableStore.subscribe(cb),
|
|
182
|
-
[variableStore]
|
|
170
|
+
(cb) => variableStore.subscribe(cb, { keys: [prefixedKey] }),
|
|
171
|
+
[variableStore, prefixedKey]
|
|
183
172
|
);
|
|
184
173
|
const getSnapshot = useCallback(
|
|
185
174
|
() => variableStore.get(prefixedKey),
|
|
@@ -252,84 +241,53 @@ function useTranslation() {
|
|
|
252
241
|
}
|
|
253
242
|
function useNavigation() {
|
|
254
243
|
const { router, variableStore, tracker } = useFunnelContext();
|
|
255
|
-
|
|
256
|
-
(cb) =>
|
|
257
|
-
[
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
244
|
+
useSyncExternalStore(
|
|
245
|
+
useCallback((cb) => router.subscribe(cb), [router]),
|
|
246
|
+
useCallback(() => router.getSnapshot(), [router]),
|
|
247
|
+
useCallback(() => router.getSnapshot(), [router])
|
|
248
|
+
);
|
|
249
|
+
const afterNavigate = useCallback((key) => {
|
|
250
|
+
const page = router.getCurrentPage();
|
|
251
|
+
if (page) {
|
|
252
|
+
tracker.track("page.view", {
|
|
253
|
+
pageId: page.key,
|
|
254
|
+
pageKey: page.key,
|
|
255
|
+
pageName: page.name
|
|
256
|
+
});
|
|
257
|
+
tracker.startPageTracking(page.key);
|
|
258
|
+
}
|
|
259
|
+
variableStore.setMany({
|
|
260
|
+
"page.currentId": key,
|
|
261
|
+
"page.currentIndex": router.getPageHistory().length,
|
|
262
|
+
"page.current": router.getPageHistory().length + 1,
|
|
263
|
+
"page.startedAt": Date.now()
|
|
264
|
+
});
|
|
265
|
+
}, [router, tracker, variableStore]);
|
|
264
266
|
const goToNextPage = useCallback(() => {
|
|
265
267
|
const previousPage = router.getCurrentPage();
|
|
266
268
|
if (previousPage) {
|
|
267
269
|
tracker.stopPageTracking();
|
|
268
270
|
}
|
|
271
|
+
const variables = variableStore.getState();
|
|
269
272
|
const nextKey = router.goToNextPage(variables);
|
|
270
273
|
if (nextKey) {
|
|
271
|
-
|
|
272
|
-
if (nextPage) {
|
|
273
|
-
tracker.track("page.view", {
|
|
274
|
-
pageId: nextPage.key,
|
|
275
|
-
pageKey: nextPage.key,
|
|
276
|
-
pageName: nextPage.name
|
|
277
|
-
});
|
|
278
|
-
tracker.startPageTracking(nextPage.key);
|
|
279
|
-
}
|
|
280
|
-
variableStore.setMany({
|
|
281
|
-
"page.currentId": nextKey,
|
|
282
|
-
"page.currentIndex": router.getPageHistory().length,
|
|
283
|
-
"page.current": router.getPageHistory().length + 1,
|
|
284
|
-
"page.startedAt": Date.now(),
|
|
285
|
-
"page.timeOnCurrent": 0
|
|
286
|
-
});
|
|
274
|
+
afterNavigate(nextKey);
|
|
287
275
|
}
|
|
288
|
-
}, [router,
|
|
276
|
+
}, [router, tracker, variableStore, afterNavigate]);
|
|
289
277
|
const goBack = useCallback(() => {
|
|
290
278
|
tracker.stopPageTracking();
|
|
291
279
|
const prevKey = router.goBack();
|
|
292
280
|
if (prevKey) {
|
|
293
|
-
|
|
294
|
-
if (page) {
|
|
295
|
-
tracker.track("page.view", {
|
|
296
|
-
pageId: page.key,
|
|
297
|
-
pageKey: page.key,
|
|
298
|
-
pageName: page.name
|
|
299
|
-
});
|
|
300
|
-
tracker.startPageTracking(page.key);
|
|
301
|
-
}
|
|
302
|
-
variableStore.setMany({
|
|
303
|
-
"page.currentId": prevKey,
|
|
304
|
-
"page.currentIndex": router.getPageHistory().length,
|
|
305
|
-
"page.current": router.getPageHistory().length + 1,
|
|
306
|
-
"page.startedAt": Date.now(),
|
|
307
|
-
"page.timeOnCurrent": 0
|
|
308
|
-
});
|
|
281
|
+
afterNavigate(prevKey);
|
|
309
282
|
}
|
|
310
|
-
}, [router, tracker,
|
|
283
|
+
}, [router, tracker, afterNavigate]);
|
|
311
284
|
const goToPage = useCallback((pageKey) => {
|
|
312
285
|
tracker.stopPageTracking();
|
|
313
286
|
const key = router.goToPage(pageKey);
|
|
314
287
|
if (key) {
|
|
315
|
-
|
|
316
|
-
if (page) {
|
|
317
|
-
tracker.track("page.view", {
|
|
318
|
-
pageId: page.key,
|
|
319
|
-
pageKey: page.key,
|
|
320
|
-
pageName: page.name
|
|
321
|
-
});
|
|
322
|
-
tracker.startPageTracking(page.key);
|
|
323
|
-
}
|
|
324
|
-
variableStore.setMany({
|
|
325
|
-
"page.currentId": key,
|
|
326
|
-
"page.currentIndex": router.getPageHistory().length,
|
|
327
|
-
"page.current": router.getPageHistory().length + 1,
|
|
328
|
-
"page.startedAt": Date.now(),
|
|
329
|
-
"page.timeOnCurrent": 0
|
|
330
|
-
});
|
|
288
|
+
afterNavigate(key);
|
|
331
289
|
}
|
|
332
|
-
}, [router, tracker,
|
|
290
|
+
}, [router, tracker, afterNavigate]);
|
|
333
291
|
return {
|
|
334
292
|
goToNextPage,
|
|
335
293
|
goBack,
|
|
@@ -342,7 +300,7 @@ function useNavigation() {
|
|
|
342
300
|
function useProducts() {
|
|
343
301
|
const { products, variableStore, selectProduct: ctxSelect } = useFunnelContext();
|
|
344
302
|
const subscribe = useCallback(
|
|
345
|
-
(cb) => variableStore.subscribe(cb),
|
|
303
|
+
(cb) => variableStore.subscribe(cb, { keys: ["products.selectedProductId"] }),
|
|
346
304
|
[variableStore]
|
|
347
305
|
);
|
|
348
306
|
const getSnapshot = useCallback(
|
|
@@ -372,10 +330,19 @@ function useTracking() {
|
|
|
372
330
|
);
|
|
373
331
|
return { track, identify };
|
|
374
332
|
}
|
|
333
|
+
var PAYMENT_KEYS = [
|
|
334
|
+
"card.last4",
|
|
335
|
+
"card.brand",
|
|
336
|
+
"card.expMonth",
|
|
337
|
+
"card.expYear",
|
|
338
|
+
"payment.loading",
|
|
339
|
+
"payment.error",
|
|
340
|
+
"payment.customerId"
|
|
341
|
+
];
|
|
375
342
|
function usePayment() {
|
|
376
|
-
const { variableStore
|
|
343
|
+
const { variableStore } = useFunnelContext();
|
|
377
344
|
const subscribe = useCallback(
|
|
378
|
-
(cb) => variableStore.subscribe(cb),
|
|
345
|
+
(cb) => variableStore.subscribe(cb, { keys: PAYMENT_KEYS }),
|
|
379
346
|
[variableStore]
|
|
380
347
|
);
|
|
381
348
|
const getSnapshot = useCallback(
|
|
@@ -388,14 +355,99 @@ function usePayment() {
|
|
|
388
355
|
const brand = variables["card.brand"] || "";
|
|
389
356
|
const expMonth = variables["card.expMonth"] || 0;
|
|
390
357
|
const expYear = variables["card.expYear"] || 0;
|
|
358
|
+
const customerId = variables["payment.customerId"] || null;
|
|
391
359
|
return {
|
|
392
|
-
customerId
|
|
360
|
+
customerId,
|
|
393
361
|
isAuthorized: !!last4,
|
|
394
362
|
loading: !!variables["payment.loading"],
|
|
395
363
|
error: variables["payment.error"] || null,
|
|
396
364
|
cardDetails: last4 ? { last4, brand, expMonth, expYear } : null
|
|
397
365
|
};
|
|
398
|
-
}, [variables
|
|
366
|
+
}, [variables]);
|
|
367
|
+
}
|
|
368
|
+
var DEVICE_KEYS = [
|
|
369
|
+
"os.name",
|
|
370
|
+
"os.timezone",
|
|
371
|
+
"device.type",
|
|
372
|
+
"device.isMobile",
|
|
373
|
+
"device.isTablet",
|
|
374
|
+
"device.screenWidth",
|
|
375
|
+
"device.screenHeight",
|
|
376
|
+
"device.viewportWidth",
|
|
377
|
+
"device.viewportHeight",
|
|
378
|
+
"device.colorDepth",
|
|
379
|
+
"device.pixelRatio",
|
|
380
|
+
"browser.name",
|
|
381
|
+
"browser.version",
|
|
382
|
+
"browser.userAgent",
|
|
383
|
+
"browser.cookieEnabled",
|
|
384
|
+
"browser.online",
|
|
385
|
+
"browser.language"
|
|
386
|
+
];
|
|
387
|
+
function useDeviceInfo() {
|
|
388
|
+
const { variableStore } = useFunnelContext();
|
|
389
|
+
const subscribe = useCallback(
|
|
390
|
+
(cb) => variableStore.subscribe(cb, { keys: DEVICE_KEYS }),
|
|
391
|
+
[variableStore]
|
|
392
|
+
);
|
|
393
|
+
const getSnapshot = useCallback(
|
|
394
|
+
() => variableStore.getState(),
|
|
395
|
+
[variableStore]
|
|
396
|
+
);
|
|
397
|
+
const variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
398
|
+
return useMemo(() => ({
|
|
399
|
+
os: {
|
|
400
|
+
name: variables["os.name"] || "",
|
|
401
|
+
timezone: variables["os.timezone"] || ""
|
|
402
|
+
},
|
|
403
|
+
device: {
|
|
404
|
+
type: variables["device.type"] || "desktop",
|
|
405
|
+
isMobile: !!variables["device.isMobile"],
|
|
406
|
+
isTablet: !!variables["device.isTablet"],
|
|
407
|
+
screenWidth: variables["device.screenWidth"] || 0,
|
|
408
|
+
screenHeight: variables["device.screenHeight"] || 0,
|
|
409
|
+
viewportWidth: variables["device.viewportWidth"] || 0,
|
|
410
|
+
viewportHeight: variables["device.viewportHeight"] || 0,
|
|
411
|
+
colorDepth: variables["device.colorDepth"] || 24,
|
|
412
|
+
pixelRatio: variables["device.pixelRatio"] || 1
|
|
413
|
+
},
|
|
414
|
+
browser: {
|
|
415
|
+
name: variables["browser.name"] || "",
|
|
416
|
+
version: variables["browser.version"] || "",
|
|
417
|
+
userAgent: variables["browser.userAgent"] || "",
|
|
418
|
+
cookieEnabled: variables["browser.cookieEnabled"] !== false,
|
|
419
|
+
online: variables["browser.online"] !== false,
|
|
420
|
+
language: variables["browser.language"] || "en"
|
|
421
|
+
}
|
|
422
|
+
}), [variables]);
|
|
423
|
+
}
|
|
424
|
+
var PAGE_KEYS = [
|
|
425
|
+
"page.currentId",
|
|
426
|
+
"page.currentIndex",
|
|
427
|
+
"page.current",
|
|
428
|
+
"page.total",
|
|
429
|
+
"page.progressPercentage",
|
|
430
|
+
"page.startedAt"
|
|
431
|
+
];
|
|
432
|
+
function usePageData() {
|
|
433
|
+
const { variableStore } = useFunnelContext();
|
|
434
|
+
const subscribe = useCallback(
|
|
435
|
+
(cb) => variableStore.subscribe(cb, { keys: PAGE_KEYS }),
|
|
436
|
+
[variableStore]
|
|
437
|
+
);
|
|
438
|
+
const getSnapshot = useCallback(
|
|
439
|
+
() => variableStore.getState(),
|
|
440
|
+
[variableStore]
|
|
441
|
+
);
|
|
442
|
+
const variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
443
|
+
return useMemo(() => ({
|
|
444
|
+
currentId: variables["page.currentId"] || "",
|
|
445
|
+
currentIndex: variables["page.currentIndex"] || 0,
|
|
446
|
+
current: variables["page.current"] || 1,
|
|
447
|
+
total: variables["page.total"] || 0,
|
|
448
|
+
progressPercentage: variables["page.progressPercentage"] || 0,
|
|
449
|
+
startedAt: variables["page.startedAt"] || 0
|
|
450
|
+
}), [variables]);
|
|
399
451
|
}
|
|
400
452
|
|
|
401
453
|
// src/hooks/useFunnel.ts
|
|
@@ -415,242 +467,282 @@ function useFunnel() {
|
|
|
415
467
|
payment: usePayment()
|
|
416
468
|
};
|
|
417
469
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
validateOnly,
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
setError(null);
|
|
436
|
-
variableStore.set("payment.loading", true);
|
|
437
|
-
try {
|
|
438
|
-
const confirmFn = paymentMode === "setup" ? stripe.confirmSetup : stripe.confirmPayment;
|
|
439
|
-
const confirmResult = await confirmFn({
|
|
440
|
-
elements,
|
|
441
|
-
redirect: "if_required",
|
|
442
|
-
confirmParams: { return_url: window.location.href }
|
|
443
|
-
});
|
|
444
|
-
if (confirmResult.error) {
|
|
445
|
-
const msg = confirmResult.error.message || "Payment failed";
|
|
470
|
+
var API_BASE_URL = "https://api.appfunnel.net";
|
|
471
|
+
var InnerPaymentForm = forwardRef(
|
|
472
|
+
function InnerPaymentForm2({ paymentMode, validateOnly, onSuccess, onError, onReady, layout }, ref) {
|
|
473
|
+
const stripe = useStripe();
|
|
474
|
+
const elements = useElements();
|
|
475
|
+
const [error, setError] = useState(null);
|
|
476
|
+
const { variableStore, campaignId, tracker, products } = useFunnelContext();
|
|
477
|
+
const readyFired = useRef(false);
|
|
478
|
+
useEffect(() => {
|
|
479
|
+
if (stripe && elements && !readyFired.current) {
|
|
480
|
+
readyFired.current = true;
|
|
481
|
+
onReady?.();
|
|
482
|
+
}
|
|
483
|
+
}, [stripe, elements, onReady]);
|
|
484
|
+
const handleSubmit = useCallback(async () => {
|
|
485
|
+
if (!stripe || !elements) {
|
|
486
|
+
const msg = "Stripe not loaded";
|
|
446
487
|
setError(msg);
|
|
447
|
-
variableStore.set("payment.error", msg);
|
|
448
488
|
onError?.(msg);
|
|
449
489
|
return;
|
|
450
490
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
491
|
+
setError(null);
|
|
492
|
+
variableStore.set("payment.loading", true);
|
|
493
|
+
try {
|
|
494
|
+
const confirmFn = paymentMode === "setup" ? stripe.confirmSetup : stripe.confirmPayment;
|
|
495
|
+
const confirmResult = await confirmFn({
|
|
496
|
+
elements,
|
|
497
|
+
redirect: "if_required",
|
|
498
|
+
confirmParams: { return_url: window.location.href }
|
|
499
|
+
});
|
|
500
|
+
if (confirmResult.error) {
|
|
501
|
+
const msg = confirmResult.error.message || "Payment failed";
|
|
502
|
+
setError(msg);
|
|
503
|
+
variableStore.set("payment.error", msg);
|
|
504
|
+
onError?.(msg);
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
tracker.track("checkout.payment_added");
|
|
508
|
+
if (validateOnly) {
|
|
509
|
+
const piId = "paymentIntent" in confirmResult ? confirmResult.paymentIntent : void 0;
|
|
510
|
+
if (!piId?.id) {
|
|
511
|
+
const msg = "PaymentIntent not found after confirmation";
|
|
512
|
+
setError(msg);
|
|
513
|
+
variableStore.set("payment.error", msg);
|
|
514
|
+
onError?.(msg);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
const response2 = await fetch(
|
|
518
|
+
`${API_BASE_URL}/campaign/${campaignId}/stripe/validate-card`,
|
|
519
|
+
{
|
|
520
|
+
method: "POST",
|
|
521
|
+
headers: { "Content-Type": "application/json" },
|
|
522
|
+
body: JSON.stringify({
|
|
523
|
+
campaignId,
|
|
524
|
+
sessionId: tracker.getSessionId(),
|
|
525
|
+
paymentIntentId: piId.id
|
|
526
|
+
})
|
|
527
|
+
}
|
|
528
|
+
);
|
|
529
|
+
const result2 = await response2.json();
|
|
530
|
+
if (!result2.success) {
|
|
531
|
+
const msg = result2.error || "Card validation failed";
|
|
532
|
+
setError(msg);
|
|
533
|
+
variableStore.set("payment.error", msg);
|
|
534
|
+
onError?.(msg);
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
variableStore.setMany({
|
|
538
|
+
"card.last4": result2.card.last4,
|
|
539
|
+
"card.brand": result2.card.brand,
|
|
540
|
+
"card.expMonth": result2.card.expMonth,
|
|
541
|
+
"card.expYear": result2.card.expYear,
|
|
542
|
+
"card.funding": result2.card.funding,
|
|
543
|
+
"payment.error": ""
|
|
544
|
+
});
|
|
545
|
+
onSuccess?.();
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const paymentIntentId = "paymentIntent" in confirmResult ? confirmResult.paymentIntent?.id : void 0;
|
|
549
|
+
const selectedId = variableStore.get("products.selectedProductId");
|
|
550
|
+
const product = products.find((p) => p.id === selectedId);
|
|
551
|
+
if (!product?.stripePriceId) {
|
|
552
|
+
const msg = "No product selected or missing Stripe price";
|
|
456
553
|
setError(msg);
|
|
457
554
|
variableStore.set("payment.error", msg);
|
|
458
555
|
onError?.(msg);
|
|
459
556
|
return;
|
|
460
557
|
}
|
|
461
|
-
const
|
|
462
|
-
`${
|
|
558
|
+
const response = await fetch(
|
|
559
|
+
`${API_BASE_URL}/campaign/${campaignId}/stripe/purchase`,
|
|
463
560
|
{
|
|
464
561
|
method: "POST",
|
|
465
562
|
headers: { "Content-Type": "application/json" },
|
|
466
563
|
body: JSON.stringify({
|
|
467
564
|
campaignId,
|
|
468
565
|
sessionId: tracker.getSessionId(),
|
|
469
|
-
|
|
566
|
+
stripePriceId: product.stripePriceId,
|
|
567
|
+
trialPeriodDays: product.hasTrial ? product.trialDays : void 0,
|
|
568
|
+
onSessionPiId: paymentMode === "payment" ? paymentIntentId : void 0
|
|
470
569
|
})
|
|
471
570
|
}
|
|
472
571
|
);
|
|
473
|
-
const
|
|
474
|
-
if (
|
|
475
|
-
|
|
572
|
+
const result = await response.json();
|
|
573
|
+
if (result.success) {
|
|
574
|
+
variableStore.set("payment.error", "");
|
|
575
|
+
if (result.eventId || result.eventIds?.firstPeriod) {
|
|
576
|
+
tracker.track("purchase.complete", {
|
|
577
|
+
amount: product.rawPrice ? product.rawPrice / 100 : 0,
|
|
578
|
+
currency: product.currencyCode || "USD"
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
onSuccess?.();
|
|
582
|
+
} else {
|
|
583
|
+
const msg = result.error || "Failed to process payment";
|
|
476
584
|
setError(msg);
|
|
477
585
|
variableStore.set("payment.error", msg);
|
|
478
586
|
onError?.(msg);
|
|
479
|
-
return;
|
|
480
587
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
"card.brand": result2.card.brand,
|
|
484
|
-
"card.expMonth": result2.card.expMonth,
|
|
485
|
-
"card.expYear": result2.card.expYear,
|
|
486
|
-
"card.funding": result2.card.funding,
|
|
487
|
-
"payment.error": ""
|
|
488
|
-
});
|
|
489
|
-
onSuccess?.();
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
const paymentIntentId = "paymentIntent" in confirmResult ? confirmResult.paymentIntent?.id : void 0;
|
|
493
|
-
const selectedId = variableStore.get("products.selectedProductId");
|
|
494
|
-
const product = products.find((p) => p.id === selectedId);
|
|
495
|
-
if (!product?.stripePriceId) {
|
|
496
|
-
const msg = "No product selected or missing Stripe price";
|
|
588
|
+
} catch (err) {
|
|
589
|
+
const msg = err instanceof Error ? err.message : "An error occurred";
|
|
497
590
|
setError(msg);
|
|
498
591
|
variableStore.set("payment.error", msg);
|
|
499
592
|
onError?.(msg);
|
|
500
|
-
|
|
593
|
+
} finally {
|
|
594
|
+
variableStore.set("payment.loading", false);
|
|
501
595
|
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
596
|
+
}, [stripe, elements, paymentMode, validateOnly, variableStore, campaignId, tracker, products, onSuccess, onError]);
|
|
597
|
+
useImperativeHandle(ref, () => ({ submit: handleSubmit }), [handleSubmit]);
|
|
598
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
599
|
+
/* @__PURE__ */ jsx(PaymentElement, { options: { layout: layout || "tabs" } }),
|
|
600
|
+
error && /* @__PURE__ */ jsx("div", { style: { color: "#ef4444", fontSize: "14px", marginTop: "12px" }, children: error })
|
|
601
|
+
] });
|
|
602
|
+
}
|
|
603
|
+
);
|
|
604
|
+
var StripePaymentForm = forwardRef(
|
|
605
|
+
function StripePaymentForm2({
|
|
606
|
+
productId,
|
|
607
|
+
mode = "checkout",
|
|
608
|
+
variant = "elements",
|
|
609
|
+
onSuccess,
|
|
610
|
+
onError,
|
|
611
|
+
onReady,
|
|
612
|
+
className,
|
|
613
|
+
appearance,
|
|
614
|
+
layout
|
|
615
|
+
}, ref) {
|
|
616
|
+
const { campaignId, tracker, variableStore, products } = useFunnelContext();
|
|
617
|
+
const [email] = useVariable("user.email");
|
|
618
|
+
const validateOnly = mode === "validate-only";
|
|
619
|
+
const product = useMemo(() => {
|
|
620
|
+
if (productId) return products.find((p) => p.id === productId) || null;
|
|
621
|
+
const selectedId = variableStore.get("products.selectedProductId");
|
|
622
|
+
return products.find((p) => p.id === selectedId) || null;
|
|
623
|
+
}, [productId, products, variableStore]);
|
|
624
|
+
const paymentMode = useMemo(() => {
|
|
625
|
+
if (validateOnly) return "payment";
|
|
626
|
+
if (product?.hasTrial && !product.paidTrial) return "setup";
|
|
627
|
+
return "payment";
|
|
628
|
+
}, [product, validateOnly]);
|
|
629
|
+
const [stripePromise, setStripePromise] = useState(null);
|
|
630
|
+
const [clientSecret, setClientSecret] = useState(null);
|
|
631
|
+
const [error, setError] = useState(null);
|
|
632
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
633
|
+
const hasInitialized = useRef(false);
|
|
634
|
+
useEffect(() => {
|
|
635
|
+
if (!email || !campaignId || hasInitialized.current) return;
|
|
636
|
+
if (!product?.storePriceId) return;
|
|
637
|
+
hasInitialized.current = true;
|
|
638
|
+
setIsLoading(true);
|
|
639
|
+
variableStore.set("payment.loading", true);
|
|
640
|
+
const createIntent = async () => {
|
|
641
|
+
try {
|
|
642
|
+
if (variant === "embedded") {
|
|
643
|
+
const response = await fetch(
|
|
644
|
+
`${API_BASE_URL}/campaign/${campaignId}/stripe/checkout-session`,
|
|
645
|
+
{
|
|
646
|
+
method: "POST",
|
|
647
|
+
headers: { "Content-Type": "application/json" },
|
|
648
|
+
body: JSON.stringify({
|
|
649
|
+
campaignId,
|
|
650
|
+
sessionId: tracker.getSessionId(),
|
|
651
|
+
customerEmail: email,
|
|
652
|
+
priceId: product.storePriceId,
|
|
653
|
+
trialPeriodDays: product.hasTrial ? product.trialDays : void 0
|
|
654
|
+
})
|
|
655
|
+
}
|
|
656
|
+
);
|
|
657
|
+
const result = await response.json();
|
|
658
|
+
if (!result.success) throw new Error(result.error || "Failed to create checkout session");
|
|
659
|
+
setStripePromise(loadStripe(result.publishableKey));
|
|
660
|
+
setClientSecret(result.clientSecret);
|
|
661
|
+
} else {
|
|
662
|
+
const endpoint = paymentMode === "setup" ? `/campaign/${campaignId}/stripe/setup-intent` : `/campaign/${campaignId}/stripe/payment-intent`;
|
|
663
|
+
const body = {
|
|
664
|
+
campaignId,
|
|
665
|
+
sessionId: tracker.getSessionId(),
|
|
666
|
+
customerEmail: email,
|
|
667
|
+
priceId: product.storePriceId
|
|
668
|
+
};
|
|
669
|
+
if (validateOnly) body.validateOnly = true;
|
|
670
|
+
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
|
671
|
+
method: "POST",
|
|
672
|
+
headers: { "Content-Type": "application/json" },
|
|
673
|
+
body: JSON.stringify(body)
|
|
674
|
+
});
|
|
675
|
+
const result = await response.json();
|
|
676
|
+
if (!result.success) throw new Error(result.error || "Failed to create intent");
|
|
677
|
+
setStripePromise(loadStripe(result.publishableKey));
|
|
678
|
+
setClientSecret(result.clientSecret);
|
|
679
|
+
variableStore.set("user.stripeCustomerId", result.customerId);
|
|
680
|
+
}
|
|
681
|
+
tracker.track("checkout.start", {
|
|
682
|
+
productId: product.id,
|
|
683
|
+
priceId: product.stripePriceId || product.storePriceId,
|
|
684
|
+
productName: product.displayName
|
|
525
685
|
});
|
|
686
|
+
} catch (err) {
|
|
687
|
+
const msg = err instanceof Error ? err.message : "Failed to initialize payment";
|
|
688
|
+
setError(msg);
|
|
689
|
+
variableStore.set("payment.error", msg);
|
|
690
|
+
} finally {
|
|
691
|
+
setIsLoading(false);
|
|
692
|
+
variableStore.set("payment.loading", false);
|
|
526
693
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
onError?.(msg);
|
|
533
|
-
}
|
|
534
|
-
} catch (err) {
|
|
535
|
-
const msg = err instanceof Error ? err.message : "An error occurred";
|
|
536
|
-
setError(msg);
|
|
537
|
-
variableStore.set("payment.error", msg);
|
|
538
|
-
onError?.(msg);
|
|
539
|
-
} finally {
|
|
540
|
-
variableStore.set("payment.loading", false);
|
|
694
|
+
};
|
|
695
|
+
createIntent();
|
|
696
|
+
}, [email, campaignId, product, paymentMode, validateOnly, variant, tracker, variableStore]);
|
|
697
|
+
if (isLoading) {
|
|
698
|
+
return /* @__PURE__ */ jsx("div", { className, style: { padding: "20px", textAlign: "center", color: "#6b7280" }, children: "Loading payment form..." });
|
|
541
699
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
if (typeof window !== "undefined") {
|
|
545
|
-
window.__paymentElementSubmit = handleSubmit;
|
|
700
|
+
if (!email) {
|
|
701
|
+
return /* @__PURE__ */ jsx("div", { className, style: { padding: "20px", textAlign: "center", color: "#ef4444", fontSize: "14px" }, children: "Email is required to initialize payment" });
|
|
546
702
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
const product = useMemo(() => {
|
|
570
|
-
if (productId) return products.find((p) => p.id === productId) || null;
|
|
571
|
-
const selectedId = variableStore.get("products.selectedProductId");
|
|
572
|
-
return products.find((p) => p.id === selectedId) || null;
|
|
573
|
-
}, [productId, products, variableStore]);
|
|
574
|
-
const paymentMode = useMemo(() => {
|
|
575
|
-
if (validateOnly) return "payment";
|
|
576
|
-
if (product?.hasTrial && !product.paidTrial) return "setup";
|
|
577
|
-
return "payment";
|
|
578
|
-
}, [product, validateOnly]);
|
|
579
|
-
const [stripePromise, setStripePromise] = useState(null);
|
|
580
|
-
const [clientSecret, setClientSecret] = useState(null);
|
|
581
|
-
const [error, setError] = useState(null);
|
|
582
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
583
|
-
const hasInitialized = useRef(false);
|
|
584
|
-
useEffect(() => {
|
|
585
|
-
if (!email || !campaignId || hasInitialized.current) return;
|
|
586
|
-
if (!product?.storePriceId) return;
|
|
587
|
-
hasInitialized.current = true;
|
|
588
|
-
setIsLoading(true);
|
|
589
|
-
variableStore.set("payment.loading", true);
|
|
590
|
-
const createIntent = async () => {
|
|
591
|
-
try {
|
|
592
|
-
const endpoint = paymentMode === "setup" ? `/campaign/${campaignId}/stripe/setup-intent` : `/campaign/${campaignId}/stripe/payment-intent`;
|
|
593
|
-
const body = {
|
|
594
|
-
campaignId,
|
|
595
|
-
sessionId: tracker.getSessionId(),
|
|
596
|
-
customerEmail: email,
|
|
597
|
-
priceId: product.storePriceId
|
|
598
|
-
};
|
|
599
|
-
if (validateOnly) body.validateOnly = true;
|
|
600
|
-
const response = await fetch(`${apiBaseUrl}${endpoint}`, {
|
|
601
|
-
method: "POST",
|
|
602
|
-
headers: { "Content-Type": "application/json" },
|
|
603
|
-
body: JSON.stringify(body)
|
|
604
|
-
});
|
|
605
|
-
const result = await response.json();
|
|
606
|
-
if (!result.success) {
|
|
607
|
-
throw new Error(result.error || "Failed to create intent");
|
|
703
|
+
if (error) {
|
|
704
|
+
return /* @__PURE__ */ jsx("div", { className, style: { padding: "20px", textAlign: "center", color: "#ef4444", fontSize: "14px" }, children: error });
|
|
705
|
+
}
|
|
706
|
+
if (!stripePromise || !clientSecret) {
|
|
707
|
+
return /* @__PURE__ */ jsx("div", { className, style: { padding: "20px", textAlign: "center", color: "#6b7280" }, children: "Initializing payment..." });
|
|
708
|
+
}
|
|
709
|
+
if (variant === "embedded") {
|
|
710
|
+
return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(
|
|
711
|
+
EmbeddedCheckoutProvider,
|
|
712
|
+
{
|
|
713
|
+
stripe: stripePromise,
|
|
714
|
+
options: {
|
|
715
|
+
clientSecret,
|
|
716
|
+
onComplete: () => {
|
|
717
|
+
tracker.track("purchase.complete", {
|
|
718
|
+
amount: product?.rawPrice ? product.rawPrice / 100 : 0,
|
|
719
|
+
currency: product?.currencyCode || "USD"
|
|
720
|
+
});
|
|
721
|
+
onSuccess?.();
|
|
722
|
+
}
|
|
723
|
+
},
|
|
724
|
+
children: /* @__PURE__ */ jsx(EmbeddedCheckout, {})
|
|
608
725
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
priceId: product.stripePriceId || product.storePriceId,
|
|
615
|
-
productName: product.displayName
|
|
616
|
-
});
|
|
617
|
-
} catch (err) {
|
|
618
|
-
const msg = err instanceof Error ? err.message : "Failed to initialize payment";
|
|
619
|
-
setError(msg);
|
|
620
|
-
variableStore.set("payment.error", msg);
|
|
621
|
-
} finally {
|
|
622
|
-
setIsLoading(false);
|
|
623
|
-
variableStore.set("payment.loading", false);
|
|
624
|
-
}
|
|
726
|
+
) });
|
|
727
|
+
}
|
|
728
|
+
const defaultAppearance = {
|
|
729
|
+
theme: "stripe",
|
|
730
|
+
variables: { colorPrimary: "#3b82f6", borderRadius: "8px" }
|
|
625
731
|
};
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
return /* @__PURE__ */ jsx("div", { className, style: { padding: "20px", textAlign: "center", color: "#6b7280" }, children: "Initializing payment..." });
|
|
732
|
+
return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(Elements, { stripe: stripePromise, options: { clientSecret, appearance: appearance || defaultAppearance }, children: /* @__PURE__ */ jsx(
|
|
733
|
+
InnerPaymentForm,
|
|
734
|
+
{
|
|
735
|
+
ref,
|
|
736
|
+
paymentMode,
|
|
737
|
+
validateOnly,
|
|
738
|
+
onSuccess,
|
|
739
|
+
onError,
|
|
740
|
+
onReady,
|
|
741
|
+
layout
|
|
742
|
+
}
|
|
743
|
+
) }) });
|
|
639
744
|
}
|
|
640
|
-
|
|
641
|
-
theme: "stripe",
|
|
642
|
-
variables: { colorPrimary: "#3b82f6", borderRadius: "8px" }
|
|
643
|
-
};
|
|
644
|
-
return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(Elements, { stripe: stripePromise, options: { clientSecret, appearance: appearance || defaultAppearance }, children: /* @__PURE__ */ jsx(
|
|
645
|
-
InnerPaymentForm,
|
|
646
|
-
{
|
|
647
|
-
paymentMode,
|
|
648
|
-
validateOnly,
|
|
649
|
-
onSuccess,
|
|
650
|
-
onError
|
|
651
|
-
}
|
|
652
|
-
) }) });
|
|
653
|
-
}
|
|
745
|
+
);
|
|
654
746
|
function PaddleCheckout({
|
|
655
747
|
productId,
|
|
656
748
|
mode = "overlay",
|
|
@@ -715,6 +807,6 @@ function PaddleCheckout({
|
|
|
715
807
|
return null;
|
|
716
808
|
}
|
|
717
809
|
|
|
718
|
-
export { PaddleCheckout,
|
|
810
|
+
export { PaddleCheckout, StripePaymentForm, defineConfig, definePage, useData, useDeviceInfo, useFunnel, useLocale, useNavigation, usePageData, usePayment, useProducts, useQueryParam, useQueryParams, useResponse, useResponses, useTracking, useTranslation, useUser, useUserProperty, useVariable, useVariables };
|
|
719
811
|
//# sourceMappingURL=index.js.map
|
|
720
812
|
//# sourceMappingURL=index.js.map
|