@tagadapay/plugin-sdk 2.6.13 → 2.6.16
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 +1129 -1129
- package/dist/data/languages.d.ts +1834 -0
- package/dist/data/languages.js +921 -0
- package/dist/react/hooks/usePluginConfig.d.ts +2 -6
- package/dist/react/hooks/usePluginConfig.js +9 -90
- package/dist/react/providers/TagadaProvider.js +5 -5
- package/dist/v2/index.d.ts +3 -2
- package/dist/v2/index.js +1 -1
- package/dist/v2/react/hooks/useDiscountQuery.d.ts +79 -0
- package/dist/v2/react/hooks/useDiscountQuery.js +24 -0
- package/dist/v2/react/hooks/useTranslation.d.ts +46 -0
- package/dist/v2/react/hooks/useTranslation.js +61 -0
- package/dist/v2/react/index.d.ts +5 -1
- package/dist/v2/react/index.js +2 -0
- package/dist/v2/react/providers/TagadaProvider.d.ts +1 -2
- package/dist/v2/react/providers/TagadaProvider.js +31 -24
- package/package.json +91 -91
|
@@ -30,14 +30,10 @@ export interface RawPluginConfig<TConfig = Record<string, any>> {
|
|
|
30
30
|
basePath?: string;
|
|
31
31
|
config?: TConfig;
|
|
32
32
|
}
|
|
33
|
-
export interface LocalDevConfig {
|
|
34
|
-
storeId: string;
|
|
35
|
-
accountId: string;
|
|
36
|
-
basePath: string;
|
|
37
|
-
}
|
|
38
33
|
/**
|
|
39
34
|
* Load plugin configuration (cached)
|
|
40
|
-
* Tries raw config first, then
|
|
35
|
+
* Tries raw config first, then production config
|
|
36
|
+
* Note: Local dev config should be passed via rawConfig parameter
|
|
41
37
|
*/
|
|
42
38
|
export declare const loadPluginConfig: (configVariant?: string, rawConfig?: RawPluginConfig) => Promise<PluginConfig>;
|
|
43
39
|
/**
|
|
@@ -22,88 +22,6 @@ import { useTagadaContext } from '../providers/TagadaProvider';
|
|
|
22
22
|
// Simple cache for plugin configuration
|
|
23
23
|
let cachedConfig = null;
|
|
24
24
|
let configPromise = null;
|
|
25
|
-
/**
|
|
26
|
-
* Load local development configuration
|
|
27
|
-
* Combines .local.json + config/default.tgd.json (or specified variant)
|
|
28
|
-
*/
|
|
29
|
-
const loadLocalDevConfig = async (configVariant = 'default') => {
|
|
30
|
-
try {
|
|
31
|
-
// Only try to load local config in development
|
|
32
|
-
// Use hostname-based detection for better Vite compatibility
|
|
33
|
-
const isLocalDev = typeof window !== 'undefined' &&
|
|
34
|
-
(window.location.hostname === 'localhost' ||
|
|
35
|
-
window.location.hostname.includes('ngrok-free.app') ||
|
|
36
|
-
window.location.hostname.includes('.localhost') ||
|
|
37
|
-
window.location.hostname.includes('127.0.0.1'));
|
|
38
|
-
if (!isLocalDev) {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
// Load local store/account config
|
|
42
|
-
const localResponse = await fetch('/.local.json');
|
|
43
|
-
if (!localResponse.ok) {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
const localConfig = await localResponse.json();
|
|
47
|
-
// Load deployment config (specified variant or fallback to default)
|
|
48
|
-
let config = {};
|
|
49
|
-
let configLoaded = false;
|
|
50
|
-
try {
|
|
51
|
-
// Try .tgd.json first (new format), then fallback to .json
|
|
52
|
-
let deploymentResponse = await fetch(`/config/${configVariant}.tgd.json`);
|
|
53
|
-
if (!deploymentResponse.ok) {
|
|
54
|
-
deploymentResponse = await fetch(`/config/${configVariant}.json`);
|
|
55
|
-
}
|
|
56
|
-
if (deploymentResponse.ok) {
|
|
57
|
-
config = await deploymentResponse.json();
|
|
58
|
-
configLoaded = true;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
// Config fetch failed, will try fallback
|
|
63
|
-
}
|
|
64
|
-
// If config didn't load and it's not 'default', try fallback to default
|
|
65
|
-
if (!configLoaded && configVariant !== 'default') {
|
|
66
|
-
console.warn(`⚠️ Config variant '${configVariant}' not found, falling back to 'default'`);
|
|
67
|
-
try {
|
|
68
|
-
let defaultResponse = await fetch('/config/default.tgd.json');
|
|
69
|
-
if (!defaultResponse.ok) {
|
|
70
|
-
defaultResponse = await fetch('/config/default.json');
|
|
71
|
-
}
|
|
72
|
-
if (defaultResponse.ok) {
|
|
73
|
-
config = await defaultResponse.json();
|
|
74
|
-
configLoaded = true;
|
|
75
|
-
console.log(`✅ Fallback to 'default' config successful`);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
// Default config also failed
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
// Final warning if no config was loaded
|
|
83
|
-
if (!configLoaded) {
|
|
84
|
-
if (configVariant === 'default') {
|
|
85
|
-
console.warn(`⚠️ No 'default' config found. Create /config/default.tgd.json`);
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
console.warn(`⚠️ Neither '${configVariant}' nor 'default' config found. Create /config/default.tgd.json`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
console.log('🛠️ Using local development plugin config:', {
|
|
92
|
-
configName: config.configName || configVariant,
|
|
93
|
-
local: localConfig,
|
|
94
|
-
deployment: config
|
|
95
|
-
});
|
|
96
|
-
return {
|
|
97
|
-
storeId: localConfig.storeId,
|
|
98
|
-
accountId: localConfig.accountId,
|
|
99
|
-
basePath: localConfig.basePath,
|
|
100
|
-
config,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
catch {
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
25
|
/**
|
|
108
26
|
* Load production config from headers and meta tags
|
|
109
27
|
*/
|
|
@@ -135,12 +53,18 @@ const loadProductionConfig = async () => {
|
|
|
135
53
|
};
|
|
136
54
|
/**
|
|
137
55
|
* Load plugin configuration (cached)
|
|
138
|
-
* Tries raw config first, then
|
|
56
|
+
* Tries raw config first, then production config
|
|
57
|
+
* Note: Local dev config should be passed via rawConfig parameter
|
|
139
58
|
*/
|
|
140
59
|
export const loadPluginConfig = async (configVariant = 'default', rawConfig) => {
|
|
141
60
|
// If raw config is provided, use it directly
|
|
142
61
|
if (rawConfig) {
|
|
143
|
-
console.log('🛠️ Using raw plugin config:',
|
|
62
|
+
console.log('🛠️ Using raw plugin config:', {
|
|
63
|
+
hasStoreId: !!rawConfig.storeId,
|
|
64
|
+
hasAccountId: !!rawConfig.accountId,
|
|
65
|
+
hasConfig: !!rawConfig.config,
|
|
66
|
+
configKeys: rawConfig.config ? Object.keys(rawConfig.config) : [],
|
|
67
|
+
});
|
|
144
68
|
return {
|
|
145
69
|
storeId: rawConfig.storeId,
|
|
146
70
|
accountId: rawConfig.accountId,
|
|
@@ -148,12 +72,7 @@ export const loadPluginConfig = async (configVariant = 'default', rawConfig) =>
|
|
|
148
72
|
config: rawConfig.config ?? {},
|
|
149
73
|
};
|
|
150
74
|
}
|
|
151
|
-
//
|
|
152
|
-
const localConfig = await loadLocalDevConfig(configVariant);
|
|
153
|
-
if (localConfig) {
|
|
154
|
-
return localConfig;
|
|
155
|
-
}
|
|
156
|
-
// Fall back to production config
|
|
75
|
+
// Fall back to production config (from headers/meta tags)
|
|
157
76
|
return loadProductionConfig();
|
|
158
77
|
};
|
|
159
78
|
/**
|
|
@@ -38,11 +38,11 @@ const InitializationLoader = () => (_jsxs("div", { style: {
|
|
|
38
38
|
borderTop: '1.5px solid #9ca3af',
|
|
39
39
|
borderRadius: '50%',
|
|
40
40
|
animation: 'tagada-spin 1s linear infinite',
|
|
41
|
-
} }), _jsx("span", { children: "Loading..." }), _jsx("style", { children: `
|
|
42
|
-
@keyframes tagada-spin {
|
|
43
|
-
0% { transform: rotate(0deg); }
|
|
44
|
-
100% { transform: rotate(360deg); }
|
|
45
|
-
}
|
|
41
|
+
} }), _jsx("span", { children: "Loading..." }), _jsx("style", { children: `
|
|
42
|
+
@keyframes tagada-spin {
|
|
43
|
+
0% { transform: rotate(0deg); }
|
|
44
|
+
100% { transform: rotate(360deg); }
|
|
45
|
+
}
|
|
46
46
|
` })] }));
|
|
47
47
|
const TagadaContext = createContext(null);
|
|
48
48
|
export function TagadaProvider({ children, environment, customApiConfig, debugMode, // Remove default, will be set based on environment
|
package/dist/v2/index.d.ts
CHANGED
|
@@ -20,5 +20,6 @@ export type { ShippingRate, ShippingRatesResponse } from './core/resources/shipp
|
|
|
20
20
|
export type { ApplyDiscountResponse, Discount, DiscountCodeValidation, RemoveDiscountResponse } from './core/resources/discounts';
|
|
21
21
|
export type { ToggleOrderBumpResponse, VipOffer, VipPreviewResponse } from './core/resources/vipOffers';
|
|
22
22
|
export type { StoreConfig } from './core/resources/storeConfig';
|
|
23
|
-
export type {
|
|
24
|
-
export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useCheckout, useCheckoutToken, useCountryOptions, useCurrency, useDiscounts, useExpressPaymentMethods, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useOffers, useOrder, useOrderBump, usePayment, usePluginConfig, usePostPurchases, usePreloadQuery, useProducts, usePromotions, useRegionOptions, useShippingRates, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal,
|
|
23
|
+
export type { FunnelContextUpdateRequest, FunnelContextUpdateResponse, FunnelEvent, FunnelInitializeRequest, FunnelInitializeResponse, FunnelNavigateRequest, FunnelNavigateResponse, FunnelNavigationAction, FunnelNavigationResult, SimpleFunnelContext } from './core/resources/funnel';
|
|
24
|
+
export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useCheckout, useCheckoutToken, useCountryOptions, useCurrency, useDiscount, useDiscounts, useExpressPaymentMethods, useFunnel, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useOffers, useOrder, useOrderBump, usePayment, usePluginConfig, usePostPurchases, usePreloadQuery, useProducts, usePromotions, useRegionOptions, useShippingRates, useSimpleFunnel, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers } from './react';
|
|
25
|
+
export type { StoreDiscount, TranslateFunction, TranslationText, UseTranslationOptions, UseTranslationResult } from './react';
|
package/dist/v2/index.js
CHANGED
|
@@ -12,4 +12,4 @@ export * from './core/utils/currency';
|
|
|
12
12
|
export * from './core/utils/pluginConfig';
|
|
13
13
|
export * from './core/utils/products';
|
|
14
14
|
// React exports (hooks and components only, types are exported above)
|
|
15
|
-
export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useCheckout, useCheckoutToken, useCountryOptions, useCurrency, useDiscounts, useExpressPaymentMethods, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useOffers, useOrder, useOrderBump, usePayment, usePluginConfig, usePostPurchases, usePreloadQuery, useProducts, usePromotions, useRegionOptions, useShippingRates, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal,
|
|
15
|
+
export { ApplePayButton, ExpressPaymentMethodsProvider, formatMoney, getAvailableLanguages, GooglePayButton, queryKeys, TagadaProvider, useApiMutation, useApiQuery, useCheckout, useCheckoutToken, useCountryOptions, useCurrency, useDiscount, useDiscounts, useExpressPaymentMethods, useFunnel, useGeoLocation, useGoogleAutocomplete, useInvalidateQuery, useISOData, useLanguageImport, useOffers, useOrder, useOrderBump, usePayment, usePluginConfig, usePostPurchases, usePreloadQuery, useProducts, usePromotions, useRegionOptions, useShippingRates, useSimpleFunnel, useStoreConfig, useTagadaContext, useThreeds, useThreedsModal, useTranslation, useVipOffers } from './react';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single Discount Hook using TanStack Query
|
|
3
|
+
* Fetches a specific discount for a given store
|
|
4
|
+
*/
|
|
5
|
+
import { UseQueryResult } from '@tanstack/react-query';
|
|
6
|
+
export interface StoreDiscountRuleAmount {
|
|
7
|
+
rate: number;
|
|
8
|
+
amount: number;
|
|
9
|
+
lock: boolean;
|
|
10
|
+
date: string;
|
|
11
|
+
}
|
|
12
|
+
export interface StoreDiscountRule {
|
|
13
|
+
id: string;
|
|
14
|
+
createdAt: string;
|
|
15
|
+
updatedAt: string;
|
|
16
|
+
promotionId: string;
|
|
17
|
+
type: string;
|
|
18
|
+
productId: string | null;
|
|
19
|
+
minimumQuantity: number | null;
|
|
20
|
+
minimumAmount: Record<string, StoreDiscountRuleAmount> | null;
|
|
21
|
+
variantIds: string[] | null;
|
|
22
|
+
}
|
|
23
|
+
export interface StoreDiscountAction {
|
|
24
|
+
id: string;
|
|
25
|
+
createdAt: string;
|
|
26
|
+
updatedAt: string;
|
|
27
|
+
promotionId: string;
|
|
28
|
+
type: string;
|
|
29
|
+
adjustmentAmount: number | null;
|
|
30
|
+
adjustmentPercentage: number | null;
|
|
31
|
+
adjustmentType: string | null;
|
|
32
|
+
freeShipping: boolean | null;
|
|
33
|
+
priceIdToAdd: string | null;
|
|
34
|
+
productIdToAdd: string | null;
|
|
35
|
+
variantIdToAdd: string | null;
|
|
36
|
+
subscriptionFreeTrialDuration: number | null;
|
|
37
|
+
subscriptionFreeTrialDurationType: string | null;
|
|
38
|
+
targetProductId: string | null;
|
|
39
|
+
targetVariantIds: string[] | null;
|
|
40
|
+
maxQuantityDiscounted: number | null;
|
|
41
|
+
appliesOnEachItem: boolean | null;
|
|
42
|
+
}
|
|
43
|
+
export interface StoreDiscount {
|
|
44
|
+
id: string;
|
|
45
|
+
createdAt: string;
|
|
46
|
+
updatedAt: string;
|
|
47
|
+
storeId: string;
|
|
48
|
+
accountId: string;
|
|
49
|
+
name: string;
|
|
50
|
+
code: string;
|
|
51
|
+
automatic: boolean;
|
|
52
|
+
usageLimit: number | null;
|
|
53
|
+
usageCount: number;
|
|
54
|
+
startDate: string;
|
|
55
|
+
endDate: string | null;
|
|
56
|
+
enabled: boolean;
|
|
57
|
+
archived: boolean;
|
|
58
|
+
ruleOperator: string;
|
|
59
|
+
externalId: string | null;
|
|
60
|
+
combinesWithOrderLevelDiscounts: boolean;
|
|
61
|
+
combinesWithLineItemDiscounts: boolean;
|
|
62
|
+
combinesWithShippingDiscounts: boolean;
|
|
63
|
+
forceCombine: boolean;
|
|
64
|
+
isTemporary: boolean;
|
|
65
|
+
rules: StoreDiscountRule[];
|
|
66
|
+
actions: StoreDiscountAction[];
|
|
67
|
+
}
|
|
68
|
+
export interface UseDiscountQueryOptions {
|
|
69
|
+
storeId?: string;
|
|
70
|
+
discountId?: string;
|
|
71
|
+
enabled?: boolean;
|
|
72
|
+
}
|
|
73
|
+
export interface UseDiscountQueryResult<TData = StoreDiscount> {
|
|
74
|
+
discount: TData | undefined;
|
|
75
|
+
isLoading: boolean;
|
|
76
|
+
error: Error | null;
|
|
77
|
+
refetch: UseQueryResult<TData>['refetch'];
|
|
78
|
+
}
|
|
79
|
+
export declare function useDiscountQuery<TData = StoreDiscount>(options: UseDiscountQueryOptions): UseDiscountQueryResult<TData>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single Discount Hook using TanStack Query
|
|
3
|
+
* Fetches a specific discount for a given store
|
|
4
|
+
*/
|
|
5
|
+
import { useMemo } from 'react';
|
|
6
|
+
import { useApiQuery } from './useApiQuery';
|
|
7
|
+
import { usePluginConfig } from './usePluginConfig';
|
|
8
|
+
export function useDiscountQuery(options) {
|
|
9
|
+
const { storeId: storeIdFromConfig } = usePluginConfig();
|
|
10
|
+
const { storeId = storeIdFromConfig, discountId, enabled = true } = options;
|
|
11
|
+
const key = useMemo(() => ['discount', storeId, discountId], [storeId, discountId]);
|
|
12
|
+
const url = useMemo(() => {
|
|
13
|
+
if (!storeId || !discountId)
|
|
14
|
+
return null;
|
|
15
|
+
return `/api/v1/stores/${storeId}/discounts/${discountId}`;
|
|
16
|
+
}, [storeId, discountId]);
|
|
17
|
+
const query = useApiQuery(key, url, { enabled });
|
|
18
|
+
return {
|
|
19
|
+
discount: query.data,
|
|
20
|
+
isLoading: query.isLoading,
|
|
21
|
+
error: query.error || null,
|
|
22
|
+
refetch: query.refetch,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { LanguageCode } from '../../../data/languages';
|
|
2
|
+
export type TranslationText = {
|
|
3
|
+
[key in LanguageCode | string]?: string;
|
|
4
|
+
};
|
|
5
|
+
export interface UseTranslationOptions {
|
|
6
|
+
defaultLanguage?: string;
|
|
7
|
+
}
|
|
8
|
+
export type TranslateFunction = (text: TranslationText | string | undefined, fallback?: string, languageCode?: string) => string;
|
|
9
|
+
export interface UseTranslationResult {
|
|
10
|
+
/**
|
|
11
|
+
* Translate function that handles multi-language text objects
|
|
12
|
+
* @param text - The text to translate (can be a string or MultiLangText object)
|
|
13
|
+
* @param fallback - Optional fallback text if translation is not found
|
|
14
|
+
* @param languageCode - Optional language code to override the current locale
|
|
15
|
+
* @returns The translated string
|
|
16
|
+
*/
|
|
17
|
+
t: TranslateFunction;
|
|
18
|
+
/**
|
|
19
|
+
* Current locale code (e.g., 'en', 'fr', 'es')
|
|
20
|
+
*/
|
|
21
|
+
locale: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Hook for translating multi-language text objects
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* const { t, locale } = useTranslation({ defaultLanguage: 'en' });
|
|
29
|
+
*
|
|
30
|
+
* const multiLangText = {
|
|
31
|
+
* en: 'Hello',
|
|
32
|
+
* fr: 'Bonjour',
|
|
33
|
+
* es: 'Hola'
|
|
34
|
+
* };
|
|
35
|
+
*
|
|
36
|
+
* // Translates to current locale
|
|
37
|
+
* const translated = t(multiLangText);
|
|
38
|
+
*
|
|
39
|
+
* // With fallback
|
|
40
|
+
* const withFallback = t(multiLangText, 'Default text');
|
|
41
|
+
*
|
|
42
|
+
* // Override locale
|
|
43
|
+
* const inFrench = t(multiLangText, '', 'fr');
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare const useTranslation: (options?: UseTranslationOptions) => UseTranslationResult;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Hook for translating multi-language text objects
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```tsx
|
|
7
|
+
* const { t, locale } = useTranslation({ defaultLanguage: 'en' });
|
|
8
|
+
*
|
|
9
|
+
* const multiLangText = {
|
|
10
|
+
* en: 'Hello',
|
|
11
|
+
* fr: 'Bonjour',
|
|
12
|
+
* es: 'Hola'
|
|
13
|
+
* };
|
|
14
|
+
*
|
|
15
|
+
* // Translates to current locale
|
|
16
|
+
* const translated = t(multiLangText);
|
|
17
|
+
*
|
|
18
|
+
* // With fallback
|
|
19
|
+
* const withFallback = t(multiLangText, 'Default text');
|
|
20
|
+
*
|
|
21
|
+
* // Override locale
|
|
22
|
+
* const inFrench = t(multiLangText, '', 'fr');
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export const useTranslation = (options = {}) => {
|
|
26
|
+
const { defaultLanguage = 'en' } = options;
|
|
27
|
+
// Get the current language from query params, browser, or fallback to default
|
|
28
|
+
const locale = useMemo(() => {
|
|
29
|
+
// Check for language query parameter
|
|
30
|
+
if (typeof window !== 'undefined') {
|
|
31
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
32
|
+
const langFromQuery = urlParams.get('language');
|
|
33
|
+
if (langFromQuery)
|
|
34
|
+
return langFromQuery;
|
|
35
|
+
}
|
|
36
|
+
// Try to get browser language
|
|
37
|
+
if (typeof navigator !== 'undefined') {
|
|
38
|
+
const browserLang = navigator.language.split('-')[0]; // e.g., 'en-US' -> 'en'
|
|
39
|
+
return browserLang;
|
|
40
|
+
}
|
|
41
|
+
return defaultLanguage;
|
|
42
|
+
}, [defaultLanguage]);
|
|
43
|
+
const t = useCallback((text, fallback, languageCode) => {
|
|
44
|
+
if (!text)
|
|
45
|
+
return fallback || '';
|
|
46
|
+
if (typeof text === 'string')
|
|
47
|
+
return text;
|
|
48
|
+
const targetLocale = languageCode || locale;
|
|
49
|
+
if (text[targetLocale])
|
|
50
|
+
return text[targetLocale];
|
|
51
|
+
if (fallback)
|
|
52
|
+
return fallback;
|
|
53
|
+
if (text[defaultLanguage])
|
|
54
|
+
return text[defaultLanguage];
|
|
55
|
+
const firstAvailable = Object.values(text).find((value) => value !== undefined && value !== '');
|
|
56
|
+
if (firstAvailable)
|
|
57
|
+
return firstAvailable;
|
|
58
|
+
return '';
|
|
59
|
+
}, [locale, defaultLanguage]);
|
|
60
|
+
return { t, locale };
|
|
61
|
+
};
|
package/dist/v2/react/index.d.ts
CHANGED
|
@@ -12,9 +12,11 @@ export { useGeoLocation } from './hooks/useGeoLocation';
|
|
|
12
12
|
export { useGoogleAutocomplete } from './hooks/useGoogleAutocomplete';
|
|
13
13
|
export { getAvailableLanguages, useCountryOptions, useISOData, useLanguageImport, useRegionOptions } from './hooks/useISOData';
|
|
14
14
|
export { usePluginConfig } from './hooks/usePluginConfig';
|
|
15
|
+
export { useTranslation } from './hooks/useTranslation';
|
|
15
16
|
export { queryKeys, useApiMutation, useApiQuery, useInvalidateQuery, usePreloadQuery } from './hooks/useApiQuery';
|
|
16
17
|
export { useCheckoutQuery as useCheckout } from './hooks/useCheckoutQuery';
|
|
17
18
|
export { useCurrency } from './hooks/useCurrency';
|
|
19
|
+
export { useDiscountQuery as useDiscount } from './hooks/useDiscountQuery';
|
|
18
20
|
export { useDiscountsQuery as useDiscounts } from './hooks/useDiscountsQuery';
|
|
19
21
|
export { useOffersQuery as useOffers } from './hooks/useOffersQuery';
|
|
20
22
|
export { useOrderBumpQuery as useOrderBump } from './hooks/useOrderBumpQuery';
|
|
@@ -37,8 +39,11 @@ export type { GeoLocationData, UseGeoLocationOptions, UseGeoLocationReturn } fro
|
|
|
37
39
|
export type { ExtractedAddress, GooglePlaceDetails, GooglePrediction, UseGoogleAutocompleteOptions, UseGoogleAutocompleteResult } from './hooks/useGoogleAutocomplete';
|
|
38
40
|
export type { ISOCountry, ISORegion, UseISODataResult } from './hooks/useISOData';
|
|
39
41
|
export type { UsePluginConfigOptions, UsePluginConfigResult } from './hooks/usePluginConfig';
|
|
42
|
+
export type { TranslateFunction, TranslationText, UseTranslationOptions, UseTranslationResult } from './hooks/useTranslation';
|
|
40
43
|
export type { UseCheckoutQueryOptions as UseCheckoutOptions, UseCheckoutQueryResult as UseCheckoutResult } from './hooks/useCheckoutQuery';
|
|
44
|
+
export type { StoreDiscount, UseDiscountQueryOptions as UseDiscountOptions, UseDiscountQueryResult as UseDiscountResult } from './hooks/useDiscountQuery';
|
|
41
45
|
export type { UseDiscountsQueryOptions as UseDiscountsOptions, UseDiscountsQueryResult as UseDiscountsResult } from './hooks/useDiscountsQuery';
|
|
46
|
+
export type { FunnelEvent, FunnelNavigationAction, FunnelNavigationResult, SimpleFunnelContext, UseFunnelOptions, UseFunnelResult } from './hooks/useFunnel';
|
|
42
47
|
export type { UseOffersQueryOptions as UseOffersOptions, UseOffersQueryResult as UseOffersResult } from './hooks/useOffersQuery';
|
|
43
48
|
export type { UseOrderBumpQueryOptions as UseOrderBumpOptions, UseOrderBumpQueryResult as UseOrderBumpResult } from './hooks/useOrderBumpQuery';
|
|
44
49
|
export type { UseOrderQueryOptions as UseOrderOptions, UseOrderQueryResult as UseOrderResult } from './hooks/useOrderQuery';
|
|
@@ -50,6 +55,5 @@ export type { UseShippingRatesQueryOptions as UseShippingRatesOptions, UseShippi
|
|
|
50
55
|
export type { UseStoreConfigQueryOptions as UseStoreConfigOptions, UseStoreConfigQueryResult as UseStoreConfigResult } from './hooks/useStoreConfigQuery';
|
|
51
56
|
export type { PaymentInstrument, ThreedsChallenge, ThreedsHook, ThreedsOptions, ThreedsProvider, ThreedsSession } from './hooks/useThreeds';
|
|
52
57
|
export type { UseVipOffersQueryOptions as UseVipOffersOptions, UseVipOffersQueryResult as UseVipOffersResult } from './hooks/useVipOffersQuery';
|
|
53
|
-
export type { UseFunnelOptions, UseFunnelResult, FunnelEvent, FunnelNavigationAction, FunnelNavigationResult, SimpleFunnelContext } from './hooks/useFunnel';
|
|
54
58
|
export { formatMoney } from '../../react/utils/money';
|
|
55
59
|
export type OrderItem = import('../core/utils/order').OrderLineItem;
|
package/dist/v2/react/index.js
CHANGED
|
@@ -15,10 +15,12 @@ export { useGeoLocation } from './hooks/useGeoLocation';
|
|
|
15
15
|
export { useGoogleAutocomplete } from './hooks/useGoogleAutocomplete';
|
|
16
16
|
export { getAvailableLanguages, useCountryOptions, useISOData, useLanguageImport, useRegionOptions } from './hooks/useISOData';
|
|
17
17
|
export { usePluginConfig } from './hooks/usePluginConfig';
|
|
18
|
+
export { useTranslation } from './hooks/useTranslation';
|
|
18
19
|
// TanStack Query hooks (recommended)
|
|
19
20
|
export { queryKeys, useApiMutation, useApiQuery, useInvalidateQuery, usePreloadQuery } from './hooks/useApiQuery';
|
|
20
21
|
export { useCheckoutQuery as useCheckout } from './hooks/useCheckoutQuery';
|
|
21
22
|
export { useCurrency } from './hooks/useCurrency';
|
|
23
|
+
export { useDiscountQuery as useDiscount } from './hooks/useDiscountQuery';
|
|
22
24
|
export { useDiscountsQuery as useDiscounts } from './hooks/useDiscountsQuery';
|
|
23
25
|
export { useOffersQuery as useOffers } from './hooks/useOffersQuery';
|
|
24
26
|
export { useOrderBumpQuery as useOrderBump } from './hooks/useOrderBumpQuery';
|
|
@@ -52,12 +52,11 @@ interface TagadaProviderProps {
|
|
|
52
52
|
environment?: Environment;
|
|
53
53
|
customApiConfig?: Partial<EnvironmentConfig>;
|
|
54
54
|
debugMode?: boolean;
|
|
55
|
-
localConfig?: string;
|
|
56
55
|
blockUntilSessionReady?: boolean;
|
|
57
56
|
rawPluginConfig?: RawPluginConfig;
|
|
58
57
|
}
|
|
59
58
|
export declare function TagadaProvider({ children, environment, customApiConfig, debugMode, // Remove default, will be set based on environment
|
|
60
|
-
|
|
59
|
+
blockUntilSessionReady, // Default to new non-blocking behavior
|
|
61
60
|
rawPluginConfig, }: TagadaProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
62
61
|
export declare function useTagadaContext(): TagadaContextValue;
|
|
63
62
|
export {};
|
|
@@ -41,18 +41,18 @@ const InitializationLoader = () => (_jsxs("div", { style: {
|
|
|
41
41
|
borderTop: '1.5px solid #9ca3af',
|
|
42
42
|
borderRadius: '50%',
|
|
43
43
|
animation: 'tagada-spin 1s linear infinite',
|
|
44
|
-
} }), _jsx("span", { children: "Loading..." }), _jsx("style", { children: `
|
|
45
|
-
@keyframes tagada-spin {
|
|
46
|
-
0% { transform: rotate(0deg); }
|
|
47
|
-
100% { transform: rotate(360deg); }
|
|
48
|
-
}
|
|
44
|
+
} }), _jsx("span", { children: "Loading..." }), _jsx("style", { children: `
|
|
45
|
+
@keyframes tagada-spin {
|
|
46
|
+
0% { transform: rotate(0deg); }
|
|
47
|
+
100% { transform: rotate(360deg); }
|
|
48
|
+
}
|
|
49
49
|
` })] }));
|
|
50
50
|
const TagadaContext = createContext(null);
|
|
51
51
|
// Global instance tracking for TagadaProvider
|
|
52
52
|
let globalTagadaInstance = null;
|
|
53
53
|
let globalTagadaInitialized = false;
|
|
54
54
|
export function TagadaProvider({ children, environment, customApiConfig, debugMode, // Remove default, will be set based on environment
|
|
55
|
-
|
|
55
|
+
blockUntilSessionReady = false, // Default to new non-blocking behavior
|
|
56
56
|
rawPluginConfig, }) {
|
|
57
57
|
// Instance tracking
|
|
58
58
|
const [instanceId] = useState(() => {
|
|
@@ -81,20 +81,13 @@ rawPluginConfig, }) {
|
|
|
81
81
|
}
|
|
82
82
|
};
|
|
83
83
|
}, [instanceId]);
|
|
84
|
-
// LOCAL DEV ONLY: Use localConfig override if in local development, otherwise use default
|
|
85
|
-
const isLocalDev = typeof window !== 'undefined' &&
|
|
86
|
-
(window.location.hostname === 'localhost' ||
|
|
87
|
-
window.location.hostname.includes('.localhost') ||
|
|
88
|
-
window.location.hostname.includes('127.0.0.1'));
|
|
89
|
-
const configVariant = isLocalDev ? localConfig || 'default' : 'default';
|
|
90
84
|
// Debug logging (only log once during initial render)
|
|
91
85
|
const hasLoggedRef = useRef(false);
|
|
92
86
|
if (!hasLoggedRef.current) {
|
|
93
|
-
console.log(`🔍 [TagadaProvider] Instance ${instanceId}
|
|
87
|
+
console.log(`🔍 [TagadaProvider] Instance ${instanceId} Initializing with:`, {
|
|
94
88
|
hostname: typeof window !== 'undefined' ? window.location.hostname : 'SSR',
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
configVariant,
|
|
89
|
+
hasRawConfig: !!rawPluginConfig,
|
|
90
|
+
rawConfigStoreId: rawPluginConfig?.storeId,
|
|
98
91
|
});
|
|
99
92
|
hasLoggedRef.current = true;
|
|
100
93
|
}
|
|
@@ -102,6 +95,10 @@ rawPluginConfig, }) {
|
|
|
102
95
|
// Initialize with raw config if available to avoid empty config during loading
|
|
103
96
|
const [pluginConfig, setPluginConfig] = useState(() => {
|
|
104
97
|
if (rawPluginConfig) {
|
|
98
|
+
console.log('🛠️ [TagadaProvider] Using raw plugin config immediately:', {
|
|
99
|
+
storeId: rawPluginConfig.storeId,
|
|
100
|
+
accountId: rawPluginConfig.accountId,
|
|
101
|
+
});
|
|
105
102
|
return {
|
|
106
103
|
storeId: rawPluginConfig.storeId,
|
|
107
104
|
accountId: rawPluginConfig.accountId,
|
|
@@ -109,9 +106,11 @@ rawPluginConfig, }) {
|
|
|
109
106
|
config: rawPluginConfig.config ?? {},
|
|
110
107
|
};
|
|
111
108
|
}
|
|
109
|
+
console.log('⏳ [TagadaProvider] No raw config, will load from headers/files');
|
|
112
110
|
return { basePath: '/', config: {} };
|
|
113
111
|
});
|
|
114
112
|
const [configLoading, setConfigLoading] = useState(!rawPluginConfig);
|
|
113
|
+
const [apiClientReady, setApiClientReady] = useState(false);
|
|
115
114
|
// Load plugin config on mount with the specified variant
|
|
116
115
|
useEffect(() => {
|
|
117
116
|
// Prevent multiple config loads
|
|
@@ -121,8 +120,8 @@ rawPluginConfig, }) {
|
|
|
121
120
|
}
|
|
122
121
|
const loadConfig = async () => {
|
|
123
122
|
try {
|
|
124
|
-
// Use the v2 core loadPluginConfig function
|
|
125
|
-
const config = await loadPluginConfig(
|
|
123
|
+
// Use the v2 core loadPluginConfig function (only used when no rawPluginConfig)
|
|
124
|
+
const config = await loadPluginConfig('default', rawPluginConfig);
|
|
126
125
|
// Ensure we have required store ID before proceeding
|
|
127
126
|
if (!config.storeId) {
|
|
128
127
|
console.warn('⚠️ No store ID found in plugin config. This may cause hooks to fail.');
|
|
@@ -133,7 +132,7 @@ rawPluginConfig, }) {
|
|
|
133
132
|
accountId: config.accountId,
|
|
134
133
|
basePath: config.basePath,
|
|
135
134
|
hasConfig: !!config.config,
|
|
136
|
-
source: rawPluginConfig ? 'raw' : '
|
|
135
|
+
source: rawPluginConfig ? 'raw' : 'headers/files',
|
|
137
136
|
});
|
|
138
137
|
if (blockUntilSessionReady) {
|
|
139
138
|
console.log('⏳ Blocking mode: Children will render after Phase 3 (session init) completes');
|
|
@@ -151,7 +150,7 @@ rawPluginConfig, }) {
|
|
|
151
150
|
}
|
|
152
151
|
};
|
|
153
152
|
void loadConfig();
|
|
154
|
-
}, [
|
|
153
|
+
}, [rawPluginConfig]);
|
|
155
154
|
// Extract store/account IDs from plugin config (only source now)
|
|
156
155
|
const storeId = pluginConfig.storeId;
|
|
157
156
|
const _accountId = pluginConfig.accountId;
|
|
@@ -217,7 +216,8 @@ rawPluginConfig, }) {
|
|
|
217
216
|
});
|
|
218
217
|
// Set the global client for TanStack Query hooks
|
|
219
218
|
setGlobalApiClient(client);
|
|
220
|
-
|
|
219
|
+
setApiClientReady(true);
|
|
220
|
+
console.log('[SDK] ✅ ApiClient initialized with baseURL:', environmentConfig.apiConfig.baseUrl);
|
|
221
221
|
}, [environmentConfig]);
|
|
222
222
|
// Sync token updates between ApiService and ApiClient
|
|
223
223
|
useEffect(() => {
|
|
@@ -669,9 +669,16 @@ rawPluginConfig, }) {
|
|
|
669
669
|
// debugCheckout removed from deps to prevent unnecessary re-renders
|
|
670
670
|
]);
|
|
671
671
|
// Determine if we should show loading
|
|
672
|
-
// Always block until config is loaded
|
|
673
|
-
const shouldShowLoading = configLoading;
|
|
674
|
-
const canRenderChildren = !configLoading;
|
|
672
|
+
// Always block until BOTH config is loaded AND API client is ready
|
|
673
|
+
const shouldShowLoading = configLoading || !apiClientReady;
|
|
674
|
+
const canRenderChildren = !configLoading && apiClientReady;
|
|
675
|
+
if (!hasLoggedRef.current && canRenderChildren) {
|
|
676
|
+
console.log('✅ [TagadaProvider] All initialization complete, ready to render children:', {
|
|
677
|
+
configLoading,
|
|
678
|
+
apiClientReady,
|
|
679
|
+
hasStoreId: !!pluginConfig.storeId,
|
|
680
|
+
});
|
|
681
|
+
}
|
|
675
682
|
// Initialize TanStack Query client
|
|
676
683
|
const [queryClient] = useState(() => new QueryClient({
|
|
677
684
|
defaultOptions: {
|