@tagadapay/plugin-sdk 3.1.25 → 4.0.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/README.md +1129 -1129
- package/build-cdn.js +499 -499
- package/dist/external-tracker.js +5 -5
- package/dist/external-tracker.min.js +2 -2
- package/dist/external-tracker.min.js.map +2 -2
- package/dist/react/config/payment.d.ts +2 -2
- package/dist/react/config/payment.js +5 -5
- package/dist/react/hooks/usePayment.d.ts +7 -0
- package/dist/react/hooks/usePayment.js +1 -0
- package/dist/react/providers/TagadaProvider.js +5 -5
- package/dist/tagada-react-sdk-minimal.min.js +2 -2
- package/dist/tagada-react-sdk-minimal.min.js.map +4 -4
- package/dist/tagada-react-sdk.js +1616 -1275
- package/dist/tagada-react-sdk.min.js +2 -2
- package/dist/tagada-react-sdk.min.js.map +4 -4
- package/dist/tagada-sdk.js +869 -27
- package/dist/tagada-sdk.min.js +2 -2
- package/dist/tagada-sdk.min.js.map +4 -4
- package/dist/v2/core/config/environment.d.ts +3 -3
- package/dist/v2/core/config/environment.js +7 -7
- package/dist/v2/core/funnelClient.d.ts +2 -0
- package/dist/v2/core/resources/funnel.d.ts +1 -1
- package/dist/v2/core/resources/geo.d.ts +50 -0
- package/dist/v2/core/resources/geo.js +35 -0
- package/dist/v2/core/resources/payments.d.ts +19 -1
- package/dist/v2/core/resources/payments.js +8 -0
- package/dist/v2/core/utils/previewModeIndicator.js +101 -101
- package/dist/v2/react/components/FunnelScriptInjector.js +167 -19
- package/dist/v2/react/components/StripeExpressButton.d.ts +8 -0
- package/dist/v2/react/components/StripeExpressButton.js +22 -1
- package/dist/v2/react/hooks/payment-actions/useNgeniusThreedsAction.d.ts +15 -0
- package/dist/v2/react/hooks/payment-actions/useNgeniusThreedsAction.js +166 -0
- package/dist/v2/react/hooks/payment-actions/usePaymentActionHandler.js +12 -0
- package/dist/v2/react/hooks/payment-processing/usePaymentProcessors.js +1 -0
- package/dist/v2/react/hooks/useISOData.js +25 -7
- package/dist/v2/react/hooks/usePaymentPolling.d.ts +1 -1
- package/dist/v2/react/providers/ExpressPaymentMethodsProvider.js +12 -4
- package/dist/v2/react/providers/TagadaProvider.js +5 -5
- package/dist/v2/standalone/apple-pay-service.d.ts +12 -0
- package/dist/v2/standalone/apple-pay-service.js +12 -0
- package/dist/v2/standalone/external-tracker.d.ts +1 -1
- package/dist/v2/standalone/google-pay-service.d.ts +9 -0
- package/dist/v2/standalone/google-pay-service.js +9 -0
- package/dist/v2/standalone/index.d.ts +8 -1
- package/dist/v2/standalone/index.js +7 -0
- package/dist/v2/standalone/payment-service.d.ts +18 -5
- package/dist/v2/standalone/payment-service.js +62 -9
- package/package.json +115 -114
|
@@ -8,11 +8,11 @@ import { ApiConfig, Environment, EnvironmentConfig } from '../types';
|
|
|
8
8
|
* Environment detection priority (highest to lowest):
|
|
9
9
|
* 1. **tagadaClientEnv** - Explicit override via URL param, localStorage, or cookie
|
|
10
10
|
* Example: ?tagadaClientEnv=production
|
|
11
|
-
* 2. **Production domains** → production API (
|
|
12
|
-
* 3. **Dev/staging domains** → development API (
|
|
11
|
+
* 2. **Production domains** → production API (api.tagada.io)
|
|
12
|
+
* 3. **Dev/staging domains** → development API (api.tagada.dev, vercel.app, etc.)
|
|
13
13
|
* 4. **Localhost/local IPs** → local API (localhost, 127.0.0.1, etc.)
|
|
14
14
|
* - Can be overridden via window.__TAGADA_ENV__.TAGADA_ENVIRONMENT
|
|
15
|
-
* 5. **Default fallback** → production API (safest
|
|
15
|
+
* 5. **Default fallback** → production API (safest)
|
|
16
16
|
*
|
|
17
17
|
* Build-time .env variables (VITE_*, REACT_APP_*, NEXT_PUBLIC_*) are IGNORED
|
|
18
18
|
* to prevent incorrect API connections when plugins are deployed to different environments.
|
|
@@ -19,11 +19,11 @@ function getCookie(name) {
|
|
|
19
19
|
* Environment detection priority (highest to lowest):
|
|
20
20
|
* 1. **tagadaClientEnv** - Explicit override via URL param, localStorage, or cookie
|
|
21
21
|
* Example: ?tagadaClientEnv=production
|
|
22
|
-
* 2. **Production domains** → production API (
|
|
23
|
-
* 3. **Dev/staging domains** → development API (
|
|
22
|
+
* 2. **Production domains** → production API (api.tagada.io)
|
|
23
|
+
* 3. **Dev/staging domains** → development API (api.tagada.dev, vercel.app, etc.)
|
|
24
24
|
* 4. **Localhost/local IPs** → local API (localhost, 127.0.0.1, etc.)
|
|
25
25
|
* - Can be overridden via window.__TAGADA_ENV__.TAGADA_ENVIRONMENT
|
|
26
|
-
* 5. **Default fallback** → production API (safest
|
|
26
|
+
* 5. **Default fallback** → production API (safest)
|
|
27
27
|
*
|
|
28
28
|
* Build-time .env variables (VITE_*, REACT_APP_*, NEXT_PUBLIC_*) are IGNORED
|
|
29
29
|
* to prevent incorrect API connections when plugins are deployed to different environments.
|
|
@@ -33,7 +33,7 @@ function getCookie(name) {
|
|
|
33
33
|
*/
|
|
34
34
|
export const ENVIRONMENT_CONFIGS = {
|
|
35
35
|
production: {
|
|
36
|
-
baseUrl: 'https://
|
|
36
|
+
baseUrl: 'https://api.tagada.io',
|
|
37
37
|
endpoints: {
|
|
38
38
|
checkout: {
|
|
39
39
|
sessionInit: '/api/v1/checkout/session/init',
|
|
@@ -51,7 +51,7 @@ export const ENVIRONMENT_CONFIGS = {
|
|
|
51
51
|
},
|
|
52
52
|
},
|
|
53
53
|
development: {
|
|
54
|
-
baseUrl: 'https://
|
|
54
|
+
baseUrl: 'https://api.tagada.dev',
|
|
55
55
|
endpoints: {
|
|
56
56
|
checkout: {
|
|
57
57
|
sessionInit: '/api/v1/checkout/session/init',
|
|
@@ -213,13 +213,13 @@ export function detectEnvironment() {
|
|
|
213
213
|
return 'local';
|
|
214
214
|
}
|
|
215
215
|
// 2. Production: deployed to production domains
|
|
216
|
-
if (hostname
|
|
216
|
+
if (hostname.includes('tagada.io') ||
|
|
217
217
|
hostname.includes('tagadapay.com') ||
|
|
218
218
|
hostname.includes('yourproductiondomain.com')) {
|
|
219
219
|
return 'production';
|
|
220
220
|
}
|
|
221
221
|
// 3. Development: deployed to staging/dev domains or has dev indicators
|
|
222
|
-
if (hostname
|
|
222
|
+
if (hostname.includes('tagada.dev') ||
|
|
223
223
|
hostname.includes('tagadapay.dev') ||
|
|
224
224
|
hostname.includes('vercel.app') ||
|
|
225
225
|
hostname.includes('netlify.app') ||
|
|
@@ -137,6 +137,8 @@ export interface PaymentMethodConfig {
|
|
|
137
137
|
note?: string;
|
|
138
138
|
}>;
|
|
139
139
|
metadata?: Record<string, any>;
|
|
140
|
+
/** Integration settings (e.g. custom_payment checkout instructions, thank-you text) */
|
|
141
|
+
settings?: Record<string, any>;
|
|
140
142
|
}
|
|
141
143
|
export type PaymentSetupConfig = Record<string, PaymentMethodConfig>;
|
|
142
144
|
/** Get all enabled entries from a paymentSetupConfig */
|
|
@@ -405,7 +405,7 @@ export interface SimpleFunnelContext<TCustom = {}> {
|
|
|
405
405
|
* ✅ Environment context (staging or production)
|
|
406
406
|
* - Determined at session initialization based on entry URL
|
|
407
407
|
* - Ensures all navigation stays in the same environment
|
|
408
|
-
* - 'staging': Uses funnel.config (alias domains like funnel--store.cdn.
|
|
408
|
+
* - 'staging': Uses funnel.config (alias domains like funnel--store.cdn.tagada.io)
|
|
409
409
|
* - 'production': Uses funnel.productionConfig (custom domains)
|
|
410
410
|
*/
|
|
411
411
|
environment?: 'staging' | 'production';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Geo Resource Client
|
|
3
|
+
* API client for IP geolocation endpoint
|
|
4
|
+
*/
|
|
5
|
+
import { ApiClient } from './apiClient';
|
|
6
|
+
export interface GeoLocationData {
|
|
7
|
+
ip_address?: string | null;
|
|
8
|
+
city?: string | null;
|
|
9
|
+
region?: string | null;
|
|
10
|
+
region_iso_code?: string | null;
|
|
11
|
+
postal_code?: string | null;
|
|
12
|
+
country?: string | null;
|
|
13
|
+
country_code?: string | null;
|
|
14
|
+
country_is_eu?: boolean | null;
|
|
15
|
+
continent?: string | null;
|
|
16
|
+
continent_code?: string | null;
|
|
17
|
+
latitude?: number | null;
|
|
18
|
+
longitude?: number | null;
|
|
19
|
+
security?: {
|
|
20
|
+
is_vpn?: boolean | null;
|
|
21
|
+
} | null;
|
|
22
|
+
timezone?: {
|
|
23
|
+
name?: string | null;
|
|
24
|
+
abbreviation?: string | null;
|
|
25
|
+
gmt_offset?: number | null;
|
|
26
|
+
current_time?: string | null;
|
|
27
|
+
is_dst?: boolean | null;
|
|
28
|
+
} | null;
|
|
29
|
+
currency?: {
|
|
30
|
+
currency_name?: string | null;
|
|
31
|
+
currency_code?: string | null;
|
|
32
|
+
} | null;
|
|
33
|
+
}
|
|
34
|
+
export declare class GeoResource {
|
|
35
|
+
private apiClient;
|
|
36
|
+
constructor(apiClient: ApiClient);
|
|
37
|
+
/**
|
|
38
|
+
* Get geolocation data from the visitor's IP address
|
|
39
|
+
*/
|
|
40
|
+
getGeoLocation(): Promise<GeoLocationData>;
|
|
41
|
+
/**
|
|
42
|
+
* Get geolocation data for a specific IP address
|
|
43
|
+
*/
|
|
44
|
+
getGeoLocationByIp(ip: string): Promise<GeoLocationData>;
|
|
45
|
+
/**
|
|
46
|
+
* Convenience: get just the country code from IP geolocation
|
|
47
|
+
* Returns ISO 3166-1 alpha-2 code (e.g. 'US', 'FR') or null
|
|
48
|
+
*/
|
|
49
|
+
detectCountry(): Promise<string | null>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Geo Resource Client
|
|
3
|
+
* API client for IP geolocation endpoint
|
|
4
|
+
*/
|
|
5
|
+
export class GeoResource {
|
|
6
|
+
constructor(apiClient) {
|
|
7
|
+
this.apiClient = apiClient;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Get geolocation data from the visitor's IP address
|
|
11
|
+
*/
|
|
12
|
+
async getGeoLocation() {
|
|
13
|
+
return this.apiClient.get('/api/v1/geo');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get geolocation data for a specific IP address
|
|
17
|
+
*/
|
|
18
|
+
async getGeoLocationByIp(ip) {
|
|
19
|
+
return this.apiClient.get(`/api/v1/geo?ip=${encodeURIComponent(ip)}`);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Convenience: get just the country code from IP geolocation
|
|
23
|
+
* Returns ISO 3166-1 alpha-2 code (e.g. 'US', 'FR') or null
|
|
24
|
+
*/
|
|
25
|
+
async detectCountry() {
|
|
26
|
+
try {
|
|
27
|
+
const data = await this.getGeoLocation();
|
|
28
|
+
const code = data?.country_code;
|
|
29
|
+
return code && typeof code === 'string' && code.length === 2 ? code : null;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -10,7 +10,7 @@ export interface Payment {
|
|
|
10
10
|
subStatus: string;
|
|
11
11
|
requireAction: 'none' | 'redirect' | 'redirect_to_payment' | 'error' | 'radar' | 'stripe_express_checkout';
|
|
12
12
|
requireActionData?: {
|
|
13
|
-
type: 'redirect' | 'redirect_to_payment' | 'threeds_auth' | 'processor_auth' | 'error' | 'stripe_radar' | 'finix_radar' | 'radar' | 'kesspay_auth' | 'trustflow_auth' | 'mastercard_auth' | 'stripe_express_checkout';
|
|
13
|
+
type: 'redirect' | 'redirect_to_payment' | 'threeds_auth' | 'processor_auth' | 'error' | 'stripe_radar' | 'finix_radar' | 'radar' | 'kesspay_auth' | 'trustflow_auth' | 'mastercard_auth' | 'stripe_express_checkout' | 'ngenius_3ds';
|
|
14
14
|
url?: string;
|
|
15
15
|
processed: boolean;
|
|
16
16
|
processorId?: string;
|
|
@@ -112,6 +112,14 @@ export interface PaymentOptions {
|
|
|
112
112
|
* Payment method type (e.g., 'klarna', 'afterpay', 'paypal')
|
|
113
113
|
*/
|
|
114
114
|
paymentMethod?: string;
|
|
115
|
+
/**
|
|
116
|
+
* Shipping rate selected by the customer at checkout. Forwarded to
|
|
117
|
+
* `processPaymentDirect` so the order is created with the right shipping
|
|
118
|
+
* even if the session's stored rate hasn't fully round-tripped or got
|
|
119
|
+
* cleared (race conditions). The backend treats this as authoritative
|
|
120
|
+
* when present, otherwise falls back to the session's stored rate.
|
|
121
|
+
*/
|
|
122
|
+
shippingRateId?: string;
|
|
115
123
|
/** @deprecated Use onPaymentSuccess instead - this will be removed in v3 */
|
|
116
124
|
onSuccess?: (response: PaymentResponse) => void;
|
|
117
125
|
/** @deprecated Use onPaymentFailed instead - this will be removed in v3 */
|
|
@@ -247,6 +255,7 @@ export declare class PaymentsResource {
|
|
|
247
255
|
processorId?: string;
|
|
248
256
|
paymentMethod?: string;
|
|
249
257
|
isExpress?: boolean;
|
|
258
|
+
shippingRateId?: string;
|
|
250
259
|
}): Promise<PaymentResponse>;
|
|
251
260
|
/**
|
|
252
261
|
* Get card payment instruments for customer
|
|
@@ -304,4 +313,13 @@ export declare class PaymentsResource {
|
|
|
304
313
|
status: 'succeeded' | 'failed' | 'pending';
|
|
305
314
|
paymentIntentId: string;
|
|
306
315
|
}): Promise<Payment>;
|
|
316
|
+
/**
|
|
317
|
+
* Complete N-Genius payment after WebSDK 3DS flow finishes.
|
|
318
|
+
* Verifies state from N-Genius server-side and updates the payment record.
|
|
319
|
+
*/
|
|
320
|
+
ngeniusThreedsComplete(data: {
|
|
321
|
+
paymentId: string;
|
|
322
|
+
orderReference: string;
|
|
323
|
+
paymentReference: string;
|
|
324
|
+
}): Promise<Payment>;
|
|
307
325
|
}
|
|
@@ -148,6 +148,7 @@ export class PaymentsResource {
|
|
|
148
148
|
...(options.processorId && { processorId: options.processorId }),
|
|
149
149
|
...(options.paymentMethod && { paymentMethod: options.paymentMethod }),
|
|
150
150
|
...(options.isExpress && { isExpress: options.isExpress }),
|
|
151
|
+
...(options.shippingRateId && { shippingRateId: options.shippingRateId }),
|
|
151
152
|
};
|
|
152
153
|
console.log('[PaymentsResource] Request body being sent:', JSON.stringify(requestBody, null, 2));
|
|
153
154
|
const response = await this.apiClient.post('/api/public/v1/checkout/pay-v2', requestBody);
|
|
@@ -206,4 +207,11 @@ export class PaymentsResource {
|
|
|
206
207
|
async updateThreedsStatus(data) {
|
|
207
208
|
return this.apiClient.post('/api/v1/threeds/status', data);
|
|
208
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Complete N-Genius payment after WebSDK 3DS flow finishes.
|
|
212
|
+
* Verifies state from N-Genius server-side and updates the payment record.
|
|
213
|
+
*/
|
|
214
|
+
async ngeniusThreedsComplete(data) {
|
|
215
|
+
return this.apiClient.post('/api/v1/payments/ngenius/threeds-complete', data);
|
|
216
|
+
}
|
|
209
217
|
}
|
|
@@ -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
|