@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.
Files changed (38) hide show
  1. package/README.md +1129 -1129
  2. package/build-cdn.js +113 -228
  3. package/dist/external-tracker.js +2 -3
  4. package/dist/external-tracker.min.js +2 -2
  5. package/dist/external-tracker.min.js.map +3 -3
  6. package/dist/react/hooks/useShippingRates.d.ts +6 -0
  7. package/dist/react/hooks/useShippingRates.js +38 -0
  8. package/dist/react/providers/TagadaProvider.js +5 -5
  9. package/dist/react/services/apiService.d.ts +21 -0
  10. package/dist/react/services/apiService.js +10 -0
  11. package/dist/v2/core/funnelClient.d.ts +14 -15
  12. package/dist/v2/core/funnelClient.js +1 -1
  13. package/dist/v2/core/resources/shippingRates.d.ts +15 -0
  14. package/dist/v2/core/resources/shippingRates.js +11 -0
  15. package/dist/v2/core/utils/currency.d.ts +0 -14
  16. package/dist/v2/core/utils/currency.js +0 -40
  17. package/dist/v2/core/utils/index.d.ts +0 -1
  18. package/dist/v2/core/utils/index.js +0 -2
  19. package/dist/v2/core/utils/pluginConfig.d.ts +0 -8
  20. package/dist/v2/core/utils/pluginConfig.js +0 -28
  21. package/dist/v2/core/utils/previewModeIndicator.js +101 -101
  22. package/dist/v2/index.d.ts +1 -1
  23. package/dist/v2/react/components/ApplePayButton.js +13 -4
  24. package/dist/v2/react/components/FunnelScriptInjector.js +30 -30
  25. package/dist/v2/react/hooks/useFunnel.d.ts +1 -2
  26. package/dist/v2/react/hooks/useGoogleAutocomplete.js +82 -33
  27. package/dist/v2/react/hooks/usePixelTracking.d.ts +5 -0
  28. package/dist/v2/react/hooks/usePixelTracking.js +108 -0
  29. package/dist/v2/react/hooks/useShippingRatesQuery.d.ts +6 -0
  30. package/dist/v2/react/hooks/useShippingRatesQuery.js +36 -1
  31. package/dist/v2/react/hooks/useStepConfig.d.ts +2 -8
  32. package/dist/v2/react/hooks/useStepConfig.js +1 -1
  33. package/dist/v2/react/providers/TagadaProvider.js +5 -5
  34. package/dist/v2/standalone/index.js +1 -1
  35. package/package.json +112 -112
  36. package/dist/tagada-sdk.js +0 -10166
  37. package/dist/tagada-sdk.min.js +0 -48
  38. 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
- META_CONVERSION = "meta_conversion",
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["META_CONVERSION"] = "meta_conversion";
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
@@ -12,4 +12,3 @@ export * from './postPurchases';
12
12
  export * from './orderBump';
13
13
  export * from './sessionStorage';
14
14
  export * from './funnelQueryKeys';
15
- export * from './configHotReload';
@@ -12,5 +12,3 @@ export * from './postPurchases';
12
12
  export * from './orderBump';
13
13
  export * from './sessionStorage';
14
14
  export * from './funnelQueryKeys';
15
- // Config hot reload for live preview editing
16
- export * from './configHotReload';
@@ -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
@@ -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';