@tagadapay/plugin-sdk 2.8.8 → 2.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/react/config/environment.d.ts +1 -22
  2. package/dist/react/config/environment.js +1 -132
  3. package/dist/react/utils/deviceInfo.d.ts +1 -39
  4. package/dist/react/utils/deviceInfo.js +1 -163
  5. package/dist/react/utils/jwtDecoder.d.ts +1 -14
  6. package/dist/react/utils/jwtDecoder.js +1 -86
  7. package/dist/react/utils/tokenStorage.d.ts +1 -16
  8. package/dist/react/utils/tokenStorage.js +1 -53
  9. package/dist/v2/core/client.d.ts +92 -0
  10. package/dist/v2/core/client.js +386 -0
  11. package/dist/v2/core/config/environment.d.ts +22 -0
  12. package/dist/v2/core/config/environment.js +140 -0
  13. package/dist/v2/core/pathRemapping.js +61 -3
  14. package/dist/v2/core/resources/apiClient.d.ts +8 -0
  15. package/dist/v2/core/resources/apiClient.js +30 -9
  16. package/dist/v2/core/resources/funnel.d.ts +14 -0
  17. package/dist/v2/core/resources/payments.d.ts +23 -0
  18. package/dist/v2/core/types.d.ts +271 -0
  19. package/dist/v2/core/types.js +4 -0
  20. package/dist/v2/core/utils/deviceInfo.d.ts +39 -0
  21. package/dist/v2/core/utils/deviceInfo.js +162 -0
  22. package/dist/v2/core/utils/eventDispatcher.d.ts +10 -0
  23. package/dist/v2/core/utils/eventDispatcher.js +24 -0
  24. package/dist/v2/core/utils/jwtDecoder.d.ts +14 -0
  25. package/dist/v2/core/utils/jwtDecoder.js +85 -0
  26. package/dist/v2/core/utils/pluginConfig.js +6 -0
  27. package/dist/v2/core/utils/tokenStorage.d.ts +19 -0
  28. package/dist/v2/core/utils/tokenStorage.js +52 -0
  29. package/dist/v2/react/components/DebugDrawer.js +90 -1
  30. package/dist/v2/react/hooks/__examples__/FunnelContextExample.d.ts +12 -0
  31. package/dist/v2/react/hooks/__examples__/FunnelContextExample.js +54 -0
  32. package/dist/v2/react/hooks/useFunnel.d.ts +1 -1
  33. package/dist/v2/react/hooks/useFunnel.js +209 -32
  34. package/dist/v2/react/hooks/useGoogleAutocomplete.js +26 -18
  35. package/dist/v2/react/hooks/useISOData.js +4 -2
  36. package/dist/v2/react/hooks/useOffersQuery.d.ts +24 -29
  37. package/dist/v2/react/hooks/useOffersQuery.js +164 -204
  38. package/dist/v2/react/hooks/usePaymentQuery.js +99 -6
  39. package/dist/v2/react/providers/TagadaProvider.d.ts +8 -21
  40. package/dist/v2/react/providers/TagadaProvider.js +79 -673
  41. package/package.json +1 -1
@@ -5,7 +5,7 @@
5
5
  * and the v2 ApiClient for API calls.
6
6
  */
7
7
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
8
- import { useCallback, useEffect, useMemo, useState } from 'react';
8
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
9
9
  import { FunnelActionType, FunnelResource } from '../../core/resources/funnel';
10
10
  import { useTagadaContext } from '../providers/TagadaProvider';
11
11
  import { getGlobalApiClient } from './useApiQuery';
@@ -20,7 +20,7 @@ const funnelQueryKeys = {
20
20
  * Modern funnel navigation using TanStack Query for state management
21
21
  * and the v2 ApiClient architecture.
22
22
  */
23
- export function useFunnel(options) {
23
+ export function useFunnel(options = {}) {
24
24
  const { auth, store, debugMode, updateFunnelDebugData } = useTagadaContext();
25
25
  const queryClient = useQueryClient();
26
26
  const apiClient = getGlobalApiClient();
@@ -29,10 +29,53 @@ export function useFunnel(options) {
29
29
  const [context, setContext] = useState(null);
30
30
  const [initializationAttempted, setInitializationAttempted] = useState(false);
31
31
  const [initializationError, setInitializationError] = useState(null);
32
+ // Track the last processed URL funnelId to avoid re-processing on context changes
33
+ const lastProcessedUrlFunnelIdRef = useRef(undefined);
34
+ // Check if we have an existing session in cookies (to avoid unnecessary re-initialization)
35
+ const hasExistingSessionCookie = useMemo(() => {
36
+ if (typeof document === 'undefined')
37
+ return false;
38
+ const funnelSessionCookie = document.cookie
39
+ .split('; ')
40
+ .find(row => row.startsWith('tgd-funnel-session-id='));
41
+ return !!funnelSessionCookie;
42
+ }, []); // Only check once on mount
32
43
  const currentStepId = options.currentStepId || context?.currentStepId;
33
- // Check for URL parameter overrides
34
- const urlParams = typeof window !== 'undefined' ? new URLSearchParams(window.location.search) : new URLSearchParams();
35
- const urlFunnelId = urlParams.get('funnelId') || undefined;
44
+ // Check for URL parameter overrides - recalculate on every render to detect URL changes
45
+ // This is cheap and ensures we always have the latest URL params
46
+ const [currentUrl, setCurrentUrl] = useState(() => typeof window !== 'undefined' ? window.location.href : '');
47
+ // Listen for URL changes (navigation)
48
+ useEffect(() => {
49
+ if (typeof window === 'undefined')
50
+ return;
51
+ const updateUrl = () => {
52
+ setCurrentUrl(window.location.href);
53
+ };
54
+ // Listen for popstate (back/forward buttons) and pushState/replaceState
55
+ window.addEventListener('popstate', updateUrl);
56
+ // Also update on any navigation
57
+ const originalPushState = window.history.pushState;
58
+ const originalReplaceState = window.history.replaceState;
59
+ window.history.pushState = function (...args) {
60
+ originalPushState.apply(window.history, args);
61
+ updateUrl();
62
+ };
63
+ window.history.replaceState = function (...args) {
64
+ originalReplaceState.apply(window.history, args);
65
+ updateUrl();
66
+ };
67
+ return () => {
68
+ window.removeEventListener('popstate', updateUrl);
69
+ window.history.pushState = originalPushState;
70
+ window.history.replaceState = originalReplaceState;
71
+ };
72
+ }, []);
73
+ const urlFunnelId = useMemo(() => {
74
+ if (typeof window === 'undefined')
75
+ return undefined;
76
+ const params = new URLSearchParams(window.location.search);
77
+ return params.get('funnelId') || undefined;
78
+ }, [currentUrl]); // Re-compute when URL changes
36
79
  const effectiveFunnelId = urlFunnelId || options.funnelId;
37
80
  /**
38
81
  * Fetch debug data for the funnel debugger
@@ -66,13 +109,8 @@ export function useFunnel(options) {
66
109
  console.warn('🍪 Funnel: No session ID available for query');
67
110
  return null;
68
111
  }
69
- // ✅ Automatically include currentUrl for session sync on page load/refresh
70
- const currentUrl = typeof window !== 'undefined' ? window.location.href : undefined;
71
112
  console.log(`🍪 Funnel: Fetching session data for ID: ${context.sessionId}`);
72
- if (currentUrl) {
73
- console.log(`🍪 Funnel: Including current URL for sync: ${currentUrl}`);
74
- }
75
- const response = await funnelResource.getSession(context.sessionId, currentUrl);
113
+ const response = await funnelResource.getSession(context.sessionId);
76
114
  console.log(`🍪 Funnel: Session fetch response:`, response);
77
115
  if (response.success && response.context) {
78
116
  return response.context;
@@ -90,8 +128,14 @@ export function useFunnel(options) {
90
128
  if (!auth.session?.customerId || !store?.id) {
91
129
  throw new Error('Authentication required for funnel session');
92
130
  }
131
+ // Get CURRENT URL params (not cached) to ensure we have latest values
132
+ const currentUrlParams = typeof window !== 'undefined'
133
+ ? new URLSearchParams(window.location.search)
134
+ : new URLSearchParams();
135
+ const currentUrlFunnelId = currentUrlParams.get('funnelId') || undefined;
136
+ const currentEffectiveFunnelId = currentUrlFunnelId || options.funnelId;
93
137
  // Check for existing session ID in URL parameters
94
- let existingSessionId = urlParams.get('funnelSessionId') || undefined;
138
+ let existingSessionId = currentUrlParams.get('funnelSessionId') || undefined;
95
139
  if (existingSessionId) {
96
140
  console.log(`🍪 Funnel: Found session ID in URL params: ${existingSessionId}`);
97
141
  }
@@ -102,11 +146,23 @@ export function useFunnel(options) {
102
146
  .find(row => row.startsWith('tgd-funnel-session-id='));
103
147
  existingSessionId = funnelSessionCookie ? funnelSessionCookie.split('=')[1] : undefined;
104
148
  if (existingSessionId) {
105
- console.log(`🍪 Funnel: Found session in cookie: ${existingSessionId}`);
149
+ console.log(`🍪 Funnel: Found existing session in cookie: ${existingSessionId}`);
106
150
  }
107
151
  }
108
- if (!existingSessionId) {
109
- console.log(`🍪 Funnel: No existing session found in URL params or cookie`);
152
+ // Log initialization strategy
153
+ console.log(`🍪 Funnel: Initialize request:`);
154
+ console.log(` - Existing session ID: ${existingSessionId || 'none'}`);
155
+ console.log(` - URL funnelId: ${currentUrlFunnelId || 'none'}`);
156
+ console.log(` - Hook funnelId: ${options.funnelId || 'none'}`);
157
+ console.log(` - Effective funnelId to send: ${currentEffectiveFunnelId || 'none (will use existing or backend default)'}`);
158
+ if (existingSessionId && !currentEffectiveFunnelId) {
159
+ console.log(` → Strategy: REUSE existing session from cookie`);
160
+ }
161
+ else if (existingSessionId && currentEffectiveFunnelId) {
162
+ console.log(` → Strategy: VALIDATE existing session matches funnelId, or create new`);
163
+ }
164
+ else {
165
+ console.log(` → Strategy: CREATE new session`);
110
166
  }
111
167
  // Send minimal CMS session data
112
168
  const cmsSessionData = {
@@ -115,17 +171,35 @@ export function useFunnel(options) {
115
171
  sessionId: auth.session.sessionId,
116
172
  accountId: auth.session.accountId
117
173
  };
174
+ // Get current URL for session synchronization
175
+ const currentUrl = typeof window !== 'undefined' ? window.location.href : undefined;
118
176
  // Call API to initialize session - backend will restore existing or create new
119
177
  const requestBody = {
120
178
  cmsSession: cmsSessionData,
121
179
  entryStepId, // Optional override
122
- existingSessionId // Pass existing session ID from URL or cookie
180
+ existingSessionId, // Pass existing session ID from URL or cookie
181
+ currentUrl // Include current URL for step tracking
123
182
  };
124
183
  // Only include funnelId if it's provided (for backend fallback)
125
- if (effectiveFunnelId) {
126
- requestBody.funnelId = effectiveFunnelId;
184
+ if (currentEffectiveFunnelId) {
185
+ requestBody.funnelId = currentEffectiveFunnelId;
127
186
  }
187
+ console.log(`📤 Funnel: Sending initialize request to backend:`);
188
+ console.log(` Request body:`, JSON.stringify({
189
+ ...requestBody,
190
+ cmsSession: { ...cmsSessionData, sessionId: `${cmsSessionData.sessionId.substring(0, 20)}...` }
191
+ }, null, 2));
128
192
  const response = await funnelResource.initialize(requestBody);
193
+ console.log(`📥 Funnel: Received response from backend:`);
194
+ console.log(` Success: ${response.success}`);
195
+ if (response.context) {
196
+ console.log(` Returned session ID: ${response.context.sessionId}`);
197
+ console.log(` Returned funnel ID: ${response.context.funnelId}`);
198
+ console.log(` Is same session? ${response.context.sessionId === existingSessionId ? '✅ YES (reused)' : '❌ NO (new session created)'}`);
199
+ }
200
+ if (response.error) {
201
+ console.log(` Error: ${response.error}`);
202
+ }
129
203
  if (response.success && response.context) {
130
204
  return response.context;
131
205
  }
@@ -138,7 +212,10 @@ export function useFunnel(options) {
138
212
  setInitializationError(null);
139
213
  // Set session cookie for persistence across page reloads
140
214
  setSessionCookie(newContext.sessionId);
141
- console.log(`🍪 Funnel: Initialized session for funnel ${effectiveFunnelId || 'default'}`, newContext);
215
+ console.log(`✅ Funnel: Session initialized/loaded successfully`);
216
+ console.log(` - Session ID: ${newContext.sessionId}`);
217
+ console.log(` - Funnel ID: ${newContext.funnelId}`);
218
+ console.log(` - Current Step: ${newContext.currentStepId}`);
142
219
  // Fetch debug data if in debug mode
143
220
  if (debugMode) {
144
221
  void fetchFunnelDebugData(newContext.sessionId);
@@ -317,6 +394,8 @@ export function useFunnel(options) {
317
394
  return;
318
395
  console.log(`🍪 Funnel: Ended session ${context.sessionId}`);
319
396
  setContext(null);
397
+ // Reset the processed URL funnelId ref to allow re-initialization
398
+ lastProcessedUrlFunnelIdRef.current = undefined;
320
399
  // Clear queries
321
400
  queryClient.removeQueries({
322
401
  queryKey: funnelQueryKeys.session(context.sessionId)
@@ -421,29 +500,127 @@ export function useFunnel(options) {
421
500
  setInitializationError(null);
422
501
  await initializeSession();
423
502
  }, [initializeSession]);
424
- // Auto-initialize if requested and not already initialized
503
+ /**
504
+ * Auto-initialization effect
505
+ *
506
+ * Handles funnel session initialization with the following logic:
507
+ * 1. If no session exists => Initialize with URL funnelId or hook funnelId or backend default
508
+ * 2. If session exists + explicit funnelId provided that differs => Reset and create new
509
+ * 3. If session exists + no funnelId provided => Keep existing session
510
+ *
511
+ * IMPORTANT: Only resets session if an EXPLICIT funnelId is provided that differs
512
+ * from the current session. If no funnelId is provided, keeps the existing session.
513
+ *
514
+ * Priority: URL funnelId > Hook funnelId > Existing session funnelId > Backend default
515
+ */
425
516
  useEffect(() => {
426
- if (options.autoInitialize &&
427
- !context &&
428
- !initializationAttempted &&
429
- !initializationError &&
430
- auth.session?.customerId &&
431
- store?.id &&
432
- !initializeMutation.isPending) {
433
- console.log('🍪 Funnel: Auto-initializing session...');
517
+ console.log('🔍 Funnel: Auto-init effect triggered');
518
+ console.log(` - autoInitialize: ${options.autoInitialize ?? true}`);
519
+ console.log(` - hasAuth: ${!!auth.session?.customerId}`);
520
+ console.log(` - hasStore: ${!!store?.id}`);
521
+ console.log(` - isPending: ${initializeMutation.isPending}`);
522
+ console.log(` - hasContext: ${!!context}`);
523
+ console.log(` - context.sessionId: ${context?.sessionId || 'none'}`);
524
+ console.log(` - context.funnelId: ${context?.funnelId || 'none'}`);
525
+ console.log(` - urlFunnelId: ${urlFunnelId || 'none'}`);
526
+ console.log(` - options.funnelId: ${options.funnelId || 'none'}`);
527
+ console.log(` - initializationAttempted: ${initializationAttempted}`);
528
+ console.log(` - hasExistingSessionCookie: ${hasExistingSessionCookie}`);
529
+ // Skip if auto-initialize is disabled
530
+ const autoInit = options.autoInitialize ?? true; // Default to true
531
+ if (!autoInit) {
532
+ console.log('⏭️ Funnel: Skipping - auto-initialize disabled');
533
+ return;
534
+ }
535
+ // Skip if required dependencies are not available
536
+ if (!auth.session?.customerId || !store?.id) {
537
+ console.log('⏭️ Funnel: Skipping - missing auth or store');
538
+ return;
539
+ }
540
+ // Skip if already initializing
541
+ if (initializeMutation.isPending) {
542
+ console.log('⏭️ Funnel: Skipping - already initializing');
543
+ return;
544
+ }
545
+ // Determine if we have an explicit funnelId request (URL has priority)
546
+ const explicitFunnelId = urlFunnelId || options.funnelId;
547
+ console.log(` - explicitFunnelId: ${explicitFunnelId || 'none'}`);
548
+ // Case 1: No session exists yet - need to initialize
549
+ if (!context) {
550
+ console.log('📍 Funnel: Case 1 - No context exists');
551
+ // Check if we've already attempted initialization
552
+ if (!initializationAttempted) {
553
+ if (hasExistingSessionCookie) {
554
+ console.log('🍪 Funnel: Loading existing session from cookie...');
555
+ }
556
+ else {
557
+ console.log('🍪 Funnel: No session found - creating new session...');
558
+ }
559
+ if (explicitFunnelId) {
560
+ console.log(` with funnelId: ${explicitFunnelId}`);
561
+ }
562
+ setInitializationAttempted(true);
563
+ initializeSession().catch(error => {
564
+ console.error('❌ Funnel: Auto-initialization failed:', error);
565
+ });
566
+ }
567
+ else {
568
+ console.log('⏭️ Funnel: Skipping - already attempted initialization');
569
+ }
570
+ return;
571
+ }
572
+ console.log('📍 Funnel: Case 2 - Context exists, checking for reset needs');
573
+ // Case 2: Session exists - check if we need to reset it
574
+ // ONLY reset if an explicit funnelId is provided AND it differs from current session
575
+ if (explicitFunnelId && context.funnelId && explicitFunnelId !== context.funnelId) {
576
+ console.log(`🔍 Funnel: Mismatch check - explicitFunnelId: ${explicitFunnelId}, context.funnelId: ${context.funnelId}`);
577
+ // Check if we've already processed this funnelId to prevent loops
578
+ if (lastProcessedUrlFunnelIdRef.current === explicitFunnelId) {
579
+ console.log('⏭️ Funnel: Skipping - already processed this funnelId');
580
+ return;
581
+ }
582
+ console.log(`🔄 Funnel: Explicit funnelId mismatch detected!`);
583
+ console.log(` Current session funnelId: ${context.funnelId}`);
584
+ console.log(` Requested funnelId: ${explicitFunnelId}`);
585
+ console.log(` Resetting session...`);
586
+ // Mark this funnelId as processed
587
+ lastProcessedUrlFunnelIdRef.current = explicitFunnelId;
588
+ // Clear existing session
589
+ setContext(null);
590
+ setInitializationAttempted(false);
591
+ setInitializationError(null);
592
+ // Clear session cookie
593
+ document.cookie = 'tgd-funnel-session-id=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax';
594
+ // Clear queries for old session
595
+ queryClient.removeQueries({
596
+ queryKey: funnelQueryKeys.session(context.sessionId)
597
+ });
598
+ // Initialize new session with correct funnelId
599
+ console.log(`🍪 Funnel: Creating new session with funnelId: ${explicitFunnelId}`);
434
600
  initializeSession().catch(error => {
435
- console.error('Auto-initialization failed - will not retry:', error);
601
+ console.error(' Funnel: Failed to reset session:', error);
436
602
  });
437
603
  }
604
+ else {
605
+ // Case 3: Session exists and no conflicting funnelId - keep using it
606
+ console.log('✅ Funnel: Case 3 - Keeping existing session (no reset needed)');
607
+ console.log(` - explicitFunnelId: ${explicitFunnelId || 'none (will keep existing)'}`);
608
+ console.log(` - context.funnelId: ${context.funnelId}`);
609
+ console.log(` - Match or no explicit request: keeping session ${context.sessionId}`);
610
+ }
438
611
  }, [
439
612
  options.autoInitialize,
440
- context,
613
+ options.funnelId,
614
+ urlFunnelId,
615
+ context?.funnelId,
616
+ context?.sessionId,
441
617
  initializationAttempted,
442
- initializationError,
443
618
  auth.session?.customerId,
444
619
  store?.id,
445
620
  initializeMutation.isPending,
446
- initializeSession
621
+ initializeSession,
622
+ hasExistingSessionCookie,
623
+ queryClient
447
624
  ]);
448
625
  // Sync session data from query to local state
449
626
  useEffect(() => {
@@ -15,6 +15,7 @@ export function useGoogleAutocomplete(options) {
15
15
  const autocompleteServiceRef = useRef(null);
16
16
  const placesServiceRef = useRef(null);
17
17
  const scriptLoadedRef = useRef(false);
18
+ const debounceTimeoutRef = useRef(null);
18
19
  // Inject Google Maps script
19
20
  useEffect(() => {
20
21
  if (!apiKey) {
@@ -97,25 +98,32 @@ export function useGoogleAutocomplete(options) {
97
98
  setPredictions([]);
98
99
  return;
99
100
  }
100
- setIsLoading(true);
101
- const request = {
102
- input,
103
- ...(countryRestriction && {
104
- componentRestrictions: { country: countryRestriction.toLowerCase() },
105
- }),
106
- };
107
- autocompleteServiceRef.current.getPlacePredictions(request, (results, status) => {
108
- setIsLoading(false);
109
- if (status === window.google.maps.places.PlacesServiceStatus.OK && results) {
110
- setPredictions(results);
111
- }
112
- else {
113
- setPredictions([]);
114
- if (status !== window.google.maps.places.PlacesServiceStatus.ZERO_RESULTS) {
115
- // Prediction failed but not zero results
101
+ // Clear existing timeout
102
+ if (debounceTimeoutRef.current) {
103
+ clearTimeout(debounceTimeoutRef.current);
104
+ }
105
+ // Set new timeout
106
+ debounceTimeoutRef.current = setTimeout(() => {
107
+ setIsLoading(true);
108
+ const request = {
109
+ input,
110
+ ...(countryRestriction && {
111
+ componentRestrictions: { country: countryRestriction.toLowerCase() },
112
+ }),
113
+ };
114
+ autocompleteServiceRef.current.getPlacePredictions(request, (results, status) => {
115
+ setIsLoading(false);
116
+ if (status === window.google.maps.places.PlacesServiceStatus.OK && results) {
117
+ setPredictions(results);
116
118
  }
117
- }
118
- });
119
+ else {
120
+ setPredictions([]);
121
+ if (status !== window.google.maps.places.PlacesServiceStatus.ZERO_RESULTS) {
122
+ // Prediction failed but not zero results
123
+ }
124
+ }
125
+ });
126
+ }, 300); // 300ms debounce
119
127
  }, [initializeServices, isScriptLoaded]);
120
128
  // Get detailed place information
121
129
  const getPlaceDetails = useCallback((placeId) => {
@@ -25,8 +25,10 @@ export function useISOData(language = 'en', autoImport = true, disputeSetting =
25
25
  }, [language, autoImport]);
26
26
  const data = useMemo(() => {
27
27
  try {
28
+ console.log('[SDK] Loading ISO data for language:', language, 'autoImport:', autoImport);
28
29
  // Get countries from pre-built data with language support
29
30
  const countriesArray = getCountries(language);
31
+ console.log('[SDK] Loaded countries count:', countriesArray.length);
30
32
  // Transform to our expected format (Record<string, ISOCountry>)
31
33
  const countries = {};
32
34
  countriesArray.forEach((country) => {
@@ -85,8 +87,8 @@ export function useISOData(language = 'en', autoImport = true, disputeSetting =
85
87
  registeredLanguages,
86
88
  };
87
89
  }
88
- catch (_error) {
89
- // Error handling removed
90
+ catch (error) {
91
+ console.error('[SDK] Error loading ISO data:', error);
90
92
  return {
91
93
  countries: {},
92
94
  getRegions: () => [],
@@ -2,8 +2,8 @@
2
2
  * Offers Hook using TanStack Query
3
3
  * Handles offers with automatic caching
4
4
  */
5
- import { Offer } from '../../core/resources/offers';
6
- import { CheckoutSessionState, OrderSummary, CurrencyOptions } from '../../core/resources/postPurchases';
5
+ import { Offer, OfferSummary } from '../../core/resources/offers';
6
+ import { CurrencyOptions, OrderSummary } from '../../core/resources/postPurchases';
7
7
  export interface UseOffersQueryOptions {
8
8
  /**
9
9
  * Array of offer IDs to fetch
@@ -18,32 +18,27 @@ export interface UseOffersQueryOptions {
18
18
  * Return URL for checkout sessions
19
19
  */
20
20
  returnUrl?: string;
21
+ /**
22
+ * Order ID to associate with the offers (required for payments)
23
+ */
24
+ orderId?: string;
21
25
  }
22
26
  export interface UseOffersQueryResult {
23
27
  offers: Offer[];
24
28
  isLoading: boolean;
25
29
  error: Error | null;
26
- refetch: () => Promise<void>;
27
- createCheckoutSession: (offerId: string, options?: {
28
- returnUrl?: string;
29
- }) => Promise<{
30
- checkoutUrl: string;
31
- }>;
30
+ /**
31
+ * Pay for an offer
32
+ * Initializes a checkout session and pays it
33
+ */
32
34
  payOffer: (offerId: string, orderId?: string) => Promise<void>;
33
- transformToCheckout: (offerId: string, options?: {
34
- returnUrl?: string;
35
- }) => Promise<{
36
- checkoutUrl: string;
37
- }>;
38
- getOffer: (offerId: string) => Offer | undefined;
39
- getTotalValue: () => number;
40
- getTotalSavings: () => number;
41
- payWithCheckoutSession: (checkoutSessionId: string, orderId?: string) => Promise<void>;
42
- initCheckoutSession: (offerId: string, orderId: string, customerId?: string) => Promise<{
43
- checkoutSessionId: string;
44
- }>;
45
- getCheckoutSessionState: (offerId: string) => CheckoutSessionState | null;
46
- initializeOfferCheckout: (offerId: string) => Promise<void>;
35
+ /**
36
+ * Preview an offer's price/summary
37
+ */
38
+ preview: (offerId: string) => Promise<OrderSummary | OfferSummary | null>;
39
+ /**
40
+ * Get available variants for a product in an offer
41
+ */
47
42
  getAvailableVariants: (offerId: string, productId: string) => {
48
43
  variantId: string;
49
44
  variantName: string;
@@ -53,13 +48,13 @@ export interface UseOffersQueryResult {
53
48
  priceId: string;
54
49
  currencyOptions: CurrencyOptions;
55
50
  }[];
56
- selectVariant: (offerId: string, productId: string, variantId: string) => Promise<void>;
57
- getOrderSummary: (offerId: string) => OrderSummary | null;
51
+ /**
52
+ * Select a variant for a product in an offer
53
+ */
54
+ selectVariant: (offerId: string, productId: string, variantId: string) => Promise<OrderSummary | null>;
55
+ /**
56
+ * Check if variants are loading for a product
57
+ */
58
58
  isLoadingVariants: (offerId: string, productId: string) => boolean;
59
- isUpdatingOrderSummary: (offerId: string) => boolean;
60
- confirmPurchase: (offerId: string, options?: {
61
- draft?: boolean;
62
- returnUrl?: string;
63
- }) => Promise<void>;
64
59
  }
65
60
  export declare function useOffersQuery(options?: UseOffersQueryOptions): UseOffersQueryResult;