@tagadapay/plugin-sdk 2.4.39 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/react/hooks/useCheckout.js +19 -2
- package/dist/react/hooks/useCheckoutSession.d.ts +19 -0
- package/dist/react/hooks/useCheckoutSession.js +108 -0
- package/dist/react/hooks/useCheckoutToken.d.ts +17 -0
- package/dist/react/hooks/useCheckoutToken.js +80 -0
- package/dist/react/hooks/useOrderBump.js +92 -13
- package/dist/react/hooks/useOrderBumpV2.d.ts +17 -0
- package/dist/react/hooks/useOrderBumpV2.js +95 -0
- package/dist/react/hooks/useOrderBumpV3.d.ts +23 -0
- package/dist/react/hooks/useOrderBumpV3.js +109 -0
- package/dist/react/hooks/usePostPurchases.js +11 -5
- package/dist/react/index.d.ts +8 -0
- package/dist/react/index.js +4 -0
- package/dist/react/services/apiService.d.ts +1 -0
- package/dist/react/services/apiService.js +3 -0
- package/dist/v2/core/googleAutocomplete.d.ts +65 -0
- package/dist/v2/core/googleAutocomplete.js +94 -0
- package/dist/v2/core/index.d.ts +8 -0
- package/dist/v2/core/index.js +11 -0
- package/dist/v2/core/isoData.d.ts +50 -0
- package/dist/v2/core/isoData.js +103 -0
- package/dist/v2/core/resources/apiClient.d.ts +25 -0
- package/dist/v2/core/resources/apiClient.js +95 -0
- package/dist/v2/core/resources/checkout.d.ts +189 -0
- package/dist/v2/core/resources/checkout.js +119 -0
- package/dist/v2/core/resources/index.d.ts +13 -0
- package/dist/v2/core/resources/index.js +13 -0
- package/dist/v2/core/resources/offers.d.ts +98 -0
- package/dist/v2/core/resources/offers.js +115 -0
- package/dist/v2/core/resources/orders.d.ts +40 -0
- package/dist/v2/core/resources/orders.js +59 -0
- package/dist/v2/core/resources/payments.d.ts +140 -0
- package/dist/v2/core/resources/payments.js +126 -0
- package/dist/v2/core/resources/postPurchases.d.ts +182 -0
- package/dist/v2/core/resources/postPurchases.js +116 -0
- package/dist/v2/core/resources/products.d.ts +29 -0
- package/dist/v2/core/resources/products.js +49 -0
- package/dist/v2/core/resources/promotions.d.ts +45 -0
- package/dist/v2/core/resources/promotions.js +87 -0
- package/dist/v2/core/resources/threeds.d.ts +23 -0
- package/dist/v2/core/resources/threeds.js +15 -0
- package/dist/v2/core/utils/checkout.d.ts +24 -0
- package/dist/v2/core/utils/checkout.js +30 -0
- package/dist/v2/core/utils/currency.d.ts +28 -0
- package/dist/v2/core/utils/currency.js +272 -0
- package/dist/v2/core/utils/index.d.ts +12 -0
- package/dist/v2/core/utils/index.js +12 -0
- package/dist/v2/core/utils/order.d.ts +159 -0
- package/dist/v2/core/utils/order.js +42 -0
- package/dist/v2/core/utils/orderBump.d.ts +40 -0
- package/dist/v2/core/utils/orderBump.js +47 -0
- package/dist/v2/core/utils/pluginConfig.d.ts +43 -0
- package/dist/v2/core/utils/pluginConfig.js +155 -0
- package/dist/v2/core/utils/postPurchases.d.ts +32 -0
- package/dist/v2/core/utils/postPurchases.js +42 -0
- package/dist/v2/core/utils/products.d.ts +58 -0
- package/dist/v2/core/utils/products.js +64 -0
- package/dist/v2/core/utils/promotions.d.ts +24 -0
- package/dist/v2/core/utils/promotions.js +30 -0
- package/dist/v2/index.d.ts +19 -0
- package/dist/v2/index.js +15 -0
- package/dist/v2/react/components/DebugDrawer.d.ts +7 -0
- package/dist/v2/react/components/DebugDrawer.js +383 -0
- package/dist/v2/react/hooks/useApiQuery.d.ts +28 -0
- package/dist/v2/react/hooks/useApiQuery.js +84 -0
- package/dist/v2/react/hooks/useCheckoutQuery.d.ts +39 -0
- package/dist/v2/react/hooks/useCheckoutQuery.js +208 -0
- package/dist/v2/react/hooks/useCheckoutToken.d.ts +17 -0
- package/dist/v2/react/hooks/useCheckoutToken.js +80 -0
- package/dist/v2/react/hooks/useCurrency.d.ts +9 -0
- package/dist/v2/react/hooks/useCurrency.js +21 -0
- package/dist/v2/react/hooks/useGeoLocation.d.ts +138 -0
- package/dist/v2/react/hooks/useGeoLocation.js +126 -0
- package/dist/v2/react/hooks/useGoogleAutocomplete.d.ts +74 -0
- package/dist/v2/react/hooks/useGoogleAutocomplete.js +207 -0
- package/dist/v2/react/hooks/useISOData.d.ts +61 -0
- package/dist/v2/react/hooks/useISOData.js +176 -0
- package/dist/v2/react/hooks/useOffersQuery.d.ts +65 -0
- package/dist/v2/react/hooks/useOffersQuery.js +353 -0
- package/dist/v2/react/hooks/useOrderBumpQuery.d.ts +20 -0
- package/dist/v2/react/hooks/useOrderBumpQuery.js +88 -0
- package/dist/v2/react/hooks/useOrderQuery.d.ts +29 -0
- package/dist/v2/react/hooks/useOrderQuery.js +98 -0
- package/dist/v2/react/hooks/usePaymentPolling.d.ts +45 -0
- package/dist/v2/react/hooks/usePaymentPolling.js +153 -0
- package/dist/v2/react/hooks/usePaymentQuery.d.ts +19 -0
- package/dist/v2/react/hooks/usePaymentQuery.js +283 -0
- package/dist/v2/react/hooks/usePluginConfig.d.ts +16 -0
- package/dist/v2/react/hooks/usePluginConfig.js +36 -0
- package/dist/v2/react/hooks/usePostPurchasesQuery.d.ts +63 -0
- package/dist/v2/react/hooks/usePostPurchasesQuery.js +365 -0
- package/dist/v2/react/hooks/useProductsQuery.d.ts +31 -0
- package/dist/v2/react/hooks/useProductsQuery.js +102 -0
- package/dist/v2/react/hooks/usePromotionsQuery.d.ts +28 -0
- package/dist/v2/react/hooks/usePromotionsQuery.js +97 -0
- package/dist/v2/react/hooks/useThreeds.d.ts +36 -0
- package/dist/v2/react/hooks/useThreeds.js +166 -0
- package/dist/v2/react/hooks/useThreedsModal.d.ts +13 -0
- package/dist/v2/react/hooks/useThreedsModal.js +343 -0
- package/dist/v2/react/index.d.ts +38 -0
- package/dist/v2/react/index.js +27 -0
- package/dist/v2/react/providers/TagadaProvider.d.ts +63 -0
- package/dist/v2/react/providers/TagadaProvider.js +680 -0
- package/package.json +10 -3
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Autocomplete Hook - V2 Implementation
|
|
3
|
+
* Compatible with V1 interface while using V2 core architecture
|
|
4
|
+
*/
|
|
5
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
6
|
+
/**
|
|
7
|
+
* React hook for Google Places Autocomplete with automatic script injection
|
|
8
|
+
* Automatically loads the Google Maps JavaScript API with Places library
|
|
9
|
+
*/
|
|
10
|
+
export function useGoogleAutocomplete(options) {
|
|
11
|
+
const { apiKey, libraries = ['places'], version = 'weekly', language, region } = options;
|
|
12
|
+
const [predictions, setPredictions] = useState([]);
|
|
13
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
14
|
+
const [isScriptLoaded, setIsScriptLoaded] = useState(false);
|
|
15
|
+
const autocompleteServiceRef = useRef(null);
|
|
16
|
+
const placesServiceRef = useRef(null);
|
|
17
|
+
const scriptLoadedRef = useRef(false);
|
|
18
|
+
// Inject Google Maps script
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (!apiKey) {
|
|
21
|
+
console.error('Google Maps API key is required');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (scriptLoadedRef.current || window.google?.maps) {
|
|
25
|
+
setIsScriptLoaded(true);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// Check if script is already being loaded
|
|
29
|
+
const existingScript = document.querySelector('script[src*="maps.googleapis.com"]');
|
|
30
|
+
if (existingScript) {
|
|
31
|
+
// Wait for existing script to load
|
|
32
|
+
const checkLoaded = () => {
|
|
33
|
+
if (window.google?.maps?.places?.AutocompleteService) {
|
|
34
|
+
setIsScriptLoaded(true);
|
|
35
|
+
scriptLoadedRef.current = true;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
setTimeout(checkLoaded, 100);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
checkLoaded();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Create and inject the script
|
|
45
|
+
const script = document.createElement('script');
|
|
46
|
+
const params = new URLSearchParams({
|
|
47
|
+
key: apiKey,
|
|
48
|
+
libraries: libraries.join(','),
|
|
49
|
+
v: version,
|
|
50
|
+
});
|
|
51
|
+
if (language)
|
|
52
|
+
params.append('language', language);
|
|
53
|
+
if (region)
|
|
54
|
+
params.append('region', region);
|
|
55
|
+
script.src = `https://maps.googleapis.com/maps/api/js?${params.toString()}`;
|
|
56
|
+
script.async = true;
|
|
57
|
+
script.defer = true;
|
|
58
|
+
script.onload = () => {
|
|
59
|
+
console.log('🗺️ Google Maps API loaded successfully');
|
|
60
|
+
setIsScriptLoaded(true);
|
|
61
|
+
scriptLoadedRef.current = true;
|
|
62
|
+
};
|
|
63
|
+
script.onerror = () => {
|
|
64
|
+
console.error('Failed to load Google Maps API');
|
|
65
|
+
};
|
|
66
|
+
document.head.appendChild(script);
|
|
67
|
+
// Cleanup function
|
|
68
|
+
return () => {
|
|
69
|
+
// Note: We don't remove the script as it might be used by other components
|
|
70
|
+
// The script will remain in the DOM for the session
|
|
71
|
+
};
|
|
72
|
+
}, [apiKey, libraries, version, language, region]);
|
|
73
|
+
// Initialize Google Places services
|
|
74
|
+
const initializeServices = useCallback(() => {
|
|
75
|
+
if (typeof window === 'undefined')
|
|
76
|
+
return false;
|
|
77
|
+
if (!window.google?.maps?.places?.AutocompleteService) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
if (!autocompleteServiceRef.current) {
|
|
81
|
+
autocompleteServiceRef.current = new window.google.maps.places.AutocompleteService();
|
|
82
|
+
}
|
|
83
|
+
if (!placesServiceRef.current) {
|
|
84
|
+
// Create a dummy map for PlacesService (required by Google API)
|
|
85
|
+
const map = new window.google.maps.Map(document.createElement('div'));
|
|
86
|
+
placesServiceRef.current = new window.google.maps.places.PlacesService(map);
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
}, []);
|
|
90
|
+
// Search for place predictions
|
|
91
|
+
const searchPlaces = useCallback((input, countryRestriction) => {
|
|
92
|
+
if (!isScriptLoaded) {
|
|
93
|
+
console.warn('Google Maps API not yet loaded');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (!initializeServices()) {
|
|
97
|
+
console.error('Google Places services not available');
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (input.length < 3) {
|
|
101
|
+
setPredictions([]);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
setIsLoading(true);
|
|
105
|
+
const request = {
|
|
106
|
+
input,
|
|
107
|
+
...(countryRestriction && {
|
|
108
|
+
componentRestrictions: { country: countryRestriction.toLowerCase() },
|
|
109
|
+
}),
|
|
110
|
+
};
|
|
111
|
+
autocompleteServiceRef.current.getPlacePredictions(request, (results, status) => {
|
|
112
|
+
setIsLoading(false);
|
|
113
|
+
if (status === window.google.maps.places.PlacesServiceStatus.OK && results) {
|
|
114
|
+
setPredictions(results);
|
|
115
|
+
console.log(`🔍 Found ${results.length} predictions for "${input}"`);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
setPredictions([]);
|
|
119
|
+
if (status !== window.google.maps.places.PlacesServiceStatus.ZERO_RESULTS) {
|
|
120
|
+
console.warn('Google Places prediction failed:', status);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}, [initializeServices, isScriptLoaded]);
|
|
125
|
+
// Get detailed place information
|
|
126
|
+
const getPlaceDetails = useCallback((placeId) => {
|
|
127
|
+
return new Promise((resolve) => {
|
|
128
|
+
if (!isScriptLoaded) {
|
|
129
|
+
console.warn('Google Maps API not yet loaded');
|
|
130
|
+
resolve(null);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (!initializeServices()) {
|
|
134
|
+
console.error('Google Places services not available');
|
|
135
|
+
resolve(null);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const request = {
|
|
139
|
+
placeId,
|
|
140
|
+
fields: ['place_id', 'formatted_address', 'address_components', 'geometry'],
|
|
141
|
+
};
|
|
142
|
+
placesServiceRef.current.getDetails(request, (place, status) => {
|
|
143
|
+
if (status === window.google.maps.places.PlacesServiceStatus.OK && place) {
|
|
144
|
+
console.log('📍 Got place details:', place);
|
|
145
|
+
resolve(place);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
console.error('Failed to get place details:', status);
|
|
149
|
+
resolve(null);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
}, [initializeServices, isScriptLoaded]);
|
|
154
|
+
// Extract structured address components from Google place
|
|
155
|
+
const extractAddressComponents = useCallback((place) => {
|
|
156
|
+
const extracted = {
|
|
157
|
+
streetNumber: '',
|
|
158
|
+
route: '',
|
|
159
|
+
locality: '',
|
|
160
|
+
administrativeAreaLevel1: '',
|
|
161
|
+
administrativeAreaLevel1Long: '',
|
|
162
|
+
country: '',
|
|
163
|
+
postalCode: '',
|
|
164
|
+
};
|
|
165
|
+
console.log('🏗️ Extracted address components:', place.address_components);
|
|
166
|
+
place.address_components?.forEach((component) => {
|
|
167
|
+
const types = component.types;
|
|
168
|
+
if (types.includes('street_number')) {
|
|
169
|
+
extracted.streetNumber = component.long_name;
|
|
170
|
+
}
|
|
171
|
+
if (types.includes('route')) {
|
|
172
|
+
extracted.route = component.long_name;
|
|
173
|
+
}
|
|
174
|
+
if (types.includes('locality')) {
|
|
175
|
+
extracted.locality = component.long_name;
|
|
176
|
+
}
|
|
177
|
+
if (types.includes('administrative_area_level_2') && !extracted.locality) {
|
|
178
|
+
extracted.locality = component.long_name;
|
|
179
|
+
}
|
|
180
|
+
if (types.includes('administrative_area_level_1')) {
|
|
181
|
+
extracted.administrativeAreaLevel1 = component.short_name;
|
|
182
|
+
extracted.administrativeAreaLevel1Long = component.long_name;
|
|
183
|
+
}
|
|
184
|
+
if (types.includes('country')) {
|
|
185
|
+
extracted.country = component.short_name;
|
|
186
|
+
}
|
|
187
|
+
if (types.includes('postal_code')) {
|
|
188
|
+
extracted.postalCode = component.long_name;
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
console.log('🏗️ Extracted address components:', extracted);
|
|
192
|
+
return extracted;
|
|
193
|
+
}, []);
|
|
194
|
+
// Clear predictions
|
|
195
|
+
const clearPredictions = useCallback(() => {
|
|
196
|
+
setPredictions([]);
|
|
197
|
+
}, []);
|
|
198
|
+
return {
|
|
199
|
+
predictions,
|
|
200
|
+
isLoading,
|
|
201
|
+
isScriptLoaded,
|
|
202
|
+
searchPlaces,
|
|
203
|
+
getPlaceDetails,
|
|
204
|
+
extractAddressComponents,
|
|
205
|
+
clearPredictions,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type SupportedLanguage } from '../../../data/iso3166';
|
|
2
|
+
export interface ISOCountry {
|
|
3
|
+
iso: string;
|
|
4
|
+
iso3: string;
|
|
5
|
+
numeric: number;
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ISORegion {
|
|
9
|
+
iso: string;
|
|
10
|
+
name: string;
|
|
11
|
+
}
|
|
12
|
+
export interface UseISODataResult {
|
|
13
|
+
countries: Record<string, ISOCountry>;
|
|
14
|
+
getRegions: (countryCode: string) => ISORegion[];
|
|
15
|
+
findRegion: (countryCode: string, regionCode: string) => ISORegion | null;
|
|
16
|
+
mapGoogleToISO: (googleState: string, googleStateLong: string, countryCode: string) => ISORegion | null;
|
|
17
|
+
isLanguageLoaded: boolean;
|
|
18
|
+
registeredLanguages: SupportedLanguage[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* React hook for accessing ISO3166 countries and regions data with dynamic language loading
|
|
22
|
+
* @param language - Language code (supports: en, ru, de, fr, es, zh, hi, pt, ja, ar, it, he)
|
|
23
|
+
* @param autoImport - Whether to automatically import the language if not registered (default: true)
|
|
24
|
+
* @param disputeSetting - Territorial dispute perspective (currently only UN is supported)
|
|
25
|
+
* @returns Object with countries data and helper functions
|
|
26
|
+
*/
|
|
27
|
+
export declare function useISOData(language?: SupportedLanguage, autoImport?: boolean, disputeSetting?: string): UseISODataResult;
|
|
28
|
+
/**
|
|
29
|
+
* Get available languages for ISO data
|
|
30
|
+
*/
|
|
31
|
+
export declare function getAvailableLanguages(): SupportedLanguage[];
|
|
32
|
+
/**
|
|
33
|
+
* Hook to manually import and register a language
|
|
34
|
+
* @param language - Language code to import
|
|
35
|
+
* @returns Object with loading state and error handling
|
|
36
|
+
*/
|
|
37
|
+
export declare function useLanguageImport(language: SupportedLanguage): {
|
|
38
|
+
importLanguage: () => Promise<void>;
|
|
39
|
+
isLoading: boolean;
|
|
40
|
+
error: string | null;
|
|
41
|
+
isRegistered: boolean;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Get list of countries as options for select components
|
|
45
|
+
* @param language - Language code (defaults to 'en')
|
|
46
|
+
* @param autoImport - Whether to automatically import the language if not registered (default: true)
|
|
47
|
+
*/
|
|
48
|
+
export declare function useCountryOptions(language?: SupportedLanguage, autoImport?: boolean): {
|
|
49
|
+
value: string;
|
|
50
|
+
label: string;
|
|
51
|
+
}[];
|
|
52
|
+
/**
|
|
53
|
+
* Get list of regions/states for a country as options for select components
|
|
54
|
+
* @param countryCode - ISO country code
|
|
55
|
+
* @param language - Language code (defaults to 'en')
|
|
56
|
+
* @param autoImport - Whether to automatically import the language if not registered (default: true)
|
|
57
|
+
*/
|
|
58
|
+
export declare function useRegionOptions(countryCode: string, language?: SupportedLanguage, autoImport?: boolean): {
|
|
59
|
+
value: string;
|
|
60
|
+
label: string;
|
|
61
|
+
}[];
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { useMemo, useEffect, useState, useCallback } from 'react';
|
|
2
|
+
// Import the pre-built ISO data functions
|
|
3
|
+
import { getCountries, getStatesForCountry, importLanguage, isLanguageRegistered, getRegisteredLanguages } from '../../../data/iso3166';
|
|
4
|
+
/**
|
|
5
|
+
* React hook for accessing ISO3166 countries and regions data with dynamic language loading
|
|
6
|
+
* @param language - Language code (supports: en, ru, de, fr, es, zh, hi, pt, ja, ar, it, he)
|
|
7
|
+
* @param autoImport - Whether to automatically import the language if not registered (default: true)
|
|
8
|
+
* @param disputeSetting - Territorial dispute perspective (currently only UN is supported)
|
|
9
|
+
* @returns Object with countries data and helper functions
|
|
10
|
+
*/
|
|
11
|
+
export function useISOData(language = 'en', autoImport = true, disputeSetting = 'UN') {
|
|
12
|
+
const [isLanguageLoaded, setIsLanguageLoaded] = useState(isLanguageRegistered(language));
|
|
13
|
+
const [registeredLanguages, setRegisteredLanguages] = useState(getRegisteredLanguages);
|
|
14
|
+
// Auto-import language if not registered and autoImport is true
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (!isLanguageRegistered(language) && autoImport && language !== 'en') {
|
|
17
|
+
importLanguage(language)
|
|
18
|
+
.then(() => {
|
|
19
|
+
setIsLanguageLoaded(true);
|
|
20
|
+
setRegisteredLanguages(getRegisteredLanguages());
|
|
21
|
+
})
|
|
22
|
+
.catch((error) => {
|
|
23
|
+
console.error(`Failed to auto-import language ${language}:`, error);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}, [language, autoImport]);
|
|
27
|
+
const data = useMemo(() => {
|
|
28
|
+
try {
|
|
29
|
+
// Get countries from pre-built data with language support
|
|
30
|
+
const countriesArray = getCountries(language);
|
|
31
|
+
// Transform to our expected format (Record<string, ISOCountry>)
|
|
32
|
+
const countries = {};
|
|
33
|
+
countriesArray.forEach((country) => {
|
|
34
|
+
countries[country.code] = {
|
|
35
|
+
iso: country.code,
|
|
36
|
+
iso3: country.iso3 || '',
|
|
37
|
+
numeric: country.numeric || 0,
|
|
38
|
+
name: country.name,
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
// Helper to load regions for a specific country
|
|
42
|
+
const getRegions = (countryCode) => {
|
|
43
|
+
try {
|
|
44
|
+
const states = getStatesForCountry(countryCode, language);
|
|
45
|
+
return states.map((state) => ({
|
|
46
|
+
iso: state.code,
|
|
47
|
+
name: state.name,
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return []; // Return empty array if no regions
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
// Find a specific region by ISO code
|
|
55
|
+
const findRegion = (countryCode, regionCode) => {
|
|
56
|
+
const regions = getRegions(countryCode);
|
|
57
|
+
return regions.find((region) => region.iso === regionCode) ?? null;
|
|
58
|
+
};
|
|
59
|
+
// Map Google Places state to ISO region (proven 100% success rate)
|
|
60
|
+
const mapGoogleToISO = (googleState, googleStateLong, countryCode) => {
|
|
61
|
+
const regions = getRegions(countryCode);
|
|
62
|
+
if (regions.length === 0)
|
|
63
|
+
return null;
|
|
64
|
+
// Strategy 1: Exact ISO code match (86% success rate)
|
|
65
|
+
let match = regions.find((r) => r.iso === googleState);
|
|
66
|
+
if (match)
|
|
67
|
+
return match;
|
|
68
|
+
// Strategy 2: Name matching (14% success rate)
|
|
69
|
+
match = regions.find((r) => r.name.toLowerCase() === googleState.toLowerCase());
|
|
70
|
+
if (match)
|
|
71
|
+
return match;
|
|
72
|
+
match = regions.find((r) => r.name.toLowerCase() === googleStateLong.toLowerCase());
|
|
73
|
+
if (match)
|
|
74
|
+
return match;
|
|
75
|
+
// Strategy 3: Partial name matching (fallback)
|
|
76
|
+
match = regions.find((r) => r.name.toLowerCase().includes(googleStateLong.toLowerCase()) ||
|
|
77
|
+
googleStateLong.toLowerCase().includes(r.name.toLowerCase()));
|
|
78
|
+
return match ?? null;
|
|
79
|
+
};
|
|
80
|
+
return {
|
|
81
|
+
countries,
|
|
82
|
+
getRegions,
|
|
83
|
+
findRegion,
|
|
84
|
+
mapGoogleToISO,
|
|
85
|
+
isLanguageLoaded,
|
|
86
|
+
registeredLanguages,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
console.error(`Failed to load ISO data for language: ${language}`, error);
|
|
91
|
+
return {
|
|
92
|
+
countries: {},
|
|
93
|
+
getRegions: () => [],
|
|
94
|
+
findRegion: () => null,
|
|
95
|
+
mapGoogleToISO: () => null,
|
|
96
|
+
isLanguageLoaded,
|
|
97
|
+
registeredLanguages,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}, [language, disputeSetting, isLanguageLoaded, registeredLanguages]);
|
|
101
|
+
return data;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get available languages for ISO data
|
|
105
|
+
*/
|
|
106
|
+
export function getAvailableLanguages() {
|
|
107
|
+
// Return all available languages (not just registered ones)
|
|
108
|
+
return ['en', 'ru', 'de', 'fr', 'es', 'zh', 'hi', 'pt', 'ja', 'ar', 'it', 'he'];
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Hook to manually import and register a language
|
|
112
|
+
* @param language - Language code to import
|
|
113
|
+
* @returns Object with loading state and error handling
|
|
114
|
+
*/
|
|
115
|
+
export function useLanguageImport(language) {
|
|
116
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
117
|
+
const [error, setError] = useState(null);
|
|
118
|
+
const importLanguageData = useCallback(async () => {
|
|
119
|
+
if (isLanguageRegistered(language)) {
|
|
120
|
+
return; // Already registered
|
|
121
|
+
}
|
|
122
|
+
setIsLoading(true);
|
|
123
|
+
setError(null);
|
|
124
|
+
try {
|
|
125
|
+
await importLanguage(language);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
setError(err instanceof Error ? err.message : 'Failed to import language');
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
setIsLoading(false);
|
|
132
|
+
}
|
|
133
|
+
}, [language]);
|
|
134
|
+
return {
|
|
135
|
+
importLanguage: importLanguageData,
|
|
136
|
+
isLoading,
|
|
137
|
+
error,
|
|
138
|
+
isRegistered: isLanguageRegistered(language),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get list of countries as options for select components
|
|
143
|
+
* @param language - Language code (defaults to 'en')
|
|
144
|
+
* @param autoImport - Whether to automatically import the language if not registered (default: true)
|
|
145
|
+
*/
|
|
146
|
+
export function useCountryOptions(language = 'en', autoImport = true) {
|
|
147
|
+
const { countries } = useISOData(language, autoImport);
|
|
148
|
+
return useMemo(() => {
|
|
149
|
+
return Object.entries(countries)
|
|
150
|
+
.map(([code, country]) => ({
|
|
151
|
+
value: code,
|
|
152
|
+
label: country.name,
|
|
153
|
+
}))
|
|
154
|
+
.sort((a, b) => a.label.localeCompare(b.label));
|
|
155
|
+
}, [countries]);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get list of regions/states for a country as options for select components
|
|
159
|
+
* @param countryCode - ISO country code
|
|
160
|
+
* @param language - Language code (defaults to 'en')
|
|
161
|
+
* @param autoImport - Whether to automatically import the language if not registered (default: true)
|
|
162
|
+
*/
|
|
163
|
+
export function useRegionOptions(countryCode, language = 'en', autoImport = true) {
|
|
164
|
+
const { getRegions } = useISOData(language, autoImport);
|
|
165
|
+
return useMemo(() => {
|
|
166
|
+
if (!countryCode)
|
|
167
|
+
return [];
|
|
168
|
+
const regions = getRegions(countryCode);
|
|
169
|
+
return regions
|
|
170
|
+
.map((region) => ({
|
|
171
|
+
value: region.iso,
|
|
172
|
+
label: region.name,
|
|
173
|
+
}))
|
|
174
|
+
.sort((a, b) => a.label.localeCompare(b.label));
|
|
175
|
+
}, [countryCode, getRegions]);
|
|
176
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offers Hook using TanStack Query
|
|
3
|
+
* Handles offers with automatic caching
|
|
4
|
+
*/
|
|
5
|
+
import { Offer } from '../../core/resources/offers';
|
|
6
|
+
import { CheckoutSessionState, OrderSummary, CurrencyOptions } from '../../core/resources/postPurchases';
|
|
7
|
+
export interface UseOffersQueryOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Array of offer IDs to fetch
|
|
10
|
+
*/
|
|
11
|
+
offerIds?: string[];
|
|
12
|
+
/**
|
|
13
|
+
* Whether to fetch offers automatically on mount
|
|
14
|
+
* @default true
|
|
15
|
+
*/
|
|
16
|
+
enabled?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Return URL for checkout sessions
|
|
19
|
+
*/
|
|
20
|
+
returnUrl?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface UseOffersQueryResult {
|
|
23
|
+
offers: Offer[];
|
|
24
|
+
isLoading: boolean;
|
|
25
|
+
error: Error | null;
|
|
26
|
+
refetch: () => Promise<void>;
|
|
27
|
+
createCheckoutSession: (offerId: string, options?: {
|
|
28
|
+
returnUrl?: string;
|
|
29
|
+
}) => Promise<{
|
|
30
|
+
checkoutUrl: string;
|
|
31
|
+
}>;
|
|
32
|
+
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>;
|
|
47
|
+
getAvailableVariants: (offerId: string, productId: string) => {
|
|
48
|
+
variantId: string;
|
|
49
|
+
variantName: string;
|
|
50
|
+
variantSku: string | null;
|
|
51
|
+
variantDefault: boolean | null;
|
|
52
|
+
variantExternalId: string | null;
|
|
53
|
+
priceId: string;
|
|
54
|
+
currencyOptions: CurrencyOptions;
|
|
55
|
+
}[];
|
|
56
|
+
selectVariant: (offerId: string, productId: string, variantId: string) => Promise<void>;
|
|
57
|
+
getOrderSummary: (offerId: string) => OrderSummary | null;
|
|
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
|
+
}
|
|
65
|
+
export declare function useOffersQuery(options?: UseOffersQueryOptions): UseOffersQueryResult;
|