@appfunnel-dev/sdk 0.1.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/index.cjs ADDED
@@ -0,0 +1,660 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var stripeJs = require('@stripe/stripe-js');
6
+ var reactStripeJs = require('@stripe/react-stripe-js');
7
+
8
+ // src/config.ts
9
+ function defineConfig(config) {
10
+ return config;
11
+ }
12
+ function definePage(definition) {
13
+ return definition;
14
+ }
15
+ function registerIntegration(id, loader) {
16
+ }
17
+ var FunnelContext = react.createContext(null);
18
+ function useFunnelContext() {
19
+ const ctx = react.useContext(FunnelContext);
20
+ if (!ctx) {
21
+ throw new Error("useFunnelContext must be used within a <FunnelProvider>");
22
+ }
23
+ return ctx;
24
+ }
25
+
26
+ // src/hooks/useVariable.ts
27
+ function useVariable(id) {
28
+ const { variableStore } = useFunnelContext();
29
+ const subscribe = react.useCallback(
30
+ (callback) => variableStore.subscribe(callback),
31
+ [variableStore]
32
+ );
33
+ const getSnapshot = react.useCallback(
34
+ () => variableStore.get(id),
35
+ [variableStore, id]
36
+ );
37
+ const value = react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
38
+ const setValue = react.useCallback(
39
+ (v) => variableStore.set(id, v),
40
+ [variableStore, id]
41
+ );
42
+ return [value, setValue];
43
+ }
44
+ function useVariables() {
45
+ const { variableStore } = useFunnelContext();
46
+ const subscribe = react.useCallback(
47
+ (callback) => variableStore.subscribe(callback),
48
+ [variableStore]
49
+ );
50
+ const getSnapshot = react.useCallback(
51
+ () => variableStore.getState(),
52
+ [variableStore]
53
+ );
54
+ return react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
55
+ }
56
+ function useUser() {
57
+ const { variableStore, tracker } = useFunnelContext();
58
+ const subscribe = react.useCallback(
59
+ (cb) => variableStore.subscribe(cb),
60
+ [variableStore]
61
+ );
62
+ const getSnapshot = react.useCallback(
63
+ () => variableStore.getState(),
64
+ [variableStore]
65
+ );
66
+ const variables = react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
67
+ return react.useMemo(() => ({
68
+ email: variables["user.email"] || "",
69
+ name: variables["user.name"] || "",
70
+ stripeCustomerId: variables["user.stripeCustomerId"] || "",
71
+ paddleCustomerId: variables["user.paddleCustomerId"] || "",
72
+ setEmail(email) {
73
+ variableStore.set("user.email", email);
74
+ tracker.identify(email);
75
+ },
76
+ setName(name) {
77
+ variableStore.set("user.name", name);
78
+ }
79
+ }), [variables, variableStore, tracker]);
80
+ }
81
+ function useUserVariable(field) {
82
+ const { variableStore } = useFunnelContext();
83
+ const key = `user.${field}`;
84
+ const subscribe = react.useCallback(
85
+ (cb) => variableStore.subscribe(cb),
86
+ [variableStore]
87
+ );
88
+ const getSnapshot = react.useCallback(
89
+ () => variableStore.get(key) || "",
90
+ [variableStore, key]
91
+ );
92
+ const value = react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
93
+ const setValue = react.useCallback(
94
+ (v) => variableStore.set(key, v),
95
+ [variableStore, key]
96
+ );
97
+ return [value, setValue];
98
+ }
99
+ function useQueryParams() {
100
+ const { variableStore } = useFunnelContext();
101
+ const subscribe = react.useCallback(
102
+ (cb) => variableStore.subscribe(cb),
103
+ [variableStore]
104
+ );
105
+ const getSnapshot = react.useCallback(
106
+ () => variableStore.getState(),
107
+ [variableStore]
108
+ );
109
+ const variables = react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
110
+ return react.useMemo(() => {
111
+ const params = {};
112
+ for (const [key, value] of Object.entries(variables)) {
113
+ if (key.startsWith("query.") && typeof value === "string") {
114
+ params[key.slice(6)] = value;
115
+ }
116
+ }
117
+ return params;
118
+ }, [variables]);
119
+ }
120
+ function useLocale() {
121
+ return react.useMemo(() => {
122
+ if (typeof navigator === "undefined") {
123
+ return {
124
+ locale: "en-US",
125
+ language: "en",
126
+ region: "US",
127
+ languages: ["en-US"],
128
+ timeZone: "UTC",
129
+ is24Hour: false
130
+ };
131
+ }
132
+ const locale = navigator.language || "en-US";
133
+ const [language, region] = locale.split("-");
134
+ const languages = [...navigator.languages || [locale]];
135
+ const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
136
+ const is24Hour = detect24Hour(locale);
137
+ return {
138
+ locale,
139
+ language: language || "en",
140
+ region: region?.toUpperCase() || "US",
141
+ languages,
142
+ timeZone,
143
+ is24Hour
144
+ };
145
+ }, []);
146
+ }
147
+ function detect24Hour(locale) {
148
+ try {
149
+ const formatted = new Intl.DateTimeFormat(locale, { hour: "numeric" }).format(/* @__PURE__ */ new Date());
150
+ return !formatted.match(/am|pm/i);
151
+ } catch {
152
+ return false;
153
+ }
154
+ }
155
+ function useTranslation() {
156
+ const { i18n } = useFunnelContext();
157
+ const subscribe = react.useCallback(
158
+ (cb) => i18n.subscribe(cb),
159
+ [i18n]
160
+ );
161
+ const getSnapshot = react.useCallback(
162
+ () => i18n.getLocale(),
163
+ [i18n]
164
+ );
165
+ const locale = react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
166
+ const t = react.useCallback(
167
+ (key, params) => i18n.t(key, params),
168
+ [i18n, locale]
169
+ // eslint-disable-line react-hooks/exhaustive-deps
170
+ );
171
+ const setLocale = react.useCallback(
172
+ (l) => i18n.setLocale(l),
173
+ [i18n]
174
+ );
175
+ const availableLocales = i18n.getAvailableLocales();
176
+ return { t, locale, setLocale, availableLocales };
177
+ }
178
+ function useNavigation() {
179
+ const { router, variableStore, tracker } = useFunnelContext();
180
+ const subscribe = react.useCallback(
181
+ (cb) => variableStore.subscribe(cb),
182
+ [variableStore]
183
+ );
184
+ const getSnapshot = react.useCallback(
185
+ () => variableStore.getState(),
186
+ [variableStore]
187
+ );
188
+ const variables = react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
189
+ const goToNextPage = react.useCallback(() => {
190
+ const previousPage = router.getCurrentPage();
191
+ if (previousPage) {
192
+ tracker.stopPageTracking();
193
+ }
194
+ const nextKey = router.goToNextPage(variables);
195
+ if (nextKey) {
196
+ const nextPage = router.getCurrentPage();
197
+ if (nextPage) {
198
+ tracker.track("page.view", {
199
+ pageId: nextPage.key,
200
+ pageKey: nextPage.key,
201
+ pageName: nextPage.name
202
+ });
203
+ tracker.startPageTracking(nextPage.key);
204
+ }
205
+ variableStore.setMany({
206
+ "page.currentId": nextKey,
207
+ "page.currentIndex": router.getPageHistory().length,
208
+ "page.current": router.getPageHistory().length + 1,
209
+ "page.startedAt": Date.now(),
210
+ "page.timeOnCurrent": 0
211
+ });
212
+ }
213
+ }, [router, variables, tracker, variableStore]);
214
+ const goBack = react.useCallback(() => {
215
+ tracker.stopPageTracking();
216
+ const prevKey = router.goBack();
217
+ if (prevKey) {
218
+ const page = router.getCurrentPage();
219
+ if (page) {
220
+ tracker.track("page.view", {
221
+ pageId: page.key,
222
+ pageKey: page.key,
223
+ pageName: page.name
224
+ });
225
+ tracker.startPageTracking(page.key);
226
+ }
227
+ variableStore.setMany({
228
+ "page.currentId": prevKey,
229
+ "page.currentIndex": router.getPageHistory().length,
230
+ "page.current": router.getPageHistory().length + 1,
231
+ "page.startedAt": Date.now(),
232
+ "page.timeOnCurrent": 0
233
+ });
234
+ }
235
+ }, [router, tracker, variableStore]);
236
+ const goToPage = react.useCallback((pageKey) => {
237
+ tracker.stopPageTracking();
238
+ const key = router.goToPage(pageKey);
239
+ if (key) {
240
+ const page = router.getCurrentPage();
241
+ if (page) {
242
+ tracker.track("page.view", {
243
+ pageId: page.key,
244
+ pageKey: page.key,
245
+ pageName: page.name
246
+ });
247
+ tracker.startPageTracking(page.key);
248
+ }
249
+ variableStore.setMany({
250
+ "page.currentId": key,
251
+ "page.currentIndex": router.getPageHistory().length,
252
+ "page.current": router.getPageHistory().length + 1,
253
+ "page.startedAt": Date.now(),
254
+ "page.timeOnCurrent": 0
255
+ });
256
+ }
257
+ }, [router, tracker, variableStore]);
258
+ return {
259
+ goToNextPage,
260
+ goBack,
261
+ goToPage,
262
+ currentPage: router.getCurrentPage(),
263
+ pageHistory: router.getPageHistory(),
264
+ progress: router.getProgress()
265
+ };
266
+ }
267
+ function useProducts() {
268
+ const { products, variableStore, selectProduct: ctxSelect } = useFunnelContext();
269
+ const subscribe = react.useCallback(
270
+ (cb) => variableStore.subscribe(cb),
271
+ [variableStore]
272
+ );
273
+ const getSnapshot = react.useCallback(
274
+ () => variableStore.get("products.selectedProductId"),
275
+ [variableStore]
276
+ );
277
+ const selectedId = react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
278
+ const selected = products.find((p) => p.id === selectedId) || null;
279
+ const select = react.useCallback((productId) => {
280
+ ctxSelect(productId);
281
+ }, [ctxSelect]);
282
+ return { products, selected, select };
283
+ }
284
+ function useTracking() {
285
+ const { tracker } = useFunnelContext();
286
+ const track = react.useCallback(
287
+ (eventName, data) => {
288
+ tracker.track(eventName, data);
289
+ },
290
+ [tracker]
291
+ );
292
+ const identify = react.useCallback(
293
+ (email) => {
294
+ tracker.identify(email);
295
+ },
296
+ [tracker]
297
+ );
298
+ return { track, identify };
299
+ }
300
+ function usePayment() {
301
+ const { variableStore, tracker } = useFunnelContext();
302
+ const subscribe = react.useCallback(
303
+ (cb) => variableStore.subscribe(cb),
304
+ [variableStore]
305
+ );
306
+ const getSnapshot = react.useCallback(
307
+ () => variableStore.getState(),
308
+ [variableStore]
309
+ );
310
+ const variables = react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
311
+ return react.useMemo(() => {
312
+ const last4 = variables["card.last4"] || "";
313
+ const brand = variables["card.brand"] || "";
314
+ const expMonth = variables["card.expMonth"] || 0;
315
+ const expYear = variables["card.expYear"] || 0;
316
+ return {
317
+ customerId: tracker.getCustomerId(),
318
+ isAuthorized: !!last4,
319
+ loading: !!variables["payment.loading"],
320
+ error: variables["payment.error"] || null,
321
+ cardDetails: last4 ? { last4, brand, expMonth, expYear } : null
322
+ };
323
+ }, [variables, tracker]);
324
+ }
325
+
326
+ // src/hooks/useFunnel.ts
327
+ function useFunnel() {
328
+ const { funnelId, campaignId, tracker } = useFunnelContext();
329
+ return {
330
+ funnelId,
331
+ campaignId,
332
+ sessionId: tracker.getSessionId(),
333
+ variables: useVariables(),
334
+ user: useUser(),
335
+ queryParams: useQueryParams(),
336
+ navigation: useNavigation(),
337
+ products: useProducts(),
338
+ tracking: useTracking(),
339
+ payment: usePayment()
340
+ };
341
+ }
342
+ function InnerPaymentForm({
343
+ paymentMode,
344
+ validateOnly,
345
+ onSuccess,
346
+ onError
347
+ }) {
348
+ const stripe = reactStripeJs.useStripe();
349
+ const elements = reactStripeJs.useElements();
350
+ const [error, setError] = react.useState(null);
351
+ const { variableStore, campaignId, tracker, apiBaseUrl, products } = useFunnelContext();
352
+ const handleSubmit = react.useCallback(async () => {
353
+ if (!stripe || !elements) {
354
+ const msg = "Stripe not loaded";
355
+ setError(msg);
356
+ onError?.(msg);
357
+ return;
358
+ }
359
+ setError(null);
360
+ variableStore.set("payment.loading", true);
361
+ try {
362
+ const confirmFn = paymentMode === "setup" ? stripe.confirmSetup : stripe.confirmPayment;
363
+ const confirmResult = await confirmFn({
364
+ elements,
365
+ redirect: "if_required",
366
+ confirmParams: { return_url: window.location.href }
367
+ });
368
+ if (confirmResult.error) {
369
+ const msg = confirmResult.error.message || "Payment failed";
370
+ setError(msg);
371
+ variableStore.set("payment.error", msg);
372
+ onError?.(msg);
373
+ return;
374
+ }
375
+ tracker.track("checkout.payment_added");
376
+ if (validateOnly) {
377
+ const piId = "paymentIntent" in confirmResult ? confirmResult.paymentIntent : void 0;
378
+ if (!piId?.id) {
379
+ const msg = "PaymentIntent not found after confirmation";
380
+ setError(msg);
381
+ variableStore.set("payment.error", msg);
382
+ onError?.(msg);
383
+ return;
384
+ }
385
+ const response2 = await fetch(
386
+ `${apiBaseUrl}/campaign/${campaignId}/stripe/validate-card`,
387
+ {
388
+ method: "POST",
389
+ headers: { "Content-Type": "application/json" },
390
+ body: JSON.stringify({
391
+ campaignId,
392
+ sessionId: tracker.getSessionId(),
393
+ paymentIntentId: piId.id
394
+ })
395
+ }
396
+ );
397
+ const result2 = await response2.json();
398
+ if (!result2.success) {
399
+ const msg = result2.error || "Card validation failed";
400
+ setError(msg);
401
+ variableStore.set("payment.error", msg);
402
+ onError?.(msg);
403
+ return;
404
+ }
405
+ variableStore.setMany({
406
+ "card.last4": result2.card.last4,
407
+ "card.brand": result2.card.brand,
408
+ "card.expMonth": result2.card.expMonth,
409
+ "card.expYear": result2.card.expYear,
410
+ "card.funding": result2.card.funding,
411
+ "payment.error": ""
412
+ });
413
+ onSuccess?.();
414
+ return;
415
+ }
416
+ const paymentIntentId = "paymentIntent" in confirmResult ? confirmResult.paymentIntent?.id : void 0;
417
+ const selectedId = variableStore.get("products.selectedProductId");
418
+ const product = products.find((p) => p.id === selectedId);
419
+ if (!product?.stripePriceId) {
420
+ const msg = "No product selected or missing Stripe price";
421
+ setError(msg);
422
+ variableStore.set("payment.error", msg);
423
+ onError?.(msg);
424
+ return;
425
+ }
426
+ const variables = variableStore.getState();
427
+ await tracker.updateUserData(variables);
428
+ const response = await fetch(
429
+ `${apiBaseUrl}/campaign/${campaignId}/stripe/purchase`,
430
+ {
431
+ method: "POST",
432
+ headers: { "Content-Type": "application/json" },
433
+ body: JSON.stringify({
434
+ campaignId,
435
+ sessionId: tracker.getSessionId(),
436
+ stripePriceId: product.stripePriceId,
437
+ trialPeriodDays: product.hasTrial ? product.trialDays : void 0,
438
+ onSessionPiId: paymentMode === "payment" ? paymentIntentId : void 0
439
+ })
440
+ }
441
+ );
442
+ const result = await response.json();
443
+ if (result.success) {
444
+ variableStore.set("payment.error", "");
445
+ if (result.eventId || result.eventIds?.firstPeriod) {
446
+ tracker.track("purchase.complete", {
447
+ amount: product.rawPrice ? product.rawPrice / 100 : 0,
448
+ currency: product.currencyCode || "USD"
449
+ });
450
+ }
451
+ onSuccess?.();
452
+ } else {
453
+ const msg = result.error || "Failed to process payment";
454
+ setError(msg);
455
+ variableStore.set("payment.error", msg);
456
+ onError?.(msg);
457
+ }
458
+ } catch (err) {
459
+ const msg = err instanceof Error ? err.message : "An error occurred";
460
+ setError(msg);
461
+ variableStore.set("payment.error", msg);
462
+ onError?.(msg);
463
+ } finally {
464
+ variableStore.set("payment.loading", false);
465
+ }
466
+ }, [stripe, elements, paymentMode, validateOnly, variableStore, campaignId, tracker, apiBaseUrl, products, onSuccess, onError]);
467
+ react.useEffect(() => {
468
+ if (typeof window !== "undefined") {
469
+ window.__paymentElementSubmit = handleSubmit;
470
+ }
471
+ return () => {
472
+ if (typeof window !== "undefined") {
473
+ delete window.__paymentElementSubmit;
474
+ }
475
+ };
476
+ }, [handleSubmit]);
477
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
478
+ /* @__PURE__ */ jsxRuntime.jsx(reactStripeJs.PaymentElement, { options: { layout: "tabs" } }),
479
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#ef4444", fontSize: "14px", marginTop: "12px" }, children: error })
480
+ ] });
481
+ }
482
+ function PaymentForm({
483
+ productId,
484
+ mode = "checkout",
485
+ onSuccess,
486
+ onError,
487
+ className,
488
+ appearance
489
+ }) {
490
+ const { campaignId, tracker, variableStore, apiBaseUrl, products } = useFunnelContext();
491
+ const [email] = useVariable("user.email");
492
+ const validateOnly = mode === "validate-only";
493
+ const product = react.useMemo(() => {
494
+ if (productId) return products.find((p) => p.id === productId) || null;
495
+ const selectedId = variableStore.get("products.selectedProductId");
496
+ return products.find((p) => p.id === selectedId) || null;
497
+ }, [productId, products, variableStore]);
498
+ const paymentMode = react.useMemo(() => {
499
+ if (validateOnly) return "payment";
500
+ if (product?.hasTrial && !product.paidTrial) return "setup";
501
+ return "payment";
502
+ }, [product, validateOnly]);
503
+ const [stripePromise, setStripePromise] = react.useState(null);
504
+ const [clientSecret, setClientSecret] = react.useState(null);
505
+ const [error, setError] = react.useState(null);
506
+ const [isLoading, setIsLoading] = react.useState(false);
507
+ const hasInitialized = react.useRef(false);
508
+ react.useEffect(() => {
509
+ if (!email || !campaignId || hasInitialized.current) return;
510
+ if (!product?.storePriceId) return;
511
+ hasInitialized.current = true;
512
+ setIsLoading(true);
513
+ variableStore.set("payment.loading", true);
514
+ const createIntent = async () => {
515
+ try {
516
+ const endpoint = paymentMode === "setup" ? `/campaign/${campaignId}/stripe/setup-intent` : `/campaign/${campaignId}/stripe/payment-intent`;
517
+ const body = {
518
+ campaignId,
519
+ sessionId: tracker.getSessionId(),
520
+ customerEmail: email,
521
+ priceId: product.storePriceId
522
+ };
523
+ if (validateOnly) body.validateOnly = true;
524
+ const response = await fetch(`${apiBaseUrl}${endpoint}`, {
525
+ method: "POST",
526
+ headers: { "Content-Type": "application/json" },
527
+ body: JSON.stringify(body)
528
+ });
529
+ const result = await response.json();
530
+ if (!result.success) {
531
+ throw new Error(result.error || "Failed to create intent");
532
+ }
533
+ setStripePromise(stripeJs.loadStripe(result.publishableKey));
534
+ setClientSecret(result.clientSecret);
535
+ variableStore.set("user.stripeCustomerId", result.customerId);
536
+ tracker.track("checkout.start", {
537
+ productId: product.id,
538
+ priceId: product.stripePriceId || product.storePriceId,
539
+ productName: product.displayName
540
+ });
541
+ } catch (err) {
542
+ const msg = err instanceof Error ? err.message : "Failed to initialize payment";
543
+ setError(msg);
544
+ variableStore.set("payment.error", msg);
545
+ } finally {
546
+ setIsLoading(false);
547
+ variableStore.set("payment.loading", false);
548
+ }
549
+ };
550
+ createIntent();
551
+ }, [email, campaignId, product, paymentMode, validateOnly, tracker, variableStore, apiBaseUrl]);
552
+ if (isLoading) {
553
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { padding: "20px", textAlign: "center", color: "#6b7280" }, children: "Loading payment form..." });
554
+ }
555
+ if (!email) {
556
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { padding: "20px", textAlign: "center", color: "#ef4444", fontSize: "14px" }, children: "Email is required to initialize payment" });
557
+ }
558
+ if (error) {
559
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { padding: "20px", textAlign: "center", color: "#ef4444", fontSize: "14px" }, children: error });
560
+ }
561
+ if (!stripePromise || !clientSecret) {
562
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { padding: "20px", textAlign: "center", color: "#6b7280" }, children: "Initializing payment..." });
563
+ }
564
+ const defaultAppearance = {
565
+ theme: "stripe",
566
+ variables: { colorPrimary: "#3b82f6", borderRadius: "8px" }
567
+ };
568
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children: /* @__PURE__ */ jsxRuntime.jsx(reactStripeJs.Elements, { stripe: stripePromise, options: { clientSecret, appearance: appearance || defaultAppearance }, children: /* @__PURE__ */ jsxRuntime.jsx(
569
+ InnerPaymentForm,
570
+ {
571
+ paymentMode,
572
+ validateOnly,
573
+ onSuccess,
574
+ onError
575
+ }
576
+ ) }) });
577
+ }
578
+ function PaddleCheckout({
579
+ productId,
580
+ mode = "overlay",
581
+ onSuccess,
582
+ onError,
583
+ className
584
+ }) {
585
+ const { variableStore, tracker, products } = useFunnelContext();
586
+ const containerRef = react.useRef(null);
587
+ const initializedRef = react.useRef(false);
588
+ const product = productId ? products.find((p) => p.id === productId) : products.find((p) => p.id === variableStore.get("products.selectedProductId"));
589
+ const handleCheckoutComplete = react.useCallback(() => {
590
+ tracker.track("purchase.complete", {
591
+ amount: product?.rawPrice ? product.rawPrice / 100 : 0,
592
+ currency: product?.currencyCode || "USD"
593
+ });
594
+ onSuccess?.();
595
+ }, [tracker, product, onSuccess]);
596
+ react.useEffect(() => {
597
+ if (initializedRef.current || !product?.paddlePriceId) return;
598
+ initializedRef.current = true;
599
+ if (!window.Paddle) {
600
+ onError?.("Paddle.js not loaded. Include the Paddle script in your HTML.");
601
+ return;
602
+ }
603
+ const email = variableStore.get("user.email") || "";
604
+ if (mode === "overlay") {
605
+ window.Paddle.Checkout.open({
606
+ items: [{ priceId: product.paddlePriceId, quantity: 1 }],
607
+ customer: email ? { email } : void 0,
608
+ successCallback: handleCheckoutComplete,
609
+ closeCallback: () => {
610
+ }
611
+ });
612
+ } else {
613
+ if (containerRef.current) {
614
+ window.Paddle.Checkout.open({
615
+ items: [{ priceId: product.paddlePriceId, quantity: 1 }],
616
+ customer: email ? { email } : void 0,
617
+ settings: {
618
+ displayMode: "inline",
619
+ frameTarget: containerRef.current.id || "paddle-checkout",
620
+ frameInitialHeight: 450,
621
+ frameStyle: "width: 100%; min-width: 312px; background-color: transparent; border: none;"
622
+ },
623
+ successCallback: handleCheckoutComplete
624
+ });
625
+ }
626
+ }
627
+ tracker.track("checkout.start", {
628
+ productId: product.id,
629
+ priceId: product.paddlePriceId,
630
+ productName: product.displayName
631
+ });
632
+ }, [product, mode, variableStore, tracker, handleCheckoutComplete, onError]);
633
+ if (!product) {
634
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { padding: "20px", textAlign: "center", color: "#ef4444", fontSize: "14px" }, children: "No product selected" });
635
+ }
636
+ if (mode === "inline") {
637
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, id: "paddle-checkout", className });
638
+ }
639
+ return null;
640
+ }
641
+
642
+ exports.PaddleCheckout = PaddleCheckout;
643
+ exports.PaymentForm = PaymentForm;
644
+ exports.defineConfig = defineConfig;
645
+ exports.definePage = definePage;
646
+ exports.registerIntegration = registerIntegration;
647
+ exports.useFunnel = useFunnel;
648
+ exports.useLocale = useLocale;
649
+ exports.useNavigation = useNavigation;
650
+ exports.usePayment = usePayment;
651
+ exports.useProducts = useProducts;
652
+ exports.useQueryParams = useQueryParams;
653
+ exports.useTracking = useTracking;
654
+ exports.useTranslation = useTranslation;
655
+ exports.useUser = useUser;
656
+ exports.useUserVariable = useUserVariable;
657
+ exports.useVariable = useVariable;
658
+ exports.useVariables = useVariables;
659
+ //# sourceMappingURL=index.cjs.map
660
+ //# sourceMappingURL=index.cjs.map