@tagadapay/plugin-sdk 3.1.8 → 3.1.9
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 +1129 -1129
- package/build-cdn.js +220 -113
- package/dist/external-tracker.js +135 -81
- package/dist/external-tracker.min.js +2 -2
- package/dist/external-tracker.min.js.map +4 -4
- package/dist/react/providers/TagadaProvider.js +5 -5
- package/dist/tagada-sdk.js +10142 -0
- package/dist/tagada-sdk.min.js +43 -0
- package/dist/tagada-sdk.min.js.map +7 -0
- package/dist/v2/core/funnelClient.d.ts +91 -4
- package/dist/v2/core/funnelClient.js +42 -3
- package/dist/v2/core/resources/funnel.d.ts +10 -0
- package/dist/v2/core/resources/payments.d.ts +21 -1
- package/dist/v2/core/resources/payments.js +34 -0
- package/dist/v2/core/utils/index.d.ts +1 -0
- package/dist/v2/core/utils/index.js +2 -0
- package/dist/v2/core/utils/pluginConfig.d.ts +8 -0
- package/dist/v2/core/utils/pluginConfig.js +28 -0
- package/dist/v2/core/utils/previewMode.d.ts +4 -0
- package/dist/v2/core/utils/previewMode.js +28 -0
- package/dist/v2/core/utils/previewModeIndicator.js +101 -101
- package/dist/v2/index.d.ts +7 -6
- package/dist/v2/index.js +6 -6
- package/dist/v2/react/components/ApplePayButton.d.ts +1 -2
- package/dist/v2/react/components/ApplePayButton.js +57 -58
- package/dist/v2/react/components/FunnelScriptInjector.js +161 -172
- package/dist/v2/react/components/GooglePayButton.d.ts +2 -0
- package/dist/v2/react/components/GooglePayButton.js +80 -64
- package/dist/v2/react/hooks/useFunnel.d.ts +8 -2
- package/dist/v2/react/hooks/useFunnel.js +2 -2
- package/dist/v2/react/hooks/useGoogleAutocomplete.d.ts +10 -0
- package/dist/v2/react/hooks/useGoogleAutocomplete.js +48 -0
- package/dist/v2/react/hooks/useGooglePayCheckout.d.ts +21 -0
- package/dist/v2/react/hooks/useGooglePayCheckout.js +198 -0
- package/dist/v2/react/hooks/usePaymentPolling.d.ts +7 -1
- package/dist/v2/react/hooks/usePaymentQuery.d.ts +2 -0
- package/dist/v2/react/hooks/usePaymentQuery.js +435 -8
- package/dist/v2/react/hooks/usePixelTracking.d.ts +56 -0
- package/dist/v2/react/hooks/usePixelTracking.js +508 -0
- package/dist/v2/react/hooks/useStepConfig.d.ts +8 -6
- package/dist/v2/react/hooks/useStepConfig.js +3 -2
- package/dist/v2/react/index.d.ts +6 -2
- package/dist/v2/react/index.js +3 -1
- package/dist/v2/react/providers/ExpressPaymentMethodsProvider.d.ts +1 -0
- package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +33 -13
- package/dist/v2/react/providers/TagadaProvider.js +22 -21
- 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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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 {
|
|
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
|
|
51
|
+
pixels
|
|
51
52
|
};
|
|
52
53
|
}
|
package/dist/v2/react/index.d.ts
CHANGED
|
@@ -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';
|
package/dist/v2/react/index.js
CHANGED
|
@@ -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';
|