@probat/react 0.1.4 → 0.2.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 +88 -0
- package/dist/index.d.mts +60 -2
- package/dist/index.d.ts +60 -2
- package/dist/index.js +419 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +418 -15
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/context/ProbatContext.tsx +57 -2
- package/src/hoc/withExperiment.tsx +35 -5
- package/src/index.ts +2 -0
- package/src/utils/api.ts +36 -8
- package/src/utils/heatmapTracker.ts +478 -0
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use client";
|
|
3
|
-
import React4, { createContext, useMemo, useContext, useCallback, useState
|
|
3
|
+
import React4, { createContext, useMemo, useEffect, useContext, useCallback, useState } from 'react';
|
|
4
4
|
|
|
5
5
|
// src/utils/environment.ts
|
|
6
6
|
function detectEnvironment() {
|
|
@@ -14,6 +14,336 @@ function detectEnvironment() {
|
|
|
14
14
|
return "prod";
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
// src/utils/heatmapTracker.ts
|
|
18
|
+
function getStoredExperimentInfo() {
|
|
19
|
+
if (typeof window === "undefined") return {};
|
|
20
|
+
try {
|
|
21
|
+
const proposalId = window.localStorage.getItem("probat_active_proposal_id") || void 0;
|
|
22
|
+
const variantLabel = window.localStorage.getItem("probat_active_variant_label") || void 0;
|
|
23
|
+
return { proposalId, variantLabel };
|
|
24
|
+
} catch {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
var HeatmapTracker = class {
|
|
29
|
+
constructor(config) {
|
|
30
|
+
this.clicks = [];
|
|
31
|
+
this.movements = [];
|
|
32
|
+
this.batchTimer = null;
|
|
33
|
+
this.cursorBatchTimer = null;
|
|
34
|
+
this.lastCursorTime = 0;
|
|
35
|
+
this.isInitialized = false;
|
|
36
|
+
this.handleMouseMove = (event) => {
|
|
37
|
+
if (!this.config.enabled || !this.config.trackCursor) return;
|
|
38
|
+
if (typeof window === "undefined") return;
|
|
39
|
+
const stored = getStoredExperimentInfo();
|
|
40
|
+
const proposalId = this.config.proposalId || stored.proposalId;
|
|
41
|
+
const variantLabel = this.config.variantLabel || stored.variantLabel;
|
|
42
|
+
const now2 = Date.now();
|
|
43
|
+
const cursorThrottle = this.config.cursorThrottle ?? 100;
|
|
44
|
+
if (now2 - this.lastCursorTime < cursorThrottle) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
this.lastCursorTime = now2;
|
|
48
|
+
if (this.movements.length < 3) {
|
|
49
|
+
console.log("[PROBAT Heatmap] Cursor movement captured:", {
|
|
50
|
+
x: event.clientX,
|
|
51
|
+
y: event.clientY,
|
|
52
|
+
movementsInBatch: this.movements.length + 1
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const pageUrl = window.location.href;
|
|
56
|
+
const siteUrl = window.location.origin;
|
|
57
|
+
const x = event.clientX;
|
|
58
|
+
const y = event.clientY;
|
|
59
|
+
const viewportWidth = window.innerWidth;
|
|
60
|
+
const viewportHeight = window.innerHeight;
|
|
61
|
+
const movementEvent = {
|
|
62
|
+
page_url: pageUrl,
|
|
63
|
+
site_url: siteUrl,
|
|
64
|
+
x_coordinate: x,
|
|
65
|
+
y_coordinate: y,
|
|
66
|
+
viewport_width: viewportWidth,
|
|
67
|
+
viewport_height: viewportHeight,
|
|
68
|
+
session_id: this.sessionId,
|
|
69
|
+
proposal_id: proposalId,
|
|
70
|
+
variant_label: variantLabel
|
|
71
|
+
};
|
|
72
|
+
this.movements.push(movementEvent);
|
|
73
|
+
const cursorBatchSize = this.config.cursorBatchSize ?? 50;
|
|
74
|
+
if (this.movements.length >= cursorBatchSize) {
|
|
75
|
+
this.sendCursorBatch();
|
|
76
|
+
} else {
|
|
77
|
+
this.scheduleCursorBatchSend();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
this.handleClick = (event) => {
|
|
81
|
+
if (!this.config.enabled) return;
|
|
82
|
+
if (typeof window === "undefined") return;
|
|
83
|
+
const stored = getStoredExperimentInfo();
|
|
84
|
+
const proposalId = this.config.proposalId || stored.proposalId;
|
|
85
|
+
const variantLabel = this.config.variantLabel || stored.variantLabel;
|
|
86
|
+
const target = event.target;
|
|
87
|
+
if (!target) return;
|
|
88
|
+
if (this.shouldExcludeElement(target)) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const pageUrl = window.location.href;
|
|
92
|
+
const siteUrl = window.location.origin;
|
|
93
|
+
const x = event.clientX;
|
|
94
|
+
const y = event.clientY;
|
|
95
|
+
const viewportWidth = window.innerWidth;
|
|
96
|
+
const viewportHeight = window.innerHeight;
|
|
97
|
+
const elementInfo = this.extractElementInfo(target);
|
|
98
|
+
const clickEvent = {
|
|
99
|
+
page_url: pageUrl,
|
|
100
|
+
site_url: siteUrl,
|
|
101
|
+
x_coordinate: x,
|
|
102
|
+
y_coordinate: y,
|
|
103
|
+
viewport_width: viewportWidth,
|
|
104
|
+
viewport_height: viewportHeight,
|
|
105
|
+
element_tag: elementInfo.tag,
|
|
106
|
+
element_class: elementInfo.class,
|
|
107
|
+
element_id: elementInfo.id,
|
|
108
|
+
session_id: this.sessionId,
|
|
109
|
+
proposal_id: proposalId,
|
|
110
|
+
variant_label: variantLabel
|
|
111
|
+
};
|
|
112
|
+
this.clicks.push(clickEvent);
|
|
113
|
+
const batchSize = this.config.batchSize ?? 10;
|
|
114
|
+
if (this.clicks.length >= batchSize) {
|
|
115
|
+
this.sendBatch();
|
|
116
|
+
} else {
|
|
117
|
+
this.scheduleBatchSend();
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
this.sessionId = this.getOrCreateSessionId();
|
|
121
|
+
const stored = getStoredExperimentInfo();
|
|
122
|
+
this.config = {
|
|
123
|
+
apiBaseUrl: config.apiBaseUrl,
|
|
124
|
+
batchSize: config.batchSize || 10,
|
|
125
|
+
batchInterval: config.batchInterval || 5e3,
|
|
126
|
+
enabled: config.enabled !== false,
|
|
127
|
+
excludeSelectors: config.excludeSelectors || [
|
|
128
|
+
"[data-heatmap-exclude]",
|
|
129
|
+
'input[type="password"]',
|
|
130
|
+
'input[type="email"]',
|
|
131
|
+
"textarea"
|
|
132
|
+
],
|
|
133
|
+
trackCursor: config.trackCursor !== false,
|
|
134
|
+
// Enable cursor tracking by default
|
|
135
|
+
cursorThrottle: config.cursorThrottle || 100,
|
|
136
|
+
// Capture cursor position every 100ms
|
|
137
|
+
cursorBatchSize: config.cursorBatchSize || 50,
|
|
138
|
+
// Send every 50 movements
|
|
139
|
+
proposalId: config.proposalId || stored.proposalId,
|
|
140
|
+
variantLabel: config.variantLabel || stored.variantLabel
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
getOrCreateSessionId() {
|
|
144
|
+
if (typeof window === "undefined") return "";
|
|
145
|
+
const storageKey = "probat_heatmap_session_id";
|
|
146
|
+
let sessionId = localStorage.getItem(storageKey);
|
|
147
|
+
if (!sessionId) {
|
|
148
|
+
sessionId = `heatmap_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
|
|
149
|
+
localStorage.setItem(storageKey, sessionId);
|
|
150
|
+
}
|
|
151
|
+
return sessionId;
|
|
152
|
+
}
|
|
153
|
+
shouldExcludeElement(element) {
|
|
154
|
+
if (!this.config.excludeSelectors) return false;
|
|
155
|
+
for (const selector of this.config.excludeSelectors) {
|
|
156
|
+
if (element.matches(selector) || element.closest(selector)) {
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
extractElementInfo(element) {
|
|
163
|
+
return {
|
|
164
|
+
tag: element.tagName || null,
|
|
165
|
+
class: element.className && typeof element.className === "string" ? element.className : null,
|
|
166
|
+
id: element.id || null
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
scheduleCursorBatchSend() {
|
|
170
|
+
if (this.cursorBatchTimer) {
|
|
171
|
+
clearTimeout(this.cursorBatchTimer);
|
|
172
|
+
}
|
|
173
|
+
this.cursorBatchTimer = setTimeout(() => {
|
|
174
|
+
if (this.movements.length > 0) {
|
|
175
|
+
this.sendCursorBatch();
|
|
176
|
+
}
|
|
177
|
+
}, this.config.batchInterval ?? 5e3);
|
|
178
|
+
}
|
|
179
|
+
async sendCursorBatch() {
|
|
180
|
+
if (this.movements.length === 0) return;
|
|
181
|
+
const siteUrl = this.movements[0]?.site_url || window.location.origin;
|
|
182
|
+
const batch = {
|
|
183
|
+
movements: this.movements,
|
|
184
|
+
site_url: siteUrl,
|
|
185
|
+
proposal_id: this.config.proposalId,
|
|
186
|
+
variant_label: this.config.variantLabel
|
|
187
|
+
};
|
|
188
|
+
this.movements = [];
|
|
189
|
+
if (this.cursorBatchTimer) {
|
|
190
|
+
clearTimeout(this.cursorBatchTimer);
|
|
191
|
+
this.cursorBatchTimer = null;
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
console.log("[PROBAT Heatmap] Sending cursor movements batch:", {
|
|
195
|
+
count: batch.movements.length,
|
|
196
|
+
site_url: batch.site_url
|
|
197
|
+
});
|
|
198
|
+
const response = await fetch(`${this.config.apiBaseUrl}/api/heatmap/cursor-movements`, {
|
|
199
|
+
method: "POST",
|
|
200
|
+
headers: {
|
|
201
|
+
"Content-Type": "application/json"
|
|
202
|
+
},
|
|
203
|
+
body: JSON.stringify(batch)
|
|
204
|
+
// Don't wait for response - fire and forget for performance
|
|
205
|
+
});
|
|
206
|
+
if (!response.ok) {
|
|
207
|
+
console.warn("[PROBAT Heatmap] Failed to send cursor movements:", response.status);
|
|
208
|
+
} else {
|
|
209
|
+
console.log("[PROBAT Heatmap] Successfully sent cursor movements batch");
|
|
210
|
+
}
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.warn("[PROBAT Heatmap] Error sending cursor movements:", error);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
scheduleBatchSend() {
|
|
216
|
+
if (this.batchTimer) {
|
|
217
|
+
clearTimeout(this.batchTimer);
|
|
218
|
+
}
|
|
219
|
+
this.batchTimer = setTimeout(() => {
|
|
220
|
+
if (this.clicks.length > 0) {
|
|
221
|
+
this.sendBatch();
|
|
222
|
+
}
|
|
223
|
+
}, this.config.batchInterval ?? 5e3);
|
|
224
|
+
}
|
|
225
|
+
async sendBatch() {
|
|
226
|
+
if (this.clicks.length === 0) return;
|
|
227
|
+
if (this.batchTimer) {
|
|
228
|
+
clearTimeout(this.batchTimer);
|
|
229
|
+
this.batchTimer = null;
|
|
230
|
+
}
|
|
231
|
+
const siteUrl = this.clicks[0]?.site_url || window.location.origin;
|
|
232
|
+
const batch = {
|
|
233
|
+
clicks: [...this.clicks],
|
|
234
|
+
site_url: siteUrl
|
|
235
|
+
};
|
|
236
|
+
this.clicks = [];
|
|
237
|
+
try {
|
|
238
|
+
const response = await fetch(`${this.config.apiBaseUrl}/api/heatmap/clicks`, {
|
|
239
|
+
method: "POST",
|
|
240
|
+
headers: {
|
|
241
|
+
"Content-Type": "application/json"
|
|
242
|
+
},
|
|
243
|
+
body: JSON.stringify(batch)
|
|
244
|
+
});
|
|
245
|
+
if (!response.ok) {
|
|
246
|
+
console.warn("[PROBAT Heatmap] Failed to send clicks:", response.status);
|
|
247
|
+
}
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.warn("[PROBAT Heatmap] Error sending clicks:", error);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
init() {
|
|
253
|
+
if (this.isInitialized) {
|
|
254
|
+
console.warn("[PROBAT Heatmap] Tracker already initialized");
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (typeof window === "undefined") {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
document.addEventListener("click", this.handleClick, true);
|
|
261
|
+
if (this.config.trackCursor) {
|
|
262
|
+
document.addEventListener("mousemove", this.handleMouseMove, { passive: true });
|
|
263
|
+
console.log("[PROBAT Heatmap] Cursor tracking enabled");
|
|
264
|
+
} else {
|
|
265
|
+
console.log("[PROBAT Heatmap] Cursor tracking disabled");
|
|
266
|
+
}
|
|
267
|
+
this.isInitialized = true;
|
|
268
|
+
console.log("[PROBAT Heatmap] Tracker initialized", {
|
|
269
|
+
enabled: this.config.enabled,
|
|
270
|
+
trackCursor: this.config.trackCursor,
|
|
271
|
+
cursorThrottle: this.config.cursorThrottle,
|
|
272
|
+
cursorBatchSize: this.config.cursorBatchSize
|
|
273
|
+
});
|
|
274
|
+
window.addEventListener("beforeunload", () => {
|
|
275
|
+
if (this.clicks.length > 0) {
|
|
276
|
+
const siteUrl = this.clicks[0]?.site_url || window.location.origin;
|
|
277
|
+
const batch = {
|
|
278
|
+
clicks: this.clicks,
|
|
279
|
+
site_url: siteUrl
|
|
280
|
+
};
|
|
281
|
+
const blob = new Blob([JSON.stringify(batch)], {
|
|
282
|
+
type: "application/json"
|
|
283
|
+
});
|
|
284
|
+
navigator.sendBeacon(
|
|
285
|
+
`${this.config.apiBaseUrl}/api/heatmap/clicks`,
|
|
286
|
+
blob
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
if (this.movements.length > 0) {
|
|
290
|
+
const siteUrl = this.movements[0]?.site_url || window.location.origin;
|
|
291
|
+
const batch = {
|
|
292
|
+
movements: this.movements,
|
|
293
|
+
site_url: siteUrl
|
|
294
|
+
};
|
|
295
|
+
const blob = new Blob([JSON.stringify(batch)], {
|
|
296
|
+
type: "application/json"
|
|
297
|
+
});
|
|
298
|
+
navigator.sendBeacon(
|
|
299
|
+
`${this.config.apiBaseUrl}/api/heatmap/cursor-movements`,
|
|
300
|
+
blob
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
stop() {
|
|
306
|
+
if (!this.isInitialized) return;
|
|
307
|
+
if (this.clicks.length > 0) {
|
|
308
|
+
this.sendBatch();
|
|
309
|
+
}
|
|
310
|
+
if (this.movements.length > 0) {
|
|
311
|
+
this.sendCursorBatch();
|
|
312
|
+
}
|
|
313
|
+
document.removeEventListener("click", this.handleClick, true);
|
|
314
|
+
if (this.config.trackCursor) {
|
|
315
|
+
document.removeEventListener("mousemove", this.handleMouseMove);
|
|
316
|
+
}
|
|
317
|
+
if (this.batchTimer) {
|
|
318
|
+
clearTimeout(this.batchTimer);
|
|
319
|
+
this.batchTimer = null;
|
|
320
|
+
}
|
|
321
|
+
if (this.cursorBatchTimer) {
|
|
322
|
+
clearTimeout(this.cursorBatchTimer);
|
|
323
|
+
this.cursorBatchTimer = null;
|
|
324
|
+
}
|
|
325
|
+
this.isInitialized = false;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
var trackerInstance = null;
|
|
329
|
+
function initHeatmapTracking(config) {
|
|
330
|
+
if (trackerInstance) {
|
|
331
|
+
trackerInstance.stop();
|
|
332
|
+
}
|
|
333
|
+
trackerInstance = new HeatmapTracker(config);
|
|
334
|
+
trackerInstance.init();
|
|
335
|
+
return trackerInstance;
|
|
336
|
+
}
|
|
337
|
+
function getHeatmapTracker() {
|
|
338
|
+
return trackerInstance;
|
|
339
|
+
}
|
|
340
|
+
function stopHeatmapTracking() {
|
|
341
|
+
if (trackerInstance) {
|
|
342
|
+
trackerInstance.stop();
|
|
343
|
+
trackerInstance = null;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
17
347
|
// src/context/ProbatContext.tsx
|
|
18
348
|
var ProbatContext = createContext(null);
|
|
19
349
|
function ProbatProvider({
|
|
@@ -21,8 +351,12 @@ function ProbatProvider({
|
|
|
21
351
|
clientKey,
|
|
22
352
|
environment: explicitEnvironment,
|
|
23
353
|
repoFullName: explicitRepoFullName,
|
|
354
|
+
proposalId,
|
|
355
|
+
variantLabel,
|
|
24
356
|
children
|
|
25
357
|
}) {
|
|
358
|
+
const storedProposalId = typeof window !== "undefined" ? window.localStorage.getItem("probat_active_proposal_id") || void 0 : void 0;
|
|
359
|
+
const storedVariantLabel = typeof window !== "undefined" ? window.localStorage.getItem("probat_active_variant_label") || void 0 : void 0;
|
|
26
360
|
const contextValue = useMemo(() => {
|
|
27
361
|
const resolvedApiBaseUrl = apiBaseUrl || typeof import.meta !== "undefined" && import.meta.env?.VITE_PROBAT_API || typeof globalThis !== "undefined" && globalThis.process?.env?.NEXT_PUBLIC_PROBAT_API || typeof window !== "undefined" && window.__PROBAT_API || "https://gushi.onrender.com";
|
|
28
362
|
const environment = explicitEnvironment || detectEnvironment();
|
|
@@ -31,9 +365,38 @@ function ProbatProvider({
|
|
|
31
365
|
apiBaseUrl: resolvedApiBaseUrl,
|
|
32
366
|
environment,
|
|
33
367
|
clientKey,
|
|
34
|
-
repoFullName: resolvedRepoFullName
|
|
368
|
+
repoFullName: resolvedRepoFullName,
|
|
369
|
+
proposalId: proposalId || storedProposalId,
|
|
370
|
+
variantLabel: variantLabel || storedVariantLabel
|
|
35
371
|
};
|
|
36
|
-
}, [apiBaseUrl, clientKey, explicitEnvironment, explicitRepoFullName]);
|
|
372
|
+
}, [apiBaseUrl, clientKey, explicitEnvironment, explicitRepoFullName, proposalId, variantLabel, storedProposalId, storedVariantLabel]);
|
|
373
|
+
useEffect(() => {
|
|
374
|
+
if (typeof window !== "undefined") {
|
|
375
|
+
initHeatmapTracking({
|
|
376
|
+
apiBaseUrl: contextValue.apiBaseUrl,
|
|
377
|
+
batchSize: 10,
|
|
378
|
+
batchInterval: 5e3,
|
|
379
|
+
enabled: true,
|
|
380
|
+
excludeSelectors: [
|
|
381
|
+
"[data-heatmap-exclude]",
|
|
382
|
+
'input[type="password"]',
|
|
383
|
+
'input[type="email"]',
|
|
384
|
+
"textarea"
|
|
385
|
+
],
|
|
386
|
+
// Explicitly enable cursor tracking with sensible defaults
|
|
387
|
+
trackCursor: true,
|
|
388
|
+
cursorThrottle: 100,
|
|
389
|
+
// capture every 100ms
|
|
390
|
+
cursorBatchSize: 50,
|
|
391
|
+
// send every 50 movements (or after batchInterval)
|
|
392
|
+
proposalId: contextValue.proposalId,
|
|
393
|
+
variantLabel: contextValue.variantLabel
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
return () => {
|
|
397
|
+
stopHeatmapTracking();
|
|
398
|
+
};
|
|
399
|
+
}, [contextValue.apiBaseUrl]);
|
|
37
400
|
return /* @__PURE__ */ React4.createElement(ProbatContext.Provider, { value: contextValue }, children);
|
|
38
401
|
}
|
|
39
402
|
function useProbatContext() {
|
|
@@ -67,6 +430,14 @@ async function fetchDecision(baseUrl, proposalId) {
|
|
|
67
430
|
const data = await res.json();
|
|
68
431
|
const experiment_id = (data.experiment_id || `exp_${proposalId}`).toString();
|
|
69
432
|
const label = data.label && data.label.trim() ? data.label : "control";
|
|
433
|
+
if (typeof window !== "undefined") {
|
|
434
|
+
try {
|
|
435
|
+
window.localStorage.setItem("probat_active_proposal_id", proposalId);
|
|
436
|
+
window.localStorage.setItem("probat_active_variant_label", label);
|
|
437
|
+
} catch (e) {
|
|
438
|
+
console.warn("[PROBAT] Failed to set proposal/variant in localStorage:", e);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
70
441
|
return { experiment_id, label };
|
|
71
442
|
} finally {
|
|
72
443
|
pendingFetches.delete(proposalId);
|
|
@@ -145,6 +516,13 @@ async function fetchComponentExperimentConfig(baseUrl, repoFullName, componentPa
|
|
|
145
516
|
throw new Error(`HTTP ${res.status}`);
|
|
146
517
|
}
|
|
147
518
|
const data = await res.json();
|
|
519
|
+
if (typeof window !== "undefined" && data?.proposal_id) {
|
|
520
|
+
try {
|
|
521
|
+
window.localStorage.setItem("probat_active_proposal_id", data.proposal_id);
|
|
522
|
+
} catch (e) {
|
|
523
|
+
console.warn("[PROBAT] Failed to set proposal_id in localStorage:", e);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
148
526
|
return data;
|
|
149
527
|
} catch (e) {
|
|
150
528
|
console.warn(`[PROBAT] Failed to fetch component config: ${e}`);
|
|
@@ -274,14 +652,12 @@ async function loadVariantComponent(baseUrl, proposalId, experimentId, filePath,
|
|
|
274
652
|
let rawCode = "";
|
|
275
653
|
let rawCodeFetched = false;
|
|
276
654
|
const isBrowser = typeof window !== "undefined";
|
|
277
|
-
const
|
|
278
|
-
if (isBrowser && !
|
|
655
|
+
const isNextJS = isBrowser && (window.__NEXT_DATA__ !== void 0 || window.__NEXT_LOADED_PAGES__ !== void 0 || typeof globalThis.__NEXT_DATA__ !== "undefined");
|
|
656
|
+
if (isBrowser && !isNextJS) {
|
|
279
657
|
try {
|
|
280
658
|
const variantUrl = `/probat/${filePath}`;
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
variantUrl
|
|
284
|
-
);
|
|
659
|
+
const dynamicImportFunc = new Function("url", "return import(url)");
|
|
660
|
+
const mod = await dynamicImportFunc(variantUrl);
|
|
285
661
|
const VariantComponent2 = mod?.default || mod;
|
|
286
662
|
if (VariantComponent2 && typeof VariantComponent2 === "function") {
|
|
287
663
|
console.log(`[PROBAT] \u2705 Loaded variant via dynamic import (CSR): ${variantUrl}`);
|
|
@@ -781,23 +1157,50 @@ function withExperiment(Control, options) {
|
|
|
781
1157
|
let alive = true;
|
|
782
1158
|
const cached = readChoice(proposalId);
|
|
783
1159
|
if (cached) {
|
|
784
|
-
|
|
1160
|
+
const choiceData = {
|
|
785
1161
|
experiment_id: cached.experiment_id,
|
|
786
1162
|
label: cached.label
|
|
787
|
-
}
|
|
1163
|
+
};
|
|
1164
|
+
setChoice(choiceData);
|
|
1165
|
+
if (typeof window !== "undefined") {
|
|
1166
|
+
try {
|
|
1167
|
+
window.localStorage.setItem("probat_active_proposal_id", proposalId);
|
|
1168
|
+
window.localStorage.setItem("probat_active_variant_label", cached.label);
|
|
1169
|
+
} catch (e) {
|
|
1170
|
+
console.warn("[PROBAT] Failed to set proposal/variant in localStorage:", e);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
788
1173
|
} else {
|
|
789
1174
|
(async () => {
|
|
790
1175
|
try {
|
|
791
1176
|
const { experiment_id, label: label2 } = await fetchDecision(apiBaseUrl, proposalId);
|
|
792
1177
|
if (!alive) return;
|
|
793
1178
|
writeChoice(proposalId, experiment_id, label2);
|
|
794
|
-
|
|
1179
|
+
const choiceData = { experiment_id, label: label2 };
|
|
1180
|
+
setChoice(choiceData);
|
|
1181
|
+
if (typeof window !== "undefined") {
|
|
1182
|
+
try {
|
|
1183
|
+
window.localStorage.setItem("probat_active_proposal_id", proposalId);
|
|
1184
|
+
window.localStorage.setItem("probat_active_variant_label", label2);
|
|
1185
|
+
} catch (e) {
|
|
1186
|
+
console.warn("[PROBAT] Failed to set proposal/variant in localStorage:", e);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
795
1189
|
} catch (e) {
|
|
796
1190
|
if (!alive) return;
|
|
797
|
-
|
|
1191
|
+
const choiceData = {
|
|
798
1192
|
experiment_id: `exp_${proposalId}`,
|
|
799
1193
|
label: "control"
|
|
800
|
-
}
|
|
1194
|
+
};
|
|
1195
|
+
setChoice(choiceData);
|
|
1196
|
+
if (typeof window !== "undefined") {
|
|
1197
|
+
try {
|
|
1198
|
+
window.localStorage.setItem("probat_active_proposal_id", proposalId);
|
|
1199
|
+
window.localStorage.setItem("probat_active_variant_label", "control");
|
|
1200
|
+
} catch (err) {
|
|
1201
|
+
console.warn("[PROBAT] Failed to set proposal/variant in localStorage:", err);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
801
1204
|
}
|
|
802
1205
|
})();
|
|
803
1206
|
}
|
|
@@ -855,6 +1258,6 @@ function withExperiment(Control, options) {
|
|
|
855
1258
|
return Wrapped;
|
|
856
1259
|
}
|
|
857
1260
|
|
|
858
|
-
export { ProbatProvider, ProbatProviderClient, detectEnvironment, extractClickMeta, fetchDecision, hasTrackedVisit, markTrackedVisit, readChoice, sendMetric, useExperiment, useProbatContext, useProbatMetrics, withExperiment, writeChoice };
|
|
1261
|
+
export { ProbatProvider, ProbatProviderClient, detectEnvironment, extractClickMeta, fetchDecision, getHeatmapTracker, hasTrackedVisit, initHeatmapTracking, markTrackedVisit, readChoice, sendMetric, stopHeatmapTracking, useExperiment, useProbatContext, useProbatMetrics, withExperiment, writeChoice };
|
|
859
1262
|
//# sourceMappingURL=index.mjs.map
|
|
860
1263
|
//# sourceMappingURL=index.mjs.map
|