@tagadapay/plugin-sdk 3.1.8 → 3.1.10

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.
Files changed (50) hide show
  1. package/README.md +1129 -1129
  2. package/build-cdn.js +223 -113
  3. package/dist/external-tracker.js +135 -81
  4. package/dist/external-tracker.min.js +2 -2
  5. package/dist/external-tracker.min.js.map +4 -4
  6. package/dist/react/providers/TagadaProvider.js +5 -5
  7. package/dist/tagada-sdk.js +10164 -0
  8. package/dist/tagada-sdk.min.js +45 -0
  9. package/dist/tagada-sdk.min.js.map +7 -0
  10. package/dist/v2/core/funnelClient.d.ts +91 -4
  11. package/dist/v2/core/funnelClient.js +42 -3
  12. package/dist/v2/core/resources/funnel.d.ts +10 -0
  13. package/dist/v2/core/resources/payments.d.ts +21 -1
  14. package/dist/v2/core/resources/payments.js +34 -0
  15. package/dist/v2/core/utils/currency.d.ts +14 -0
  16. package/dist/v2/core/utils/currency.js +40 -0
  17. package/dist/v2/core/utils/index.d.ts +1 -0
  18. package/dist/v2/core/utils/index.js +2 -0
  19. package/dist/v2/core/utils/pluginConfig.d.ts +8 -0
  20. package/dist/v2/core/utils/pluginConfig.js +28 -0
  21. package/dist/v2/core/utils/previewMode.d.ts +4 -0
  22. package/dist/v2/core/utils/previewMode.js +28 -0
  23. package/dist/v2/core/utils/previewModeIndicator.js +101 -101
  24. package/dist/v2/index.d.ts +7 -6
  25. package/dist/v2/index.js +6 -6
  26. package/dist/v2/react/components/ApplePayButton.d.ts +1 -2
  27. package/dist/v2/react/components/ApplePayButton.js +57 -58
  28. package/dist/v2/react/components/FunnelScriptInjector.js +161 -172
  29. package/dist/v2/react/components/GooglePayButton.d.ts +2 -0
  30. package/dist/v2/react/components/GooglePayButton.js +80 -64
  31. package/dist/v2/react/hooks/useFunnel.d.ts +8 -2
  32. package/dist/v2/react/hooks/useFunnel.js +2 -2
  33. package/dist/v2/react/hooks/useGoogleAutocomplete.d.ts +10 -0
  34. package/dist/v2/react/hooks/useGoogleAutocomplete.js +48 -0
  35. package/dist/v2/react/hooks/useGooglePayCheckout.d.ts +21 -0
  36. package/dist/v2/react/hooks/useGooglePayCheckout.js +198 -0
  37. package/dist/v2/react/hooks/usePaymentPolling.d.ts +7 -1
  38. package/dist/v2/react/hooks/usePaymentQuery.d.ts +2 -0
  39. package/dist/v2/react/hooks/usePaymentQuery.js +435 -8
  40. package/dist/v2/react/hooks/usePixelTracking.d.ts +56 -0
  41. package/dist/v2/react/hooks/usePixelTracking.js +508 -0
  42. package/dist/v2/react/hooks/useStepConfig.d.ts +8 -6
  43. package/dist/v2/react/hooks/useStepConfig.js +3 -2
  44. package/dist/v2/react/index.d.ts +6 -2
  45. package/dist/v2/react/index.js +3 -1
  46. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.d.ts +1 -0
  47. package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +33 -13
  48. package/dist/v2/react/providers/TagadaProvider.js +22 -21
  49. package/dist/v2/standalone/index.js +1 -1
  50. package/package.json +112 -112
@@ -0,0 +1,508 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ /**
4
+ * usePixelTracking Hook & Provider
5
+ *
6
+ * SDK-level pixel tracking based on runtime stepConfig.pixels injected
7
+ * by the CRM. This mirrors the CMS pixel context pattern but uses the
8
+ * funnel step configuration as the source of truth instead of store
9
+ * integrations.
10
+ */
11
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react';
12
+ import { minorUnitsToMajorUnits } from '../../../react/utils/money';
13
+ import { useStepConfig } from './useStepConfig';
14
+ const PixelTrackingContext = createContext(null);
15
+ /**
16
+ * Simple per-page duplicate guard (time-window based)
17
+ * Avoids accidental double-fires during rerenders.
18
+ */
19
+ function createDuplicateGuard(windowMs) {
20
+ const lastEvents = new Map();
21
+ return (eventName, parameters) => {
22
+ try {
23
+ const key = JSON.stringify({ eventName, parameters });
24
+ const now = Date.now();
25
+ const last = lastEvents.get(key);
26
+ if (last && now - last < windowMs)
27
+ return false;
28
+ lastEvents.set(key, now);
29
+ return true;
30
+ }
31
+ catch {
32
+ // If hashing fails for any reason, just allow the event
33
+ return true;
34
+ }
35
+ };
36
+ }
37
+ const shouldTrackEvent = createDuplicateGuard(5000);
38
+ /**
39
+ * Provider that initializes pixels based on stepConfig.pixels
40
+ * and exposes a simple track(event, params) API.
41
+ */
42
+ export function PixelTrackingProvider({ children }) {
43
+ const { pixels } = useStepConfig();
44
+ const [pixelsInitialized, setPixelsInitialized] = useState(false);
45
+ const isMountedRef = useRef(true);
46
+ useEffect(() => {
47
+ isMountedRef.current = true;
48
+ return () => {
49
+ isMountedRef.current = false;
50
+ };
51
+ }, []);
52
+ // Initialize pixels once when configuration is available
53
+ useEffect(() => {
54
+ if (!pixels || pixelsInitialized || !isMountedRef.current)
55
+ return;
56
+ try {
57
+ // Facebook / Meta - support multiple pixels
58
+ const facebookPixels = pixels.facebook; // Support both 'facebook' and legacy 'meta'
59
+ if (facebookPixels) {
60
+ if (Array.isArray(facebookPixels)) {
61
+ facebookPixels.forEach((pixel) => {
62
+ if (pixel.enabled && pixel.pixelId) {
63
+ initMetaPixel(pixel.pixelId);
64
+ }
65
+ });
66
+ }
67
+ }
68
+ // TikTok - support multiple pixels
69
+ const tiktokPixels = pixels.tiktok;
70
+ if (tiktokPixels) {
71
+ if (Array.isArray(tiktokPixels)) {
72
+ tiktokPixels.forEach((pixel) => {
73
+ if (pixel.enabled && pixel.pixelId) {
74
+ initTikTokPixel(pixel.pixelId);
75
+ }
76
+ });
77
+ }
78
+ }
79
+ // Snapchat - support multiple pixels
80
+ const snapchatPixels = pixels.snapchat;
81
+ if (snapchatPixels) {
82
+ if (Array.isArray(snapchatPixels)) {
83
+ snapchatPixels.forEach((pixel) => {
84
+ if (pixel.enabled && pixel.pixelId) {
85
+ initSnapchatPixel(pixel.pixelId);
86
+ }
87
+ });
88
+ }
89
+ }
90
+ // GTM - support multiple containers
91
+ const gtmPixels = pixels.gtm;
92
+ if (gtmPixels) {
93
+ if (Array.isArray(gtmPixels)) {
94
+ gtmPixels.forEach((pixel) => {
95
+ if (pixel.enabled && pixel.containerId) {
96
+ initGTM(pixel.containerId);
97
+ }
98
+ });
99
+ }
100
+ }
101
+ if (isMountedRef.current) {
102
+ setPixelsInitialized(true);
103
+ }
104
+ }
105
+ catch (error) {
106
+ // Fail-safe: never break the host page because of pixel issues
107
+ if (typeof console !== 'undefined') {
108
+ console.error('[SDK Pixels] Error during pixel initialization:', error);
109
+ }
110
+ }
111
+ }, [pixels, pixelsInitialized]);
112
+ const track = useCallback((eventName, parameters = {}) => {
113
+ if (!pixels || !pixelsInitialized || !isMountedRef.current) {
114
+ return;
115
+ }
116
+ // Duplicate guard
117
+ if (!shouldTrackEvent(eventName, parameters)) {
118
+ return;
119
+ }
120
+ try {
121
+ // Facebook / Meta - track to all enabled pixels
122
+ const facebookPixels = pixels.facebook; // Support both 'facebook' and legacy 'meta'
123
+ if (facebookPixels) {
124
+ const pixelArray = Array.isArray(facebookPixels)
125
+ ? facebookPixels
126
+ : [facebookPixels];
127
+ const enabledPixels = pixelArray.filter((p) => p.enabled);
128
+ if (enabledPixels.length > 0) {
129
+ const { name, params } = mapMetaEvent(eventName, parameters);
130
+ // Track to all enabled Facebook pixels
131
+ enabledPixels.forEach(() => {
132
+ trackMetaEvent(name, params);
133
+ });
134
+ }
135
+ }
136
+ // TikTok - track to all enabled pixels
137
+ const tiktokPixels = pixels.tiktok;
138
+ if (tiktokPixels) {
139
+ const pixelArray = Array.isArray(tiktokPixels)
140
+ ? tiktokPixels
141
+ : [tiktokPixels];
142
+ const enabledPixels = pixelArray.filter((p) => p.enabled);
143
+ if (enabledPixels.length > 0) {
144
+ const { name, params } = mapTikTokEvent(eventName, parameters);
145
+ // Track to all enabled TikTok pixels
146
+ enabledPixels.forEach(() => {
147
+ trackTikTokEvent(name, params);
148
+ });
149
+ }
150
+ }
151
+ // Snapchat - track to all enabled pixels
152
+ const snapchatPixels = pixels.snapchat;
153
+ if (snapchatPixels) {
154
+ const pixelArray = Array.isArray(snapchatPixels)
155
+ ? snapchatPixels
156
+ : [snapchatPixels];
157
+ const enabledPixels = pixelArray.filter((p) => p.enabled);
158
+ if (enabledPixels.length > 0) {
159
+ const { name, params } = mapSnapchatEvent(eventName, parameters);
160
+ // Track to all enabled Snapchat pixels
161
+ enabledPixels.forEach(() => {
162
+ trackSnapchatEvent(name, params);
163
+ });
164
+ }
165
+ }
166
+ // GTM - track to all enabled containers
167
+ const gtmPixels = pixels.gtm;
168
+ if (gtmPixels) {
169
+ const pixelArray = Array.isArray(gtmPixels)
170
+ ? gtmPixels
171
+ : [gtmPixels];
172
+ const enabledPixels = pixelArray.filter((p) => p.enabled);
173
+ if (enabledPixels.length > 0) {
174
+ const { name, params } = mapGTMEvent(eventName, parameters);
175
+ // Track to all enabled GTM containers
176
+ enabledPixels.forEach(() => {
177
+ console.log('trackGTMEvent', name, params);
178
+ trackGTMEvent(name, params);
179
+ });
180
+ }
181
+ }
182
+ }
183
+ catch (error) {
184
+ if (typeof console !== 'undefined') {
185
+ console.error('[SDK Pixels] Error tracking pixel event:', error);
186
+ }
187
+ }
188
+ }, [pixels, pixelsInitialized]);
189
+ // Track page views automatically when pixels are initialized
190
+ useEffect(() => {
191
+ if (!pixelsInitialized || !isMountedRef.current)
192
+ return;
193
+ // Small delay to ensure we don't double fire during strict mode remounts
194
+ const pageViewTimeoutId = setTimeout(() => {
195
+ if (isMountedRef.current) {
196
+ track('PageView', {
197
+ path: typeof window !== 'undefined' ? window.location.pathname : '',
198
+ });
199
+ }
200
+ }, 0);
201
+ return () => {
202
+ if (pageViewTimeoutId) {
203
+ clearTimeout(pageViewTimeoutId);
204
+ }
205
+ };
206
+ }, [pixelsInitialized, track]);
207
+ const value = useMemo(() => ({
208
+ track,
209
+ pixelsInitialized,
210
+ }), [track, pixelsInitialized]);
211
+ return _jsx(PixelTrackingContext.Provider, { value: value, children: children });
212
+ }
213
+ /**
214
+ * Hook to access SDK pixel tracking.
215
+ * Must be used within TagadaProvider (which wraps PixelTrackingProvider).
216
+ */
217
+ export function usePixelTracking() {
218
+ const context = useContext(PixelTrackingContext);
219
+ if (!context) {
220
+ throw new Error('usePixelTracking must be used within a PixelTrackingProvider');
221
+ }
222
+ return context;
223
+ }
224
+ function initMetaPixel(pixelId) {
225
+ if (typeof window === 'undefined')
226
+ return;
227
+ if (window.fbq)
228
+ return;
229
+ // Standard Facebook Pixel bootstrap
230
+ (function (f, b, e) {
231
+ if (f.fbq)
232
+ return;
233
+ const n = function (...args) {
234
+ if (n.callMethod) {
235
+ n.callMethod(...args);
236
+ }
237
+ else {
238
+ n.queue.push(args);
239
+ }
240
+ };
241
+ f.fbq = n;
242
+ if (!f._fbq)
243
+ f._fbq = n;
244
+ n.queue = n.queue ?? [];
245
+ n.loaded = true;
246
+ n.version = '2.0';
247
+ n.queue = [];
248
+ const t = b.createElement(e);
249
+ t.async = true;
250
+ t.src = 'https://connect.facebook.net/en_US/fbevents.js';
251
+ const s = b.getElementsByTagName(e)[0];
252
+ s.parentNode?.insertBefore(t, s);
253
+ })(window, document, 'script');
254
+ const fbq = window.fbq;
255
+ if (fbq) {
256
+ fbq('init', pixelId);
257
+ }
258
+ }
259
+ function trackMetaEvent(name, params) {
260
+ if (typeof window === 'undefined' || !window.fbq)
261
+ return;
262
+ const fbq = window.fbq;
263
+ fbq?.('track', name, params);
264
+ }
265
+ function initTikTokPixel(pixelId) {
266
+ if (typeof window === 'undefined')
267
+ return;
268
+ if (window.ttq)
269
+ return;
270
+ (function (w, d, t) {
271
+ const ttq = w.ttq ||
272
+ function (...args) {
273
+ ttq.queue.push(args);
274
+ };
275
+ if (!ttq.queue) {
276
+ ttq.queue = [];
277
+ }
278
+ w.ttq = ttq;
279
+ ttq.methods = [
280
+ 'page',
281
+ 'track',
282
+ 'identify',
283
+ 'instances',
284
+ 'debug',
285
+ 'on',
286
+ 'off',
287
+ 'once',
288
+ 'ready',
289
+ 'alias',
290
+ 'group',
291
+ 'enableCookie',
292
+ 'disableCookie',
293
+ ];
294
+ ttq.setAndDefer = function (target, method) {
295
+ target[method] = function (...args) {
296
+ target.queue.push([method, ...args]);
297
+ };
298
+ };
299
+ for (const method of ttq.methods) {
300
+ ttq.setAndDefer(ttq, method);
301
+ }
302
+ ttq.load = function (e) {
303
+ const n = 'https://analytics.tiktok.com/i18n/pixel/events.js';
304
+ const a = d.createElement(t);
305
+ a.type = 'text/javascript';
306
+ a.async = true;
307
+ a.src = n + '?sdkid=' + e + '&lib=ttq';
308
+ const s = d.getElementsByTagName(t)[0];
309
+ s.parentNode.insertBefore(a, s);
310
+ };
311
+ })(window, document, 'script');
312
+ const ttqInstance = window.ttq;
313
+ if (!ttqInstance)
314
+ return;
315
+ ttqInstance.load?.(pixelId);
316
+ ttqInstance.page?.();
317
+ }
318
+ function trackTikTokEvent(name, params) {
319
+ if (typeof window === 'undefined' || !window.ttq)
320
+ return;
321
+ const ttq = window.ttq;
322
+ ttq?.track?.(name, params);
323
+ }
324
+ function initSnapchatPixel(pixelId) {
325
+ if (typeof window === 'undefined')
326
+ return;
327
+ if (window.snaptr)
328
+ return;
329
+ (function (w, d, tagName) {
330
+ if (w.snaptr)
331
+ return;
332
+ const a = (function (...args) {
333
+ if (a.handleRequest) {
334
+ a.handleRequest(...args);
335
+ }
336
+ else {
337
+ a.queue.push(args);
338
+ }
339
+ });
340
+ a.queue = [];
341
+ w.snaptr = a;
342
+ const s = 'script';
343
+ const r = d.createElement(s);
344
+ r.async = true;
345
+ r.src = 'https://sc-static.net/scevent.min.js';
346
+ const u = d.getElementsByTagName(tagName)[0];
347
+ u.parentNode?.insertBefore(r, u);
348
+ })(window, document, 'script');
349
+ const snaptr = window.snaptr;
350
+ snaptr?.('init', pixelId);
351
+ }
352
+ function trackSnapchatEvent(name, params) {
353
+ if (typeof window === 'undefined' || !window.snaptr)
354
+ return;
355
+ const snaptr = window.snaptr;
356
+ snaptr?.('track', name, params);
357
+ }
358
+ function initGTM(containerId) {
359
+ if (typeof window === 'undefined' || typeof document === 'undefined')
360
+ return;
361
+ if (!containerId)
362
+ return;
363
+ // Check if GTM script is already loaded for this container
364
+ const existingScript = document.querySelector(`script[src*="googletagmanager.com/gtm.js?id=${containerId}"]`);
365
+ if (existingScript) {
366
+ return; // GTM already initialized for this container
367
+ }
368
+ // Initialize dataLayer before GTM script (Google's official pattern)
369
+ window.dataLayer = window.dataLayer || [];
370
+ // Push gtm.start event (must be done before script loads)
371
+ window.dataLayer.push({
372
+ 'gtm.start': new Date().getTime(),
373
+ event: 'gtm.js',
374
+ });
375
+ // Create and inject GTM script (Google's official pattern)
376
+ // This matches Google's exact implementation from their documentation
377
+ (function (w, d, s, l, i) {
378
+ const f = d.getElementsByTagName(s)[0];
379
+ const j = d.createElement(s);
380
+ const dl = l != 'dataLayer' ? '&l=' + l : '';
381
+ j.async = true;
382
+ j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
383
+ // Insert before first script tag (typically in head)
384
+ if (f && f.parentNode) {
385
+ f.parentNode.insertBefore(j, f);
386
+ }
387
+ else {
388
+ // Fallback: append to head if no script tags found
389
+ const head = d.head || d.getElementsByTagName('head')[0];
390
+ if (head) {
391
+ head.appendChild(j);
392
+ }
393
+ }
394
+ })(window, document, 'script', 'dataLayer', containerId);
395
+ // Also add noscript fallback in body (Google's official pattern)
396
+ // This ensures GTM works even if JavaScript is disabled
397
+ const noscript = document.createElement('noscript');
398
+ const iframe = document.createElement('iframe');
399
+ iframe.src = `https://www.googletagmanager.com/ns.html?id=${containerId}`;
400
+ iframe.height = '0';
401
+ iframe.width = '0';
402
+ iframe.style.display = 'none';
403
+ iframe.style.visibility = 'hidden';
404
+ noscript.appendChild(iframe);
405
+ // Insert noscript at the beginning of body
406
+ const body = document.body || document.getElementsByTagName('body')[0];
407
+ if (body) {
408
+ body.insertBefore(noscript, body.firstChild);
409
+ }
410
+ }
411
+ function trackGTMEvent(event, params = {}) {
412
+ if (typeof window === 'undefined') {
413
+ console.warn('[SDK GTM] Window not available, event not tracked:', event);
414
+ return;
415
+ }
416
+ // Ensure dataLayer exists (should be initialized by initGTM, but double-check)
417
+ if (!window.dataLayer) {
418
+ console.warn('[SDK GTM] dataLayer not initialized, initializing now...');
419
+ window.dataLayer = [];
420
+ }
421
+ try {
422
+ const eventData = {
423
+ event,
424
+ ...params,
425
+ };
426
+ console.log('[SDK GTM] Pushing event to dataLayer:', eventData);
427
+ window.dataLayer.push(eventData);
428
+ console.log('[SDK GTM] Event pushed successfully. Current dataLayer length:', window.dataLayer.length);
429
+ }
430
+ catch (error) {
431
+ if (typeof console !== 'undefined') {
432
+ console.error('[SDK GTM] Error tracking event:', error);
433
+ }
434
+ }
435
+ }
436
+ // --- Basic event mapping (can be extended later if needed) ---
437
+ function mapMetaEvent(eventName, parameters) {
438
+ return { name: eventName, params: parameters };
439
+ }
440
+ function mapTikTokEvent(eventName, parameters) {
441
+ // TikTok naming is usually aligned; adjust here if needed later
442
+ return { name: eventName, params: parameters };
443
+ }
444
+ function mapSnapchatEvent(eventName, parameters) {
445
+ return { name: eventName, params: parameters };
446
+ }
447
+ function mapGTMEvent(eventName, parameters) {
448
+ // Map standard event names to GTM event names
449
+ const gtmEventMap = {
450
+ PageView: 'page_view',
451
+ AddPaymentInfo: 'add_payment_info',
452
+ AddToCart: 'add_to_cart',
453
+ InitiateCheckout: 'begin_checkout',
454
+ Purchase: 'purchase',
455
+ ViewContent: 'view_item',
456
+ CompleteRegistration: 'sign_up',
457
+ };
458
+ const gtmEventName = gtmEventMap[eventName] ?? eventName.toLowerCase();
459
+ // Transform parameters for GTM
460
+ const gtmParams = transformGTMParameters(eventName, parameters);
461
+ return { name: gtmEventName, params: gtmParams };
462
+ }
463
+ function transformGTMParameters(eventName, parameters) {
464
+ const gtmParameters = { ...parameters };
465
+ // Ensure currency is uppercase
466
+ if (gtmParameters.currency) {
467
+ gtmParameters.currency = String(gtmParameters.currency).toUpperCase();
468
+ }
469
+ // Transform currency values to major units if needed
470
+ if (gtmParameters.currency && gtmParameters.value) {
471
+ try {
472
+ gtmParameters.value = minorUnitsToMajorUnits(Number(gtmParameters.value), String(gtmParameters.currency));
473
+ }
474
+ catch (error) {
475
+ // If conversion fails, try simple division by 100 as fallback
476
+ if (typeof console !== 'undefined') {
477
+ console.warn('[SDK GTM] Currency conversion failed, using fallback:', error);
478
+ }
479
+ gtmParameters.value = Number(gtmParameters.value) / 100;
480
+ }
481
+ }
482
+ // Ensure numeric values
483
+ if (gtmParameters.value !== undefined) {
484
+ gtmParameters.value = Number(gtmParameters.value);
485
+ }
486
+ if (gtmParameters.num_items !== undefined) {
487
+ gtmParameters.num_items = Number(gtmParameters.num_items);
488
+ }
489
+ // Transform contents to a format better suited for GTM
490
+ if (gtmParameters.contents && Array.isArray(gtmParameters.contents)) {
491
+ gtmParameters.items = gtmParameters.contents.map((item) => ({
492
+ item_id: item.content_id,
493
+ item_name: item.content_name,
494
+ item_category: item.content_category,
495
+ price: item.price ? Number(item.price) : undefined,
496
+ quantity: item.quantity ? Number(item.quantity) : undefined,
497
+ }));
498
+ // Keep original contents for compatibility
499
+ gtmParameters.contents = gtmParameters.contents.map((item) => ({
500
+ id: item.content_id,
501
+ name: item.content_name,
502
+ category: item.content_category,
503
+ price: item.price ? Number(item.price) : undefined,
504
+ quantity: item.quantity ? Number(item.quantity) : undefined,
505
+ }));
506
+ }
507
+ return gtmParameters;
508
+ }
@@ -21,7 +21,7 @@
21
21
  * const offerId = staticResources?.offer;
22
22
  * ```
23
23
  */
24
- import { RuntimeStepConfig } from '../../core/funnelClient';
24
+ import { GTMTrackingConfig, MetaConversionTrackingConfig, PixelTrackingConfig, RuntimeStepConfig, SnapchatTrackingConfig, TrackingProvider } from '../../core/funnelClient';
25
25
  export interface UseStepConfigResult {
26
26
  /**
27
27
  * Full step configuration object
@@ -45,11 +45,13 @@ export interface UseStepConfigResult {
45
45
  * @param position - Where the scripts should be injected
46
46
  */
47
47
  getScripts: (position?: 'head-start' | 'head-end' | 'body-start' | 'body-end') => RuntimeStepConfig['scripts'];
48
- /**
49
- * Pixel tracking configuration
50
- * e.g., { facebook: 'pixel_id', google: 'ga_id' }
51
- */
52
- pixels: Record<string, string> | undefined;
48
+ pixels: {
49
+ [TrackingProvider.FACEBOOK]?: PixelTrackingConfig[];
50
+ [TrackingProvider.TIKTOK]?: PixelTrackingConfig[];
51
+ [TrackingProvider.SNAPCHAT]?: SnapchatTrackingConfig[];
52
+ [TrackingProvider.META_CONVERSION]?: MetaConversionTrackingConfig[];
53
+ [TrackingProvider.GTM]?: GTMTrackingConfig[];
54
+ } | undefined;
53
55
  }
54
56
  /**
55
57
  * Hook to access runtime step configuration injected via HTML
@@ -22,7 +22,7 @@
22
22
  * ```
23
23
  */
24
24
  import { useMemo } from 'react';
25
- import { getAssignedStepConfig, getAssignedPaymentFlowId, getAssignedStaticResources, getAssignedScripts, } from '../../core/funnelClient';
25
+ import { getAssignedPaymentFlowId, getAssignedPixels, getAssignedScripts, getAssignedStaticResources, getAssignedStepConfig, TrackingProvider } from '../../core/funnelClient';
26
26
  /**
27
27
  * Hook to access runtime step configuration injected via HTML
28
28
  *
@@ -36,6 +36,7 @@ export function useStepConfig() {
36
36
  const stepConfig = useMemo(() => getAssignedStepConfig(), []);
37
37
  const paymentFlowId = useMemo(() => getAssignedPaymentFlowId(), []);
38
38
  const staticResources = useMemo(() => getAssignedStaticResources(), []);
39
+ const pixels = useMemo(() => getAssignedPixels(), []);
39
40
  // Create a stable reference for getScripts
40
41
  const getScripts = useMemo(() => {
41
42
  return (position) => {
@@ -47,6 +48,6 @@ export function useStepConfig() {
47
48
  paymentFlowId,
48
49
  staticResources,
49
50
  getScripts,
50
- pixels: stepConfig?.pixels,
51
+ pixels
51
52
  };
52
53
  }
@@ -20,8 +20,11 @@ export { useCustomerSubscriptions } from './hooks/useCustomerSubscriptions';
20
20
  export { useExpressPaymentMethods } from './hooks/useExpressPaymentMethods';
21
21
  export { useGeoLocation } from './hooks/useGeoLocation';
22
22
  export { useGoogleAutocomplete } from './hooks/useGoogleAutocomplete';
23
+ export { useGooglePayCheckout } from './hooks/useGooglePayCheckout';
23
24
  export { getAvailableLanguages, useCountryOptions, useISOData, useLanguageImport, useRegionOptions } from './hooks/useISOData';
24
25
  export { useLogin } from './hooks/useLogin';
26
+ export { PixelTrackingProvider, usePixelTracking } from './hooks/usePixelTracking';
27
+ export type { PixelTrackingContextValue, StandardPixelEvent } from './hooks/usePixelTracking';
25
28
  export { usePluginConfig } from './hooks/usePluginConfig';
26
29
  export { useRemappableParams } from './hooks/useRemappableParams';
27
30
  export { queryKeys, useApiMutation, useApiQuery, useInvalidateQuery, usePreloadQuery } from './hooks/useApiQuery';
@@ -29,12 +32,12 @@ export { useCheckoutQuery as useCheckout } from './hooks/useCheckoutQuery';
29
32
  export { useCurrency } from './hooks/useCurrency';
30
33
  export { useDiscountsQuery as useDiscounts } from './hooks/useDiscountsQuery';
31
34
  export { useOfferQuery as useOffer } from './hooks/useOfferQuery';
32
- export { usePreviewOffer } from './hooks/usePreviewOffer';
33
35
  export { useOrderBumpQuery as useOrderBump } from './hooks/useOrderBumpQuery';
34
36
  export { useOrderQuery as useOrder } from './hooks/useOrderQuery';
35
37
  export { usePaymentQuery as usePayment } from './hooks/usePaymentQuery';
36
38
  export { usePaymentRetrieve } from './hooks/usePaymentRetrieve';
37
39
  export { usePostPurchasesQuery as usePostPurchases } from './hooks/usePostPurchasesQuery';
40
+ export { usePreviewOffer } from './hooks/usePreviewOffer';
38
41
  export { useProductsQuery as useProducts } from './hooks/useProductsQuery';
39
42
  export { usePromotionsQuery as usePromotions } from './hooks/usePromotionsQuery';
40
43
  export { useShippingRatesQuery as useShippingRates } from './hooks/useShippingRatesQuery';
@@ -55,6 +58,7 @@ export type { UseCustomerInfosOptions, UseCustomerInfosResult } from './hooks/us
55
58
  export type { UseCustomerOrdersOptions, UseCustomerOrdersResult } from './hooks/useCustomerOrders';
56
59
  export type { UseCustomerSubscriptionsOptions, UseCustomerSubscriptionsResult } from './hooks/useCustomerSubscriptions';
57
60
  export type { ExpressPaymentMethodsContextType, ExpressPaymentMethodsProviderProps } from './hooks/useExpressPaymentMethods';
61
+ export type { UseGooglePayCheckoutOptions } from './hooks/useGooglePayCheckout';
58
62
  export type { UseLoginOptions, UseLoginResult } from './hooks/useLogin';
59
63
  export type { ApplePayButtonProps } from './components/ApplePayButton';
60
64
  export type { GooglePayButtonProps } from './components/GooglePayButton';
@@ -72,12 +76,12 @@ export type { FunnelContextValue, StepConfigValue } from './hooks/useFunnel';
72
76
  export type { UseStepConfigResult } from './hooks/useStepConfig';
73
77
  export type { UseFunnelOptions as UseFunnelLegacyOptions, UseFunnelResult as UseFunnelLegacyResult } from './hooks/useFunnelLegacy';
74
78
  export type { AvailableVariant, LineItemSelection, OfferLineItem, OfferPreviewSummary, UseOfferQueryOptions as UseOfferOptions, UseOfferQueryResult as UseOfferResult } from './hooks/useOfferQuery';
75
- export type { PreviewOfferSummary, UsePreviewOfferOptions, UsePreviewOfferResult } from './hooks/usePreviewOffer';
76
79
  export type { UseOrderBumpQueryOptions as UseOrderBumpOptions, UseOrderBumpQueryResult as UseOrderBumpResult } from './hooks/useOrderBumpQuery';
77
80
  export type { UseOrderQueryOptions as UseOrderOptions, UseOrderQueryResult as UseOrderResult } from './hooks/useOrderQuery';
78
81
  export type { PaymentHook as UsePaymentResult } from './hooks/usePaymentQuery';
79
82
  export type { PaymentRetrieveHook as UsePaymentRetrieveResult } from './hooks/usePaymentRetrieve';
80
83
  export type { UsePostPurchasesQueryOptions as UsePostPurchasesOptions, UsePostPurchasesQueryResult as UsePostPurchasesResult } from './hooks/usePostPurchasesQuery';
84
+ export type { PreviewOfferSummary, UsePreviewOfferOptions, UsePreviewOfferResult } from './hooks/usePreviewOffer';
81
85
  export type { UseProductsQueryOptions as UseProductsOptions, UseProductsQueryResult as UseProductsResult } from './hooks/useProductsQuery';
82
86
  export type { UsePromotionsQueryOptions as UsePromotionsOptions, UsePromotionsQueryResult as UsePromotionsResult } from './hooks/usePromotionsQuery';
83
87
  export type { UseShippingRatesQueryOptions as UseShippingRatesOptions, UseShippingRatesQueryResult as UseShippingRatesResult } from './hooks/useShippingRatesQuery';
@@ -22,8 +22,10 @@ export { useCustomerSubscriptions } from './hooks/useCustomerSubscriptions';
22
22
  export { useExpressPaymentMethods } from './hooks/useExpressPaymentMethods';
23
23
  export { useGeoLocation } from './hooks/useGeoLocation';
24
24
  export { useGoogleAutocomplete } from './hooks/useGoogleAutocomplete';
25
+ export { useGooglePayCheckout } from './hooks/useGooglePayCheckout';
25
26
  export { getAvailableLanguages, useCountryOptions, useISOData, useLanguageImport, useRegionOptions } from './hooks/useISOData';
26
27
  export { useLogin } from './hooks/useLogin';
28
+ export { PixelTrackingProvider, usePixelTracking } from './hooks/usePixelTracking';
27
29
  export { usePluginConfig } from './hooks/usePluginConfig';
28
30
  export { useRemappableParams } from './hooks/useRemappableParams';
29
31
  // TanStack Query hooks (recommended)
@@ -32,12 +34,12 @@ export { useCheckoutQuery as useCheckout } from './hooks/useCheckoutQuery';
32
34
  export { useCurrency } from './hooks/useCurrency';
33
35
  export { useDiscountsQuery as useDiscounts } from './hooks/useDiscountsQuery';
34
36
  export { useOfferQuery as useOffer } from './hooks/useOfferQuery';
35
- export { usePreviewOffer } from './hooks/usePreviewOffer';
36
37
  export { useOrderBumpQuery as useOrderBump } from './hooks/useOrderBumpQuery';
37
38
  export { useOrderQuery as useOrder } from './hooks/useOrderQuery';
38
39
  export { usePaymentQuery as usePayment } from './hooks/usePaymentQuery';
39
40
  export { usePaymentRetrieve } from './hooks/usePaymentRetrieve';
40
41
  export { usePostPurchasesQuery as usePostPurchases } from './hooks/usePostPurchasesQuery';
42
+ export { usePreviewOffer } from './hooks/usePreviewOffer';
41
43
  export { useProductsQuery as useProducts } from './hooks/useProductsQuery';
42
44
  export { usePromotionsQuery as usePromotions } from './hooks/usePromotionsQuery';
43
45
  export { useShippingRatesQuery as useShippingRates } from './hooks/useShippingRatesQuery';
@@ -33,6 +33,7 @@ interface ExpressPaymentMethodsContextType {
33
33
  amount: string;
34
34
  };
35
35
  shippingMethods: ExpressShippingMethod[];
36
+ selectedShippingRateId?: string;
36
37
  } | undefined>;
37
38
  updateCheckoutSessionValues: (input: {
38
39
  data: {