@tagadapay/plugin-sdk 3.1.11 → 3.1.12
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/build-cdn.js +113 -228
- package/dist/external-tracker.js +2 -3
- package/dist/external-tracker.min.js +2 -2
- package/dist/external-tracker.min.js.map +3 -3
- package/dist/react/hooks/useShippingRates.d.ts +6 -0
- package/dist/react/hooks/useShippingRates.js +38 -0
- package/dist/react/providers/TagadaProvider.js +5 -5
- package/dist/react/services/apiService.d.ts +21 -0
- package/dist/react/services/apiService.js +10 -0
- package/dist/v2/core/funnelClient.d.ts +14 -15
- package/dist/v2/core/funnelClient.js +1 -1
- package/dist/v2/core/resources/shippingRates.d.ts +15 -0
- package/dist/v2/core/resources/shippingRates.js +11 -0
- package/dist/v2/core/utils/currency.d.ts +0 -14
- package/dist/v2/core/utils/currency.js +0 -40
- package/dist/v2/core/utils/index.d.ts +0 -1
- package/dist/v2/core/utils/index.js +0 -2
- package/dist/v2/core/utils/pluginConfig.d.ts +0 -8
- package/dist/v2/core/utils/pluginConfig.js +0 -28
- package/dist/v2/core/utils/previewModeIndicator.js +101 -101
- package/dist/v2/index.d.ts +1 -1
- package/dist/v2/react/components/ApplePayButton.js +13 -4
- package/dist/v2/react/components/FunnelScriptInjector.js +30 -30
- package/dist/v2/react/hooks/useFunnel.d.ts +1 -2
- package/dist/v2/react/hooks/useGoogleAutocomplete.js +82 -33
- package/dist/v2/react/hooks/usePixelTracking.d.ts +5 -0
- package/dist/v2/react/hooks/usePixelTracking.js +108 -0
- package/dist/v2/react/hooks/useShippingRatesQuery.d.ts +6 -0
- package/dist/v2/react/hooks/useShippingRatesQuery.js +36 -1
- package/dist/v2/react/hooks/useStepConfig.d.ts +2 -8
- package/dist/v2/react/hooks/useStepConfig.js +1 -1
- package/dist/v2/react/providers/TagadaProvider.js +5 -5
- package/dist/v2/standalone/index.js +1 -1
- package/package.json +112 -112
- package/dist/tagada-sdk.js +0 -10166
- package/dist/tagada-sdk.min.js +0 -48
- package/dist/tagada-sdk.min.js.map +0 -7
|
@@ -27,5 +27,11 @@ export interface UseShippingRatesResult {
|
|
|
27
27
|
error: Error | null;
|
|
28
28
|
clearError: () => void;
|
|
29
29
|
refetch: () => Promise<void>;
|
|
30
|
+
/** Preview shipping rates for a country without updating session */
|
|
31
|
+
previewRates: (countryCode: string, stateCode?: string) => Promise<ShippingRate[]>;
|
|
32
|
+
/** Rates from the last previewRates call */
|
|
33
|
+
previewedRates: ShippingRate[] | undefined;
|
|
34
|
+
/** Loading state for previewRates */
|
|
35
|
+
isPreviewLoading: boolean;
|
|
30
36
|
}
|
|
31
37
|
export declare const useShippingRates: ({ onSuccess, checkout }?: UseShippingRatesOptions) => UseShippingRatesResult;
|
|
@@ -39,6 +39,9 @@ export const useShippingRates = ({ onSuccess, checkout } = {}) => {
|
|
|
39
39
|
const previousSessionIdRef = useRef(undefined);
|
|
40
40
|
const isFetchingRef = useRef(false);
|
|
41
41
|
const hasSyncedSelectionFromCheckoutRef = useRef(false);
|
|
42
|
+
// Preview rates state
|
|
43
|
+
const [previewedRates, setPreviewedRates] = useState();
|
|
44
|
+
const [isPreviewLoading, setIsPreviewLoading] = useState(false);
|
|
42
45
|
const sessionId = checkout?.checkoutSession.id;
|
|
43
46
|
// Track mounted state
|
|
44
47
|
useEffect(() => {
|
|
@@ -87,6 +90,38 @@ export const useShippingRates = ({ onSuccess, checkout } = {}) => {
|
|
|
87
90
|
}
|
|
88
91
|
}
|
|
89
92
|
}, [sessionId, apiService]);
|
|
93
|
+
// Preview shipping rates for a country without updating session
|
|
94
|
+
const previewRates = useCallback(async (countryCode, stateCode) => {
|
|
95
|
+
if (!sessionId || !apiService)
|
|
96
|
+
return [];
|
|
97
|
+
try {
|
|
98
|
+
setIsPreviewLoading(true);
|
|
99
|
+
const queryParams = new URLSearchParams({ countryCode });
|
|
100
|
+
if (stateCode)
|
|
101
|
+
queryParams.set('stateCode', stateCode);
|
|
102
|
+
const response = await apiService.fetch(`/api/v1/checkout-sessions/${sessionId}/shipping-rates/preview?${queryParams}`, { method: 'GET' });
|
|
103
|
+
const sortedRates = response.rates.slice().sort((a, b) => {
|
|
104
|
+
if (a.isFree && !b.isFree)
|
|
105
|
+
return -1;
|
|
106
|
+
if (!a.isFree && b.isFree)
|
|
107
|
+
return 1;
|
|
108
|
+
return (a.amount ?? 0) - (b.amount ?? 0);
|
|
109
|
+
});
|
|
110
|
+
if (isMountedRef.current) {
|
|
111
|
+
setPreviewedRates(sortedRates);
|
|
112
|
+
}
|
|
113
|
+
return sortedRates;
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
console.error('Error previewing shipping rates:', err);
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
if (isMountedRef.current) {
|
|
121
|
+
setIsPreviewLoading(false);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}, [sessionId, apiService]);
|
|
90
125
|
useEffect(() => {
|
|
91
126
|
if (sessionId && isMountedRef.current && sessionId !== previousSessionIdRef.current) {
|
|
92
127
|
previousSessionIdRef.current = sessionId;
|
|
@@ -196,5 +231,8 @@ export const useShippingRates = ({ onSuccess, checkout } = {}) => {
|
|
|
196
231
|
error,
|
|
197
232
|
clearError,
|
|
198
233
|
refetch,
|
|
234
|
+
previewRates,
|
|
235
|
+
previewedRates,
|
|
236
|
+
isPreviewLoading,
|
|
199
237
|
};
|
|
200
238
|
};
|
|
@@ -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
|
|
@@ -146,6 +146,27 @@ export declare class ApiService {
|
|
|
146
146
|
shippingCountryChanged: boolean;
|
|
147
147
|
billingCountryChanged: boolean;
|
|
148
148
|
}>;
|
|
149
|
+
/**
|
|
150
|
+
* Update shipping address only (no email required)
|
|
151
|
+
* Useful for fetching shipping rates before email is entered
|
|
152
|
+
*/
|
|
153
|
+
updateShippingAddressOnly(checkoutSessionId: string, shippingAddress: {
|
|
154
|
+
firstName?: string;
|
|
155
|
+
lastName?: string;
|
|
156
|
+
address1?: string;
|
|
157
|
+
city?: string;
|
|
158
|
+
country: string;
|
|
159
|
+
state?: string;
|
|
160
|
+
postal?: string;
|
|
161
|
+
phone?: string;
|
|
162
|
+
}): Promise<{
|
|
163
|
+
success: boolean;
|
|
164
|
+
countryChanged: boolean;
|
|
165
|
+
errors?: Record<string, {
|
|
166
|
+
message: string;
|
|
167
|
+
type: string;
|
|
168
|
+
}>;
|
|
169
|
+
}>;
|
|
149
170
|
/**
|
|
150
171
|
* Clear the authentication token
|
|
151
172
|
*/
|
|
@@ -166,6 +166,16 @@ export class ApiService {
|
|
|
166
166
|
body: data,
|
|
167
167
|
});
|
|
168
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Update shipping address only (no email required)
|
|
171
|
+
* Useful for fetching shipping rates before email is entered
|
|
172
|
+
*/
|
|
173
|
+
async updateShippingAddressOnly(checkoutSessionId, shippingAddress) {
|
|
174
|
+
return this.fetch(`/api/v1/checkout-sessions/${checkoutSessionId}/shipping-address`, {
|
|
175
|
+
method: 'POST',
|
|
176
|
+
body: { shippingAddress },
|
|
177
|
+
});
|
|
178
|
+
}
|
|
169
179
|
/**
|
|
170
180
|
* Clear the authentication token
|
|
171
181
|
*/
|
|
@@ -9,7 +9,7 @@ export declare enum TrackingProvider {
|
|
|
9
9
|
FACEBOOK = "facebook",
|
|
10
10
|
TIKTOK = "tiktok",
|
|
11
11
|
SNAPCHAT = "snapchat",
|
|
12
|
-
|
|
12
|
+
PINTEREST = "pinterest",
|
|
13
13
|
GTM = "gtm"
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
@@ -71,6 +71,17 @@ export interface GTMTrackingConfig extends BaseTrackingConfig {
|
|
|
71
71
|
* This mirrors `TrackingFormValues` from the CRM.
|
|
72
72
|
*/
|
|
73
73
|
export type PixelConfig = PixelTrackingConfig | SnapchatTrackingConfig | MetaConversionTrackingConfig | GTMTrackingConfig;
|
|
74
|
+
/**
|
|
75
|
+
* Pixels configuration keyed by provider.
|
|
76
|
+
* Used in RuntimeStepConfig and getAssignedPixels().
|
|
77
|
+
*/
|
|
78
|
+
export type PixelsConfig = {
|
|
79
|
+
[TrackingProvider.FACEBOOK]?: PixelTrackingConfig[];
|
|
80
|
+
[TrackingProvider.TIKTOK]?: PixelTrackingConfig[];
|
|
81
|
+
[TrackingProvider.SNAPCHAT]?: SnapchatTrackingConfig[];
|
|
82
|
+
[TrackingProvider.PINTEREST]?: PixelTrackingConfig[];
|
|
83
|
+
[TrackingProvider.GTM]?: GTMTrackingConfig[];
|
|
84
|
+
};
|
|
74
85
|
/**
|
|
75
86
|
* Runtime step configuration injected from the CRM
|
|
76
87
|
* Contains payment flows, static resources, scripts, and tracking configs
|
|
@@ -86,13 +97,7 @@ export interface RuntimeStepConfig {
|
|
|
86
97
|
content: string;
|
|
87
98
|
position?: 'head-start' | 'head-end' | 'body-start' | 'body-end';
|
|
88
99
|
}>;
|
|
89
|
-
pixels?:
|
|
90
|
-
[TrackingProvider.FACEBOOK]?: PixelTrackingConfig[];
|
|
91
|
-
[TrackingProvider.TIKTOK]?: PixelTrackingConfig[];
|
|
92
|
-
[TrackingProvider.SNAPCHAT]?: SnapchatTrackingConfig[];
|
|
93
|
-
[TrackingProvider.META_CONVERSION]?: MetaConversionTrackingConfig[];
|
|
94
|
-
[TrackingProvider.GTM]?: GTMTrackingConfig[];
|
|
95
|
-
};
|
|
100
|
+
pixels?: PixelsConfig;
|
|
96
101
|
}
|
|
97
102
|
/**
|
|
98
103
|
* Local funnel configuration for development
|
|
@@ -165,13 +170,7 @@ export declare function getAssignedScripts(position?: 'head-start' | 'head-end'
|
|
|
165
170
|
* Get assigned pixel tracking configuration (normalized to arrays)
|
|
166
171
|
* Always returns arrays of PixelConfig for consistent consumption.
|
|
167
172
|
*/
|
|
168
|
-
export declare function getAssignedPixels():
|
|
169
|
-
[TrackingProvider.FACEBOOK]?: PixelTrackingConfig[];
|
|
170
|
-
[TrackingProvider.TIKTOK]?: PixelTrackingConfig[];
|
|
171
|
-
[TrackingProvider.SNAPCHAT]?: SnapchatTrackingConfig[];
|
|
172
|
-
[TrackingProvider.META_CONVERSION]?: MetaConversionTrackingConfig[];
|
|
173
|
-
[TrackingProvider.GTM]?: GTMTrackingConfig[];
|
|
174
|
-
} | undefined;
|
|
173
|
+
export declare function getAssignedPixels(): PixelsConfig | undefined;
|
|
175
174
|
export interface FunnelClientConfig {
|
|
176
175
|
apiClient: ApiClient;
|
|
177
176
|
debugMode?: boolean;
|
|
@@ -13,7 +13,7 @@ export var TrackingProvider;
|
|
|
13
13
|
TrackingProvider["FACEBOOK"] = "facebook";
|
|
14
14
|
TrackingProvider["TIKTOK"] = "tiktok";
|
|
15
15
|
TrackingProvider["SNAPCHAT"] = "snapchat";
|
|
16
|
-
TrackingProvider["
|
|
16
|
+
TrackingProvider["PINTEREST"] = "pinterest";
|
|
17
17
|
TrackingProvider["GTM"] = "gtm";
|
|
18
18
|
})(TrackingProvider || (TrackingProvider = {}));
|
|
19
19
|
/**
|
|
@@ -19,6 +19,16 @@ export interface ShippingRatesResponse {
|
|
|
19
19
|
rates: ShippingRate[];
|
|
20
20
|
forceCheckoutSessionRefetch?: boolean;
|
|
21
21
|
}
|
|
22
|
+
export interface ShippingRatesPreviewParams {
|
|
23
|
+
countryCode: string;
|
|
24
|
+
stateCode?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ShippingRatesPreviewResponse {
|
|
27
|
+
rates: ShippingRate[];
|
|
28
|
+
pickupPoint?: {
|
|
29
|
+
apiKey: string | null;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
22
32
|
export declare class ShippingRatesResource {
|
|
23
33
|
private apiClient;
|
|
24
34
|
constructor(apiClient: ApiClient);
|
|
@@ -33,4 +43,9 @@ export declare class ShippingRatesResource {
|
|
|
33
43
|
success: boolean;
|
|
34
44
|
error?: any;
|
|
35
45
|
}>;
|
|
46
|
+
/**
|
|
47
|
+
* Preview shipping rates for a country without updating session
|
|
48
|
+
* Useful for showing rates before user enters email
|
|
49
|
+
*/
|
|
50
|
+
previewShippingRates(sessionId: string, params: ShippingRatesPreviewParams): Promise<ShippingRatesPreviewResponse>;
|
|
36
51
|
}
|
|
@@ -20,4 +20,15 @@ export class ShippingRatesResource {
|
|
|
20
20
|
shippingRateId,
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Preview shipping rates for a country without updating session
|
|
25
|
+
* Useful for showing rates before user enters email
|
|
26
|
+
*/
|
|
27
|
+
async previewShippingRates(sessionId, params) {
|
|
28
|
+
const queryParams = new URLSearchParams({ countryCode: params.countryCode });
|
|
29
|
+
if (params.stateCode) {
|
|
30
|
+
queryParams.set('stateCode', params.stateCode);
|
|
31
|
+
}
|
|
32
|
+
return this.apiClient.get(`/api/v1/checkout-sessions/${sessionId}/shipping-rates/preview?${queryParams.toString()}`);
|
|
33
|
+
}
|
|
23
34
|
}
|
|
@@ -8,20 +8,6 @@ export interface Currency {
|
|
|
8
8
|
name: string;
|
|
9
9
|
decimalPlaces: number;
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
12
|
-
* Format money amount from minor units (cents) to a formatted string
|
|
13
|
-
*
|
|
14
|
-
* @param amountMinorUnits - Amount in minor units (e.g., 12345 for $123.45)
|
|
15
|
-
* @param currencyCode - ISO 4217 currency code (e.g., "USD", "EUR")
|
|
16
|
-
* @param locale - Locale for formatting (default: "en-US")
|
|
17
|
-
* @returns Formatted money string (e.g., "$123.45")
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* formatMoney(12345, 'USD') // "$123.45"
|
|
21
|
-
* formatMoney(10000, 'EUR', 'de-DE') // "100,00 €"
|
|
22
|
-
* formatMoney(1000, 'JPY') // "¥1,000"
|
|
23
|
-
*/
|
|
24
|
-
export declare function formatMoney(amountMinorUnits: number, currencyCode?: string, locale?: string): string;
|
|
25
11
|
export declare class CurrencyUtils {
|
|
26
12
|
/**
|
|
27
13
|
* Get currency from context or fallback to default
|
|
@@ -2,46 +2,6 @@
|
|
|
2
2
|
* Currency Utility Functions
|
|
3
3
|
* Pure functions for currency management
|
|
4
4
|
*/
|
|
5
|
-
/**
|
|
6
|
-
* Format money amount from minor units (cents) to a formatted string
|
|
7
|
-
*
|
|
8
|
-
* @param amountMinorUnits - Amount in minor units (e.g., 12345 for $123.45)
|
|
9
|
-
* @param currencyCode - ISO 4217 currency code (e.g., "USD", "EUR")
|
|
10
|
-
* @param locale - Locale for formatting (default: "en-US")
|
|
11
|
-
* @returns Formatted money string (e.g., "$123.45")
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* formatMoney(12345, 'USD') // "$123.45"
|
|
15
|
-
* formatMoney(10000, 'EUR', 'de-DE') // "100,00 €"
|
|
16
|
-
* formatMoney(1000, 'JPY') // "¥1,000"
|
|
17
|
-
*/
|
|
18
|
-
export function formatMoney(amountMinorUnits, currencyCode = 'USD', locale = 'en-US') {
|
|
19
|
-
const decimalPlaces = CurrencyUtils.getDecimalPlaces(currencyCode);
|
|
20
|
-
// Convert minor units to major units
|
|
21
|
-
// Backend stores amounts with 2 decimal places for all currencies
|
|
22
|
-
// For currencies with 0 decimal places (JPY, KRW, etc.), divide by 100
|
|
23
|
-
let value;
|
|
24
|
-
if (decimalPlaces === 0) {
|
|
25
|
-
// For zero-decimal currencies, backend still stores with 2 decimals
|
|
26
|
-
value = amountMinorUnits / 100;
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
value = amountMinorUnits / Math.pow(10, decimalPlaces);
|
|
30
|
-
}
|
|
31
|
-
try {
|
|
32
|
-
return new Intl.NumberFormat(locale, {
|
|
33
|
-
style: 'currency',
|
|
34
|
-
currency: currencyCode,
|
|
35
|
-
minimumFractionDigits: decimalPlaces,
|
|
36
|
-
maximumFractionDigits: decimalPlaces,
|
|
37
|
-
}).format(value);
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
// Fallback if Intl.NumberFormat fails
|
|
41
|
-
const symbol = CurrencyUtils.getCurrencySymbol(currencyCode);
|
|
42
|
-
return `${symbol}${value.toFixed(decimalPlaces)}`;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
5
|
export class CurrencyUtils {
|
|
46
6
|
/**
|
|
47
7
|
* Get currency from context or fallback to default
|
|
@@ -22,14 +22,6 @@ export type RawPluginConfig<TConfig = Record<string, any>> = {
|
|
|
22
22
|
basePath?: string;
|
|
23
23
|
config?: any;
|
|
24
24
|
} & TConfig;
|
|
25
|
-
/**
|
|
26
|
-
* Synchronously get plugin config from meta tags
|
|
27
|
-
* This is a lightweight sync alternative to loadPluginConfig
|
|
28
|
-
* Use this when you need immediate config access (e.g., in CDN bundles)
|
|
29
|
-
*
|
|
30
|
-
* @returns Plugin config from meta tags or defaults
|
|
31
|
-
*/
|
|
32
|
-
export declare function getPluginConfig(): PluginConfig;
|
|
33
25
|
/**
|
|
34
26
|
* Core plugin config loading function
|
|
35
27
|
*
|
|
@@ -154,37 +154,9 @@ const loadStaticResources = async () => {
|
|
|
154
154
|
* Helper to get content from meta tag
|
|
155
155
|
*/
|
|
156
156
|
const getMetaContent = (name) => {
|
|
157
|
-
if (typeof document === 'undefined')
|
|
158
|
-
return undefined;
|
|
159
157
|
const metaTag = document.querySelector(`meta[name="${name}"]`);
|
|
160
158
|
return metaTag?.getAttribute('content') || undefined;
|
|
161
159
|
};
|
|
162
|
-
/**
|
|
163
|
-
* Synchronously get plugin config from meta tags
|
|
164
|
-
* This is a lightweight sync alternative to loadPluginConfig
|
|
165
|
-
* Use this when you need immediate config access (e.g., in CDN bundles)
|
|
166
|
-
*
|
|
167
|
-
* @returns Plugin config from meta tags or defaults
|
|
168
|
-
*/
|
|
169
|
-
export function getPluginConfig() {
|
|
170
|
-
if (typeof document === 'undefined') {
|
|
171
|
-
return { basePath: '/', config: {} };
|
|
172
|
-
}
|
|
173
|
-
const storeId = getMetaContent('x-plugin-store-id');
|
|
174
|
-
const accountId = getMetaContent('x-plugin-account-id');
|
|
175
|
-
const basePath = getMetaContent('x-plugin-base-path') || '/';
|
|
176
|
-
let config = {};
|
|
177
|
-
try {
|
|
178
|
-
const encodedConfig = getMetaContent('x-plugin-config');
|
|
179
|
-
if (encodedConfig) {
|
|
180
|
-
config = JSON.parse(decodeURIComponent(encodedConfig));
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
catch (error) {
|
|
184
|
-
console.warn('[TagadaSDK] Failed to parse plugin config from meta tag:', error);
|
|
185
|
-
}
|
|
186
|
-
return { storeId, accountId, basePath, config };
|
|
187
|
-
}
|
|
188
160
|
/**
|
|
189
161
|
* Load production config from meta tags (HIGHEST PRIORITY)
|
|
190
162
|
* Meta tags are injected by the plugin middleware during HTML serving
|
|
@@ -212,143 +212,143 @@ export function injectPreviewModeIndicator() {
|
|
|
212
212
|
// Create container
|
|
213
213
|
const container = document.createElement('div');
|
|
214
214
|
container.id = 'tgd-preview-indicator';
|
|
215
|
-
container.style.cssText = `
|
|
216
|
-
position: fixed;
|
|
217
|
-
bottom: 16px;
|
|
218
|
-
right: 16px;
|
|
219
|
-
z-index: 999999;
|
|
220
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
215
|
+
container.style.cssText = `
|
|
216
|
+
position: fixed;
|
|
217
|
+
bottom: 16px;
|
|
218
|
+
right: 16px;
|
|
219
|
+
z-index: 999999;
|
|
220
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
221
221
|
`;
|
|
222
222
|
// Create badge
|
|
223
223
|
const badge = document.createElement('div');
|
|
224
|
-
badge.style.cssText = `
|
|
225
|
-
background: ${draftMode ? '#ff9500' : '#007aff'};
|
|
226
|
-
color: white;
|
|
227
|
-
padding: 8px 12px;
|
|
228
|
-
border-radius: 8px;
|
|
229
|
-
font-size: 13px;
|
|
230
|
-
font-weight: 600;
|
|
231
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
232
|
-
cursor: pointer;
|
|
233
|
-
transition: all 0.2s ease;
|
|
234
|
-
display: flex;
|
|
235
|
-
align-items: center;
|
|
236
|
-
gap: 6px;
|
|
224
|
+
badge.style.cssText = `
|
|
225
|
+
background: ${draftMode ? '#ff9500' : '#007aff'};
|
|
226
|
+
color: white;
|
|
227
|
+
padding: 8px 12px;
|
|
228
|
+
border-radius: 8px;
|
|
229
|
+
font-size: 13px;
|
|
230
|
+
font-weight: 600;
|
|
231
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
232
|
+
cursor: pointer;
|
|
233
|
+
transition: all 0.2s ease;
|
|
234
|
+
display: flex;
|
|
235
|
+
align-items: center;
|
|
236
|
+
gap: 6px;
|
|
237
237
|
`;
|
|
238
|
-
badge.innerHTML = `
|
|
239
|
-
<span style="font-size: 16px;">🔍</span>
|
|
240
|
-
<span>${draftMode ? 'Preview Mode' : 'Dev Mode'}</span>
|
|
238
|
+
badge.innerHTML = `
|
|
239
|
+
<span style="font-size: 16px;">🔍</span>
|
|
240
|
+
<span>${draftMode ? 'Preview Mode' : 'Dev Mode'}</span>
|
|
241
241
|
`;
|
|
242
242
|
// Create details popup (with padding-top to bridge gap with badge)
|
|
243
243
|
const details = document.createElement('div');
|
|
244
|
-
details.style.cssText = `
|
|
245
|
-
position: absolute;
|
|
246
|
-
bottom: calc(100% + 8px);
|
|
247
|
-
right: 0;
|
|
248
|
-
background: white;
|
|
249
|
-
border: 1px solid #e5e5e5;
|
|
250
|
-
border-radius: 8px;
|
|
251
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
252
|
-
padding: 12px;
|
|
253
|
-
min-width: 250px;
|
|
254
|
-
font-size: 12px;
|
|
255
|
-
line-height: 1.5;
|
|
256
|
-
display: none;
|
|
244
|
+
details.style.cssText = `
|
|
245
|
+
position: absolute;
|
|
246
|
+
bottom: calc(100% + 8px);
|
|
247
|
+
right: 0;
|
|
248
|
+
background: white;
|
|
249
|
+
border: 1px solid #e5e5e5;
|
|
250
|
+
border-radius: 8px;
|
|
251
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
252
|
+
padding: 12px;
|
|
253
|
+
min-width: 250px;
|
|
254
|
+
font-size: 12px;
|
|
255
|
+
line-height: 1.5;
|
|
256
|
+
display: none;
|
|
257
257
|
`;
|
|
258
258
|
details.style.paddingTop = '20px'; // Extra padding to bridge the gap
|
|
259
259
|
// Add invisible bridge between badge and popup to prevent flickering
|
|
260
260
|
const bridge = document.createElement('div');
|
|
261
|
-
bridge.style.cssText = `
|
|
262
|
-
position: absolute;
|
|
263
|
-
bottom: 100%;
|
|
264
|
-
left: 0;
|
|
265
|
-
right: 0;
|
|
266
|
-
height: 8px;
|
|
267
|
-
display: none;
|
|
261
|
+
bridge.style.cssText = `
|
|
262
|
+
position: absolute;
|
|
263
|
+
bottom: 100%;
|
|
264
|
+
left: 0;
|
|
265
|
+
right: 0;
|
|
266
|
+
height: 8px;
|
|
267
|
+
display: none;
|
|
268
268
|
`;
|
|
269
269
|
// Build details content
|
|
270
270
|
let detailsHTML = '<div style="margin-bottom: 8px; font-weight: 600; color: #1d1d1f;">Current Environment</div>';
|
|
271
271
|
detailsHTML += '<div style="display: flex; flex-direction: column; gap: 6px;">';
|
|
272
272
|
if (draftMode) {
|
|
273
|
-
detailsHTML += `
|
|
274
|
-
<div style="display: flex; justify-content: space-between; color: #86868b;">
|
|
275
|
-
<span>Draft Mode:</span>
|
|
276
|
-
<span style="color: #ff9500; font-weight: 600;">ON</span>
|
|
277
|
-
</div>
|
|
273
|
+
detailsHTML += `
|
|
274
|
+
<div style="display: flex; justify-content: space-between; color: #86868b;">
|
|
275
|
+
<span>Draft Mode:</span>
|
|
276
|
+
<span style="color: #ff9500; font-weight: 600;">ON</span>
|
|
277
|
+
</div>
|
|
278
278
|
`;
|
|
279
279
|
}
|
|
280
280
|
if (trackingDisabled) {
|
|
281
|
-
detailsHTML += `
|
|
282
|
-
<div style="display: flex; justify-content: space-between; color: #86868b;">
|
|
283
|
-
<span>Tracking:</span>
|
|
284
|
-
<span style="color: #ff3b30; font-weight: 600;">DISABLED</span>
|
|
285
|
-
</div>
|
|
281
|
+
detailsHTML += `
|
|
282
|
+
<div style="display: flex; justify-content: space-between; color: #86868b;">
|
|
283
|
+
<span>Tracking:</span>
|
|
284
|
+
<span style="color: #ff3b30; font-weight: 600;">DISABLED</span>
|
|
285
|
+
</div>
|
|
286
286
|
`;
|
|
287
287
|
}
|
|
288
288
|
if (params.funnelEnv) {
|
|
289
|
-
detailsHTML += `
|
|
290
|
-
<div style="display: flex; justify-content: space-between; color: #86868b;">
|
|
291
|
-
<span>Funnel Env:</span>
|
|
292
|
-
<span style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 11px;">
|
|
293
|
-
${params.funnelEnv}
|
|
294
|
-
</span>
|
|
295
|
-
</div>
|
|
289
|
+
detailsHTML += `
|
|
290
|
+
<div style="display: flex; justify-content: space-between; color: #86868b;">
|
|
291
|
+
<span>Funnel Env:</span>
|
|
292
|
+
<span style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 11px;">
|
|
293
|
+
${params.funnelEnv}
|
|
294
|
+
</span>
|
|
295
|
+
</div>
|
|
296
296
|
`;
|
|
297
297
|
}
|
|
298
298
|
if (params.tagadaClientEnv) {
|
|
299
|
-
detailsHTML += `
|
|
300
|
-
<div style="display: flex; justify-content: space-between; color: #86868b;">
|
|
301
|
-
<span>API Env:</span>
|
|
302
|
-
<span style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 11px;">
|
|
303
|
-
${params.tagadaClientEnv}
|
|
304
|
-
</span>
|
|
305
|
-
</div>
|
|
299
|
+
detailsHTML += `
|
|
300
|
+
<div style="display: flex; justify-content: space-between; color: #86868b;">
|
|
301
|
+
<span>API Env:</span>
|
|
302
|
+
<span style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 11px;">
|
|
303
|
+
${params.tagadaClientEnv}
|
|
304
|
+
</span>
|
|
305
|
+
</div>
|
|
306
306
|
`;
|
|
307
307
|
}
|
|
308
308
|
if (params.tagadaClientBaseUrl) {
|
|
309
|
-
detailsHTML += `
|
|
310
|
-
<div style="color: #86868b;">
|
|
311
|
-
<div style="margin-bottom: 4px;">API URL:</div>
|
|
312
|
-
<div style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 10px; word-break: break-all; background: #f5f5f7; padding: 4px 6px; border-radius: 4px;">
|
|
313
|
-
${params.tagadaClientBaseUrl}
|
|
314
|
-
</div>
|
|
315
|
-
</div>
|
|
309
|
+
detailsHTML += `
|
|
310
|
+
<div style="color: #86868b;">
|
|
311
|
+
<div style="margin-bottom: 4px;">API URL:</div>
|
|
312
|
+
<div style="color: #1d1d1f; font-weight: 600; font-family: monospace; font-size: 10px; word-break: break-all; background: #f5f5f7; padding: 4px 6px; border-radius: 4px;">
|
|
313
|
+
${params.tagadaClientBaseUrl}
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
316
|
`;
|
|
317
317
|
}
|
|
318
318
|
if (params.funnelId) {
|
|
319
|
-
detailsHTML += `
|
|
320
|
-
<div style="color: #86868b; margin-top: 4px; padding-top: 8px; border-top: 1px solid #e5e5e5;">
|
|
321
|
-
<div style="margin-bottom: 4px;">Funnel ID:</div>
|
|
322
|
-
<div style="color: #1d1d1f; font-family: monospace; font-size: 10px; word-break: break-all; background: #f5f5f7; padding: 4px 6px; border-radius: 4px;">
|
|
323
|
-
${params.funnelId}
|
|
324
|
-
</div>
|
|
325
|
-
</div>
|
|
319
|
+
detailsHTML += `
|
|
320
|
+
<div style="color: #86868b; margin-top: 4px; padding-top: 8px; border-top: 1px solid #e5e5e5;">
|
|
321
|
+
<div style="margin-bottom: 4px;">Funnel ID:</div>
|
|
322
|
+
<div style="color: #1d1d1f; font-family: monospace; font-size: 10px; word-break: break-all; background: #f5f5f7; padding: 4px 6px; border-radius: 4px;">
|
|
323
|
+
${params.funnelId}
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
326
|
`;
|
|
327
327
|
}
|
|
328
328
|
detailsHTML += '</div>';
|
|
329
|
-
detailsHTML += `
|
|
330
|
-
<div style="margin-top: 12px; padding-top: 8px; border-top: 1px solid #e5e5e5; font-size: 11px; color: #86868b; text-align: center;">
|
|
331
|
-
Add <code style="background: #f5f5f7; padding: 2px 4px; border-radius: 3px;">?forceReset=true</code> to reset
|
|
332
|
-
</div>
|
|
329
|
+
detailsHTML += `
|
|
330
|
+
<div style="margin-top: 12px; padding-top: 8px; border-top: 1px solid #e5e5e5; font-size: 11px; color: #86868b; text-align: center;">
|
|
331
|
+
Add <code style="background: #f5f5f7; padding: 2px 4px; border-radius: 3px;">?forceReset=true</code> to reset
|
|
332
|
+
</div>
|
|
333
333
|
`;
|
|
334
334
|
// Add action button
|
|
335
|
-
detailsHTML += `
|
|
336
|
-
<div style="margin-top: 12px; padding-top: 8px; border-top: 1px solid #e5e5e5;">
|
|
337
|
-
<button id="tgd-leave-preview" style="
|
|
338
|
-
background: #ff3b30;
|
|
339
|
-
color: white;
|
|
340
|
-
border: none;
|
|
341
|
-
border-radius: 6px;
|
|
342
|
-
padding: 10px 12px;
|
|
343
|
-
font-size: 13px;
|
|
344
|
-
font-weight: 600;
|
|
345
|
-
cursor: pointer;
|
|
346
|
-
transition: opacity 0.2s;
|
|
347
|
-
width: 100%;
|
|
348
|
-
">
|
|
349
|
-
🚪 Leave Preview Mode
|
|
350
|
-
</button>
|
|
351
|
-
</div>
|
|
335
|
+
detailsHTML += `
|
|
336
|
+
<div style="margin-top: 12px; padding-top: 8px; border-top: 1px solid #e5e5e5;">
|
|
337
|
+
<button id="tgd-leave-preview" style="
|
|
338
|
+
background: #ff3b30;
|
|
339
|
+
color: white;
|
|
340
|
+
border: none;
|
|
341
|
+
border-radius: 6px;
|
|
342
|
+
padding: 10px 12px;
|
|
343
|
+
font-size: 13px;
|
|
344
|
+
font-weight: 600;
|
|
345
|
+
cursor: pointer;
|
|
346
|
+
transition: opacity 0.2s;
|
|
347
|
+
width: 100%;
|
|
348
|
+
">
|
|
349
|
+
🚪 Leave Preview Mode
|
|
350
|
+
</button>
|
|
351
|
+
</div>
|
|
352
352
|
`;
|
|
353
353
|
details.innerHTML = detailsHTML;
|
|
354
354
|
// Hover behavior - keep popup visible when hovering over badge, bridge, or popup
|
package/dist/v2/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export * from './core/utils/previewMode';
|
|
|
14
14
|
export { injectPreviewModeIndicator, isIndicatorInjected, removePreviewModeIndicator } from './core/utils/previewModeIndicator';
|
|
15
15
|
export * from './core/utils/products';
|
|
16
16
|
export { getAssignedPaymentFlowId, getAssignedScripts, getAssignedStaticResources, getAssignedStepConfig, getLocalFunnelConfig, loadLocalFunnelConfig } from './core/funnelClient';
|
|
17
|
-
export type { LocalFunnelConfig, RuntimeStepConfig } from './core/funnelClient';
|
|
17
|
+
export type { LocalFunnelConfig, PixelsConfig, RuntimeStepConfig } from './core/funnelClient';
|
|
18
18
|
export * from './core/pathRemapping';
|
|
19
19
|
export type { CheckoutData, CheckoutInitParams, CheckoutLineItem, CheckoutSession, CheckoutSessionPreview, Promotion } from './core/resources/checkout';
|
|
20
20
|
export type { Order, OrderLineItem } from './core/utils/order';
|