@tagadapay/plugin-sdk 2.3.2 → 2.3.4
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 +623 -601
- package/dist/react/hooks/useCheckout.js +6 -1
- package/dist/react/hooks/useDiscounts.d.ts +47 -0
- package/dist/react/hooks/useDiscounts.js +163 -0
- package/dist/react/hooks/useProducts.d.ts +1 -0
- package/dist/react/index.d.ts +11 -9
- package/dist/react/index.js +4 -3
- package/dist/react/providers/TagadaProvider.js +5 -5
- package/dist/react/utils/trackingUtils.d.ts +24 -0
- package/dist/react/utils/trackingUtils.js +172 -0
- package/package.json +83 -78
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { useCurrency } from '../hooks/useCurrency';
|
|
3
3
|
import { useTagadaContext } from '../providers/TagadaProvider';
|
|
4
|
+
import { collectTrackingData } from '../utils/trackingUtils';
|
|
4
5
|
import { usePluginConfig } from './usePluginConfig';
|
|
5
6
|
export function useCheckout(options = {}) {
|
|
6
7
|
const { apiService, updateCheckoutDebugData, refreshCoordinator, currency, isSessionInitialized } = useTagadaContext();
|
|
@@ -77,9 +78,13 @@ export function useCheckout(options = {}) {
|
|
|
77
78
|
setIsLoading(true);
|
|
78
79
|
setError(null);
|
|
79
80
|
try {
|
|
80
|
-
//
|
|
81
|
+
// Collect tracking data
|
|
82
|
+
const trackingData = await collectTrackingData();
|
|
83
|
+
// Enhanced customerMetadata with tracking data
|
|
81
84
|
const enhancedCustomerMetadata = {
|
|
82
85
|
...params.customerMetadata,
|
|
86
|
+
localStorage: trackingData.localStorageData,
|
|
87
|
+
cookies: trackingData.trackingCookiesData,
|
|
83
88
|
};
|
|
84
89
|
const requestBody = {
|
|
85
90
|
...params,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface Discount {
|
|
2
|
+
id: string;
|
|
3
|
+
promotionId: string;
|
|
4
|
+
promotionCodeId: string | null;
|
|
5
|
+
appliedAt: string;
|
|
6
|
+
appliedManually: boolean;
|
|
7
|
+
promotion: {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface DiscountCodeValidation {
|
|
13
|
+
isValid: boolean;
|
|
14
|
+
code: string;
|
|
15
|
+
error?: string;
|
|
16
|
+
discount?: {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
type: string;
|
|
20
|
+
value: number;
|
|
21
|
+
currency: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface UseDiscountsOptions {
|
|
25
|
+
checkoutSessionId?: string;
|
|
26
|
+
autoRefresh?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface UseDiscountsResult {
|
|
29
|
+
appliedDiscounts: Discount[];
|
|
30
|
+
isLoading: boolean;
|
|
31
|
+
isApplying: boolean;
|
|
32
|
+
isRemoving: boolean;
|
|
33
|
+
error: Error | null;
|
|
34
|
+
applyDiscountCode: (code: string) => Promise<{
|
|
35
|
+
success: boolean;
|
|
36
|
+
error?: string;
|
|
37
|
+
discount?: Discount;
|
|
38
|
+
}>;
|
|
39
|
+
removeDiscountCode: (discountId: string) => Promise<{
|
|
40
|
+
success: boolean;
|
|
41
|
+
error?: string;
|
|
42
|
+
}>;
|
|
43
|
+
getAppliedDiscounts: () => Promise<Discount[]>;
|
|
44
|
+
refresh: () => Promise<void>;
|
|
45
|
+
clearError: () => void;
|
|
46
|
+
}
|
|
47
|
+
export declare function useDiscounts(options?: UseDiscountsOptions): UseDiscountsResult;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { useTagadaContext } from '../providers/TagadaProvider';
|
|
3
|
+
export function useDiscounts(options = {}) {
|
|
4
|
+
const { apiService, refreshCoordinator } = useTagadaContext();
|
|
5
|
+
const { checkoutSessionId, autoRefresh = true } = options;
|
|
6
|
+
const [appliedDiscounts, setAppliedDiscounts] = useState([]);
|
|
7
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
8
|
+
const [isApplying, setIsApplying] = useState(false);
|
|
9
|
+
const [isRemoving, setIsRemoving] = useState(false);
|
|
10
|
+
const [error, setError] = useState(null);
|
|
11
|
+
const clearError = useCallback(() => {
|
|
12
|
+
setError(null);
|
|
13
|
+
}, []);
|
|
14
|
+
const getAppliedDiscounts = useCallback(async () => {
|
|
15
|
+
if (!checkoutSessionId) {
|
|
16
|
+
throw new Error('No checkout session available');
|
|
17
|
+
}
|
|
18
|
+
setIsLoading(true);
|
|
19
|
+
setError(null);
|
|
20
|
+
try {
|
|
21
|
+
const response = await apiService.fetch(`/api/v1/checkout-sessions/${checkoutSessionId}/promotions`, {
|
|
22
|
+
method: 'GET',
|
|
23
|
+
});
|
|
24
|
+
setAppliedDiscounts(response);
|
|
25
|
+
return response;
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
const error = err instanceof Error ? err : new Error('Failed to fetch applied discounts');
|
|
29
|
+
setError(error);
|
|
30
|
+
console.error('Failed to fetch applied discounts:', error);
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
setIsLoading(false);
|
|
35
|
+
}
|
|
36
|
+
}, [checkoutSessionId, apiService]);
|
|
37
|
+
const applyDiscountCode = useCallback(async (code) => {
|
|
38
|
+
if (!checkoutSessionId) {
|
|
39
|
+
return { success: false, error: 'No checkout session available' };
|
|
40
|
+
}
|
|
41
|
+
if (!code || code.trim() === '') {
|
|
42
|
+
return { success: false, error: 'Discount code is required' };
|
|
43
|
+
}
|
|
44
|
+
setIsApplying(true);
|
|
45
|
+
setError(null);
|
|
46
|
+
try {
|
|
47
|
+
const response = await apiService.fetch(`/api/v1/checkout-sessions/${checkoutSessionId}/promotions/apply`, {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
body: { code: code.trim() },
|
|
50
|
+
});
|
|
51
|
+
if (response.success) {
|
|
52
|
+
// Refresh the applied discounts list
|
|
53
|
+
await getAppliedDiscounts();
|
|
54
|
+
// Trigger a refresh of the checkout session
|
|
55
|
+
refreshCoordinator?.notifyCheckoutChanged();
|
|
56
|
+
return { success: true, discount: response.promotion };
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
return { success: false, error: response.error?.message || 'Failed to apply discount code' };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
const error = err instanceof Error ? err : new Error('Failed to apply discount code');
|
|
64
|
+
setError(error);
|
|
65
|
+
console.error('Failed to apply discount code:', error);
|
|
66
|
+
// Try to extract error message from API response
|
|
67
|
+
let errorMessage = 'Failed to apply discount code';
|
|
68
|
+
if (err && typeof err === 'object' && 'response' in err) {
|
|
69
|
+
const apiError = err;
|
|
70
|
+
if (apiError.response?.data?.error?.message) {
|
|
71
|
+
errorMessage = apiError.response.data.error.message;
|
|
72
|
+
}
|
|
73
|
+
else if (apiError.response?.data?.message) {
|
|
74
|
+
errorMessage = apiError.response.data.message;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { success: false, error: errorMessage };
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
setIsApplying(false);
|
|
81
|
+
}
|
|
82
|
+
}, [checkoutSessionId, apiService, getAppliedDiscounts, refreshCoordinator]);
|
|
83
|
+
const removeDiscountCode = useCallback(async (discountId) => {
|
|
84
|
+
if (!checkoutSessionId) {
|
|
85
|
+
return { success: false, error: 'No checkout session available' };
|
|
86
|
+
}
|
|
87
|
+
if (!discountId) {
|
|
88
|
+
return { success: false, error: 'Discount ID is required' };
|
|
89
|
+
}
|
|
90
|
+
setIsRemoving(true);
|
|
91
|
+
setError(null);
|
|
92
|
+
try {
|
|
93
|
+
const response = await apiService.fetch(`/api/v1/checkout-sessions/${checkoutSessionId}/promotions/${discountId}`, {
|
|
94
|
+
method: 'DELETE',
|
|
95
|
+
});
|
|
96
|
+
if (response.success) {
|
|
97
|
+
// Refresh the applied discounts list
|
|
98
|
+
await getAppliedDiscounts();
|
|
99
|
+
// Trigger a refresh of the checkout session
|
|
100
|
+
refreshCoordinator?.notifyCheckoutChanged();
|
|
101
|
+
return { success: true };
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
return { success: false, error: response.error?.message || 'Failed to remove discount' };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
const error = err instanceof Error ? err : new Error('Failed to remove discount');
|
|
109
|
+
setError(error);
|
|
110
|
+
console.error('Failed to remove discount:', error);
|
|
111
|
+
// Try to extract error message from API response
|
|
112
|
+
let errorMessage = 'Failed to remove discount';
|
|
113
|
+
if (err && typeof err === 'object' && 'response' in err) {
|
|
114
|
+
const apiError = err;
|
|
115
|
+
if (apiError.response?.data?.error?.message) {
|
|
116
|
+
errorMessage = apiError.response.data.error.message;
|
|
117
|
+
}
|
|
118
|
+
else if (apiError.response?.data?.message) {
|
|
119
|
+
errorMessage = apiError.response.data.message;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { success: false, error: errorMessage };
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
setIsRemoving(false);
|
|
126
|
+
}
|
|
127
|
+
}, [checkoutSessionId, apiService, getAppliedDiscounts, refreshCoordinator]);
|
|
128
|
+
const refresh = useCallback(async () => {
|
|
129
|
+
if (checkoutSessionId) {
|
|
130
|
+
await getAppliedDiscounts();
|
|
131
|
+
}
|
|
132
|
+
}, [checkoutSessionId, getAppliedDiscounts]);
|
|
133
|
+
// Auto-refresh when checkout session changes
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
if (autoRefresh && checkoutSessionId) {
|
|
136
|
+
getAppliedDiscounts();
|
|
137
|
+
}
|
|
138
|
+
}, [checkoutSessionId, autoRefresh, getAppliedDiscounts]);
|
|
139
|
+
// Listen for checkout session refreshes
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
if (!autoRefresh || !checkoutSessionId)
|
|
142
|
+
return;
|
|
143
|
+
const handleRefresh = async () => {
|
|
144
|
+
await getAppliedDiscounts();
|
|
145
|
+
};
|
|
146
|
+
refreshCoordinator?.registerCheckoutRefresh(handleRefresh);
|
|
147
|
+
return () => refreshCoordinator?.unregisterCheckoutRefresh();
|
|
148
|
+
}, [checkoutSessionId, autoRefresh, getAppliedDiscounts, refreshCoordinator]);
|
|
149
|
+
return {
|
|
150
|
+
// State
|
|
151
|
+
appliedDiscounts,
|
|
152
|
+
isLoading,
|
|
153
|
+
isApplying,
|
|
154
|
+
isRemoving,
|
|
155
|
+
error,
|
|
156
|
+
// Actions
|
|
157
|
+
applyDiscountCode,
|
|
158
|
+
removeDiscountCode,
|
|
159
|
+
getAppliedDiscounts,
|
|
160
|
+
refresh,
|
|
161
|
+
clearError,
|
|
162
|
+
};
|
|
163
|
+
}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { useAuth } from './hooks/useAuth';
|
|
|
6
6
|
export { useCheckout } from './hooks/useCheckout';
|
|
7
7
|
export { useCurrency } from './hooks/useCurrency';
|
|
8
8
|
export { useCustomer } from './hooks/useCustomer';
|
|
9
|
+
export { useDiscounts } from './hooks/useDiscounts';
|
|
9
10
|
export { useEnvironment } from './hooks/useEnvironment';
|
|
10
11
|
export { useGoogleAutocomplete } from './hooks/useGoogleAutocomplete';
|
|
11
12
|
export { useLocale } from './hooks/useLocale';
|
|
@@ -16,22 +17,23 @@ export { usePostPurchases } from './hooks/usePostPurchases';
|
|
|
16
17
|
export { useProducts } from './hooks/useProducts';
|
|
17
18
|
export { useSession } from './hooks/useSession';
|
|
18
19
|
export { useTagadaContext } from './providers/TagadaProvider';
|
|
19
|
-
export {
|
|
20
|
+
export { clearPluginConfigCache, debugPluginConfig, getPluginConfig, useBasePath, usePluginConfig } from './hooks/usePluginConfig';
|
|
20
21
|
export type { PluginConfig } from './hooks/usePluginConfig';
|
|
21
|
-
export {
|
|
22
|
+
export { getAvailableLanguages, useCountryOptions, useISOData, useRegionOptions } from './hooks/useISOData';
|
|
22
23
|
export type { ISOCountry, ISORegion, UseISODataResult } from './hooks/useISOData';
|
|
23
|
-
export type {
|
|
24
|
+
export type { ExtractedAddress, GoogleAddressComponent, GooglePlaceDetails, GooglePrediction, UseGoogleAutocompleteOptions, UseGoogleAutocompleteResult } from './hooks/useGoogleAutocomplete';
|
|
24
25
|
export { useOrder } from './hooks/useOrder';
|
|
25
26
|
export type { UseOrderOptions, UseOrderResult } from './hooks/useOrder';
|
|
26
27
|
export { usePayment } from './hooks/usePayment';
|
|
27
28
|
export { usePaymentPolling } from './hooks/usePaymentPolling';
|
|
28
29
|
export { useThreeds } from './hooks/useThreeds';
|
|
29
30
|
export { useThreedsModal } from './hooks/useThreedsModal';
|
|
30
|
-
export type { AuthState, Currency, Customer, Environment, EnvironmentConfig, Locale, Order, OrderAddress, OrderItem, OrderSummary, PickupPoint, Session, Store
|
|
31
|
-
export type {
|
|
31
|
+
export type { AuthState, Currency, Customer, Environment, EnvironmentConfig, Locale, Order, OrderAddress, OrderItem, OrderSummary, PickupPoint, Session, Store } from './types';
|
|
32
|
+
export type { CheckoutData, CheckoutInitParams, CheckoutLineItem, CheckoutSession, CheckoutSessionPreview, Promotion, UseCheckoutOptions, UseCheckoutResult } from './hooks/useCheckout';
|
|
33
|
+
export type { Discount, DiscountCodeValidation, UseDiscountsOptions, UseDiscountsResult } from './hooks/useDiscounts';
|
|
32
34
|
export type { OrderBumpPreview, UseOrderBumpOptions, UseOrderBumpResult } from './hooks/useOrderBump';
|
|
33
|
-
export type { PostPurchaseOffer, PostPurchaseOfferItem, PostPurchaseOfferLineItem, PostPurchaseOfferSummary, UsePostPurchasesOptions, UsePostPurchasesResult
|
|
35
|
+
export type { PostPurchaseOffer, PostPurchaseOfferItem, PostPurchaseOfferLineItem, PostPurchaseOfferSummary, UsePostPurchasesOptions, UsePostPurchasesResult } from './hooks/usePostPurchases';
|
|
34
36
|
export type { Payment, PaymentPollingHook, PollingOptions } from './hooks/usePaymentPolling';
|
|
35
|
-
export type { PaymentInstrument, ThreedsChallenge, ThreedsHook, ThreedsOptions, ThreedsProvider, ThreedsSession
|
|
36
|
-
export type { ApplePayToken, CardPaymentMethod, PaymentHook, PaymentInstrumentResponse, PaymentOptions, PaymentResponse
|
|
37
|
-
export { convertCurrency, formatMoney, formatMoneyWithoutSymbol, formatSimpleMoney, getCurrencyInfo, minorUnitsToMajorUnits, moneyStringOrNumberToMinorUnits
|
|
37
|
+
export type { PaymentInstrument, ThreedsChallenge, ThreedsHook, ThreedsOptions, ThreedsProvider, ThreedsSession } from './hooks/useThreeds';
|
|
38
|
+
export type { ApplePayToken, CardPaymentMethod, PaymentHook, PaymentInstrumentResponse, PaymentOptions, PaymentResponse } from './hooks/usePayment';
|
|
39
|
+
export { convertCurrency, formatMoney, formatMoneyWithoutSymbol, formatSimpleMoney, getCurrencyInfo, minorUnitsToMajorUnits, moneyStringOrNumberToMinorUnits } from './utils/money';
|
package/dist/react/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { useAuth } from './hooks/useAuth';
|
|
|
9
9
|
export { useCheckout } from './hooks/useCheckout';
|
|
10
10
|
export { useCurrency } from './hooks/useCurrency';
|
|
11
11
|
export { useCustomer } from './hooks/useCustomer';
|
|
12
|
+
export { useDiscounts } from './hooks/useDiscounts';
|
|
12
13
|
export { useEnvironment } from './hooks/useEnvironment';
|
|
13
14
|
export { useGoogleAutocomplete } from './hooks/useGoogleAutocomplete';
|
|
14
15
|
export { useLocale } from './hooks/useLocale';
|
|
@@ -20,9 +21,9 @@ export { useProducts } from './hooks/useProducts';
|
|
|
20
21
|
export { useSession } from './hooks/useSession';
|
|
21
22
|
export { useTagadaContext } from './providers/TagadaProvider';
|
|
22
23
|
// Plugin configuration hooks
|
|
23
|
-
export {
|
|
24
|
+
export { clearPluginConfigCache, debugPluginConfig, getPluginConfig, useBasePath, usePluginConfig } from './hooks/usePluginConfig';
|
|
24
25
|
// ISO Data hooks
|
|
25
|
-
export {
|
|
26
|
+
export { getAvailableLanguages, useCountryOptions, useISOData, useRegionOptions } from './hooks/useISOData';
|
|
26
27
|
// Order hook exports
|
|
27
28
|
export { useOrder } from './hooks/useOrder';
|
|
28
29
|
// Payment hooks exports
|
|
@@ -33,4 +34,4 @@ export { useThreedsModal } from './hooks/useThreedsModal';
|
|
|
33
34
|
// Component exports (if any)
|
|
34
35
|
// export { SomeComponent } from './components/SomeComponent';
|
|
35
36
|
// Utility exports
|
|
36
|
-
export { convertCurrency, formatMoney, formatMoneyWithoutSymbol, formatSimpleMoney, getCurrencyInfo, minorUnitsToMajorUnits, moneyStringOrNumberToMinorUnits
|
|
37
|
+
export { convertCurrency, formatMoney, formatMoneyWithoutSymbol, formatSimpleMoney, getCurrencyInfo, minorUnitsToMajorUnits, moneyStringOrNumberToMinorUnits } from './utils/money';
|
|
@@ -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
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface TrackingData {
|
|
2
|
+
trackingCookiesData: Record<string, string>;
|
|
3
|
+
localStorageData: Record<string, string>;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Define pixel tracking cookie patterns for various platforms
|
|
7
|
+
*/
|
|
8
|
+
export declare const trackingCookiePatterns: RegExp[];
|
|
9
|
+
/**
|
|
10
|
+
* Function to get cookies with retry logic
|
|
11
|
+
*/
|
|
12
|
+
export declare const getCookiesWithRetry: (maxRetries?: number, delay?: number) => Promise<string[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Collect localStorage data as dictionary
|
|
15
|
+
*/
|
|
16
|
+
export declare const getLocalStorageData: () => Record<string, string>;
|
|
17
|
+
/**
|
|
18
|
+
* Collect tracking cookies data based on defined patterns
|
|
19
|
+
*/
|
|
20
|
+
export declare const getTrackingCookiesData: () => Promise<Record<string, string>>;
|
|
21
|
+
/**
|
|
22
|
+
* Collect all tracking data (localStorage and cookies)
|
|
23
|
+
*/
|
|
24
|
+
export declare const collectTrackingData: () => Promise<TrackingData>;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Define pixel tracking cookie patterns for various platforms
|
|
3
|
+
*/
|
|
4
|
+
export const trackingCookiePatterns = [
|
|
5
|
+
// Meta/Facebook pixels
|
|
6
|
+
/^_fbp/,
|
|
7
|
+
/^_fbc/,
|
|
8
|
+
/^fr$/,
|
|
9
|
+
/^_fbq/,
|
|
10
|
+
/^fbq/,
|
|
11
|
+
/^sb$/,
|
|
12
|
+
// Google Analytics & Ads
|
|
13
|
+
/^_ga/,
|
|
14
|
+
/^_gid/,
|
|
15
|
+
/^_gcl_au/,
|
|
16
|
+
/^_gac_/,
|
|
17
|
+
/^_gtag/,
|
|
18
|
+
/^_gat/,
|
|
19
|
+
/^_dc_gtm_/,
|
|
20
|
+
/^_gtm/,
|
|
21
|
+
// Google Ads
|
|
22
|
+
/^_gcl_/,
|
|
23
|
+
/^_gclid/,
|
|
24
|
+
/^_gclsrc/,
|
|
25
|
+
// Snapchat
|
|
26
|
+
/^_scid/,
|
|
27
|
+
/^_sctr/,
|
|
28
|
+
/^_schn/,
|
|
29
|
+
/^_scpx/,
|
|
30
|
+
// TikTok
|
|
31
|
+
/^_ttp/,
|
|
32
|
+
/^_tt_enable_cookie/,
|
|
33
|
+
/^_ttclid/,
|
|
34
|
+
/^_tta/,
|
|
35
|
+
// Pinterest
|
|
36
|
+
/^_pin/,
|
|
37
|
+
/^_pinterest_/,
|
|
38
|
+
/^_pinid/,
|
|
39
|
+
// Twitter/X
|
|
40
|
+
/^_twitter/,
|
|
41
|
+
/^_twid/,
|
|
42
|
+
/^muc_ads/,
|
|
43
|
+
// LinkedIn
|
|
44
|
+
/^_li/,
|
|
45
|
+
/^AnalyticsSyncHistory/,
|
|
46
|
+
/^bcookie/,
|
|
47
|
+
/^bscookie/,
|
|
48
|
+
// Microsoft/Bing
|
|
49
|
+
/^_uetsid/,
|
|
50
|
+
/^_uetvid/,
|
|
51
|
+
/^MUID/,
|
|
52
|
+
/^_msdcs/,
|
|
53
|
+
// Amazon
|
|
54
|
+
/^ad-id/,
|
|
55
|
+
/^ad-privacy/,
|
|
56
|
+
// CVG tracking
|
|
57
|
+
/^__cvg_uid/,
|
|
58
|
+
/^__cvg_sid/,
|
|
59
|
+
/^__cvg_session/,
|
|
60
|
+
// Shopify tracking
|
|
61
|
+
/^_shopify_y/,
|
|
62
|
+
/^_shopify_s/,
|
|
63
|
+
/^_shopify_ga/,
|
|
64
|
+
/^_shopify_ga_/,
|
|
65
|
+
/^_shopify_sa_p/,
|
|
66
|
+
/^_shopify_sa_t/,
|
|
67
|
+
// General tracking
|
|
68
|
+
/^_awc/,
|
|
69
|
+
/^_aw_/,
|
|
70
|
+
/^utm_/,
|
|
71
|
+
/^_clck/,
|
|
72
|
+
/^_clsk/,
|
|
73
|
+
];
|
|
74
|
+
/**
|
|
75
|
+
* Function to get cookies with retry logic
|
|
76
|
+
*/
|
|
77
|
+
export const getCookiesWithRetry = async (maxRetries = 3, delay = 100) => {
|
|
78
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
79
|
+
try {
|
|
80
|
+
const cookies = document.cookie.split('; ');
|
|
81
|
+
if (cookies.length > 0 && cookies[0] !== '') {
|
|
82
|
+
return cookies;
|
|
83
|
+
}
|
|
84
|
+
// If no cookies found, wait and retry
|
|
85
|
+
if (attempt < maxRetries) {
|
|
86
|
+
console.log(`Cookie collection attempt ${attempt} failed, retrying in ${delay}ms...`);
|
|
87
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.warn(`Cookie collection attempt ${attempt} failed:`, error);
|
|
92
|
+
if (attempt < maxRetries) {
|
|
93
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return [];
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Collect localStorage data as dictionary
|
|
101
|
+
*/
|
|
102
|
+
export const getLocalStorageData = () => {
|
|
103
|
+
const localStorageData = {};
|
|
104
|
+
try {
|
|
105
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
106
|
+
const key = localStorage.key(i);
|
|
107
|
+
if (key) {
|
|
108
|
+
localStorageData[key] = localStorage.getItem(key) || '';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
console.warn('Failed to read localStorage:', error);
|
|
114
|
+
}
|
|
115
|
+
return localStorageData;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Collect tracking cookies data based on defined patterns
|
|
119
|
+
*/
|
|
120
|
+
export const getTrackingCookiesData = async () => {
|
|
121
|
+
const trackingCookiesData = {};
|
|
122
|
+
try {
|
|
123
|
+
// Get cookies with retry logic
|
|
124
|
+
const cookies = await getCookiesWithRetry();
|
|
125
|
+
if (cookies.length === 0) {
|
|
126
|
+
console.warn('No cookies found after retry attempts');
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
console.log(`Successfully collected ${cookies.length} cookies`);
|
|
130
|
+
}
|
|
131
|
+
cookies.forEach((cookie) => {
|
|
132
|
+
const [key, ...valueParts] = cookie.split('=');
|
|
133
|
+
const value = valueParts.join('='); // Handle values that might contain =
|
|
134
|
+
if (key && trackingCookiePatterns.some((pattern) => pattern.test(key))) {
|
|
135
|
+
try {
|
|
136
|
+
trackingCookiesData[key] = decodeURIComponent(value || '');
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
// If decoding fails, use raw value
|
|
140
|
+
trackingCookiesData[key] = value || '';
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
// Log specific cookies we're looking for
|
|
145
|
+
const importantCookies = ['_shopify_y', '__cvg_uid', '_fbp', '_ga'];
|
|
146
|
+
importantCookies.forEach((cookieName) => {
|
|
147
|
+
if (trackingCookiesData[cookieName]) {
|
|
148
|
+
console.log(`Found ${cookieName}:`, trackingCookiesData[cookieName]);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.log(`Missing ${cookieName} cookie`);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
console.warn('Failed to read tracking cookies:', error);
|
|
157
|
+
}
|
|
158
|
+
return trackingCookiesData;
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Collect all tracking data (localStorage and cookies)
|
|
162
|
+
*/
|
|
163
|
+
export const collectTrackingData = async () => {
|
|
164
|
+
const [localStorageData, trackingCookiesData] = await Promise.all([
|
|
165
|
+
Promise.resolve(getLocalStorageData()),
|
|
166
|
+
getTrackingCookiesData(),
|
|
167
|
+
]);
|
|
168
|
+
return {
|
|
169
|
+
localStorageData,
|
|
170
|
+
trackingCookiesData,
|
|
171
|
+
};
|
|
172
|
+
};
|