@tagadapay/plugin-sdk 2.3.0 → 2.3.2
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
CHANGED
|
@@ -15,6 +15,7 @@ A comprehensive React SDK for building plugins on the TagadaPay platform. Create
|
|
|
15
15
|
### Plugin Development
|
|
16
16
|
|
|
17
17
|
- **[Plugin Configuration](./docs/PLUGIN_CONFIG.md)** - How to access store context, config, and branding
|
|
18
|
+
- **[Initialization Modes](#-initialization-modes)** - Choose between blocking and non-blocking initialization
|
|
18
19
|
- **[Google Autocomplete](./docs/README-google-autocomplete.md)** - Address autocomplete with Google Places API
|
|
19
20
|
- **[ISO Data](./docs/README-iso-data.md)** - Country and region data with Google integration
|
|
20
21
|
|
|
@@ -164,6 +165,95 @@ function App() {
|
|
|
164
165
|
export default App;
|
|
165
166
|
```
|
|
166
167
|
|
|
168
|
+
## 🚀 Initialization Modes
|
|
169
|
+
|
|
170
|
+
The TagadaProvider supports two initialization modes to give you control over when your components render:
|
|
171
|
+
|
|
172
|
+
### Non-Blocking Mode (Default - Recommended)
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
<TagadaProvider>
|
|
176
|
+
{/* Children render immediately after config loads */}
|
|
177
|
+
<YourApp />
|
|
178
|
+
</TagadaProvider>
|
|
179
|
+
|
|
180
|
+
// OR explicitly
|
|
181
|
+
<TagadaProvider blockUntilSessionReady={false}>
|
|
182
|
+
<YourApp />
|
|
183
|
+
</TagadaProvider>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**Flow:**
|
|
187
|
+
1. **Phase 1 & 2** ✅ Plugin config loads → Children render immediately
|
|
188
|
+
2. **Phase 3** 🔄 Session initialization runs in background
|
|
189
|
+
3. **API calls** 🔄 Hooks automatically wait for session to be ready
|
|
190
|
+
|
|
191
|
+
**Benefits:**
|
|
192
|
+
- ⚡ **Faster rendering** - UI appears immediately
|
|
193
|
+
- 🎯 **Better UX** - Show loading states while session initializes
|
|
194
|
+
- 🔄 **Automatic waiting** - Hooks handle session timing for you
|
|
195
|
+
|
|
196
|
+
### Blocking Mode (Legacy Behavior)
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
<TagadaProvider blockUntilSessionReady={true}>
|
|
200
|
+
{/* Children render only after ALL initialization completes */}
|
|
201
|
+
<YourApp />
|
|
202
|
+
</TagadaProvider>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Flow:**
|
|
206
|
+
1. **All Phases** ⏳ Config + Session must complete before children render
|
|
207
|
+
2. **API calls** ✅ Work immediately (no waiting needed)
|
|
208
|
+
|
|
209
|
+
**Use when:**
|
|
210
|
+
- 🔄 **Migrating** from older SDK versions
|
|
211
|
+
- 🎯 **Simple apps** that don't need progressive loading
|
|
212
|
+
|
|
213
|
+
### Console Logs
|
|
214
|
+
|
|
215
|
+
The SDK logs help you understand which mode you're using:
|
|
216
|
+
|
|
217
|
+
**Non-blocking mode:**
|
|
218
|
+
```
|
|
219
|
+
✅ Phase 1 & 2 Complete - Plugin config loaded
|
|
220
|
+
🚀 Non-blocking mode: Children can now render - Phase 3 will continue in background
|
|
221
|
+
🔄 [useCheckout] Waiting for session initialization to complete...
|
|
222
|
+
✅ Phase 3 Complete - Session initialization completed successfully
|
|
223
|
+
✅ [useCheckout] Session initialized, proceeding with checkout init
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Blocking mode:**
|
|
227
|
+
```
|
|
228
|
+
✅ Phase 1 & 2 Complete - Plugin config loaded
|
|
229
|
+
⏳ Blocking mode: Children will render after Phase 3 completes
|
|
230
|
+
✅ Phase 3 Complete - Session initialization completed successfully
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### TagadaProvider API
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
interface TagadaProviderProps {
|
|
237
|
+
children: ReactNode;
|
|
238
|
+
environment?: 'local' | 'development' | 'staging' | 'production';
|
|
239
|
+
customApiConfig?: Partial<EnvironmentConfig>;
|
|
240
|
+
debugMode?: boolean;
|
|
241
|
+
localConfig?: string; // LOCAL DEV ONLY: Override config variant
|
|
242
|
+
blockUntilSessionReady?: boolean; // Default: false
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
| Prop | Type | Default | Description |
|
|
247
|
+
|------|------|---------|-------------|
|
|
248
|
+
| `children` | `ReactNode` | - | Your plugin components |
|
|
249
|
+
| `environment` | `string` | auto-detect | Override environment detection |
|
|
250
|
+
| `customApiConfig` | `object` | - | Custom API configuration |
|
|
251
|
+
| `debugMode` | `boolean` | auto (false in prod) | Enable debug features |
|
|
252
|
+
| `localConfig` | `string` | `'default'` | Config variant for local dev |
|
|
253
|
+
| `blockUntilSessionReady` | `boolean` | `false` | Use legacy blocking behavior |
|
|
254
|
+
|
|
255
|
+
> **Version Compatibility:** The `blockUntilSessionReady` option was added in v2.3.0. For older versions, the blocking behavior was the default and only option.
|
|
256
|
+
|
|
167
257
|
### Development vs Production
|
|
168
258
|
|
|
169
259
|
| Environment | Store/Account ID | Deployment Config | How it Works |
|
|
@@ -1,7 +1,6 @@
|
|
|
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';
|
|
5
4
|
import { usePluginConfig } from './usePluginConfig';
|
|
6
5
|
export function useCheckout(options = {}) {
|
|
7
6
|
const { apiService, updateCheckoutDebugData, refreshCoordinator, currency, isSessionInitialized } = useTagadaContext();
|
|
@@ -78,13 +77,9 @@ export function useCheckout(options = {}) {
|
|
|
78
77
|
setIsLoading(true);
|
|
79
78
|
setError(null);
|
|
80
79
|
try {
|
|
81
|
-
//
|
|
82
|
-
const trackingData = await collectTrackingData();
|
|
83
|
-
// Enhanced customerMetadata with tracking data
|
|
80
|
+
// Enhanced customerMetadata without tracking data
|
|
84
81
|
const enhancedCustomerMetadata = {
|
|
85
82
|
...params.customerMetadata,
|
|
86
|
-
localStorage: trackingData.localStorageData,
|
|
87
|
-
cookies: trackingData.trackingCookiesData,
|
|
88
83
|
};
|
|
89
84
|
const requestBody = {
|
|
90
85
|
...params,
|
package/package.json
CHANGED
|
@@ -1,24 +0,0 @@
|
|
|
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>;
|
|
@@ -1,172 +0,0 @@
|
|
|
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
|
-
};
|