@tagadapay/plugin-sdk 2.7.20 → 2.7.21

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.
@@ -77,6 +77,54 @@ export const DebugDrawer = ({ isOpen, onClose }) => {
77
77
  const context = useTagadaContext();
78
78
  const pluginConfig = usePluginConfig();
79
79
  const [activeTab, setActiveTab] = useState('overview');
80
+ // Handler to jump to a specific step using direct_navigation
81
+ const handleJumpToStep = async (stepId, stepName) => {
82
+ // Try to get sessionId from debug data or context
83
+ const sessionId = context.debugFunnel.data?.session?.sessionId || context.session?.sessionId;
84
+ if (!sessionId) {
85
+ alert('No active funnel session found');
86
+ console.error('Debug data:', context.debugFunnel.data);
87
+ console.error('Context:', context);
88
+ return;
89
+ }
90
+ console.log(`🎯 [DebugDrawer] Jumping to step ${stepId} (${stepName}) in session ${sessionId}`);
91
+ try {
92
+ // Use direct_navigation event type to jump to any step
93
+ const response = await context.apiService.fetch('/api/v1/funnel/navigate', {
94
+ method: 'POST',
95
+ body: {
96
+ sessionId: sessionId,
97
+ event: {
98
+ type: 'direct_navigation',
99
+ data: {
100
+ targetStepId: stepId,
101
+ },
102
+ timestamp: new Date().toISOString(),
103
+ },
104
+ contextUpdates: {
105
+ metadata: {
106
+ debugJump: true,
107
+ debugJumpFrom: typeof window !== 'undefined' ? window.location.href : undefined,
108
+ },
109
+ },
110
+ currentUrl: typeof window !== 'undefined' ? window.location.href : undefined,
111
+ },
112
+ });
113
+ console.log('🎯 [DebugDrawer] Jump response:', response);
114
+ if (response.success && response.result?.url) {
115
+ // Navigate to the step URL
116
+ console.log(`🎯 [DebugDrawer] Navigating to: ${response.result.url}`);
117
+ window.location.href = response.result.url;
118
+ }
119
+ else {
120
+ alert(`Failed to jump to ${stepName}: ${response.error || 'Unknown error'}`);
121
+ }
122
+ }
123
+ catch (error) {
124
+ console.error('Failed to jump to step:', error);
125
+ alert(`Failed to jump to ${stepName}: ${error instanceof Error ? error.message : 'Unknown error'}`);
126
+ }
127
+ };
80
128
  useEffect(() => {
81
129
  const handleEscape = (e) => {
82
130
  if (e.key === 'Escape' && isOpen) {
@@ -95,13 +143,32 @@ export const DebugDrawer = ({ isOpen, onClose }) => {
95
143
  { id: 'session', label: 'Session' },
96
144
  { id: 'auth', label: 'Auth' },
97
145
  ];
146
+ // Add funnel tab if funnel is active
147
+ const funnelTab = context.debugFunnel.isActive ? [{ id: 'funnel', label: 'Funnel' }] : [];
148
+ // Debug: Log comprehensive debug drawer state
149
+ if (isOpen) {
150
+ console.group('🐛 [DebugDrawer V2] Comprehensive State Check');
151
+ console.log('1️⃣ Debug Mode:', context.debugMode);
152
+ console.log('2️⃣ Funnel Debug State:', {
153
+ isActive: context.debugFunnel.isActive,
154
+ hasData: !!context.debugFunnel.data,
155
+ hasError: !!context.debugFunnel.error,
156
+ isLoading: context.debugFunnel.isLoading,
157
+ lastUpdated: context.debugFunnel.lastUpdated,
158
+ });
159
+ console.log('3️⃣ Funnel Data (if any):', context.debugFunnel.data);
160
+ console.log('4️⃣ Funnel Error (if any):', context.debugFunnel.error);
161
+ console.log('5️⃣ Update Function Available:', typeof context.updateFunnelDebugData);
162
+ console.log('6️⃣ Will show Funnel tab:', funnelTab.length > 0);
163
+ console.groupEnd();
164
+ }
98
165
  // Add checkout tab if checkout is active
99
166
  const checkoutTab = context.debugCheckout.isActive ? [{ id: 'checkout', label: 'Checkout' }] : [];
100
167
  // Add items tab if checkout has summary data
101
168
  const itemsTab = context.debugCheckout.isActive && context.debugCheckout.data?.checkout?.summary
102
169
  ? [{ id: 'items', label: 'Items' }]
103
170
  : [];
104
- const tabs = [...baseTabs, ...checkoutTab, ...itemsTab, { id: 'raw', label: 'Raw Data' }];
171
+ const tabs = [...baseTabs, ...funnelTab, ...checkoutTab, ...itemsTab, { id: 'raw', label: 'Raw Data' }];
105
172
  return (_jsxs(_Fragment, { children: [_jsx("div", { style: {
106
173
  position: 'fixed',
107
174
  top: 0,
@@ -115,33 +182,33 @@ export const DebugDrawer = ({ isOpen, onClose }) => {
115
182
  top: 0,
116
183
  right: 0,
117
184
  bottom: 0,
118
- width: '50vw',
119
- minWidth: '500px',
120
- maxWidth: '800px',
185
+ width: '35vw',
186
+ minWidth: '400px',
187
+ maxWidth: '550px',
121
188
  backgroundColor: '#1f2937',
122
189
  color: '#f9fafb',
123
190
  boxShadow: '-4px 0 24px rgba(0, 0, 0, 0.3)',
124
191
  zIndex: 999999,
125
192
  display: 'flex',
126
193
  flexDirection: 'column',
127
- fontSize: '14px',
194
+ fontSize: '13px',
128
195
  fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',
129
196
  }, children: [_jsxs("div", { style: {
130
- padding: '16px',
197
+ padding: '12px 14px',
131
198
  borderBottom: '1px solid #374151',
132
199
  display: 'flex',
133
200
  justifyContent: 'space-between',
134
201
  alignItems: 'center',
135
202
  backgroundColor: '#111827',
136
- }, children: [_jsxs("div", { children: [_jsx("h2", { style: { margin: 0, fontSize: '18px', fontWeight: 'bold' }, children: "\uD83D\uDC1B TagadaPay SDK Debug" }), _jsx("p", { style: { margin: '4px 0 0 0', fontSize: '12px', color: '#9ca3af' }, children: "Real-time SDK state and data inspection" })] }), _jsx("button", { onClick: onClose, style: {
203
+ }, children: [_jsxs("div", { children: [_jsx("h2", { style: { margin: 0, fontSize: '16px', fontWeight: 'bold' }, children: "\uD83D\uDC1B SDK Debug" }), _jsx("p", { style: { margin: '2px 0 0 0', fontSize: '11px', color: '#9ca3af' }, children: "Real-time state inspection" })] }), _jsx("button", { onClick: onClose, style: {
137
204
  background: 'none',
138
205
  border: 'none',
139
206
  color: '#9ca3af',
140
207
  cursor: 'pointer',
141
- fontSize: '24px',
142
- padding: '4px',
208
+ fontSize: '22px',
209
+ padding: '2px',
143
210
  }, children: "\u00D7" })] }), _jsx("div", { style: {
144
- padding: '0 16px',
211
+ padding: '0 12px',
145
212
  borderBottom: '1px solid #374151',
146
213
  backgroundColor: '#111827',
147
214
  }, children: _jsx("div", { style: { display: 'flex', gap: '0' }, children: tabs.map((tab) => (_jsx("button", { onClick: () => setActiveTab(tab.id), style: {
@@ -149,15 +216,15 @@ export const DebugDrawer = ({ isOpen, onClose }) => {
149
216
  border: 'none',
150
217
  color: activeTab === tab.id ? '#60a5fa' : '#9ca3af',
151
218
  cursor: 'pointer',
152
- padding: '12px 16px',
153
- fontSize: '14px',
219
+ padding: '10px 12px',
220
+ fontSize: '12px',
154
221
  borderBottom: activeTab === tab.id ? '2px solid #60a5fa' : '2px solid transparent',
155
222
  }, children: tab.label }, tab.id))) }) }), _jsxs("div", { style: {
156
223
  flex: 1,
157
- padding: '16px',
224
+ padding: '12px',
158
225
  overflow: 'auto',
159
226
  backgroundColor: '#1f2937',
160
- }, children: [activeTab === 'overview' && (_jsxs("div", { children: [_jsx("h3", { style: { margin: '0 0 16px 0', color: '#60a5fa' }, children: "SDK Overview" }), _jsxs("div", { style: { display: 'grid', gap: '12px' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Initialized:" }), _jsx("span", { style: { color: context.isInitialized ? '#10b981' : '#ef4444' }, children: context.isInitialized ? '✅ Yes' : '❌ No' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Loading:" }), _jsx("span", { style: { color: context.isLoading ? '#f59e0b' : '#10b981' }, children: context.isLoading ? '⏳ Yes' : '✅ No' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Environment:" }), _jsx("span", { style: { color: '#60a5fa' }, children: context.environment.apiConfig.baseUrl.includes('dev') ? 'Development' : 'Production' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "API Base URL:" }), _jsx("span", { style: { color: '#10b981' }, children: context.environment.apiConfig.baseUrl })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Store ID:" }), _jsx("span", { style: { color: '#60a5fa' }, children: context.store?.id || 'Not set' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Customer ID:" }), _jsx("span", { style: { color: '#60a5fa' }, children: context.customer?.id || 'Not set' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Authenticated:" }), _jsx("span", { style: { color: context.auth.isAuthenticated ? '#10b981' : '#ef4444' }, children: context.auth.isAuthenticated ? '✅ Yes' : '❌ No' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Currency:" }), _jsxs("span", { style: { color: '#f59e0b' }, children: [context.currency.code, " (", context.currency.symbol, ")"] })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Locale:" }), _jsx("span", { style: { color: '#8b5cf6' }, children: context.locale.locale })] })] })] })), activeTab === 'config' && (_jsxs("div", { children: [_jsx("h3", { style: { margin: '0 0 16px 0', color: '#60a5fa' }, children: "Plugin Configuration" }), _jsxs("div", { style: { marginBottom: '24px' }, children: [_jsx("h4", { style: { margin: '0 0 12px 0', color: '#9ca3af', fontSize: '14px' }, children: "Configuration Summary" }), _jsxs("div", { style: { display: 'grid', gap: '8px', fontSize: '13px' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Store ID:" }), _jsx("span", { style: { color: '#60a5fa' }, children: pluginConfig.storeId || 'Not set' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Account ID:" }), _jsx("span", { style: { color: '#60a5fa' }, children: pluginConfig.accountId || 'Not set' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Base Path:" }), _jsx("span", { style: { color: '#10b981' }, children: pluginConfig.basePath || '/' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Config Name:" }), _jsx("span", { style: { color: '#f59e0b' }, children: pluginConfig.config?.configName || 'default' })] }), pluginConfig.config?.branding?.primaryColor && (_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Primary Color:" }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' }, children: [_jsx("div", { style: {
227
+ }, children: [activeTab === 'overview' && (_jsxs("div", { children: [_jsx("h3", { style: { margin: '0 0 12px 0', color: '#60a5fa', fontSize: '14px' }, children: "SDK Overview" }), _jsxs("div", { style: { display: 'grid', gap: '10px', fontSize: '12px' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Initialized:" }), _jsx("span", { style: { color: context.isInitialized ? '#10b981' : '#ef4444' }, children: context.isInitialized ? '✅ Yes' : '❌ No' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Loading:" }), _jsx("span", { style: { color: context.isLoading ? '#f59e0b' : '#10b981' }, children: context.isLoading ? '⏳ Yes' : '✅ No' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Environment:" }), _jsx("span", { style: { color: '#60a5fa' }, children: context.environment.apiConfig.baseUrl.includes('dev') ? 'Development' : 'Production' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "API Base URL:" }), _jsx("span", { style: { color: '#10b981' }, children: context.environment.apiConfig.baseUrl })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Store ID:" }), _jsx("span", { style: { color: '#60a5fa' }, children: context.store?.id || 'Not set' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Customer ID:" }), _jsx("span", { style: { color: '#60a5fa' }, children: context.customer?.id || 'Not set' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Authenticated:" }), _jsx("span", { style: { color: context.auth.isAuthenticated ? '#10b981' : '#ef4444' }, children: context.auth.isAuthenticated ? '✅ Yes' : '❌ No' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Currency:" }), _jsxs("span", { style: { color: '#f59e0b' }, children: [context.currency.code, " (", context.currency.symbol, ")"] })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Locale:" }), _jsx("span", { style: { color: '#8b5cf6' }, children: context.locale.locale })] })] })] })), activeTab === 'config' && (_jsxs("div", { children: [_jsx("h3", { style: { margin: '0 0 12px 0', color: '#60a5fa', fontSize: '14px' }, children: "Plugin Configuration" }), _jsxs("div", { style: { marginBottom: '16px' }, children: [_jsx("h4", { style: { margin: '0 0 10px 0', color: '#9ca3af', fontSize: '13px' }, children: "Configuration Summary" }), _jsxs("div", { style: { display: 'grid', gap: '8px', fontSize: '13px' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Store ID:" }), _jsx("span", { style: { color: '#60a5fa' }, children: pluginConfig.storeId || 'Not set' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Account ID:" }), _jsx("span", { style: { color: '#60a5fa' }, children: pluginConfig.accountId || 'Not set' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Base Path:" }), _jsx("span", { style: { color: '#10b981' }, children: pluginConfig.basePath || '/' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Config Name:" }), _jsx("span", { style: { color: '#f59e0b' }, children: pluginConfig.config?.configName || 'default' })] }), pluginConfig.config?.branding?.primaryColor && (_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Primary Color:" }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' }, children: [_jsx("div", { style: {
161
228
  width: '16px',
162
229
  height: '16px',
163
230
  backgroundColor: pluginConfig.config.branding.primaryColor,
@@ -368,7 +435,154 @@ export const DebugDrawer = ({ isOpen, onClose }) => {
368
435
  catch {
369
436
  return String(Math.abs(Number(adjustment.amount)));
370
437
  }
371
- })() })] }, index))) })] }))] })) : (_jsx("p", { style: { color: '#6b7280' }, children: "No checkout summary data available" }))] })), activeTab === 'checkout' && (_jsxs("div", { children: [_jsx("h3", { style: { margin: '0 0 16px 0', color: '#60a5fa' }, children: "Checkout Debug" }), context.debugCheckout.isActive ? (_jsxs("div", { children: [_jsxs("div", { style: { marginBottom: '20px' }, children: [_jsx("h4", { style: { margin: '0 0 12px 0', color: '#60a5fa' }, children: "Status" }), _jsxs("div", { style: { display: 'grid', gap: '8px' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Hook Active:" }), _jsx("span", { style: { color: '#10b981' }, children: "\u2705 Yes" })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Loading:" }), _jsx("span", { style: { color: context.debugCheckout.isLoading ? '#f59e0b' : '#10b981' }, children: context.debugCheckout.isLoading ? '⏳ Yes' : '✅ No' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Has Error:" }), _jsx("span", { style: { color: context.debugCheckout.error ? '#ef4444' : '#10b981' }, children: context.debugCheckout.error ? '❌ Yes' : '✅ No' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Last Updated:" }), _jsx("span", { style: { color: '#9ca3af', fontSize: '12px' }, children: context.debugCheckout.lastUpdated?.toLocaleTimeString() || 'Never' })] })] })] }), context.debugCheckout.error && (_jsxs("div", { style: { marginBottom: '20px' }, children: [_jsx("h4", { style: { margin: '0 0 12px 0', color: '#ef4444' }, children: "Error Details" }), _jsxs("div", { style: {
438
+ })() })] }, index))) })] }))] })) : (_jsx("p", { style: { color: '#6b7280' }, children: "No checkout summary data available" }))] })), activeTab === 'funnel' && (_jsxs("div", { children: [_jsx("h3", { style: { margin: '0 0 12px 0', color: '#60a5fa', fontSize: '14px' }, children: "\uD83D\uDE80 Funnel Debug" }), context.debugFunnel.isActive ? (_jsxs("div", { children: [_jsxs("div", { style: {
439
+ display: 'flex',
440
+ gap: '10px',
441
+ padding: '6px 10px',
442
+ backgroundColor: '#111827',
443
+ borderRadius: '4px',
444
+ marginBottom: '12px',
445
+ fontSize: '10px',
446
+ alignItems: 'center',
447
+ }, children: [_jsx("span", { style: { color: '#10b981' }, children: "\u2705 Active" }), _jsx("span", { style: { color: '#4b5563' }, children: "\u2022" }), _jsx("span", { style: { color: context.debugFunnel.isLoading ? '#f59e0b' : '#6b7280' }, children: context.debugFunnel.isLoading ? '⏳ Loading' : '✓ Ready' }), context.debugFunnel.error && (_jsxs(_Fragment, { children: [_jsx("span", { style: { color: '#4b5563' }, children: "\u2022" }), _jsx("span", { style: { color: '#ef4444' }, children: "\u274C Error" })] })), _jsx("span", { style: { color: '#4b5563', marginLeft: 'auto' }, children: context.debugFunnel.lastUpdated?.toLocaleTimeString() || 'Never' })] }), context.debugFunnel.error && (_jsxs("div", { style: { marginBottom: '24px' }, children: [_jsx("h4", { style: { margin: '0 0 12px 0', color: '#ef4444' }, children: "Error Details" }), _jsxs("div", { style: {
448
+ backgroundColor: '#372c2c',
449
+ padding: '12px',
450
+ borderRadius: '4px',
451
+ border: '1px solid #ef4444',
452
+ }, children: [_jsxs("div", { style: { color: '#ef4444', fontWeight: 'bold', marginBottom: '8px' }, children: [context.debugFunnel.error.name, ": ", context.debugFunnel.error.message] }), context.debugFunnel.error.stack && (_jsx("pre", { style: {
453
+ color: '#9ca3af',
454
+ fontSize: '11px',
455
+ margin: 0,
456
+ whiteSpace: 'pre-wrap',
457
+ }, children: context.debugFunnel.error.stack }))] })] })), context.debugFunnel.data?.funnel && (_jsxs("div", { style: {
458
+ padding: '8px 10px',
459
+ backgroundColor: '#111827',
460
+ borderRadius: '4px',
461
+ marginBottom: '12px',
462
+ fontSize: '11px',
463
+ }, children: [_jsxs("div", { style: { marginBottom: '10px' }, children: [_jsxs("div", { style: {
464
+ color: '#60a5fa',
465
+ fontSize: '11px',
466
+ fontWeight: 'bold',
467
+ marginBottom: '6px',
468
+ }, children: ["\uD83D\uDCCA ", context.debugFunnel.data.funnel.name] }), _jsxs("div", { style: {
469
+ display: 'grid',
470
+ gridTemplateColumns: '1fr 1fr',
471
+ gap: '6px',
472
+ fontSize: '11px',
473
+ }, children: [_jsxs("div", { children: [_jsx("span", { style: { color: '#6b7280' }, children: "ID: " }), _jsx("span", { style: { color: '#f59e0b', fontFamily: 'monospace', fontSize: '10px' }, children: context.debugFunnel.data.funnel.id })] }), _jsxs("div", { style: { textAlign: 'right' }, children: [_jsx("span", { style: { color: '#6b7280' }, children: "Steps: " }), _jsx("span", { style: { color: '#60a5fa', fontWeight: 'bold' }, children: context.debugFunnel.data.funnel.steps?.length || 0 })] })] })] }), context.debugFunnel.data?.session && (_jsxs("div", { style: {
474
+ paddingTop: '10px',
475
+ borderTop: '1px solid #374151',
476
+ }, children: [_jsx("div", { style: {
477
+ color: '#60a5fa',
478
+ fontSize: '11px',
479
+ fontWeight: 'bold',
480
+ marginBottom: '6px',
481
+ }, children: "\uD83C\uDFAF Session" }), _jsxs("div", { style: { display: 'grid', gap: '4px', fontSize: '11px' }, children: [context.debugFunnel.data.session.sessionId && (_jsxs("div", { style: { marginBottom: '6px' }, children: [_jsx("span", { style: { color: '#6b7280' }, children: "ID: " }), _jsx("span", { style: {
482
+ color: '#f59e0b',
483
+ fontFamily: 'monospace',
484
+ fontSize: '10px',
485
+ }, children: context.debugFunnel.data.session.sessionId })] })), _jsxs("div", { style: {
486
+ display: 'flex',
487
+ justifyContent: 'space-between',
488
+ alignItems: 'center',
489
+ }, children: [_jsx("span", { style: { color: '#6b7280' }, children: "Current:" }), _jsx("span", { style: {
490
+ color: '#10b981',
491
+ fontWeight: 'bold',
492
+ fontFamily: 'monospace',
493
+ fontSize: '10px',
494
+ backgroundColor: '#065f46',
495
+ padding: '2px 6px',
496
+ borderRadius: '3px',
497
+ }, children: context.debugFunnel.data.session.currentStepId })] }), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '6px' }, children: [_jsxs("div", { children: [_jsx("span", { style: { color: '#6b7280' }, children: "Furthest: " }), _jsx("span", { style: { color: '#60a5fa', fontSize: '10px' }, children: context.debugFunnel.data.session.furthestStepId })] }), _jsxs("div", { style: { textAlign: 'right' }, children: [_jsx("span", { style: { color: '#6b7280' }, children: "Previous: " }), _jsx("span", { style: { color: '#9ca3af', fontSize: '10px' }, children: context.debugFunnel.data.session.previousStepId || 'None' })] })] })] })] }))] })), context.debugFunnel.data?.funnel?.steps && (_jsxs("div", { style: { marginBottom: '16px' }, children: [_jsxs("h4", { style: { margin: '0 0 8px 0', color: '#60a5fa', fontSize: '13px' }, children: ["\uD83D\uDCCB Steps (", context.debugFunnel.data.funnel.steps.length, ")"] }), _jsx("div", { style: { display: 'grid', gap: '8px' }, children: context.debugFunnel.data.funnel.steps.map((step, index) => {
498
+ const isCurrent = step.id === context.debugFunnel.data?.session?.currentStepId;
499
+ const isVisited = context.debugFunnel.data?.session?.visitedSteps?.includes(step.id);
500
+ const isEntry = step.id === context.debugFunnel.data?.funnel?.entryStepId;
501
+ return (_jsxs("div", { style: {
502
+ border: isCurrent ? '2px solid #10b981' : '1px solid #374151',
503
+ borderRadius: '6px',
504
+ padding: '8px 10px',
505
+ backgroundColor: isCurrent ? '#065f46' : '#111827',
506
+ }, children: [_jsxs("div", { style: {
507
+ display: 'flex',
508
+ alignItems: 'center',
509
+ gap: '6px',
510
+ marginBottom: '4px',
511
+ }, children: [_jsxs("span", { style: {
512
+ color: isCurrent ? '#fff' : '#9ca3af',
513
+ fontSize: '10px',
514
+ minWidth: '18px',
515
+ }, children: [index + 1, "."] }), _jsx("span", { style: {
516
+ color: isCurrent ? '#fff' : '#f9fafb',
517
+ fontSize: '12px',
518
+ fontWeight: 'bold',
519
+ flex: 1,
520
+ }, children: step.name }), isCurrent && (_jsx("span", { style: {
521
+ fontSize: '9px',
522
+ backgroundColor: '#10b981',
523
+ color: '#000',
524
+ padding: '2px 5px',
525
+ borderRadius: '3px',
526
+ fontWeight: 'bold',
527
+ }, children: "CURRENT" })), isEntry && (_jsx("span", { style: {
528
+ fontSize: '9px',
529
+ backgroundColor: '#8b5cf6',
530
+ color: '#fff',
531
+ padding: '2px 5px',
532
+ borderRadius: '3px',
533
+ }, children: "ENTRY" })), isVisited && !isCurrent && (_jsx("span", { style: { fontSize: '12px', color: '#10b981' }, children: "\u2713" })), !isCurrent && (_jsx("button", { onClick: () => handleJumpToStep(step.id, step.name), style: {
534
+ fontSize: '9px',
535
+ backgroundColor: '#3b82f6',
536
+ color: '#fff',
537
+ padding: '3px 8px',
538
+ borderRadius: '4px',
539
+ border: 'none',
540
+ cursor: 'pointer',
541
+ fontWeight: 'bold',
542
+ transition: 'background-color 0.2s',
543
+ }, onMouseEnter: (e) => {
544
+ e.currentTarget.style.backgroundColor = '#2563eb';
545
+ }, onMouseLeave: (e) => {
546
+ e.currentTarget.style.backgroundColor = '#3b82f6';
547
+ }, title: `Jump to ${step.name}`, children: "\u2197 JUMP" }))] }), _jsx("div", { style: {
548
+ fontSize: '10px',
549
+ color: isCurrent ? '#d1fae5' : '#9ca3af',
550
+ fontFamily: 'monospace',
551
+ marginBottom: '2px',
552
+ marginLeft: '24px',
553
+ }, children: step.id }), _jsx("div", { style: {
554
+ fontSize: '10px',
555
+ color: isCurrent ? '#a7f3d0' : '#6b7280',
556
+ marginLeft: '24px',
557
+ }, children: step.type }), step.urls && step.urls.length > 0 && (_jsxs("div", { style: { marginTop: '6px', marginLeft: '24px' }, children: [_jsxs("div", { style: {
558
+ fontSize: '9px',
559
+ color: isCurrent ? '#a7f3d0' : '#9ca3af',
560
+ marginBottom: '2px',
561
+ }, children: ["\uD83D\uDD17 ", step.urls.length, " URL", step.urls.length > 1 ? 's' : ''] }), step.urls.map((url, urlIdx) => (_jsxs("div", { style: {
562
+ fontSize: '9px',
563
+ color: isCurrent ? '#6ee7b7' : '#6b7280',
564
+ fontFamily: 'monospace',
565
+ marginLeft: '12px',
566
+ overflow: 'hidden',
567
+ textOverflow: 'ellipsis',
568
+ whiteSpace: 'nowrap',
569
+ }, children: ["\u2022 ", url] }, urlIdx)))] })), step.conditions && step.conditions.length > 0 && (_jsxs("div", { style: {
570
+ marginTop: '6px',
571
+ padding: '6px',
572
+ backgroundColor: isCurrent ? '#047857' : '#1f2937',
573
+ borderRadius: '4px',
574
+ marginLeft: '24px',
575
+ }, children: [_jsxs("div", { style: {
576
+ fontSize: '9px',
577
+ color: '#f59e0b',
578
+ fontWeight: 'bold',
579
+ marginBottom: '3px',
580
+ }, children: ["\u2699\uFE0F ", step.conditions.length, " Condition", step.conditions.length > 1 ? 's' : ''] }), step.conditions.map((cond, condIdx) => (_jsxs("div", { style: {
581
+ fontSize: '9px',
582
+ color: isCurrent ? '#d1fae5' : '#9ca3af',
583
+ marginLeft: '8px',
584
+ }, children: ["\u2022 ", cond.type, " \u2192 ", cond.nextStepId] }, condIdx)))] }))] }, step.id));
585
+ }) })] })), _jsxs("div", { style: { marginTop: '12px' }, children: [_jsx("h4", { style: { margin: '0 0 8px 0', color: '#60a5fa', fontSize: '13px' }, children: "\uD83D\uDD0D Raw Data" }), _jsx("div", { style: { fontSize: '11px' }, children: _jsx(TreeView, { data: context.debugFunnel.data, name: "funnelData" }) })] })] })) : (_jsx("p", { style: { color: '#6b7280' }, children: "No funnel hook active" }))] })), activeTab === 'checkout' && (_jsxs("div", { children: [_jsx("h3", { style: { margin: '0 0 16px 0', color: '#60a5fa' }, children: "Checkout Debug" }), context.debugCheckout.isActive ? (_jsxs("div", { children: [_jsxs("div", { style: { marginBottom: '20px' }, children: [_jsx("h4", { style: { margin: '0 0 12px 0', color: '#60a5fa' }, children: "Status" }), _jsxs("div", { style: { display: 'grid', gap: '8px' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Hook Active:" }), _jsx("span", { style: { color: '#10b981' }, children: "\u2705 Yes" })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Loading:" }), _jsx("span", { style: { color: context.debugCheckout.isLoading ? '#f59e0b' : '#10b981' }, children: context.debugCheckout.isLoading ? '⏳ Yes' : '✅ No' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Has Error:" }), _jsx("span", { style: { color: context.debugCheckout.error ? '#ef4444' : '#10b981' }, children: context.debugCheckout.error ? '❌ Yes' : '✅ No' })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [_jsx("span", { children: "Last Updated:" }), _jsx("span", { style: { color: '#9ca3af', fontSize: '12px' }, children: context.debugCheckout.lastUpdated?.toLocaleTimeString() || 'Never' })] })] })] }), context.debugCheckout.error && (_jsxs("div", { style: { marginBottom: '20px' }, children: [_jsx("h4", { style: { margin: '0 0 12px 0', color: '#ef4444' }, children: "Error Details" }), _jsxs("div", { style: {
372
586
  backgroundColor: '#372c2c',
373
587
  padding: '12px',
374
588
  borderRadius: '4px',
@@ -4,7 +4,7 @@
4
4
  * Modern implementation using TanStack Query for state management
5
5
  * and the v2 ApiClient for API calls.
6
6
  */
7
- import { FunnelEvent, FunnelNavigationResult, SimpleFunnelContext } from '../../core/resources/funnel';
7
+ import { FunnelAction, FunnelNavigationResult, SimpleFunnelContext } from '../../core/resources/funnel';
8
8
  export interface UseFunnelOptions {
9
9
  funnelId?: string;
10
10
  currentStepId?: string;
@@ -14,7 +14,7 @@ export interface UseFunnelOptions {
14
14
  enabled?: boolean;
15
15
  }
16
16
  export interface UseFunnelResult {
17
- next: (event: FunnelEvent) => Promise<any>;
17
+ next: (event: FunnelAction) => Promise<any>;
18
18
  goToStep: (stepId: string) => Promise<any>;
19
19
  updateContext: (updates: Partial<SimpleFunnelContext>) => Promise<void>;
20
20
  currentStep: {
@@ -43,9 +43,9 @@ export declare function useFunnel(options: UseFunnelOptions): UseFunnelResult;
43
43
  */
44
44
  export declare function useSimpleFunnel(funnelId: string, initialStepId?: string): {
45
45
  currentStepId: string;
46
- next: (event: FunnelEvent) => Promise<any>;
46
+ next: (event: FunnelAction) => Promise<any>;
47
47
  goToStep: (stepId: string) => Promise<any>;
48
48
  isLoading: boolean;
49
49
  context: SimpleFunnelContext | null;
50
50
  };
51
- export type { FunnelEvent, FunnelNavigationAction, FunnelNavigationResult, SimpleFunnelContext } from '../../core/resources/funnel';
51
+ export type { FunnelAction as FunnelEvent, FunnelNavigationAction, FunnelNavigationResult, SimpleFunnelContext } from '../../core/resources/funnel';
@@ -4,10 +4,10 @@
4
4
  * Modern implementation using TanStack Query for state management
5
5
  * and the v2 ApiClient for API calls.
6
6
  */
7
- import { useState, useCallback, useEffect, useMemo } from 'react';
8
- import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
7
+ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
8
+ import { useCallback, useEffect, useMemo, useState } from 'react';
9
+ import { FunnelEventType, FunnelResource } from '../../core/resources/funnel';
9
10
  import { useTagadaContext } from '../providers/TagadaProvider';
10
- import { FunnelResource } from '../../core/resources/funnel';
11
11
  import { getGlobalApiClient } from './useApiQuery';
12
12
  // Query keys for funnel operations
13
13
  const funnelQueryKeys = {
@@ -21,7 +21,7 @@ const funnelQueryKeys = {
21
21
  * and the v2 ApiClient architecture.
22
22
  */
23
23
  export function useFunnel(options) {
24
- const { auth, store } = useTagadaContext();
24
+ const { auth, store, debugMode, updateFunnelDebugData } = useTagadaContext();
25
25
  const queryClient = useQueryClient();
26
26
  const apiClient = getGlobalApiClient();
27
27
  const funnelResource = useMemo(() => new FunnelResource(apiClient), [apiClient]);
@@ -34,6 +34,30 @@ export function useFunnel(options) {
34
34
  const urlParams = typeof window !== 'undefined' ? new URLSearchParams(window.location.search) : new URLSearchParams();
35
35
  const urlFunnelId = urlParams.get('funnelId') || undefined;
36
36
  const effectiveFunnelId = urlFunnelId || options.funnelId;
37
+ /**
38
+ * Fetch debug data for the funnel debugger
39
+ */
40
+ const fetchFunnelDebugData = useCallback(async (sessionId) => {
41
+ if (!debugMode) {
42
+ console.log('🐛 [useFunnel V2] Debug mode is OFF, skipping debug data fetch');
43
+ return;
44
+ }
45
+ console.log('🐛 [useFunnel V2] Fetching debug data for session:', sessionId);
46
+ try {
47
+ const response = await funnelResource.getSession(sessionId, undefined, true);
48
+ console.log('🐛 [useFunnel V2] Debug data response:', response);
49
+ if (response.success && response.debugData) {
50
+ updateFunnelDebugData(response.debugData, null, false);
51
+ console.log('🐛 [useFunnel V2] Debug data updated successfully:', response.debugData);
52
+ }
53
+ else {
54
+ console.warn('🐛 [useFunnel V2] No debug data in response');
55
+ }
56
+ }
57
+ catch (error) {
58
+ console.error('🐛 [useFunnel V2] Failed to fetch funnel debug data:', error);
59
+ }
60
+ }, [funnelResource, debugMode, updateFunnelDebugData]);
37
61
  // Session query - only enabled when we have a session ID
38
62
  const { data: sessionData, isLoading: isSessionLoading, error: sessionError, refetch: refetchSession } = useQuery({
39
63
  queryKey: funnelQueryKeys.session(context?.sessionId || ''),
@@ -115,6 +139,10 @@ export function useFunnel(options) {
115
139
  // Set session cookie for persistence across page reloads
116
140
  setSessionCookie(newContext.sessionId);
117
141
  console.log(`🍪 Funnel: Initialized session for funnel ${effectiveFunnelId || 'default'}`, newContext);
142
+ // Fetch debug data if in debug mode
143
+ if (debugMode) {
144
+ void fetchFunnelDebugData(newContext.sessionId);
145
+ }
118
146
  // Invalidate session query to refetch with new session ID
119
147
  void queryClient.invalidateQueries({
120
148
  queryKey: funnelQueryKeys.session(newContext.sessionId)
@@ -222,6 +250,10 @@ export function useFunnel(options) {
222
250
  performNavigation(updatedAction);
223
251
  }
224
252
  console.log(`🍪 Funnel: Navigated from ${context.currentStepId} to ${result.stepId}`);
253
+ // Fetch debug data if in debug mode
254
+ if (debugMode) {
255
+ void fetchFunnelDebugData(newContext.sessionId);
256
+ }
225
257
  // Invalidate and refetch session data
226
258
  void queryClient.invalidateQueries({
227
259
  queryKey: funnelQueryKeys.session(newContext.sessionId)
@@ -373,7 +405,7 @@ export function useFunnel(options) {
373
405
  }, [navigateMutation]);
374
406
  const goToStep = useCallback(async (stepId) => {
375
407
  return next({
376
- type: 'direct_navigation',
408
+ type: FunnelEventType.DIRECT_NAVIGATION,
377
409
  data: { targetStepId: stepId },
378
410
  timestamp: new Date().toISOString()
379
411
  });
@@ -3,16 +3,25 @@
3
3
  * Handles post-purchase offers with automatic caching
4
4
  */
5
5
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
6
- import { useCallback, useEffect, useMemo, useState } from 'react';
6
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
7
7
  import { PostPurchasesResource } from '../../core/resources/postPurchases';
8
8
  import { useTagadaContext } from '../providers/TagadaProvider';
9
9
  import { getGlobalApiClient } from './useApiQuery';
10
10
  export function usePostPurchasesQuery(options) {
11
+ console.log('usePostPurchasesQuery');
11
12
  const { orderId, enabled = true, autoInitializeCheckout = false } = options;
12
13
  const queryClient = useQueryClient();
13
14
  const { session } = useTagadaContext();
14
15
  // State for checkout sessions per offer
15
16
  const [checkoutSessions, setCheckoutSessions] = useState({});
17
+ // Ref to track checkout sessions for synchronous access
18
+ const checkoutSessionsRef = useRef({});
19
+ // Ref to track offers being initialized to prevent duplicate initialization
20
+ const initializingOffers = useRef(new Set());
21
+ // Keep ref in sync with state
22
+ useEffect(() => {
23
+ checkoutSessionsRef.current = checkoutSessions;
24
+ }, [checkoutSessions]);
16
25
  // Create post purchases resource client
17
26
  const postPurchasesResource = useMemo(() => {
18
27
  try {
@@ -70,6 +79,62 @@ export function usePostPurchasesQuery(options) {
70
79
  throw error;
71
80
  }
72
81
  }, [postPurchasesResource]);
82
+ // Initialize checkout session for an offer
83
+ const initializeOfferCheckout = useCallback(async (offerId) => {
84
+ try {
85
+ // Check if customer ID is available
86
+ if (!session?.customerId) {
87
+ throw new Error('Customer ID is required. Make sure the session is properly initialized.');
88
+ }
89
+ // Check if already initializing to avoid race conditions
90
+ if (initializingOffers.current.has(offerId)) {
91
+ return; // Already initializing, skip
92
+ }
93
+ // Check if already initialized using ref for synchronous access
94
+ if (checkoutSessionsRef.current[offerId]?.checkoutSessionId) {
95
+ return; // Already initialized, exit early
96
+ }
97
+ // Mark as initializing
98
+ initializingOffers.current.add(offerId);
99
+ try {
100
+ // Initialize checkout session
101
+ const initResult = await postPurchasesResource.initCheckoutSession(offerId, orderId, session.customerId);
102
+ if (!initResult.checkoutSessionId) {
103
+ throw new Error('Failed to initialize checkout session');
104
+ }
105
+ const sessionId = initResult.checkoutSessionId;
106
+ // Initialize session state
107
+ setCheckoutSessions(prev => {
108
+ // Double-check we're not overwriting an existing session
109
+ if (prev[offerId]?.checkoutSessionId) {
110
+ return prev;
111
+ }
112
+ return {
113
+ ...prev,
114
+ [offerId]: {
115
+ checkoutSessionId: sessionId,
116
+ orderSummary: null,
117
+ selectedVariants: {},
118
+ loadingVariants: {},
119
+ isUpdatingSummary: false,
120
+ }
121
+ };
122
+ });
123
+ // Fetch order summary with variant options
124
+ await fetchOrderSummary(offerId, sessionId);
125
+ }
126
+ finally {
127
+ // Remove from initializing set
128
+ initializingOffers.current.delete(offerId);
129
+ }
130
+ }
131
+ catch (error) {
132
+ // Remove from initializing set on error
133
+ initializingOffers.current.delete(offerId);
134
+ console.error(`[SDK] Failed to initialize checkout for offer ${offerId}:`, error);
135
+ throw error;
136
+ }
137
+ }, [session?.customerId, orderId, postPurchasesResource, fetchOrderSummary]);
73
138
  // Main post-purchase offers query
74
139
  const { data: offers = [], isLoading, error, refetch, } = useQuery({
75
140
  queryKey: ['post-purchase-offers', orderId],
@@ -80,18 +145,17 @@ export function usePostPurchasesQuery(options) {
80
145
  });
81
146
  // Auto-initialize checkout sessions if enabled
82
147
  useEffect(() => {
83
- if (autoInitializeCheckout && offers.length > 0) {
148
+ if (autoInitializeCheckout && offers.length > 0 && session?.customerId) {
84
149
  // Initialize checkout sessions for all offers
85
150
  offers.forEach((offer) => {
86
- try {
87
- // This is a placeholder - in a full implementation, you'd call initializeOfferCheckout
88
- }
89
- catch (_error) {
90
- // Error handling removed
91
- }
151
+ // The initializeOfferCheckout function will check if already initialized or initializing
152
+ void initializeOfferCheckout(offer.id).catch((error) => {
153
+ // Log errors but don't throw - auto-initialization failures shouldn't break the UI
154
+ console.error(`[SDK] Failed to auto-initialize checkout for offer ${offer.id}:`, error);
155
+ });
92
156
  });
93
157
  }
94
- }, [autoInitializeCheckout, offers]);
158
+ }, [autoInitializeCheckout, offers, session?.customerId, initializeOfferCheckout]);
95
159
  // Accept offer mutation
96
160
  const acceptMutation = useMutation({
97
161
  mutationFn: ({ offerId, items }) => {
@@ -201,40 +265,14 @@ export function usePostPurchasesQuery(options) {
201
265
  getCheckoutSessionState: (offerId) => {
202
266
  return checkoutSessions[offerId] || null;
203
267
  },
204
- initializeOfferCheckout: async (offerId) => {
205
- try {
206
- // Check if customer ID is available
207
- if (!session?.customerId) {
208
- throw new Error('Customer ID is required. Make sure the session is properly initialized.');
209
- }
210
- // Initialize checkout session
211
- const initResult = await postPurchasesResource.initCheckoutSession(offerId, orderId, session.customerId);
212
- if (!initResult.checkoutSessionId) {
213
- throw new Error('Failed to initialize checkout session');
214
- }
215
- const sessionId = initResult.checkoutSessionId;
216
- // Initialize session state
217
- setCheckoutSessions(prev => ({
218
- ...prev,
219
- [offerId]: {
220
- checkoutSessionId: sessionId,
221
- orderSummary: null,
222
- selectedVariants: {},
223
- loadingVariants: {},
224
- isUpdatingSummary: false,
225
- }
226
- }));
227
- // Fetch order summary with variant options
228
- await fetchOrderSummary(offerId, sessionId);
229
- }
230
- catch (_error) {
231
- throw _error;
232
- }
233
- },
268
+ initializeOfferCheckout,
234
269
  getAvailableVariants: (offerId, productId) => {
235
270
  const sessionState = checkoutSessions[offerId];
271
+ console.log('sessionState', sessionState);
236
272
  if (!sessionState?.orderSummary?.options?.[productId])
237
273
  return [];
274
+ console.log('getAvailableVariants', offerId, productId);
275
+ console.log('sessionState.orderSummary.options', sessionState.orderSummary.options);
238
276
  return sessionState.orderSummary.options[productId].map((variant) => ({
239
277
  variantId: variant.id,
240
278
  variantName: variant.name,