@tagadapay/plugin-sdk 3.1.5 → 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 +1225 -558
- package/dist/external-tracker.min.js +2 -2
- package/dist/external-tracker.min.js.map +4 -4
- package/dist/react/hooks/useApplePay.js +25 -36
- package/dist/react/hooks/usePaymentPolling.d.ts +9 -3
- package/dist/react/providers/TagadaProvider.js +5 -5
- package/dist/react/utils/money.d.ts +4 -3
- package/dist/react/utils/money.js +39 -6
- package/dist/react/utils/trackingUtils.js +1 -0
- 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/client.js +34 -2
- package/dist/v2/core/config/environment.js +9 -2
- package/dist/v2/core/funnelClient.d.ts +180 -2
- package/dist/v2/core/funnelClient.js +289 -6
- package/dist/v2/core/resources/apiClient.js +1 -1
- package/dist/v2/core/resources/checkout.d.ts +68 -0
- package/dist/v2/core/resources/funnel.d.ts +25 -0
- package/dist/v2/core/resources/payments.d.ts +70 -3
- package/dist/v2/core/resources/payments.js +72 -7
- 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 +68 -5
- package/dist/v2/core/utils/previewMode.d.ts +7 -0
- package/dist/v2/core/utils/previewMode.js +72 -14
- package/dist/v2/core/utils/previewModeIndicator.d.ts +19 -0
- package/dist/v2/core/utils/previewModeIndicator.js +414 -0
- package/dist/v2/core/utils/tokenStorage.d.ts +4 -0
- package/dist/v2/core/utils/tokenStorage.js +15 -1
- package/dist/v2/index.d.ts +9 -3
- package/dist/v2/index.js +8 -3
- package/dist/v2/react/components/ApplePayButton.d.ts +22 -123
- package/dist/v2/react/components/ApplePayButton.js +247 -317
- package/dist/v2/react/components/FunnelScriptInjector.d.ts +3 -1
- package/dist/v2/react/components/FunnelScriptInjector.js +255 -162
- package/dist/v2/react/components/GooglePayButton.d.ts +2 -0
- package/dist/v2/react/components/GooglePayButton.js +80 -64
- package/dist/v2/react/components/PreviewModeIndicator.d.ts +46 -0
- package/dist/v2/react/components/PreviewModeIndicator.js +113 -0
- package/dist/v2/react/hooks/useApplePayCheckout.d.ts +16 -0
- package/dist/v2/react/hooks/useApplePayCheckout.js +193 -0
- package/dist/v2/react/hooks/useFunnel.d.ts +48 -6
- package/dist/v2/react/hooks/useFunnel.js +25 -5
- 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 +15 -3
- package/dist/v2/react/hooks/usePaymentPolling.js +31 -9
- package/dist/v2/react/hooks/usePaymentQuery.d.ts +34 -2
- package/dist/v2/react/hooks/usePaymentQuery.js +731 -7
- package/dist/v2/react/hooks/usePaymentRetrieve.d.ts +26 -0
- package/dist/v2/react/hooks/usePaymentRetrieve.js +175 -0
- 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 +64 -0
- package/dist/v2/react/hooks/useStepConfig.js +53 -0
- package/dist/v2/react/index.d.ts +15 -5
- package/dist/v2/react/index.js +8 -2
- package/dist/v2/react/providers/ExpressPaymentMethodsProvider.d.ts +1 -0
- package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +41 -13
- package/dist/v2/react/providers/TagadaProvider.js +24 -23
- package/dist/v2/standalone/external-tracker.d.ts +2 -0
- package/dist/v2/standalone/external-tracker.js +6 -3
- package/package.json +112 -112
- package/dist/v2/react/hooks/useApplePay.d.ts +0 -16
- package/dist/v2/react/hooks/useApplePay.js +0 -247
|
@@ -6,7 +6,9 @@ interface FunnelScriptInjectorProps extends FunnelState {
|
|
|
6
6
|
*
|
|
7
7
|
* This component:
|
|
8
8
|
* - Sets up Tagada on the window object
|
|
9
|
-
* - Injects
|
|
9
|
+
* - Injects scripts from stepConfig.scripts (NEW: from HTML injection, supports A/B variants)
|
|
10
|
+
* - Falls back to context.script (LEGACY: from funnel context)
|
|
11
|
+
* - Handles script positions: head-start, head-end, body-start, body-end
|
|
10
12
|
* - Prevents duplicate script injection (handles React StrictMode)
|
|
11
13
|
* - Cleans up scripts when context changes or component unmounts
|
|
12
14
|
*/
|
|
@@ -1,167 +1,169 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
3
|
+
import { getAssignedStepConfig } from '../../core';
|
|
3
4
|
/**
|
|
4
5
|
* FunnelScriptInjector - Handles injection of funnel scripts into the page.
|
|
5
6
|
*
|
|
6
7
|
* This component:
|
|
7
8
|
* - Sets up Tagada on the window object
|
|
8
|
-
* - Injects
|
|
9
|
+
* - Injects scripts from stepConfig.scripts (NEW: from HTML injection, supports A/B variants)
|
|
10
|
+
* - Falls back to context.script (LEGACY: from funnel context)
|
|
11
|
+
* - Handles script positions: head-start, head-end, body-start, body-end
|
|
9
12
|
* - Prevents duplicate script injection (handles React StrictMode)
|
|
10
13
|
* - Cleans up scripts when context changes or component unmounts
|
|
11
14
|
*/
|
|
12
15
|
export function FunnelScriptInjector({ context, isInitialized }) {
|
|
13
|
-
|
|
16
|
+
// Track last injected scripts to prevent duplicate execution
|
|
14
17
|
const lastInjectedScriptRef = useRef(null);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
const lastInjectedStepConfigScriptsRef = useRef(null);
|
|
19
|
+
// Get stepConfig scripts from HTML injection or local config
|
|
20
|
+
// Re-compute when initialized (local config loads async, so we need to re-check)
|
|
21
|
+
const stepConfigScripts = useMemo(() => {
|
|
22
|
+
const stepConfig = getAssignedStepConfig();
|
|
23
|
+
const scripts = stepConfig?.scripts?.filter(s => s.enabled) || [];
|
|
24
|
+
if (scripts.length > 0) {
|
|
25
|
+
console.log('📜 [SDK] Found stepConfig scripts:', scripts.length, scripts.map(s => s.name));
|
|
19
26
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
window.Tagada.isInitialized = isInitialized;
|
|
32
|
-
// Update ressources
|
|
27
|
+
return scripts;
|
|
28
|
+
}, [isInitialized]); // Re-compute when funnel initializes (local config should be loaded by then)
|
|
29
|
+
// Set up Tagada on window object - must be available before any scripts run
|
|
30
|
+
// Memoized to prevent unnecessary recreations across re-renders
|
|
31
|
+
const setupTagada = useCallback(() => {
|
|
32
|
+
if (typeof window === 'undefined')
|
|
33
|
+
return;
|
|
34
|
+
// @ts-expect-error - Adding utilities to window
|
|
35
|
+
if (window.Tagada) {
|
|
36
|
+
// Update properties if Tagada already exists
|
|
37
|
+
if (context?.currentStepId) {
|
|
33
38
|
// @ts-expect-error - Updating window property
|
|
34
|
-
window.Tagada.
|
|
35
|
-
return; // Utils already exist, just update properties
|
|
39
|
+
window.Tagada.pageType = context.currentStepId;
|
|
36
40
|
}
|
|
37
|
-
// @ts-expect-error -
|
|
38
|
-
window.Tagada =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
// @ts-expect-error - Updating window property
|
|
42
|
+
window.Tagada.isInitialized = isInitialized;
|
|
43
|
+
// @ts-expect-error - Updating window property
|
|
44
|
+
window.Tagada.ressources = context?.resources || null;
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// @ts-expect-error - Adding utilities to window
|
|
48
|
+
window.Tagada = {
|
|
49
|
+
// Wait for DOM to be ready
|
|
50
|
+
ready: (callback) => {
|
|
51
|
+
if (document.readyState === 'loading') {
|
|
52
|
+
document.addEventListener('DOMContentLoaded', callback);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
callback();
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
// Wait for window to be fully loaded AND funnel to be initialized
|
|
59
|
+
loaded: (callback) => {
|
|
60
|
+
const checkBothConditions = () => {
|
|
61
|
+
const pageLoaded = document.readyState === 'complete';
|
|
62
|
+
// @ts-expect-error - Accessing window property
|
|
63
|
+
const funnelInitialized = window.Tagada?.isInitialized === true;
|
|
64
|
+
if (pageLoaded && funnelInitialized) {
|
|
45
65
|
callback();
|
|
66
|
+
return true;
|
|
46
67
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
};
|
|
60
|
-
// Check immediately
|
|
61
|
-
if (checkBothConditions()) {
|
|
62
|
-
return;
|
|
68
|
+
return false;
|
|
69
|
+
};
|
|
70
|
+
if (checkBothConditions()) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
let loadListener = null;
|
|
74
|
+
let initCheckInterval = null;
|
|
75
|
+
let hasCalled = false;
|
|
76
|
+
const cleanup = () => {
|
|
77
|
+
if (loadListener) {
|
|
78
|
+
window.removeEventListener('load', loadListener);
|
|
79
|
+
loadListener = null;
|
|
63
80
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
initCheckInterval = setInterval(() => {
|
|
88
|
-
if (checkBothConditions() && !hasCalled) {
|
|
89
|
-
hasCalled = true;
|
|
90
|
-
cleanup();
|
|
91
|
-
}
|
|
92
|
-
}, 100);
|
|
93
|
-
// Timeout fallback (10 seconds max wait)
|
|
94
|
-
setTimeout(() => {
|
|
95
|
-
if (!hasCalled) {
|
|
96
|
-
hasCalled = true;
|
|
97
|
-
cleanup();
|
|
98
|
-
// Call anyway if page is loaded (graceful degradation)
|
|
99
|
-
if (document.readyState === 'complete') {
|
|
100
|
-
callback();
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}, 10000);
|
|
104
|
-
},
|
|
105
|
-
// Execute with delay
|
|
106
|
-
delay: (callback, ms = 1000) => {
|
|
107
|
-
setTimeout(callback, ms);
|
|
108
|
-
},
|
|
109
|
-
// Retry until condition is met
|
|
110
|
-
retry: (condition, callback, maxAttempts = 10, interval = 500) => {
|
|
111
|
-
let attempts = 0;
|
|
112
|
-
const check = () => {
|
|
113
|
-
attempts++;
|
|
114
|
-
if (condition() || attempts >= maxAttempts) {
|
|
81
|
+
if (initCheckInterval) {
|
|
82
|
+
clearInterval(initCheckInterval);
|
|
83
|
+
initCheckInterval = null;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
loadListener = () => {
|
|
87
|
+
if (checkBothConditions() && !hasCalled) {
|
|
88
|
+
hasCalled = true;
|
|
89
|
+
cleanup();
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
window.addEventListener('load', loadListener);
|
|
93
|
+
initCheckInterval = setInterval(() => {
|
|
94
|
+
if (checkBothConditions() && !hasCalled) {
|
|
95
|
+
hasCalled = true;
|
|
96
|
+
cleanup();
|
|
97
|
+
}
|
|
98
|
+
}, 100);
|
|
99
|
+
setTimeout(() => {
|
|
100
|
+
if (!hasCalled) {
|
|
101
|
+
hasCalled = true;
|
|
102
|
+
cleanup();
|
|
103
|
+
if (document.readyState === 'complete') {
|
|
115
104
|
callback();
|
|
116
105
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
106
|
+
}
|
|
107
|
+
}, 10000);
|
|
108
|
+
},
|
|
109
|
+
delay: (callback, ms = 1000) => {
|
|
110
|
+
setTimeout(callback, ms);
|
|
111
|
+
},
|
|
112
|
+
retry: (condition, callback, maxAttempts = 10, interval = 500) => {
|
|
113
|
+
let attempts = 0;
|
|
114
|
+
const check = () => {
|
|
115
|
+
attempts++;
|
|
116
|
+
if (condition() || attempts >= maxAttempts) {
|
|
117
|
+
callback();
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
setTimeout(check, interval);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
check();
|
|
124
|
+
},
|
|
125
|
+
waitForElement: (selector, callback, timeout = 10000) => {
|
|
126
|
+
const element = document.querySelector(selector);
|
|
127
|
+
if (element) {
|
|
128
|
+
callback(element);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const observer = new MutationObserver(() => {
|
|
125
132
|
const element = document.querySelector(selector);
|
|
126
133
|
if (element) {
|
|
127
|
-
callback(element);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
const observer = new MutationObserver(() => {
|
|
131
|
-
const element = document.querySelector(selector);
|
|
132
|
-
if (element) {
|
|
133
|
-
observer.disconnect();
|
|
134
|
-
callback(element);
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
observer.observe(document.body, {
|
|
138
|
-
childList: true,
|
|
139
|
-
subtree: true,
|
|
140
|
-
});
|
|
141
|
-
// Timeout fallback
|
|
142
|
-
setTimeout(() => {
|
|
143
134
|
observer.disconnect();
|
|
144
|
-
|
|
145
|
-
},
|
|
146
|
-
// Page type helper (current step ID)
|
|
147
|
-
pageType: context?.currentStepId || null,
|
|
148
|
-
// Funnel initialization status
|
|
149
|
-
isInitialized: isInitialized,
|
|
150
|
-
// Expose resources directly (convenience access)
|
|
151
|
-
ressources: context?.resources || null,
|
|
152
|
-
// Expose funnel context data
|
|
153
|
-
funnel: context
|
|
154
|
-
? {
|
|
155
|
-
sessionId: context.sessionId,
|
|
156
|
-
funnelId: context.funnelId,
|
|
157
|
-
currentStepId: context.currentStepId,
|
|
158
|
-
previousStepId: context.previousStepId,
|
|
159
|
-
ressources: context.resources,
|
|
135
|
+
callback(element);
|
|
160
136
|
}
|
|
161
|
-
|
|
162
|
-
|
|
137
|
+
});
|
|
138
|
+
observer.observe(document.body, {
|
|
139
|
+
childList: true,
|
|
140
|
+
subtree: true,
|
|
141
|
+
});
|
|
142
|
+
setTimeout(() => {
|
|
143
|
+
observer.disconnect();
|
|
144
|
+
}, timeout);
|
|
145
|
+
},
|
|
146
|
+
pageType: context?.currentStepId || null,
|
|
147
|
+
isInitialized: isInitialized,
|
|
148
|
+
ressources: context?.resources || null,
|
|
149
|
+
funnel: context
|
|
150
|
+
? {
|
|
151
|
+
sessionId: context.sessionId,
|
|
152
|
+
funnelId: context.funnelId,
|
|
153
|
+
currentStepId: context.currentStepId,
|
|
154
|
+
previousStepId: context.previousStepId,
|
|
155
|
+
ressources: context.resources,
|
|
156
|
+
}
|
|
157
|
+
: null,
|
|
158
|
+
stepConfig: getAssignedStepConfig() || null,
|
|
163
159
|
};
|
|
164
|
-
|
|
160
|
+
}, [context, isInitialized]);
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
// Only run in browser environment
|
|
163
|
+
if (typeof document === 'undefined') {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// Set up Tagada utilities before injecting legacy script
|
|
165
167
|
setupTagada();
|
|
166
168
|
const scriptContent = context?.script;
|
|
167
169
|
const scriptId = 'tagada-funnel-script';
|
|
@@ -197,27 +199,27 @@ export function FunnelScriptInjector({ context, isInitialized }) {
|
|
|
197
199
|
existingScript.remove();
|
|
198
200
|
}
|
|
199
201
|
// Wrap script content with error handling and context checks
|
|
200
|
-
const wrappedScript = `
|
|
201
|
-
(function() {
|
|
202
|
-
try {
|
|
203
|
-
// Check if we have basic DOM access
|
|
204
|
-
if (typeof document === 'undefined') {
|
|
205
|
-
console.error('[TagadaPay] Document not available');
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Check if we have Tagada
|
|
210
|
-
if (!window.Tagada) {
|
|
211
|
-
console.error('[TagadaPay] Tagada not available');
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Execute the original script
|
|
216
|
-
${scriptBody}
|
|
217
|
-
} catch (error) {
|
|
218
|
-
console.error('[TagadaPay] Script execution error:', error);
|
|
219
|
-
}
|
|
220
|
-
})();
|
|
202
|
+
const wrappedScript = `
|
|
203
|
+
(function() {
|
|
204
|
+
try {
|
|
205
|
+
// Check if we have basic DOM access
|
|
206
|
+
if (typeof document === 'undefined') {
|
|
207
|
+
console.error('[TagadaPay] Document not available');
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Check if we have Tagada
|
|
212
|
+
if (!window.Tagada) {
|
|
213
|
+
console.error('[TagadaPay] Tagada not available');
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Execute the original script
|
|
218
|
+
${scriptBody}
|
|
219
|
+
} catch (error) {
|
|
220
|
+
console.error('[TagadaPay] Script execution error:', error);
|
|
221
|
+
}
|
|
222
|
+
})();
|
|
221
223
|
`;
|
|
222
224
|
// Create and inject new script element
|
|
223
225
|
const scriptElement = document.createElement('script');
|
|
@@ -236,7 +238,98 @@ export function FunnelScriptInjector({ context, isInitialized }) {
|
|
|
236
238
|
// This prevents React StrictMode from re-injecting the same script on the second run
|
|
237
239
|
// The ref will be cleared when script content actually changes (next effect run)
|
|
238
240
|
};
|
|
239
|
-
}, [context?.script, context?.currentStepId, isInitialized]);
|
|
241
|
+
}, [context?.script, context?.currentStepId, isInitialized, setupTagada]);
|
|
242
|
+
// Effect for NEW stepConfig.scripts (from HTML injection, supports A/B variants)
|
|
243
|
+
useEffect(() => {
|
|
244
|
+
if (typeof document === 'undefined')
|
|
245
|
+
return;
|
|
246
|
+
// IMPORTANT: Set up Tagada BEFORE injecting any scripts
|
|
247
|
+
// This ensures Tagada.ready() is always available when scripts run
|
|
248
|
+
setupTagada();
|
|
249
|
+
if (stepConfigScripts.length === 0)
|
|
250
|
+
return;
|
|
251
|
+
// Create a hash of current scripts to detect changes
|
|
252
|
+
const scriptsHash = JSON.stringify(stepConfigScripts.map(s => ({ name: s.name, content: s.content, position: s.position })));
|
|
253
|
+
// Check if scripts are actually in the DOM (handles React StrictMode cleanup)
|
|
254
|
+
const existingScripts = document.querySelectorAll('[data-tagada-stepconfig-script]');
|
|
255
|
+
const scriptsExistInDom = existingScripts.length > 0;
|
|
256
|
+
// Skip ONLY if: same hash AND scripts actually exist in DOM
|
|
257
|
+
// This handles React StrictMode where cleanup removes scripts but ref persists
|
|
258
|
+
if (lastInjectedStepConfigScriptsRef.current === scriptsHash && scriptsExistInDom) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
// Remove any existing stepConfig scripts before re-injecting
|
|
262
|
+
existingScripts.forEach(el => el.remove());
|
|
263
|
+
// Inject each enabled script at its correct position
|
|
264
|
+
stepConfigScripts.forEach((script, index) => {
|
|
265
|
+
const position = script.position || 'head-end';
|
|
266
|
+
const scriptId = `tagada-stepconfig-script-${index}`;
|
|
267
|
+
// Extract script content (remove <script> tags if present)
|
|
268
|
+
let scriptBody = script.content.trim();
|
|
269
|
+
const scriptTagMatch = scriptBody.match(/^<script[^>]*>([\s\S]*)<\/script>$/i);
|
|
270
|
+
if (scriptTagMatch) {
|
|
271
|
+
scriptBody = scriptTagMatch[1].trim();
|
|
272
|
+
}
|
|
273
|
+
if (!scriptBody)
|
|
274
|
+
return;
|
|
275
|
+
// Wrap script content with error handling
|
|
276
|
+
const wrappedScript = `
|
|
277
|
+
(function() {
|
|
278
|
+
try {
|
|
279
|
+
// Script: ${script.name}
|
|
280
|
+
${scriptBody}
|
|
281
|
+
} catch (error) {
|
|
282
|
+
console.error('[TagadaPay] StepConfig script "${script.name}" error:', error);
|
|
283
|
+
}
|
|
284
|
+
})();
|
|
285
|
+
`;
|
|
286
|
+
// Create script element
|
|
287
|
+
const scriptElement = document.createElement('script');
|
|
288
|
+
scriptElement.id = scriptId;
|
|
289
|
+
scriptElement.setAttribute('data-tagada-stepconfig-script', 'true');
|
|
290
|
+
scriptElement.setAttribute('data-script-name', script.name);
|
|
291
|
+
scriptElement.textContent = wrappedScript;
|
|
292
|
+
// Inject at the correct position
|
|
293
|
+
switch (position) {
|
|
294
|
+
case 'head-start':
|
|
295
|
+
// Insert at the beginning of <head>
|
|
296
|
+
if (document.head.firstChild) {
|
|
297
|
+
document.head.insertBefore(scriptElement, document.head.firstChild);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
document.head.appendChild(scriptElement);
|
|
301
|
+
}
|
|
302
|
+
break;
|
|
303
|
+
case 'head-end':
|
|
304
|
+
// Insert at the end of <head>
|
|
305
|
+
document.head.appendChild(scriptElement);
|
|
306
|
+
break;
|
|
307
|
+
case 'body-start':
|
|
308
|
+
// Insert at the beginning of <body>
|
|
309
|
+
if (document.body.firstChild) {
|
|
310
|
+
document.body.insertBefore(scriptElement, document.body.firstChild);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
document.body.appendChild(scriptElement);
|
|
314
|
+
}
|
|
315
|
+
break;
|
|
316
|
+
case 'body-end':
|
|
317
|
+
default:
|
|
318
|
+
// Insert at the end of <body>
|
|
319
|
+
document.body.appendChild(scriptElement);
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
// Track injected scripts to prevent re-injection
|
|
324
|
+
lastInjectedStepConfigScriptsRef.current = scriptsHash;
|
|
325
|
+
// Cleanup: remove scripts on unmount
|
|
326
|
+
// Note: We keep the ref intact but check DOM existence on re-mount
|
|
327
|
+
// This handles both StrictMode (re-inject if cleanup removed them) and
|
|
328
|
+
// real unmounts (scripts properly cleaned up)
|
|
329
|
+
return () => {
|
|
330
|
+
document.querySelectorAll('[data-tagada-stepconfig-script]').forEach(el => el.remove());
|
|
331
|
+
};
|
|
332
|
+
}, [stepConfigScripts, setupTagada]);
|
|
240
333
|
// This component doesn't render anything
|
|
241
334
|
return null;
|
|
242
335
|
}
|
|
@@ -14,6 +14,8 @@ export interface GooglePayButtonProps {
|
|
|
14
14
|
size?: 'sm' | 'md' | 'lg';
|
|
15
15
|
buttonColor?: 'default' | 'black' | 'white';
|
|
16
16
|
buttonType?: 'buy' | 'plain' | 'donate' | 'pay';
|
|
17
|
+
/** Override shipping requirement. If undefined, auto-detects based on shippingMethods. */
|
|
18
|
+
requiresShipping?: boolean;
|
|
17
19
|
}
|
|
18
20
|
export declare const GooglePayButton: React.FC<GooglePayButtonProps>;
|
|
19
21
|
export default GooglePayButton;
|