@tagadapay/plugin-sdk 3.1.11 → 3.1.22
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 +231 -228
- package/dist/data/iso3166.d.ts +23 -33
- package/dist/data/iso3166.js +134 -198
- package/dist/data/languages.d.ts +5 -64
- package/dist/data/languages.js +23 -143
- package/dist/external-tracker.js +968 -102
- package/dist/external-tracker.min.js +2 -2
- package/dist/external-tracker.min.js.map +4 -4
- package/dist/react/hooks/useISOData.js +1 -1
- package/dist/react/hooks/usePaymentPolling.d.ts +3 -3
- package/dist/react/hooks/useShippingRates.d.ts +6 -0
- package/dist/react/hooks/useShippingRates.js +38 -0
- package/dist/react/providers/TagadaProvider.js +5 -5
- package/dist/react/services/apiService.d.ts +21 -0
- package/dist/react/services/apiService.js +10 -0
- package/dist/tagada-sdk.js +2079 -179
- package/dist/tagada-sdk.min.js +4 -2
- package/dist/tagada-sdk.min.js.map +4 -4
- package/dist/v2/core/client.d.ts +4 -2
- package/dist/v2/core/client.js +4 -3
- package/dist/v2/core/errors.d.ts +75 -0
- package/dist/v2/core/errors.js +104 -0
- package/dist/v2/core/funnelClient.d.ts +16 -15
- package/dist/v2/core/funnelClient.js +1 -1
- package/dist/v2/core/index.d.ts +1 -0
- package/dist/v2/core/index.js +2 -0
- package/dist/v2/core/pixelMapping.d.ts +49 -0
- package/dist/v2/core/pixelMapping.js +325 -0
- package/dist/v2/core/resources/apiClient.d.ts +2 -0
- package/dist/v2/core/resources/apiClient.js +52 -9
- package/dist/v2/core/resources/checkout.d.ts +89 -30
- package/dist/v2/core/resources/checkout.js +8 -0
- package/dist/v2/core/resources/customer.d.ts +20 -19
- package/dist/v2/core/resources/funnel.d.ts +17 -17
- package/dist/v2/core/resources/payments.d.ts +84 -13
- package/dist/v2/core/resources/payments.js +26 -9
- package/dist/v2/core/resources/shippingRates.d.ts +15 -0
- package/dist/v2/core/resources/shippingRates.js +11 -0
- package/dist/v2/core/types.d.ts +50 -12
- package/dist/v2/core/types.js +0 -3
- package/dist/v2/core/utils/checkout.d.ts +2 -2
- package/dist/v2/core/utils/checkout.js +7 -2
- package/dist/v2/core/utils/order.d.ts +11 -9
- package/dist/v2/core/utils/previewModeIndicator.js +101 -101
- package/dist/v2/index.d.ts +4 -2
- package/dist/v2/index.js +1 -1
- package/dist/v2/react/components/ApplePayButton.js +13 -4
- package/dist/v2/react/components/FunnelScriptInjector.js +51 -30
- package/dist/v2/react/components/WhopCheckout.d.ts +24 -0
- package/dist/v2/react/components/WhopCheckout.js +231 -0
- package/dist/v2/react/hooks/__examples__/FunnelContextExample.js +1 -1
- package/dist/v2/react/hooks/payment-actions/useAirwallexRadarAction.d.ts +14 -0
- package/dist/v2/react/hooks/payment-actions/useAirwallexRadarAction.js +181 -0
- package/dist/v2/react/hooks/payment-actions/useErrorAction.d.ts +9 -0
- package/dist/v2/react/hooks/payment-actions/useErrorAction.js +21 -0
- package/dist/v2/react/hooks/payment-actions/useFinixRadarAction.d.ts +14 -0
- package/dist/v2/react/hooks/payment-actions/useFinixRadarAction.js +187 -0
- package/dist/v2/react/hooks/payment-actions/useKessPayAction.d.ts +11 -0
- package/dist/v2/react/hooks/payment-actions/useKessPayAction.js +91 -0
- package/dist/v2/react/hooks/payment-actions/useMasterCardAction.d.ts +24 -0
- package/dist/v2/react/hooks/payment-actions/useMasterCardAction.js +221 -0
- package/dist/v2/react/hooks/payment-actions/usePaymentActionHandler.d.ts +15 -0
- package/dist/v2/react/hooks/payment-actions/usePaymentActionHandler.js +142 -0
- package/dist/v2/react/hooks/payment-actions/useProcessorAuthAction.d.ts +3 -0
- package/dist/v2/react/hooks/payment-actions/useProcessorAuthAction.js +13 -0
- package/dist/v2/react/hooks/payment-actions/useRedirectAction.d.ts +10 -0
- package/dist/v2/react/hooks/payment-actions/useRedirectAction.js +35 -0
- package/dist/v2/react/hooks/payment-actions/useStripeRadarAction.d.ts +14 -0
- package/dist/v2/react/hooks/payment-actions/useStripeRadarAction.js +192 -0
- package/dist/v2/react/hooks/payment-actions/useThreedsAuthAction.d.ts +14 -0
- package/dist/v2/react/hooks/payment-actions/useThreedsAuthAction.js +81 -0
- package/dist/v2/react/hooks/payment-actions/useTrustFlowAction.d.ts +11 -0
- package/dist/v2/react/hooks/payment-actions/useTrustFlowAction.js +84 -0
- package/dist/v2/react/hooks/payment-processing/usePaymentInstruments.d.ts +14 -0
- package/dist/v2/react/hooks/payment-processing/usePaymentInstruments.js +36 -0
- package/dist/v2/react/hooks/payment-processing/usePaymentProcessors.d.ts +31 -0
- package/dist/v2/react/hooks/payment-processing/usePaymentProcessors.js +212 -0
- package/dist/v2/react/hooks/payment-redirect/useAirwallex3dsReturn.d.ts +14 -0
- package/dist/v2/react/hooks/payment-redirect/useAirwallex3dsReturn.js +207 -0
- package/dist/v2/react/hooks/payment-redirect/useGenericPaymentReturn.d.ts +12 -0
- package/dist/v2/react/hooks/payment-redirect/useGenericPaymentReturn.js +101 -0
- package/dist/v2/react/hooks/useCheckoutQuery.d.ts +6 -0
- package/dist/v2/react/hooks/useCheckoutQuery.js +45 -0
- package/dist/v2/react/hooks/useFunnel.d.ts +1 -2
- package/dist/v2/react/hooks/useGeoLocation.d.ts +2 -1
- package/dist/v2/react/hooks/useGeoLocation.js +4 -2
- package/dist/v2/react/hooks/useGoogleAutocomplete.js +82 -33
- package/dist/v2/react/hooks/useISOData.js +1 -1
- package/dist/v2/react/hooks/usePaymentPolling.d.ts +3 -3
- package/dist/v2/react/hooks/usePaymentQuery.d.ts +18 -5
- package/dist/v2/react/hooks/usePaymentQuery.js +63 -1015
- package/dist/v2/react/hooks/usePaymentRetrieve.d.ts +3 -2
- package/dist/v2/react/hooks/usePaymentRetrieve.js +3 -1
- package/dist/v2/react/hooks/usePixelTracking.d.ts +5 -43
- package/dist/v2/react/hooks/usePixelTracking.js +213 -407
- package/dist/v2/react/hooks/useShippingRatesQuery.d.ts +6 -0
- package/dist/v2/react/hooks/useShippingRatesQuery.js +47 -4
- package/dist/v2/react/hooks/useStepConfig.d.ts +2 -8
- package/dist/v2/react/hooks/useStepConfig.js +1 -1
- package/dist/v2/react/hooks/useWhopPaymentPolling.d.ts +30 -0
- package/dist/v2/react/hooks/useWhopPaymentPolling.js +61 -0
- package/dist/v2/react/index.d.ts +7 -0
- package/dist/v2/react/index.js +4 -0
- package/dist/v2/react/providers/ExpressPaymentMethodsProvider.d.ts +2 -1
- package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +3 -1
- package/dist/v2/react/providers/TagadaProvider.js +76 -7
- package/dist/v2/standalone/external-tracker.d.ts +52 -46
- package/dist/v2/standalone/external-tracker.js +205 -98
- package/dist/v2/standalone/index.d.ts +22 -0
- package/dist/v2/standalone/index.js +125 -0
- package/package.json +112 -112
- package/dist/react/utils/__tests__/urlUtils.test.d.ts +0 -1
- package/dist/react/utils/__tests__/urlUtils.test.js +0 -189
- package/dist/v2/core/__tests__/pathRemapping.test.d.ts +0 -11
- package/dist/v2/core/__tests__/pathRemapping.test.js +0 -776
|
@@ -4,18 +4,16 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
4
4
|
* usePixelTracking Hook & Provider
|
|
5
5
|
*
|
|
6
6
|
* SDK-level pixel tracking based on runtime stepConfig.pixels injected
|
|
7
|
-
* by the CRM.
|
|
8
|
-
*
|
|
9
|
-
* integrations.
|
|
7
|
+
* by the CRM. Uses core/pixelMapping for event mapping and gating,
|
|
8
|
+
* keeping browser-specific init/fire logic here.
|
|
10
9
|
*/
|
|
11
10
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react';
|
|
12
|
-
import {
|
|
11
|
+
import { resolvePixelEvents, } from '../../core/pixelMapping';
|
|
13
12
|
import { useStepConfig } from './useStepConfig';
|
|
14
13
|
const PixelTrackingContext = createContext(null);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
*/
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Duplicate guard (time-window based)
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
19
17
|
function createDuplicateGuard(windowMs) {
|
|
20
18
|
const lastEvents = new Map();
|
|
21
19
|
return (eventName, parameters) => {
|
|
@@ -29,480 +27,288 @@ function createDuplicateGuard(windowMs) {
|
|
|
29
27
|
return true;
|
|
30
28
|
}
|
|
31
29
|
catch {
|
|
32
|
-
// If hashing fails for any reason, just allow the event
|
|
33
30
|
return true;
|
|
34
31
|
}
|
|
35
32
|
};
|
|
36
33
|
}
|
|
37
34
|
const shouldTrackEvent = createDuplicateGuard(5000);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
*/
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Provider
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
42
38
|
export function PixelTrackingProvider({ children }) {
|
|
43
39
|
const { pixels } = useStepConfig();
|
|
44
40
|
const [pixelsInitialized, setPixelsInitialized] = useState(false);
|
|
45
41
|
const isMountedRef = useRef(true);
|
|
46
42
|
useEffect(() => {
|
|
47
43
|
isMountedRef.current = true;
|
|
48
|
-
return () => {
|
|
49
|
-
isMountedRef.current = false;
|
|
50
|
-
};
|
|
44
|
+
return () => { isMountedRef.current = false; };
|
|
51
45
|
}, []);
|
|
52
|
-
// Initialize
|
|
46
|
+
// ---- Initialize pixel scripts once ----
|
|
53
47
|
useEffect(() => {
|
|
54
48
|
if (!pixels || pixelsInitialized || !isMountedRef.current)
|
|
55
49
|
return;
|
|
56
50
|
try {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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) {
|
|
51
|
+
pixels.facebook?.forEach((px) => { if (px.enabled && px.pixelId)
|
|
52
|
+
initMetaPixel(px.pixelId); });
|
|
53
|
+
pixels.tiktok?.forEach((px) => { if (px.enabled && px.pixelId)
|
|
54
|
+
initTikTokPixel(px.pixelId); });
|
|
55
|
+
pixels.snapchat?.forEach((px) => { if (px.enabled && px.pixelId)
|
|
56
|
+
initSnapchatPixel(px.pixelId); });
|
|
57
|
+
pixels.pinterest?.forEach((px) => { if (px.enabled && px.pixelId)
|
|
58
|
+
initPinterestPixel(px.pixelId); });
|
|
59
|
+
pixels.gtm?.forEach((px) => { if (px.enabled && px.containerId)
|
|
60
|
+
initGTM(px.containerId); });
|
|
61
|
+
if (isMountedRef.current)
|
|
102
62
|
setPixelsInitialized(true);
|
|
103
|
-
}
|
|
104
63
|
}
|
|
105
64
|
catch (error) {
|
|
106
|
-
|
|
107
|
-
if (typeof console !== 'undefined') {
|
|
108
|
-
console.error('[SDK Pixels] Error during pixel initialization:', error);
|
|
109
|
-
}
|
|
65
|
+
console.error('[SDK Pixels] Initialization error:', error);
|
|
110
66
|
}
|
|
111
67
|
}, [pixels, pixelsInitialized]);
|
|
68
|
+
// ---- Track function ----
|
|
112
69
|
const track = useCallback((eventName, parameters = {}) => {
|
|
113
|
-
if (!pixels || !pixelsInitialized || !isMountedRef.current)
|
|
70
|
+
if (!pixels || !pixelsInitialized || !isMountedRef.current)
|
|
114
71
|
return;
|
|
115
|
-
|
|
116
|
-
// Duplicate guard
|
|
117
|
-
if (!shouldTrackEvent(eventName, parameters)) {
|
|
72
|
+
if (!shouldTrackEvent(eventName, parameters))
|
|
118
73
|
return;
|
|
119
|
-
}
|
|
120
74
|
try {
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
|
|
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
|
-
}
|
|
75
|
+
const events = resolvePixelEvents(pixels, eventName, parameters);
|
|
76
|
+
for (const { provider, mapped } of events) {
|
|
77
|
+
fire(provider, mapped.name, mapped.params);
|
|
181
78
|
}
|
|
182
79
|
}
|
|
183
80
|
catch (error) {
|
|
184
|
-
|
|
185
|
-
console.error('[SDK Pixels] Error tracking pixel event:', error);
|
|
186
|
-
}
|
|
81
|
+
console.error('[SDK Pixels] Tracking error:', error);
|
|
187
82
|
}
|
|
188
83
|
}, [pixels, pixelsInitialized]);
|
|
189
|
-
//
|
|
84
|
+
// ---- Auto page-view ----
|
|
190
85
|
useEffect(() => {
|
|
191
86
|
if (!pixelsInitialized || !isMountedRef.current)
|
|
192
87
|
return;
|
|
193
|
-
|
|
194
|
-
const pageViewTimeoutId = setTimeout(() => {
|
|
88
|
+
const id = setTimeout(() => {
|
|
195
89
|
if (isMountedRef.current) {
|
|
196
|
-
track('PageView', {
|
|
197
|
-
path: typeof window !== 'undefined' ? window.location.pathname : '',
|
|
198
|
-
});
|
|
90
|
+
track('PageView', { path: typeof window !== 'undefined' ? window.location.pathname : '' });
|
|
199
91
|
}
|
|
200
92
|
}, 0);
|
|
201
|
-
return () =>
|
|
202
|
-
if (pageViewTimeoutId) {
|
|
203
|
-
clearTimeout(pageViewTimeoutId);
|
|
204
|
-
}
|
|
205
|
-
};
|
|
93
|
+
return () => clearTimeout(id);
|
|
206
94
|
}, [pixelsInitialized, track]);
|
|
207
|
-
const value = useMemo(() => ({
|
|
208
|
-
track,
|
|
209
|
-
pixelsInitialized,
|
|
210
|
-
}), [track, pixelsInitialized]);
|
|
95
|
+
const value = useMemo(() => ({ track, pixelsInitialized }), [track, pixelsInitialized]);
|
|
211
96
|
return _jsx(PixelTrackingContext.Provider, { value: value, children: children });
|
|
212
97
|
}
|
|
213
|
-
/**
|
|
214
|
-
* Hook to access SDK pixel tracking.
|
|
215
|
-
* Must be used within TagadaProvider (which wraps PixelTrackingProvider).
|
|
216
|
-
*/
|
|
217
98
|
export function usePixelTracking() {
|
|
218
99
|
const context = useContext(PixelTrackingContext);
|
|
219
|
-
if (!context)
|
|
100
|
+
if (!context)
|
|
220
101
|
throw new Error('usePixelTracking must be used within a PixelTrackingProvider');
|
|
221
|
-
}
|
|
222
102
|
return context;
|
|
223
103
|
}
|
|
224
|
-
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Browser-specific: fire an event to the correct global pixel function
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
108
|
+
function fire(provider, name, params) {
|
|
225
109
|
if (typeof window === 'undefined')
|
|
226
110
|
return;
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if (
|
|
235
|
-
|
|
111
|
+
const w = window;
|
|
112
|
+
switch (provider) {
|
|
113
|
+
case 'facebook':
|
|
114
|
+
w.fbq?.('track', name, params);
|
|
115
|
+
break;
|
|
116
|
+
case 'tiktok':
|
|
117
|
+
// TikTok handles page views via ttq.page(), not ttq.track('Pageview')
|
|
118
|
+
if (name === 'Pageview') {
|
|
119
|
+
w.ttq?.page?.();
|
|
236
120
|
}
|
|
237
121
|
else {
|
|
238
|
-
|
|
122
|
+
w.ttq?.track?.(name, params);
|
|
239
123
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
124
|
+
break;
|
|
125
|
+
case 'snapchat':
|
|
126
|
+
w.snaptr?.('track', name, params);
|
|
127
|
+
break;
|
|
128
|
+
case 'pinterest':
|
|
129
|
+
// Pinterest handles page views via pintrk('page'), not pintrk('track', 'pagevisit')
|
|
130
|
+
if (name === 'pagevisit') {
|
|
131
|
+
w.pintrk?.('page');
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
w.pintrk?.('track', name, params);
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
case 'gtm':
|
|
138
|
+
fireGTM(name, params);
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function fireGTM(event, params) {
|
|
143
|
+
try {
|
|
144
|
+
const w = window;
|
|
145
|
+
if (w.gtag) {
|
|
146
|
+
w.gtag('event', event, params);
|
|
147
|
+
}
|
|
148
|
+
else if (w.dataLayer) {
|
|
149
|
+
w.dataLayer.push({ event, ...params });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.error('[SDK GTM] Error:', error);
|
|
257
154
|
}
|
|
258
155
|
}
|
|
259
|
-
|
|
260
|
-
|
|
156
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
157
|
+
// ===========================================================================
|
|
158
|
+
// Pixel initialization (browser-only)
|
|
159
|
+
// All pixel globals are accessed via `win` typed as `any` to avoid
|
|
160
|
+
// `declare global` augmentation issues across tsconfig scopes.
|
|
161
|
+
// ===========================================================================
|
|
162
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
163
|
+
const win = (typeof window !== 'undefined' ? window : undefined);
|
|
164
|
+
function initMetaPixel(pixelId) {
|
|
165
|
+
if (!win || win.fbq)
|
|
261
166
|
return;
|
|
262
|
-
const
|
|
263
|
-
|
|
167
|
+
const n = function (...args) {
|
|
168
|
+
if (n.callMethod)
|
|
169
|
+
n.callMethod(...args);
|
|
170
|
+
else
|
|
171
|
+
n.queue.push(args);
|
|
172
|
+
};
|
|
173
|
+
n.queue = [];
|
|
174
|
+
n.loaded = true;
|
|
175
|
+
n.version = '2.0';
|
|
176
|
+
win.fbq = n;
|
|
177
|
+
if (!win._fbq)
|
|
178
|
+
win._fbq = n;
|
|
179
|
+
const t = document.createElement('script');
|
|
180
|
+
t.async = true;
|
|
181
|
+
t.src = 'https://connect.facebook.net/en_US/fbevents.js';
|
|
182
|
+
const s = document.getElementsByTagName('script')[0];
|
|
183
|
+
s?.parentNode?.insertBefore(t, s);
|
|
184
|
+
win.fbq('init', pixelId);
|
|
264
185
|
}
|
|
265
186
|
function initTikTokPixel(pixelId) {
|
|
266
|
-
if (
|
|
267
|
-
return;
|
|
268
|
-
if (window.ttq)
|
|
187
|
+
if (!win)
|
|
269
188
|
return;
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
};
|
|
275
|
-
if (!ttq.queue) {
|
|
276
|
-
ttq.queue = [];
|
|
277
|
-
}
|
|
278
|
-
w.ttq = ttq;
|
|
189
|
+
// Initialize TikTok base code once (mirrors official TikTok snippet)
|
|
190
|
+
if (!win.ttq) {
|
|
191
|
+
win.TiktokAnalyticsObject = 'ttq';
|
|
192
|
+
const ttq = (win.ttq = win.ttq || []);
|
|
279
193
|
ttq.methods = [
|
|
280
|
-
'page',
|
|
281
|
-
'
|
|
282
|
-
'
|
|
283
|
-
'instances',
|
|
284
|
-
'debug',
|
|
285
|
-
'on',
|
|
286
|
-
'off',
|
|
287
|
-
'once',
|
|
288
|
-
'ready',
|
|
289
|
-
'alias',
|
|
290
|
-
'group',
|
|
291
|
-
'enableCookie',
|
|
292
|
-
'disableCookie',
|
|
194
|
+
'page', 'track', 'identify', 'instances', 'debug', 'on', 'off',
|
|
195
|
+
'once', 'ready', 'alias', 'group', 'enableCookie', 'disableCookie',
|
|
196
|
+
'holdConsent', 'revokeConsent', 'grantConsent',
|
|
293
197
|
];
|
|
294
|
-
ttq.setAndDefer = function (
|
|
295
|
-
|
|
296
|
-
target.queue.push([method, ...args]);
|
|
297
|
-
};
|
|
198
|
+
ttq.setAndDefer = function (t, e) {
|
|
199
|
+
t[e] = function (...args) { t.push([e, ...args]); };
|
|
298
200
|
};
|
|
299
201
|
for (const method of ttq.methods) {
|
|
300
202
|
ttq.setAndDefer(ttq, method);
|
|
301
203
|
}
|
|
302
|
-
ttq.
|
|
303
|
-
const
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const s = d.getElementsByTagName(t)[0];
|
|
309
|
-
s.parentNode.insertBefore(a, s);
|
|
204
|
+
ttq.instance = function (t) {
|
|
205
|
+
const e = ttq._i[t] || [];
|
|
206
|
+
for (const method of ttq.methods) {
|
|
207
|
+
ttq.setAndDefer(e, method);
|
|
208
|
+
}
|
|
209
|
+
return e;
|
|
310
210
|
};
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
211
|
+
ttq.load = function (e, n) {
|
|
212
|
+
const r = 'https://analytics.tiktok.com/i18n/pixel/events.js';
|
|
213
|
+
ttq._i = ttq._i || {};
|
|
214
|
+
ttq._i[e] = [];
|
|
215
|
+
ttq._i[e]._u = r;
|
|
216
|
+
ttq._t = ttq._t || {};
|
|
217
|
+
ttq._t[e] = +new Date();
|
|
218
|
+
ttq._o = ttq._o || {};
|
|
219
|
+
ttq._o[e] = n || {};
|
|
220
|
+
const s = document.createElement('script');
|
|
221
|
+
s.type = 'text/javascript';
|
|
222
|
+
s.async = true;
|
|
223
|
+
s.src = r + '?sdkid=' + e + '&lib=ttq';
|
|
224
|
+
const p = document.getElementsByTagName('script')[0];
|
|
225
|
+
p?.parentNode?.insertBefore(s, p);
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
// Skip if this specific pixel ID is already loaded
|
|
229
|
+
if (win.ttq?._i?.[pixelId])
|
|
320
230
|
return;
|
|
321
|
-
|
|
322
|
-
ttq
|
|
231
|
+
win.ttq.load(pixelId);
|
|
232
|
+
// Note: ttq.page() is NOT called here — the Provider's auto page-view
|
|
233
|
+
// effect fires track('PageView') which handles it. Calling both would
|
|
234
|
+
// double-count page views in TikTok Ads Manager.
|
|
323
235
|
}
|
|
324
236
|
function initSnapchatPixel(pixelId) {
|
|
325
|
-
if (
|
|
326
|
-
return;
|
|
327
|
-
if (window.snaptr)
|
|
237
|
+
if (!win || win.snaptr)
|
|
328
238
|
return;
|
|
329
|
-
|
|
330
|
-
if (
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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);
|
|
239
|
+
const a = function (...args) {
|
|
240
|
+
if (a.handleRequest)
|
|
241
|
+
a.handleRequest(...args);
|
|
242
|
+
else
|
|
243
|
+
a.queue.push(args);
|
|
244
|
+
};
|
|
245
|
+
a.queue = [];
|
|
246
|
+
win.snaptr = a;
|
|
247
|
+
const r = document.createElement('script');
|
|
248
|
+
r.async = true;
|
|
249
|
+
r.src = 'https://sc-static.net/scevent.min.js';
|
|
250
|
+
const u = document.getElementsByTagName('script')[0];
|
|
251
|
+
u?.parentNode?.insertBefore(r, u);
|
|
252
|
+
win.snaptr('init', pixelId);
|
|
351
253
|
}
|
|
352
|
-
function
|
|
353
|
-
if (
|
|
254
|
+
function initPinterestPixel(pixelId) {
|
|
255
|
+
if (!win || win.pintrk)
|
|
354
256
|
return;
|
|
355
|
-
const
|
|
356
|
-
|
|
257
|
+
const a = function (...args) { a.queue.push(args); };
|
|
258
|
+
a.queue = [];
|
|
259
|
+
win.pintrk = a;
|
|
260
|
+
const s = document.createElement('script');
|
|
261
|
+
s.async = true;
|
|
262
|
+
s.src = 'https://s.pinimg.com/ct/core.js';
|
|
263
|
+
const u = document.getElementsByTagName('script')[0];
|
|
264
|
+
u?.parentNode?.insertBefore(s, u);
|
|
265
|
+
win.pintrk('load', pixelId);
|
|
266
|
+
// Note: pintrk('page') is NOT called here — the Provider's auto page-view
|
|
267
|
+
// effect handles it via fire(). Calling both would double-count page views.
|
|
357
268
|
}
|
|
358
269
|
function initGTM(containerId) {
|
|
359
|
-
if (
|
|
270
|
+
if (!win || !containerId)
|
|
360
271
|
return;
|
|
361
|
-
|
|
272
|
+
const isGtmContainer = containerId.startsWith('GTM-');
|
|
273
|
+
const scriptUrlPart = isGtmContainer
|
|
274
|
+
? `googletagmanager.com/gtm.js?id=${containerId}`
|
|
275
|
+
: `googletagmanager.com/gtag/js?id=${containerId}`;
|
|
276
|
+
if (document.querySelector(`script[src*="${scriptUrlPart}"]`))
|
|
362
277
|
return;
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
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 : '';
|
|
278
|
+
win.dataLayer = win.dataLayer || [];
|
|
279
|
+
if (isGtmContainer) {
|
|
280
|
+
win.dataLayer.push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
|
|
281
|
+
const f = document.getElementsByTagName('script')[0];
|
|
282
|
+
const j = document.createElement('script');
|
|
381
283
|
j.async = true;
|
|
382
|
-
j.src = 'https://www.googletagmanager.com/gtm.js?id=' +
|
|
383
|
-
|
|
384
|
-
if (f && f.parentNode) {
|
|
284
|
+
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + containerId;
|
|
285
|
+
if (f?.parentNode)
|
|
385
286
|
f.parentNode.insertBefore(j, f);
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
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 = [];
|
|
287
|
+
else
|
|
288
|
+
(document.head || document.getElementsByTagName('head')[0])?.appendChild(j);
|
|
289
|
+
const noscript = document.createElement('noscript');
|
|
290
|
+
const iframe = document.createElement('iframe');
|
|
291
|
+
iframe.src = `https://www.googletagmanager.com/ns.html?id=${containerId}`;
|
|
292
|
+
iframe.height = '0';
|
|
293
|
+
iframe.width = '0';
|
|
294
|
+
iframe.style.display = 'none';
|
|
295
|
+
iframe.style.visibility = 'hidden';
|
|
296
|
+
noscript.appendChild(iframe);
|
|
297
|
+
(document.body || document.getElementsByTagName('body')[0])?.insertBefore(noscript, document.body?.firstChild ?? null);
|
|
420
298
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
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;
|
|
299
|
+
else {
|
|
300
|
+
if (!win.gtag) {
|
|
301
|
+
win.gtag = function (..._args) { win.dataLayer.push(arguments); };
|
|
480
302
|
}
|
|
303
|
+
win.gtag('js', new Date());
|
|
304
|
+
win.gtag('config', containerId);
|
|
305
|
+
const script = document.createElement('script');
|
|
306
|
+
script.async = true;
|
|
307
|
+
script.src = 'https://www.googletagmanager.com/gtag/js?id=' + containerId;
|
|
308
|
+
const firstScript = document.getElementsByTagName('script')[0];
|
|
309
|
+
if (firstScript?.parentNode)
|
|
310
|
+
firstScript.parentNode.insertBefore(script, firstScript);
|
|
311
|
+
else
|
|
312
|
+
(document.head || document.getElementsByTagName('head')[0])?.appendChild(script);
|
|
481
313
|
}
|
|
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
314
|
}
|