@tagadapay/plugin-sdk 3.0.9 → 3.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/external-tracker.js +3802 -195
- package/dist/external-tracker.min.js +25 -2
- package/dist/external-tracker.min.js.map +4 -4
- package/dist/react/types.d.ts +2 -0
- package/dist/v2/core/client.d.ts +4 -0
- package/dist/v2/core/client.js +314 -123
- package/dist/v2/core/config/environment.js +6 -0
- package/dist/v2/core/funnelClient.d.ts +18 -1
- package/dist/v2/core/funnelClient.js +90 -17
- package/dist/v2/core/resources/checkout.d.ts +44 -1
- package/dist/v2/core/resources/checkout.js +48 -1
- package/dist/v2/core/resources/funnel.d.ts +44 -4
- package/dist/v2/core/resources/offers.d.ts +26 -0
- package/dist/v2/core/resources/offers.js +37 -0
- package/dist/v2/core/types.d.ts +3 -1
- package/dist/v2/core/utils/authHandoff.d.ts +60 -0
- package/dist/v2/core/utils/authHandoff.js +154 -0
- package/dist/v2/core/utils/deviceInfo.d.ts +20 -3
- package/dist/v2/core/utils/deviceInfo.js +62 -94
- package/dist/v2/core/utils/previewMode.d.ts +4 -0
- package/dist/v2/core/utils/previewMode.js +4 -0
- package/dist/v2/react/components/DebugDrawer.js +68 -46
- package/dist/v2/react/hooks/useCheckoutQuery.d.ts +0 -1
- package/dist/v2/react/hooks/useCheckoutQuery.js +12 -4
- package/dist/v2/react/hooks/useFunnelLegacy.js +39 -11
- package/dist/v2/react/hooks/usePreviewOffer.d.ts +3 -3
- package/dist/v2/react/hooks/usePreviewOffer.js +20 -15
- package/dist/v2/react/hooks/useTranslation.js +12 -4
- package/dist/v2/standalone/index.d.ts +2 -1
- package/dist/v2/standalone/index.js +2 -1
- package/package.json +3 -1
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
export interface DeviceInfo {
|
|
2
2
|
userAgent: {
|
|
3
|
+
name: string;
|
|
3
4
|
browser: {
|
|
5
|
+
major: string;
|
|
4
6
|
name: string;
|
|
5
7
|
version: string;
|
|
8
|
+
type?: string;
|
|
6
9
|
};
|
|
7
10
|
os: {
|
|
8
11
|
name: string;
|
|
9
12
|
version: string;
|
|
10
13
|
};
|
|
11
14
|
device?: {
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
model?: string;
|
|
16
|
+
type?: string;
|
|
17
|
+
vendor?: string;
|
|
18
|
+
};
|
|
19
|
+
engine: {
|
|
20
|
+
name: string;
|
|
21
|
+
version: string;
|
|
22
|
+
};
|
|
23
|
+
cpu: {
|
|
24
|
+
architecture: string;
|
|
14
25
|
};
|
|
15
26
|
};
|
|
16
27
|
screenResolution: {
|
|
@@ -18,13 +29,19 @@ export interface DeviceInfo {
|
|
|
18
29
|
height: number;
|
|
19
30
|
};
|
|
20
31
|
timeZone: string;
|
|
32
|
+
flags?: {
|
|
33
|
+
isBot: boolean;
|
|
34
|
+
isChromeFamily: boolean;
|
|
35
|
+
isStandalonePWA: boolean;
|
|
36
|
+
isAppleSilicon: boolean;
|
|
37
|
+
};
|
|
21
38
|
}
|
|
22
39
|
/**
|
|
23
40
|
* Get browser locale
|
|
24
41
|
*/
|
|
25
42
|
export declare function getBrowserLocale(): string;
|
|
26
43
|
/**
|
|
27
|
-
* Collect all device information
|
|
44
|
+
* Collect all device information using UAParser
|
|
28
45
|
*/
|
|
29
46
|
export declare function collectDeviceInfo(): DeviceInfo;
|
|
30
47
|
/**
|
|
@@ -1,91 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*/
|
|
4
|
-
function getBrowserInfo() {
|
|
5
|
-
const userAgent = navigator.userAgent;
|
|
6
|
-
// Chrome
|
|
7
|
-
if (userAgent.includes('Chrome')) {
|
|
8
|
-
const match = /Chrome\/(\d+)/.exec(userAgent);
|
|
9
|
-
return { name: 'Chrome', version: match ? match[1] : 'unknown' };
|
|
10
|
-
}
|
|
11
|
-
// Firefox
|
|
12
|
-
if (userAgent.includes('Firefox')) {
|
|
13
|
-
const match = /Firefox\/(\d+)/.exec(userAgent);
|
|
14
|
-
return { name: 'Firefox', version: match ? match[1] : 'unknown' };
|
|
15
|
-
}
|
|
16
|
-
// Safari
|
|
17
|
-
if (userAgent.includes('Safari') && !userAgent.includes('Chrome')) {
|
|
18
|
-
const match = /Version\/(\d+)/.exec(userAgent);
|
|
19
|
-
return { name: 'Safari', version: match ? match[1] : 'unknown' };
|
|
20
|
-
}
|
|
21
|
-
// Edge
|
|
22
|
-
if (userAgent.includes('Edge')) {
|
|
23
|
-
const match = /Edge\/(\d+)/.exec(userAgent);
|
|
24
|
-
return { name: 'Edge', version: match ? match[1] : 'unknown' };
|
|
25
|
-
}
|
|
26
|
-
return { name: 'unknown', version: 'unknown' };
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Get basic OS information from user agent
|
|
30
|
-
*/
|
|
31
|
-
function getOSInfo() {
|
|
32
|
-
const userAgent = navigator.userAgent;
|
|
33
|
-
// Windows
|
|
34
|
-
if (userAgent.includes('Windows')) {
|
|
35
|
-
if (userAgent.includes('Windows NT 10.0'))
|
|
36
|
-
return { name: 'Windows', version: '10' };
|
|
37
|
-
if (userAgent.includes('Windows NT 6.3'))
|
|
38
|
-
return { name: 'Windows', version: '8.1' };
|
|
39
|
-
if (userAgent.includes('Windows NT 6.2'))
|
|
40
|
-
return { name: 'Windows', version: '8' };
|
|
41
|
-
if (userAgent.includes('Windows NT 6.1'))
|
|
42
|
-
return { name: 'Windows', version: '7' };
|
|
43
|
-
return { name: 'Windows', version: 'unknown' };
|
|
44
|
-
}
|
|
45
|
-
// macOS
|
|
46
|
-
if (userAgent.includes('Mac OS X')) {
|
|
47
|
-
const match = /Mac OS X (\d+[._]\d+)/.exec(userAgent);
|
|
48
|
-
return { name: 'macOS', version: match ? match[1].replace('_', '.') : 'unknown' };
|
|
49
|
-
}
|
|
50
|
-
// iOS
|
|
51
|
-
if (userAgent.includes('iPhone') || userAgent.includes('iPad')) {
|
|
52
|
-
const match = /OS (\d+[._]\d+)/.exec(userAgent);
|
|
53
|
-
return { name: 'iOS', version: match ? match[1].replace('_', '.') : 'unknown' };
|
|
54
|
-
}
|
|
55
|
-
// Android
|
|
56
|
-
if (userAgent.includes('Android')) {
|
|
57
|
-
const match = /Android (\d+[.\d]*)/.exec(userAgent);
|
|
58
|
-
return { name: 'Android', version: match ? match[1] : 'unknown' };
|
|
59
|
-
}
|
|
60
|
-
// Linux
|
|
61
|
-
if (userAgent.includes('Linux')) {
|
|
62
|
-
return { name: 'Linux', version: 'unknown' };
|
|
63
|
-
}
|
|
64
|
-
return { name: 'unknown', version: 'unknown' };
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Get device information
|
|
68
|
-
*/
|
|
69
|
-
function getDeviceInfo() {
|
|
70
|
-
const userAgent = navigator.userAgent;
|
|
71
|
-
// Mobile devices
|
|
72
|
-
if (userAgent.includes('iPhone')) {
|
|
73
|
-
return { type: 'mobile', model: 'iPhone' };
|
|
74
|
-
}
|
|
75
|
-
if (userAgent.includes('iPad')) {
|
|
76
|
-
return { type: 'tablet', model: 'iPad' };
|
|
77
|
-
}
|
|
78
|
-
if (userAgent.includes('Android')) {
|
|
79
|
-
if (userAgent.includes('Mobile')) {
|
|
80
|
-
return { type: 'mobile', model: 'Android' };
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
return { type: 'tablet', model: 'Android' };
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
// Desktop (no specific device info)
|
|
87
|
-
return undefined;
|
|
88
|
-
}
|
|
1
|
+
import { UAParser } from '@ua-parser-js/pro-enterprise';
|
|
2
|
+
import { isBot, isChromeFamily, isStandalonePWA, isAppleSilicon, } from '@ua-parser-js/pro-enterprise/helpers';
|
|
89
3
|
/**
|
|
90
4
|
* Get screen resolution
|
|
91
5
|
*/
|
|
@@ -120,28 +34,82 @@ export function getBrowserLocale() {
|
|
|
120
34
|
}
|
|
121
35
|
}
|
|
122
36
|
/**
|
|
123
|
-
* Collect all device information
|
|
37
|
+
* Collect all device information using UAParser
|
|
124
38
|
*/
|
|
125
39
|
export function collectDeviceInfo() {
|
|
126
40
|
if (typeof window === 'undefined') {
|
|
127
41
|
// Server-side fallback
|
|
128
42
|
return {
|
|
129
43
|
userAgent: {
|
|
130
|
-
|
|
131
|
-
|
|
44
|
+
name: '',
|
|
45
|
+
browser: { major: '', name: '', version: '' },
|
|
46
|
+
os: { name: '', version: '' },
|
|
47
|
+
device: undefined,
|
|
48
|
+
engine: { name: '', version: '' },
|
|
49
|
+
cpu: { architecture: '' },
|
|
132
50
|
},
|
|
133
51
|
screenResolution: { width: 0, height: 0 },
|
|
134
52
|
timeZone: 'UTC',
|
|
53
|
+
flags: {
|
|
54
|
+
isBot: false,
|
|
55
|
+
isChromeFamily: false,
|
|
56
|
+
isStandalonePWA: false,
|
|
57
|
+
isAppleSilicon: false,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const parser = new UAParser();
|
|
62
|
+
const result = parser.getResult();
|
|
63
|
+
// Enhanced detection using UAParser official helpers
|
|
64
|
+
let flags;
|
|
65
|
+
try {
|
|
66
|
+
flags = {
|
|
67
|
+
isBot: isBot(result),
|
|
68
|
+
isChromeFamily: isChromeFamily(result),
|
|
69
|
+
isStandalonePWA: isStandalonePWA(),
|
|
70
|
+
isAppleSilicon: isAppleSilicon(result),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.error('Failed to compute device flags:', error);
|
|
75
|
+
flags = {
|
|
76
|
+
isBot: false,
|
|
77
|
+
isChromeFamily: false,
|
|
78
|
+
isStandalonePWA: false,
|
|
79
|
+
isAppleSilicon: false,
|
|
135
80
|
};
|
|
136
81
|
}
|
|
137
82
|
return {
|
|
138
83
|
userAgent: {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
84
|
+
name: result.ua,
|
|
85
|
+
browser: {
|
|
86
|
+
major: result.browser.major || '',
|
|
87
|
+
name: result.browser.name || '',
|
|
88
|
+
version: result.browser.version || '',
|
|
89
|
+
type: result.browser.type,
|
|
90
|
+
},
|
|
91
|
+
os: {
|
|
92
|
+
name: result.os.name || '',
|
|
93
|
+
version: result.os.version || '',
|
|
94
|
+
},
|
|
95
|
+
device: result.device.model || result.device.type || result.device.vendor
|
|
96
|
+
? {
|
|
97
|
+
model: result.device.model,
|
|
98
|
+
type: result.device.type,
|
|
99
|
+
vendor: result.device.vendor,
|
|
100
|
+
}
|
|
101
|
+
: undefined,
|
|
102
|
+
engine: {
|
|
103
|
+
name: result.engine.name || '',
|
|
104
|
+
version: result.engine.version || '',
|
|
105
|
+
},
|
|
106
|
+
cpu: {
|
|
107
|
+
architecture: result.cpu.architecture || '',
|
|
108
|
+
},
|
|
142
109
|
},
|
|
143
110
|
screenResolution: getScreenResolution(),
|
|
144
111
|
timeZone: getTimeZone(),
|
|
112
|
+
flags,
|
|
145
113
|
};
|
|
146
114
|
}
|
|
147
115
|
/**
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
* - token: Authentication token (URL > localStorage)
|
|
14
14
|
* - funnelSessionId: Active funnel session (URL > cookie)
|
|
15
15
|
*
|
|
16
|
+
* ⚠️ Note: authCode is NOT handled here - it has highest priority and is handled
|
|
17
|
+
* separately in client.ts before all other initialization logic.
|
|
18
|
+
*
|
|
16
19
|
* Usage examples:
|
|
17
20
|
* - Force production API: ?tagadaClientEnv=production
|
|
18
21
|
* - Force development API: ?tagadaClientEnv=development
|
|
@@ -20,6 +23,7 @@
|
|
|
20
23
|
* - Custom API URL: ?tagadaClientBaseUrl=https://tagada.loclx.io
|
|
21
24
|
* - Combined: ?tagadaClientEnv=local&tagadaClientBaseUrl=https://tagada.loclx.io
|
|
22
25
|
* - Hard reset + production: ?forceReset=true&tagadaClientEnv=production
|
|
26
|
+
* - Cross-domain auth: ?authCode=ah_... (automatically handled, highest priority)
|
|
23
27
|
*/
|
|
24
28
|
/**
|
|
25
29
|
* SDK Override Parameters - centralized across all SDK functions
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
* - token: Authentication token (URL > localStorage)
|
|
14
14
|
* - funnelSessionId: Active funnel session (URL > cookie)
|
|
15
15
|
*
|
|
16
|
+
* ⚠️ Note: authCode is NOT handled here - it has highest priority and is handled
|
|
17
|
+
* separately in client.ts before all other initialization logic.
|
|
18
|
+
*
|
|
16
19
|
* Usage examples:
|
|
17
20
|
* - Force production API: ?tagadaClientEnv=production
|
|
18
21
|
* - Force development API: ?tagadaClientEnv=development
|
|
@@ -20,6 +23,7 @@
|
|
|
20
23
|
* - Custom API URL: ?tagadaClientBaseUrl=https://tagada.loclx.io
|
|
21
24
|
* - Combined: ?tagadaClientEnv=local&tagadaClientBaseUrl=https://tagada.loclx.io
|
|
22
25
|
* - Hard reset + production: ?forceReset=true&tagadaClientEnv=production
|
|
26
|
+
* - Cross-domain auth: ?authCode=ah_... (automatically handled, highest priority)
|
|
23
27
|
*/
|
|
24
28
|
import { clearClientToken, setClientToken, getClientToken } from './tokenStorage';
|
|
25
29
|
import { clearFunnelSessionCookie } from './sessionStorage';
|
|
@@ -79,6 +79,7 @@ export const DebugDrawer = ({ isOpen, onClose }) => {
|
|
|
79
79
|
const [activeTab, setActiveTab] = useState('overview');
|
|
80
80
|
const [runningScripts, setRunningScripts] = useState(new Set());
|
|
81
81
|
const [scriptResults, setScriptResults] = useState({});
|
|
82
|
+
const [expandedScriptCategories, setExpandedScriptCategories] = useState({});
|
|
82
83
|
// Handler to jump to a specific step using direct_navigation
|
|
83
84
|
const handleJumpToStep = async (stepId, stepName) => {
|
|
84
85
|
// Try to get sessionId from debug data or context
|
|
@@ -187,8 +188,9 @@ export const DebugDrawer = ({ isOpen, onClose }) => {
|
|
|
187
188
|
const script = context.debugScripts?.find((s) => s.id === scriptId);
|
|
188
189
|
if (!script)
|
|
189
190
|
return;
|
|
191
|
+
// Clear previous script results so only the current script shows a status
|
|
192
|
+
setScriptResults({});
|
|
190
193
|
setRunningScripts((prev) => new Set(prev).add(scriptId));
|
|
191
|
-
setScriptResults((prev) => ({ ...prev, [scriptId]: undefined }));
|
|
192
194
|
try {
|
|
193
195
|
await script.run(context);
|
|
194
196
|
setScriptResults((prev) => ({
|
|
@@ -733,51 +735,71 @@ export const DebugDrawer = ({ isOpen, onClose }) => {
|
|
|
733
735
|
acc[category].push(script);
|
|
734
736
|
return acc;
|
|
735
737
|
}, {});
|
|
736
|
-
return Object.entries(grouped).map(([category, scripts]) =>
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
738
|
+
return Object.entries(grouped).map(([category, scripts]) => {
|
|
739
|
+
const isExpanded = expandedScriptCategories[category] ?? false;
|
|
740
|
+
const toggleCategory = () => {
|
|
741
|
+
setExpandedScriptCategories((prev) => ({
|
|
742
|
+
...prev,
|
|
743
|
+
[category]: !(prev[category] ?? false),
|
|
744
|
+
}));
|
|
745
|
+
};
|
|
746
|
+
return (_jsxs("div", { children: [_jsx("button", { type: "button", onClick: toggleCategory, style: {
|
|
747
|
+
display: 'flex',
|
|
748
|
+
alignItems: 'center',
|
|
749
|
+
justifyContent: 'space-between',
|
|
750
|
+
width: '100%',
|
|
751
|
+
background: 'none',
|
|
752
|
+
border: 'none',
|
|
753
|
+
padding: '6px 0',
|
|
754
|
+
cursor: 'pointer',
|
|
755
|
+
}, children: _jsxs("div", { style: {
|
|
756
|
+
display: 'flex',
|
|
757
|
+
alignItems: 'center',
|
|
758
|
+
gap: '6px',
|
|
759
|
+
fontSize: '11px',
|
|
760
|
+
fontWeight: 'bold',
|
|
761
|
+
textTransform: 'uppercase',
|
|
762
|
+
letterSpacing: '0.5px',
|
|
763
|
+
color: '#9ca3af',
|
|
764
|
+
}, children: [_jsx("span", { style: { fontSize: '10px' }, children: isExpanded ? '▼' : '▶' }), _jsx("span", { children: category }), _jsxs("span", { style: { fontSize: '10px', color: '#6b7280' }, children: ["(", scripts.length, ")"] })] }) }), isExpanded && (_jsx("div", { style: { display: 'grid', gap: '8px', marginTop: '4px' }, children: scripts.map((script) => {
|
|
765
|
+
const isRunning = runningScripts.has(script.id);
|
|
766
|
+
const result = scriptResults[script.id];
|
|
767
|
+
return (_jsxs("div", { style: {
|
|
768
|
+
border: '1px solid #374151',
|
|
769
|
+
borderRadius: '6px',
|
|
770
|
+
padding: '10px 12px',
|
|
771
|
+
backgroundColor: '#111827',
|
|
772
|
+
}, children: [_jsxs("div", { style: {
|
|
773
|
+
display: 'flex',
|
|
774
|
+
justifyContent: 'space-between',
|
|
775
|
+
alignItems: 'flex-start',
|
|
776
|
+
gap: '12px',
|
|
777
|
+
}, children: [_jsxs("div", { style: { flex: 1 }, children: [_jsx("div", { style: {
|
|
778
|
+
color: '#f9fafb',
|
|
779
|
+
fontWeight: 'bold',
|
|
780
|
+
fontSize: '12px',
|
|
781
|
+
marginBottom: '4px',
|
|
782
|
+
}, children: script.name }), script.description && (_jsx("div", { style: { fontSize: '11px', color: '#9ca3af' }, children: script.description }))] }), _jsx("button", { onClick: () => handleRunScript(script.id), disabled: isRunning, style: {
|
|
783
|
+
backgroundColor: isRunning ? '#374151' : '#3b82f6',
|
|
784
|
+
color: '#fff',
|
|
785
|
+
border: 'none',
|
|
786
|
+
borderRadius: '4px',
|
|
787
|
+
padding: '6px 12px',
|
|
788
|
+
fontSize: '11px',
|
|
789
|
+
fontWeight: 'bold',
|
|
790
|
+
cursor: isRunning ? 'not-allowed' : 'pointer',
|
|
791
|
+
transition: 'background-color 0.2s',
|
|
792
|
+
minWidth: '60px',
|
|
793
|
+
}, children: isRunning ? '⏳' : '▶ Run' })] }), result && (_jsxs("div", { style: {
|
|
794
|
+
marginTop: '8px',
|
|
795
|
+
padding: '6px 8px',
|
|
796
|
+
borderRadius: '4px',
|
|
797
|
+
fontSize: '10px',
|
|
798
|
+
backgroundColor: result.success ? '#065f46' : '#7f1d1d',
|
|
799
|
+
color: result.success ? '#6ee7b7' : '#fca5a5',
|
|
800
|
+
}, children: [result.success ? '✅' : '❌', " ", result.message] }))] }, script.id));
|
|
801
|
+
}) }))] }, category));
|
|
802
|
+
});
|
|
781
803
|
})() })) : (_jsx("p", { style: { color: '#6b7280' }, children: "No debug scripts available" }))] })), activeTab === 'raw' && (_jsxs("div", { children: [_jsx("h3", { style: { margin: '0 0 16px 0', color: '#60a5fa' }, children: "Raw Context Data" }), _jsx("div", { style: { fontSize: '12px' }, children: _jsx(TreeView, { data: context, name: "tagadaContext", maxLevel: 4 }) })] }))] })] })] }));
|
|
782
804
|
};
|
|
783
805
|
export default DebugDrawer;
|
|
@@ -87,9 +87,9 @@ export function useCheckoutQuery(options = {}) {
|
|
|
87
87
|
await refetch();
|
|
88
88
|
}
|
|
89
89
|
}, [refetch, checkoutToken]);
|
|
90
|
-
// Initialize checkout mutation
|
|
90
|
+
// Initialize checkout mutation (async mode for fast response)
|
|
91
91
|
const initMutation = useMutation({
|
|
92
|
-
mutationFn: (params) => {
|
|
92
|
+
mutationFn: async (params) => {
|
|
93
93
|
const requestBody = {
|
|
94
94
|
...params,
|
|
95
95
|
storeId: params.storeId || storeId,
|
|
@@ -101,7 +101,12 @@ export function useCheckoutQuery(options = {}) {
|
|
|
101
101
|
currency: params.customer?.currency ?? currency.code,
|
|
102
102
|
},
|
|
103
103
|
};
|
|
104
|
-
|
|
104
|
+
// Use async mode for fast response (~50ms vs 2-5s)
|
|
105
|
+
const asyncResponse = await checkoutResource.initCheckoutAsync(requestBody);
|
|
106
|
+
return {
|
|
107
|
+
checkoutToken: asyncResponse.checkoutToken,
|
|
108
|
+
checkoutSession: {}, // Will be populated when getCheckout is called
|
|
109
|
+
};
|
|
105
110
|
},
|
|
106
111
|
onSuccess: (response) => {
|
|
107
112
|
// Update URL with checkout token
|
|
@@ -257,9 +262,12 @@ export function useCheckoutQuery(options = {}) {
|
|
|
257
262
|
await waitForSession();
|
|
258
263
|
const result = await initMutation.mutateAsync(params);
|
|
259
264
|
// Update internal token state so the query can fetch the checkout data
|
|
265
|
+
// The query will automatically refetch when token changes, and getCheckout()
|
|
266
|
+
// will automatically wait for async completion (via SDK skipAsyncWait=false)
|
|
260
267
|
setInternalToken(result.checkoutToken);
|
|
268
|
+
// Return immediately with token
|
|
269
|
+
// checkoutSession will be populated by the query once background processing completes
|
|
261
270
|
return {
|
|
262
|
-
checkoutUrl: result.checkoutUrl,
|
|
263
271
|
checkoutSession: checkout?.checkoutSession ?? {},
|
|
264
272
|
checkoutToken: result.checkoutToken,
|
|
265
273
|
};
|
|
@@ -339,12 +339,31 @@ export function useFunnel(options = {}) {
|
|
|
339
339
|
onSuccess: (result) => {
|
|
340
340
|
if (!context)
|
|
341
341
|
return;
|
|
342
|
+
// 🔥 Fire-and-forget mode: Just acknowledge, no navigation
|
|
343
|
+
if (result.queued) {
|
|
344
|
+
// Update session ID if changed
|
|
345
|
+
if (result.sessionId && result.sessionId !== context.sessionId) {
|
|
346
|
+
const newContext = {
|
|
347
|
+
...context,
|
|
348
|
+
sessionId: result.sessionId,
|
|
349
|
+
};
|
|
350
|
+
const enrichedContext = enrichContext(newContext);
|
|
351
|
+
setContext(enrichedContext);
|
|
352
|
+
document.cookie = `funnelSessionId=${result.sessionId}; path=/; max-age=86400; SameSite=Lax`;
|
|
353
|
+
}
|
|
354
|
+
return; // Early return for fire-and-forget
|
|
355
|
+
}
|
|
342
356
|
// 🔄 Handle session recovery (if backend created a new session)
|
|
343
357
|
let recoveredSessionId;
|
|
344
358
|
if (result.sessionId && result.sessionId !== context.sessionId) {
|
|
345
359
|
console.warn(`🔄 Funnel: Session recovered! Old: ${context.sessionId}, New: ${result.sessionId}`);
|
|
346
360
|
recoveredSessionId = result.sessionId;
|
|
347
361
|
}
|
|
362
|
+
// Validate required fields for normal navigation
|
|
363
|
+
if (!result.stepId) {
|
|
364
|
+
console.warn('Funnel: Navigation result missing stepId');
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
348
367
|
// Update local context
|
|
349
368
|
const newContext = {
|
|
350
369
|
...context,
|
|
@@ -366,13 +385,13 @@ export function useFunnel(options = {}) {
|
|
|
366
385
|
document.cookie = `funnelSessionId=${recoveredSessionId}; path=/; max-age=86400; SameSite=Lax`;
|
|
367
386
|
console.log(`🍪 Funnel: Updated cookie with recovered session ID: ${recoveredSessionId}`);
|
|
368
387
|
}
|
|
369
|
-
// Create typed navigation result
|
|
388
|
+
// Create typed navigation result (only if we have URL)
|
|
370
389
|
const navigationResult = {
|
|
371
390
|
stepId: result.stepId,
|
|
372
|
-
action: {
|
|
391
|
+
action: result.url ? {
|
|
373
392
|
type: 'redirect', // Default action type
|
|
374
393
|
url: result.url
|
|
375
|
-
},
|
|
394
|
+
} : undefined,
|
|
376
395
|
context: enrichedContext,
|
|
377
396
|
tracking: result.tracking
|
|
378
397
|
};
|
|
@@ -384,18 +403,27 @@ export function useFunnel(options = {}) {
|
|
|
384
403
|
shouldPerformDefaultNavigation = false;
|
|
385
404
|
}
|
|
386
405
|
}
|
|
387
|
-
// Perform default navigation if not overridden
|
|
388
|
-
if (shouldPerformDefaultNavigation && navigationResult.action
|
|
389
|
-
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
406
|
+
// Perform default navigation if not overridden and we have an action with URL
|
|
407
|
+
if (shouldPerformDefaultNavigation && navigationResult.action?.url) {
|
|
408
|
+
const action = navigationResult.action; // Type narrowing
|
|
409
|
+
const actionUrl = action.url; // Extract URL for type narrowing
|
|
410
|
+
if (actionUrl) {
|
|
411
|
+
// Add URL parameters for cross-domain session continuity
|
|
412
|
+
const urlWithParams = addSessionParams(actionUrl, enrichedContext.sessionId, effectiveFunnelId || options.funnelId);
|
|
413
|
+
const updatedAction = {
|
|
414
|
+
type: action.type || 'redirect', // Ensure type is defined
|
|
415
|
+
url: urlWithParams,
|
|
416
|
+
data: action.data,
|
|
417
|
+
};
|
|
418
|
+
performNavigation(updatedAction);
|
|
419
|
+
}
|
|
393
420
|
}
|
|
394
421
|
// Skip background refreshes if we are navigating away (full page reload)
|
|
395
422
|
// This prevents "lingering" requests from the old page context
|
|
423
|
+
const action = navigationResult.action;
|
|
396
424
|
const isFullNavigation = shouldPerformDefaultNavigation &&
|
|
397
|
-
|
|
398
|
-
(
|
|
425
|
+
action?.url &&
|
|
426
|
+
(action.type === 'redirect' || action.type === 'replace');
|
|
399
427
|
if (!isFullNavigation) {
|
|
400
428
|
// Fetch debug data if in debug mode
|
|
401
429
|
if (debugMode) {
|
|
@@ -76,9 +76,9 @@ export interface UsePreviewOfferResult {
|
|
|
76
76
|
checkoutUrl: string;
|
|
77
77
|
}>;
|
|
78
78
|
toCheckout: (mainOrderId?: string) => Promise<{
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
checkoutToken: string;
|
|
80
|
+
customerId: string;
|
|
81
|
+
status: 'processing';
|
|
82
82
|
}>;
|
|
83
83
|
}
|
|
84
84
|
export declare function usePreviewOffer(options: UsePreviewOfferOptions): UsePreviewOfferResult;
|