@tagadapay/plugin-sdk 1.0.2
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 +475 -0
- package/dist/data/currencies.json +2410 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +37 -0
- package/dist/react/components/DebugDrawer.d.ts +7 -0
- package/dist/react/components/DebugDrawer.js +368 -0
- package/dist/react/components/OffersDemo.d.ts +1 -0
- package/dist/react/components/OffersDemo.js +50 -0
- package/dist/react/components/index.d.ts +1 -0
- package/dist/react/components/index.js +1 -0
- package/dist/react/config/environment.d.ts +22 -0
- package/dist/react/config/environment.js +132 -0
- package/dist/react/config/payment.d.ts +23 -0
- package/dist/react/config/payment.js +52 -0
- package/dist/react/hooks/useAuth.d.ts +4 -0
- package/dist/react/hooks/useAuth.js +12 -0
- package/dist/react/hooks/useCheckout.d.ts +262 -0
- package/dist/react/hooks/useCheckout.js +325 -0
- package/dist/react/hooks/useCurrency.d.ts +4 -0
- package/dist/react/hooks/useCurrency.js +640 -0
- package/dist/react/hooks/useCustomer.d.ts +7 -0
- package/dist/react/hooks/useCustomer.js +14 -0
- package/dist/react/hooks/useEnvironment.d.ts +7 -0
- package/dist/react/hooks/useEnvironment.js +18 -0
- package/dist/react/hooks/useLocale.d.ts +2 -0
- package/dist/react/hooks/useLocale.js +43 -0
- package/dist/react/hooks/useOffers.d.ts +99 -0
- package/dist/react/hooks/useOffers.js +115 -0
- package/dist/react/hooks/useOrder.d.ts +44 -0
- package/dist/react/hooks/useOrder.js +77 -0
- package/dist/react/hooks/usePayment.d.ts +60 -0
- package/dist/react/hooks/usePayment.js +343 -0
- package/dist/react/hooks/usePaymentPolling.d.ts +45 -0
- package/dist/react/hooks/usePaymentPolling.js +146 -0
- package/dist/react/hooks/useProducts.d.ts +95 -0
- package/dist/react/hooks/useProducts.js +120 -0
- package/dist/react/hooks/useSession.d.ts +10 -0
- package/dist/react/hooks/useSession.js +17 -0
- package/dist/react/hooks/useThreeds.d.ts +38 -0
- package/dist/react/hooks/useThreeds.js +162 -0
- package/dist/react/hooks/useThreedsModal.d.ts +16 -0
- package/dist/react/hooks/useThreedsModal.js +328 -0
- package/dist/react/index.d.ts +26 -0
- package/dist/react/index.js +27 -0
- package/dist/react/providers/TagadaProvider.d.ts +55 -0
- package/dist/react/providers/TagadaProvider.js +471 -0
- package/dist/react/services/apiService.d.ts +149 -0
- package/dist/react/services/apiService.js +168 -0
- package/dist/react/types.d.ts +151 -0
- package/dist/react/types.js +4 -0
- package/dist/react/utils/__tests__/urlUtils.test.d.ts +1 -0
- package/dist/react/utils/__tests__/urlUtils.test.js +189 -0
- package/dist/react/utils/deviceInfo.d.ts +39 -0
- package/dist/react/utils/deviceInfo.js +163 -0
- package/dist/react/utils/jwtDecoder.d.ts +14 -0
- package/dist/react/utils/jwtDecoder.js +86 -0
- package/dist/react/utils/money.d.ts +2273 -0
- package/dist/react/utils/money.js +104 -0
- package/dist/react/utils/tokenStorage.d.ts +16 -0
- package/dist/react/utils/tokenStorage.js +52 -0
- package/dist/react/utils/urlUtils.d.ts +239 -0
- package/dist/react/utils/urlUtils.js +449 -0
- package/package.json +64 -0
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* TagadaProvider - Main provider component for the Tagada Pay React SDK
|
|
5
|
+
*/
|
|
6
|
+
import { createContext, useContext, useState, useEffect, useRef, useCallback } from 'react';
|
|
7
|
+
import { getEnvironmentConfig, detectEnvironment } from '../config/environment';
|
|
8
|
+
import { ApiService } from '../services/apiService';
|
|
9
|
+
import { setClientToken, getClientToken, clearClientToken } from '../utils/tokenStorage';
|
|
10
|
+
import { decodeJWTClient, isTokenExpired } from '../utils/jwtDecoder';
|
|
11
|
+
import { collectDeviceInfo, getBrowserLocale, getUrlParams } from '../utils/deviceInfo';
|
|
12
|
+
import DebugDrawer from '../components/DebugDrawer';
|
|
13
|
+
import { formatMoney, getCurrencyInfo, moneyStringOrNumberToMinorUnits, minorUnitsToMajorUnits, formatMoneyWithoutSymbol, convertCurrency, formatSimpleMoney, } from '../utils/money';
|
|
14
|
+
// Subtle loading component for initialization
|
|
15
|
+
const InitializationLoader = () => (_jsx("div", { style: {
|
|
16
|
+
position: 'fixed',
|
|
17
|
+
top: 0,
|
|
18
|
+
left: 0,
|
|
19
|
+
right: 0,
|
|
20
|
+
height: '2px',
|
|
21
|
+
background: 'linear-gradient(90deg, #3b82f6 0%, #8b5cf6 50%, #3b82f6 100%)',
|
|
22
|
+
backgroundSize: '200% 100%',
|
|
23
|
+
animation: 'tagada-loading 1.5s ease-in-out infinite',
|
|
24
|
+
zIndex: 9999,
|
|
25
|
+
}, children: _jsx("style", { children: `
|
|
26
|
+
@keyframes tagada-loading {
|
|
27
|
+
0% { background-position: 200% 0; }
|
|
28
|
+
100% { background-position: -200% 0; }
|
|
29
|
+
}
|
|
30
|
+
` }) }));
|
|
31
|
+
const TagadaContext = createContext(null);
|
|
32
|
+
export function TagadaProvider({ children, environment, customApiConfig, developmentMode = false, debugMode, // Remove default, will be set based on environment
|
|
33
|
+
storeId, accountId, mockData, }) {
|
|
34
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
35
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
36
|
+
const [token, setToken] = useState(null);
|
|
37
|
+
const [hasAttemptedAnonymousToken, setHasAttemptedAnonymousToken] = useState(false);
|
|
38
|
+
const [isDebugDrawerOpen, setIsDebugDrawerOpen] = useState(false);
|
|
39
|
+
const isInitializing = useRef(false);
|
|
40
|
+
// Initialize environment configuration
|
|
41
|
+
const [environmentConfig, setEnvironmentConfig] = useState(() => {
|
|
42
|
+
const detectedEnv = environment || detectEnvironment();
|
|
43
|
+
const config = getEnvironmentConfig(detectedEnv);
|
|
44
|
+
// Log environment detection for debugging
|
|
45
|
+
if (environment) {
|
|
46
|
+
console.log(`[TagadaSDK] Using explicit environment: ${environment}`);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
console.log(`[TagadaSDK] Auto-detected environment: ${detectedEnv} (${typeof window !== 'undefined' ? window.location.hostname : 'SSR'})`);
|
|
50
|
+
}
|
|
51
|
+
// Apply custom API config if provided
|
|
52
|
+
if (customApiConfig) {
|
|
53
|
+
return {
|
|
54
|
+
...config,
|
|
55
|
+
...customApiConfig,
|
|
56
|
+
apiConfig: {
|
|
57
|
+
...config.apiConfig,
|
|
58
|
+
...customApiConfig.apiConfig,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return config;
|
|
63
|
+
});
|
|
64
|
+
// Auto-set debugMode based on environment (unless explicitly provided)
|
|
65
|
+
const finalDebugMode = debugMode ?? environmentConfig.environment !== 'production';
|
|
66
|
+
// Initialize API service
|
|
67
|
+
const [apiService] = useState(() => {
|
|
68
|
+
const service = new ApiService({
|
|
69
|
+
environmentConfig,
|
|
70
|
+
token,
|
|
71
|
+
onTokenUpdate: (newToken) => {
|
|
72
|
+
setToken(newToken);
|
|
73
|
+
setClientToken(newToken);
|
|
74
|
+
},
|
|
75
|
+
onTokenClear: () => {
|
|
76
|
+
setToken(null);
|
|
77
|
+
clearClientToken();
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
// Store the provided store ID immediately if available
|
|
81
|
+
if (storeId) {
|
|
82
|
+
console.log(`[SDK] Using provided store ID: ${storeId}`);
|
|
83
|
+
service.storeStoreId(storeId);
|
|
84
|
+
}
|
|
85
|
+
return service;
|
|
86
|
+
});
|
|
87
|
+
// Update API service when config or token changes
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
apiService.updateConfig(environmentConfig);
|
|
90
|
+
apiService.updateToken(token);
|
|
91
|
+
}, [apiService, environmentConfig, token]);
|
|
92
|
+
// Initialize state
|
|
93
|
+
const [customer, setCustomer] = useState(null);
|
|
94
|
+
const [session, setSession] = useState(null);
|
|
95
|
+
const [store, setStore] = useState(null);
|
|
96
|
+
// Initialize locale and currency with defaults
|
|
97
|
+
const [locale, setLocale] = useState({
|
|
98
|
+
locale: 'en-US',
|
|
99
|
+
language: 'en',
|
|
100
|
+
region: 'US',
|
|
101
|
+
messages: {},
|
|
102
|
+
});
|
|
103
|
+
const [currency, setCurrency] = useState({
|
|
104
|
+
code: 'USD',
|
|
105
|
+
symbol: '$',
|
|
106
|
+
name: 'US Dollar',
|
|
107
|
+
});
|
|
108
|
+
// Initialize debug checkout state
|
|
109
|
+
const [debugCheckout, setDebugCheckout] = useState({
|
|
110
|
+
isActive: false,
|
|
111
|
+
data: null,
|
|
112
|
+
error: null,
|
|
113
|
+
isLoading: false,
|
|
114
|
+
lastUpdated: null,
|
|
115
|
+
});
|
|
116
|
+
// Initialize auth state
|
|
117
|
+
const [auth, setAuth] = useState({
|
|
118
|
+
isAuthenticated: false,
|
|
119
|
+
isLoading: false,
|
|
120
|
+
customer: null,
|
|
121
|
+
session: null,
|
|
122
|
+
});
|
|
123
|
+
// Initialize session
|
|
124
|
+
const initializeSession = useCallback(async (sessionData) => {
|
|
125
|
+
if (!sessionData.storeId || !sessionData.accountId) {
|
|
126
|
+
console.error('[SDK] Missing required session data');
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (finalDebugMode) {
|
|
130
|
+
console.debug('[SDK][DEBUG] Initializing session with store config...', sessionData);
|
|
131
|
+
}
|
|
132
|
+
setIsLoading(true);
|
|
133
|
+
try {
|
|
134
|
+
const deviceInfo = collectDeviceInfo();
|
|
135
|
+
const urlParams = getUrlParams();
|
|
136
|
+
const browserLocale = getBrowserLocale();
|
|
137
|
+
const sessionInitData = {
|
|
138
|
+
storeId: sessionData.storeId,
|
|
139
|
+
accountId: sessionData.accountId,
|
|
140
|
+
customerId: sessionData.customerId,
|
|
141
|
+
browserLocale,
|
|
142
|
+
queryLocale: urlParams.locale,
|
|
143
|
+
queryCurrency: urlParams.currency,
|
|
144
|
+
utmSource: urlParams.utmSource,
|
|
145
|
+
utmMedium: urlParams.utmMedium,
|
|
146
|
+
utmCampaign: urlParams.utmCampaign,
|
|
147
|
+
browser: deviceInfo.userAgent.browser.name,
|
|
148
|
+
browserVersion: deviceInfo.userAgent.browser.version,
|
|
149
|
+
os: deviceInfo.userAgent.os.name,
|
|
150
|
+
osVersion: deviceInfo.userAgent.os.version,
|
|
151
|
+
deviceType: deviceInfo.userAgent.device?.type,
|
|
152
|
+
deviceModel: deviceInfo.userAgent.device?.model,
|
|
153
|
+
screenWidth: deviceInfo.screenResolution.width,
|
|
154
|
+
screenHeight: deviceInfo.screenResolution.height,
|
|
155
|
+
timeZone: deviceInfo.timeZone,
|
|
156
|
+
};
|
|
157
|
+
if (finalDebugMode) {
|
|
158
|
+
console.debug('[SDK][DEBUG] Session init data:', sessionInitData);
|
|
159
|
+
}
|
|
160
|
+
const response = await apiService.initializeSession(sessionInitData);
|
|
161
|
+
if (finalDebugMode) {
|
|
162
|
+
console.debug('[SDK][DEBUG] Session init response:', response);
|
|
163
|
+
}
|
|
164
|
+
// Update store data
|
|
165
|
+
if (response.store) {
|
|
166
|
+
const storeData = response.store;
|
|
167
|
+
const storeConfig = {
|
|
168
|
+
...response.store,
|
|
169
|
+
presentmentCurrencies: storeData.presentmentCurrencies || [response.store.currency || 'USD'],
|
|
170
|
+
chargeCurrencies: storeData.chargeCurrencies || [response.store.currency || 'USD'],
|
|
171
|
+
};
|
|
172
|
+
setStore(storeConfig);
|
|
173
|
+
if (finalDebugMode) {
|
|
174
|
+
console.debug('[SDK][DEBUG] Store config loaded:', storeConfig);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Update locale
|
|
178
|
+
const localeConfig = {
|
|
179
|
+
locale: response.locale,
|
|
180
|
+
language: response.locale.split('-')[0],
|
|
181
|
+
region: response.locale.split('-')[1] ?? 'US',
|
|
182
|
+
messages: response.messages ?? {},
|
|
183
|
+
};
|
|
184
|
+
setLocale(localeConfig);
|
|
185
|
+
if (finalDebugMode) {
|
|
186
|
+
console.debug('[SDK][DEBUG] Locale config:', localeConfig);
|
|
187
|
+
}
|
|
188
|
+
// Update currency based on store
|
|
189
|
+
if (response.store) {
|
|
190
|
+
const currencyConfig = {
|
|
191
|
+
code: response.store.currency,
|
|
192
|
+
symbol: getCurrencySymbol(response.store.currency),
|
|
193
|
+
name: getCurrencyName(response.store.currency),
|
|
194
|
+
};
|
|
195
|
+
setCurrency(currencyConfig);
|
|
196
|
+
if (finalDebugMode) {
|
|
197
|
+
console.debug('[SDK][DEBUG] Currency config:', currencyConfig);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Update customer data if available
|
|
201
|
+
if (response.customer) {
|
|
202
|
+
setCustomer(response.customer);
|
|
203
|
+
if (finalDebugMode) {
|
|
204
|
+
console.debug('[SDK][DEBUG] Customer data:', response.customer);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Update auth state
|
|
208
|
+
const authState = {
|
|
209
|
+
isAuthenticated: response.customer?.isAuthenticated ?? false,
|
|
210
|
+
isLoading: false,
|
|
211
|
+
customer: response.customer ?? null,
|
|
212
|
+
session: sessionData,
|
|
213
|
+
};
|
|
214
|
+
setAuth(authState);
|
|
215
|
+
if (finalDebugMode) {
|
|
216
|
+
console.debug('[SDK][DEBUG] Auth state:', authState);
|
|
217
|
+
}
|
|
218
|
+
console.debug('[SDK] Session initialized successfully');
|
|
219
|
+
setIsInitialized(true);
|
|
220
|
+
setIsLoading(false);
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
console.error('[SDK] Error initializing session:', error);
|
|
224
|
+
if (finalDebugMode) {
|
|
225
|
+
console.debug('[SDK][DEBUG] Full error details:', error);
|
|
226
|
+
}
|
|
227
|
+
setIsInitialized(true);
|
|
228
|
+
setIsLoading(false);
|
|
229
|
+
}
|
|
230
|
+
}, [apiService, finalDebugMode]);
|
|
231
|
+
// Create anonymous token if needed
|
|
232
|
+
const createAnonymousToken = useCallback(async (targetStoreId) => {
|
|
233
|
+
if (hasAttemptedAnonymousToken || !targetStoreId) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
console.log('[SDK] 🚀 Starting initialization...');
|
|
237
|
+
if (finalDebugMode) {
|
|
238
|
+
console.debug('[SDK][DEBUG] Creating anonymous token for store:', targetStoreId);
|
|
239
|
+
}
|
|
240
|
+
setHasAttemptedAnonymousToken(true);
|
|
241
|
+
try {
|
|
242
|
+
const response = await apiService.createAnonymousToken(targetStoreId);
|
|
243
|
+
if (finalDebugMode) {
|
|
244
|
+
console.debug('[SDK][DEBUG] Anonymous token response:', response);
|
|
245
|
+
}
|
|
246
|
+
// Set the token in state and storage
|
|
247
|
+
setToken(response.token);
|
|
248
|
+
setClientToken(response.token);
|
|
249
|
+
// Update the API service with the new token
|
|
250
|
+
apiService.updateToken(response.token);
|
|
251
|
+
// Decode the token to get session data
|
|
252
|
+
const decodedSession = decodeJWTClient(response.token);
|
|
253
|
+
if (decodedSession) {
|
|
254
|
+
if (finalDebugMode) {
|
|
255
|
+
console.debug('[SDK][DEBUG] Decoded session from token:', decodedSession);
|
|
256
|
+
}
|
|
257
|
+
setSession(decodedSession);
|
|
258
|
+
// Initialize session with API call
|
|
259
|
+
await initializeSession(decodedSession);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
console.error('[SDK] Failed to decode anonymous token');
|
|
263
|
+
setIsInitialized(true);
|
|
264
|
+
setIsLoading(false);
|
|
265
|
+
}
|
|
266
|
+
console.log('[SDK] ✅ Initialization completed successfully');
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
console.error('[SDK] ❌ Initialization failed:', error);
|
|
270
|
+
if (finalDebugMode) {
|
|
271
|
+
console.debug('[SDK][DEBUG] Anonymous token creation failed:', error);
|
|
272
|
+
}
|
|
273
|
+
setIsInitialized(true);
|
|
274
|
+
setIsLoading(false);
|
|
275
|
+
}
|
|
276
|
+
}, [apiService, hasAttemptedAnonymousToken, initializeSession, finalDebugMode]);
|
|
277
|
+
// Initialize token from storage or create anonymous token
|
|
278
|
+
useEffect(() => {
|
|
279
|
+
if (isInitializing.current) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
isInitializing.current = true;
|
|
283
|
+
const initializeToken = async () => {
|
|
284
|
+
try {
|
|
285
|
+
console.debug('[SDK] Initializing token...');
|
|
286
|
+
setIsLoading(true);
|
|
287
|
+
if (developmentMode) {
|
|
288
|
+
console.debug('[SDK] Development mode: Using mock data');
|
|
289
|
+
// Use mock data in development mode
|
|
290
|
+
if (mockData?.customer) {
|
|
291
|
+
setCustomer({
|
|
292
|
+
id: 'dev-customer-123',
|
|
293
|
+
email: 'dev@example.com',
|
|
294
|
+
firstName: 'John',
|
|
295
|
+
lastName: 'Doe',
|
|
296
|
+
phone: '+1234567890',
|
|
297
|
+
isAuthenticated: true,
|
|
298
|
+
role: 'authenticated',
|
|
299
|
+
...mockData.customer,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
if (mockData?.session) {
|
|
303
|
+
setSession({
|
|
304
|
+
sessionId: 'dev-session-123',
|
|
305
|
+
storeId: 'dev-store-123',
|
|
306
|
+
accountId: 'dev-account-123',
|
|
307
|
+
customerId: 'dev-customer-123',
|
|
308
|
+
role: 'authenticated',
|
|
309
|
+
isValid: true,
|
|
310
|
+
isLoading: false,
|
|
311
|
+
...mockData.session,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
if (mockData?.store) {
|
|
315
|
+
setStore({
|
|
316
|
+
id: 'dev-store-123',
|
|
317
|
+
name: 'Development Store',
|
|
318
|
+
domain: 'dev.localhost',
|
|
319
|
+
currency: 'USD',
|
|
320
|
+
locale: 'en-US',
|
|
321
|
+
presentmentCurrencies: ['USD'],
|
|
322
|
+
chargeCurrencies: ['USD'],
|
|
323
|
+
...mockData.store,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
setIsInitialized(true);
|
|
327
|
+
setIsLoading(false);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
// Check for existing token
|
|
331
|
+
const existingToken = getClientToken();
|
|
332
|
+
let tokenToUse = null;
|
|
333
|
+
// Check URL params for token
|
|
334
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
335
|
+
const queryToken = urlParams.get('token');
|
|
336
|
+
if (queryToken) {
|
|
337
|
+
console.debug('[SDK] Found token in URL params');
|
|
338
|
+
tokenToUse = queryToken;
|
|
339
|
+
setClientToken(queryToken);
|
|
340
|
+
}
|
|
341
|
+
else if (existingToken && !isTokenExpired(existingToken)) {
|
|
342
|
+
console.debug('[SDK] Using existing token from storage');
|
|
343
|
+
tokenToUse = existingToken;
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
console.debug('[SDK] No valid token found');
|
|
347
|
+
// Determine storeId for anonymous token
|
|
348
|
+
const targetStoreId = storeId || 'default-store';
|
|
349
|
+
await createAnonymousToken(targetStoreId);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (tokenToUse) {
|
|
353
|
+
setToken(tokenToUse);
|
|
354
|
+
// Update the API service with the token
|
|
355
|
+
apiService.updateToken(tokenToUse);
|
|
356
|
+
// Decode token to get session data
|
|
357
|
+
const decodedSession = decodeJWTClient(tokenToUse);
|
|
358
|
+
if (decodedSession) {
|
|
359
|
+
setSession(decodedSession);
|
|
360
|
+
// Initialize session with API call
|
|
361
|
+
await initializeSession(decodedSession);
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
console.error('[SDK] Failed to decode token');
|
|
365
|
+
setIsInitialized(true);
|
|
366
|
+
setIsLoading(false);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
console.error('[SDK] Error initializing token:', error);
|
|
372
|
+
setIsInitialized(true);
|
|
373
|
+
setIsLoading(false);
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
void initializeToken();
|
|
377
|
+
}, [developmentMode, mockData, storeId, createAnonymousToken, initializeSession]);
|
|
378
|
+
// Update auth state when customer/session changes
|
|
379
|
+
useEffect(() => {
|
|
380
|
+
setAuth({
|
|
381
|
+
isAuthenticated: customer?.isAuthenticated ?? false,
|
|
382
|
+
isLoading: false,
|
|
383
|
+
customer,
|
|
384
|
+
session,
|
|
385
|
+
});
|
|
386
|
+
}, [customer, session]);
|
|
387
|
+
const contextValue = {
|
|
388
|
+
auth,
|
|
389
|
+
session,
|
|
390
|
+
customer,
|
|
391
|
+
locale,
|
|
392
|
+
currency,
|
|
393
|
+
store,
|
|
394
|
+
environment: environmentConfig,
|
|
395
|
+
apiService,
|
|
396
|
+
isLoading,
|
|
397
|
+
isInitialized,
|
|
398
|
+
debugMode: finalDebugMode,
|
|
399
|
+
debugCheckout,
|
|
400
|
+
updateCheckoutDebugData: (data, error, isLoading) => {
|
|
401
|
+
setDebugCheckout({
|
|
402
|
+
isActive: true,
|
|
403
|
+
data,
|
|
404
|
+
error: error ?? null,
|
|
405
|
+
isLoading: isLoading ?? false,
|
|
406
|
+
lastUpdated: new Date(),
|
|
407
|
+
});
|
|
408
|
+
},
|
|
409
|
+
money: {
|
|
410
|
+
formatMoney,
|
|
411
|
+
getCurrencyInfo,
|
|
412
|
+
moneyStringOrNumberToMinorUnits,
|
|
413
|
+
minorUnitsToMajorUnits,
|
|
414
|
+
formatMoneyWithoutSymbol,
|
|
415
|
+
convertCurrency,
|
|
416
|
+
formatSimpleMoney,
|
|
417
|
+
},
|
|
418
|
+
};
|
|
419
|
+
return (_jsxs(TagadaContext.Provider, { value: contextValue, children: [isLoading && !isInitialized && _jsx(InitializationLoader, {}), finalDebugMode && isInitialized && (_jsxs(_Fragment, { children: [_jsx("button", { onClick: () => setIsDebugDrawerOpen(true), style: {
|
|
420
|
+
position: 'fixed',
|
|
421
|
+
bottom: '16px',
|
|
422
|
+
right: '16px',
|
|
423
|
+
backgroundColor: '#f97316',
|
|
424
|
+
color: 'white',
|
|
425
|
+
border: 'none',
|
|
426
|
+
borderRadius: '50%',
|
|
427
|
+
width: '56px',
|
|
428
|
+
height: '56px',
|
|
429
|
+
fontSize: '20px',
|
|
430
|
+
cursor: 'pointer',
|
|
431
|
+
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
|
|
432
|
+
zIndex: 999997,
|
|
433
|
+
transition: 'all 0.2s ease',
|
|
434
|
+
}, onMouseEnter: (e) => {
|
|
435
|
+
e.currentTarget.style.backgroundColor = '#ea580c';
|
|
436
|
+
e.currentTarget.style.transform = 'scale(1.1)';
|
|
437
|
+
}, onMouseLeave: (e) => {
|
|
438
|
+
e.currentTarget.style.backgroundColor = '#f97316';
|
|
439
|
+
e.currentTarget.style.transform = 'scale(1)';
|
|
440
|
+
}, title: "Open TagadaPay SDK Debug Panel", children: "\uD83D\uDC1B" }), _jsx(DebugDrawer, { isOpen: isDebugDrawerOpen, onClose: () => setIsDebugDrawerOpen(false) })] })), isInitialized && children] }));
|
|
441
|
+
}
|
|
442
|
+
export function useTagadaContext() {
|
|
443
|
+
const context = useContext(TagadaContext);
|
|
444
|
+
if (!context) {
|
|
445
|
+
throw new Error('useTagadaContext must be used within a TagadaProvider');
|
|
446
|
+
}
|
|
447
|
+
return context;
|
|
448
|
+
}
|
|
449
|
+
// Helper functions
|
|
450
|
+
function getCurrencySymbol(code) {
|
|
451
|
+
const symbols = {
|
|
452
|
+
USD: '$',
|
|
453
|
+
EUR: '€',
|
|
454
|
+
GBP: '£',
|
|
455
|
+
JPY: '¥',
|
|
456
|
+
CAD: 'C$',
|
|
457
|
+
AUD: 'A$',
|
|
458
|
+
};
|
|
459
|
+
return symbols[code] || code;
|
|
460
|
+
}
|
|
461
|
+
function getCurrencyName(code) {
|
|
462
|
+
const names = {
|
|
463
|
+
USD: 'US Dollar',
|
|
464
|
+
EUR: 'Euro',
|
|
465
|
+
GBP: 'British Pound',
|
|
466
|
+
JPY: 'Japanese Yen',
|
|
467
|
+
CAD: 'Canadian Dollar',
|
|
468
|
+
AUD: 'Australian Dollar',
|
|
469
|
+
};
|
|
470
|
+
return names[code] || code;
|
|
471
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { EnvironmentConfig } from '../types';
|
|
2
|
+
export interface ApiServiceOptions {
|
|
3
|
+
environmentConfig: EnvironmentConfig;
|
|
4
|
+
token?: string | null;
|
|
5
|
+
onTokenUpdate?: (token: string) => void;
|
|
6
|
+
onTokenClear?: () => void;
|
|
7
|
+
}
|
|
8
|
+
export interface FetchOptions {
|
|
9
|
+
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
10
|
+
body?: any;
|
|
11
|
+
headers?: Record<string, string>;
|
|
12
|
+
params?: Record<string, string>;
|
|
13
|
+
skipAuth?: boolean;
|
|
14
|
+
captureErrors?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface AnonymousTokenResponse {
|
|
17
|
+
token: string;
|
|
18
|
+
sessionId: string;
|
|
19
|
+
storeId: string;
|
|
20
|
+
accountId: string;
|
|
21
|
+
customerId: string;
|
|
22
|
+
role: 'anonymous';
|
|
23
|
+
}
|
|
24
|
+
export interface SessionInitResponse {
|
|
25
|
+
locale: string;
|
|
26
|
+
messages: Record<string, string>;
|
|
27
|
+
store: {
|
|
28
|
+
id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
domain: string;
|
|
31
|
+
currency: string;
|
|
32
|
+
locale: string;
|
|
33
|
+
integrations?: any[];
|
|
34
|
+
};
|
|
35
|
+
customer?: {
|
|
36
|
+
id: string;
|
|
37
|
+
email?: string;
|
|
38
|
+
firstName?: string;
|
|
39
|
+
lastName?: string;
|
|
40
|
+
phone?: string;
|
|
41
|
+
isAuthenticated: boolean;
|
|
42
|
+
role: 'authenticated' | 'anonymous';
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export declare class ApiService {
|
|
46
|
+
private config;
|
|
47
|
+
private token;
|
|
48
|
+
private onTokenUpdate?;
|
|
49
|
+
private onTokenClear?;
|
|
50
|
+
constructor(options: ApiServiceOptions);
|
|
51
|
+
updateToken(token: string | null): void;
|
|
52
|
+
updateConfig(config: EnvironmentConfig): void;
|
|
53
|
+
/**
|
|
54
|
+
* Store the store ID in localStorage
|
|
55
|
+
*/
|
|
56
|
+
storeStoreId(storeId: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Get the store ID from localStorage
|
|
59
|
+
*/
|
|
60
|
+
getStoredStoreId(): string | null;
|
|
61
|
+
/**
|
|
62
|
+
* Make an authenticated request to the API
|
|
63
|
+
*/
|
|
64
|
+
fetch<T = any>(endpoint: string, options?: FetchOptions): Promise<T>;
|
|
65
|
+
/**
|
|
66
|
+
* Create an anonymous token for the given store
|
|
67
|
+
*/
|
|
68
|
+
createAnonymousToken(storeId: string): Promise<AnonymousTokenResponse>;
|
|
69
|
+
/**
|
|
70
|
+
* Initialize a CMS session with device info and user data
|
|
71
|
+
*/
|
|
72
|
+
initializeSession(sessionData: {
|
|
73
|
+
storeId: string;
|
|
74
|
+
accountId: string;
|
|
75
|
+
customerId: string;
|
|
76
|
+
browserLocale?: string;
|
|
77
|
+
queryLocale?: string;
|
|
78
|
+
queryCurrency?: string;
|
|
79
|
+
utmSource?: string;
|
|
80
|
+
utmMedium?: string;
|
|
81
|
+
utmCampaign?: string;
|
|
82
|
+
browser?: string;
|
|
83
|
+
browserVersion?: string;
|
|
84
|
+
os?: string;
|
|
85
|
+
osVersion?: string;
|
|
86
|
+
deviceType?: string;
|
|
87
|
+
deviceModel?: string;
|
|
88
|
+
screenWidth?: number;
|
|
89
|
+
screenHeight?: number;
|
|
90
|
+
timeZone?: string;
|
|
91
|
+
}): Promise<SessionInitResponse>;
|
|
92
|
+
/**
|
|
93
|
+
* Get customer profile
|
|
94
|
+
*/
|
|
95
|
+
getCustomerProfile(customerId: string): Promise<any>;
|
|
96
|
+
/**
|
|
97
|
+
* Get session status
|
|
98
|
+
*/
|
|
99
|
+
getSessionStatus(sessionId: string): Promise<any>;
|
|
100
|
+
/**
|
|
101
|
+
* Update customer information (email, marketing preferences)
|
|
102
|
+
*/
|
|
103
|
+
updateCustomer(customerId: string, data: {
|
|
104
|
+
email: string;
|
|
105
|
+
acceptsMarketing?: boolean;
|
|
106
|
+
}): Promise<any>;
|
|
107
|
+
/**
|
|
108
|
+
* Update customer and checkout session information in one request
|
|
109
|
+
*/
|
|
110
|
+
updateCustomerAndSessionInfo(checkoutSessionId: string, data: {
|
|
111
|
+
customerData: {
|
|
112
|
+
email: string;
|
|
113
|
+
acceptsMarketing?: boolean;
|
|
114
|
+
};
|
|
115
|
+
shippingAddress: {
|
|
116
|
+
firstName: string;
|
|
117
|
+
lastName: string;
|
|
118
|
+
address1: string;
|
|
119
|
+
city: string;
|
|
120
|
+
country: string;
|
|
121
|
+
state: string;
|
|
122
|
+
postal: string;
|
|
123
|
+
phone: string;
|
|
124
|
+
};
|
|
125
|
+
billingAddress: {
|
|
126
|
+
firstName: string;
|
|
127
|
+
lastName: string;
|
|
128
|
+
address1: string;
|
|
129
|
+
city: string;
|
|
130
|
+
country: string;
|
|
131
|
+
state: string;
|
|
132
|
+
postal: string;
|
|
133
|
+
phone: string;
|
|
134
|
+
};
|
|
135
|
+
differentBillingAddress: boolean;
|
|
136
|
+
}): Promise<{
|
|
137
|
+
success: boolean;
|
|
138
|
+
errors?: Record<string, {
|
|
139
|
+
message: string;
|
|
140
|
+
type: string;
|
|
141
|
+
}>;
|
|
142
|
+
shippingCountryChanged: boolean;
|
|
143
|
+
billingCountryChanged: boolean;
|
|
144
|
+
}>;
|
|
145
|
+
/**
|
|
146
|
+
* Clear the authentication token
|
|
147
|
+
*/
|
|
148
|
+
clearToken(): void;
|
|
149
|
+
}
|