@neowhale/storefront 0.2.32 → 0.2.34
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/dist/chunk-AKWSW7DW.js +329 -0
- package/dist/chunk-AKWSW7DW.js.map +1 -0
- package/dist/chunk-HOQKBNYB.cjs +331 -0
- package/dist/chunk-HOQKBNYB.cjs.map +1 -0
- package/dist/landing.global.js +1323 -0
- package/dist/react/index.cjs +132 -334
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +2 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +131 -333
- package/dist/react/index.js.map +1 -1
- package/dist/tracker-34GTXU54.js +3 -0
- package/dist/tracker-34GTXU54.js.map +1 -0
- package/dist/tracker-WYKTEQ4F.cjs +12 -0
- package/dist/tracker-WYKTEQ4F.cjs.map +1 -0
- package/package.json +4 -1
package/dist/react/index.cjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var chunkUW2U5BRY_cjs = require('../chunk-UW2U5BRY.cjs');
|
|
4
4
|
var chunkHSGM4XMK_cjs = require('../chunk-HSGM4XMK.cjs');
|
|
5
|
+
var chunkHOQKBNYB_cjs = require('../chunk-HOQKBNYB.cjs');
|
|
5
6
|
var react = require('react');
|
|
6
7
|
var navigation = require('next/navigation');
|
|
7
8
|
var vanilla = require('zustand/vanilla');
|
|
@@ -685,334 +686,6 @@ function PixelInitializer({ onReady, onTheme }) {
|
|
|
685
686
|
}, [ctx, onReady, onTheme]);
|
|
686
687
|
return null;
|
|
687
688
|
}
|
|
688
|
-
|
|
689
|
-
// src/behavioral/tracker.ts
|
|
690
|
-
var SCROLL_MILESTONES = [25, 50, 75, 100];
|
|
691
|
-
var TIME_MILESTONES = [30, 60, 120, 300];
|
|
692
|
-
var MOUSE_THROTTLE_MS = 200;
|
|
693
|
-
var MOUSE_BUFFER_MAX = 100;
|
|
694
|
-
var RAGE_CLICK_COUNT = 3;
|
|
695
|
-
var RAGE_CLICK_RADIUS = 50;
|
|
696
|
-
var RAGE_CLICK_WINDOW_MS = 2e3;
|
|
697
|
-
var MAX_CLICK_HISTORY = 10;
|
|
698
|
-
var BehavioralTracker = class {
|
|
699
|
-
constructor(config) {
|
|
700
|
-
this.buffer = [];
|
|
701
|
-
this.pageUrl = "";
|
|
702
|
-
this.pagePath = "";
|
|
703
|
-
this.flushTimer = null;
|
|
704
|
-
this.scrollMilestones = /* @__PURE__ */ new Set();
|
|
705
|
-
this.timeMilestones = /* @__PURE__ */ new Set();
|
|
706
|
-
this.timeTimers = [];
|
|
707
|
-
this.exitIntentFired = false;
|
|
708
|
-
this.startTime = 0;
|
|
709
|
-
this.clickHistory = [];
|
|
710
|
-
this.mouseBuffer = [];
|
|
711
|
-
this.lastMouseTime = 0;
|
|
712
|
-
this.listeners = [];
|
|
713
|
-
this.observer = null;
|
|
714
|
-
this.sentinels = [];
|
|
715
|
-
// ---------------------------------------------------------------------------
|
|
716
|
-
// Event handlers (arrow functions for stable `this`)
|
|
717
|
-
// ---------------------------------------------------------------------------
|
|
718
|
-
this.handleClick = (e) => {
|
|
719
|
-
const me = e;
|
|
720
|
-
const target = me.target;
|
|
721
|
-
if (!target) return;
|
|
722
|
-
const now2 = Date.now();
|
|
723
|
-
const x = me.clientX;
|
|
724
|
-
const y = me.clientY;
|
|
725
|
-
this.clickHistory.push({ x, y, t: now2 });
|
|
726
|
-
if (this.clickHistory.length > MAX_CLICK_HISTORY) {
|
|
727
|
-
this.clickHistory.shift();
|
|
728
|
-
}
|
|
729
|
-
const tag = target.tagName?.toLowerCase() ?? "";
|
|
730
|
-
const rawText = target.textContent ?? "";
|
|
731
|
-
const text = rawText.trim().slice(0, 50);
|
|
732
|
-
this.push({
|
|
733
|
-
data_type: "click",
|
|
734
|
-
data: {
|
|
735
|
-
tag,
|
|
736
|
-
text,
|
|
737
|
-
selector: this.getSelector(target),
|
|
738
|
-
x,
|
|
739
|
-
y,
|
|
740
|
-
timestamp: now2
|
|
741
|
-
},
|
|
742
|
-
page_url: this.pageUrl,
|
|
743
|
-
page_path: this.pagePath
|
|
744
|
-
});
|
|
745
|
-
this.detectRageClick(x, y, now2);
|
|
746
|
-
};
|
|
747
|
-
this.handleMouseMove = (e) => {
|
|
748
|
-
const me = e;
|
|
749
|
-
const now2 = Date.now();
|
|
750
|
-
if (now2 - this.lastMouseTime < MOUSE_THROTTLE_MS) return;
|
|
751
|
-
this.lastMouseTime = now2;
|
|
752
|
-
this.mouseBuffer.push({ x: me.clientX, y: me.clientY, t: now2 });
|
|
753
|
-
if (this.mouseBuffer.length > MOUSE_BUFFER_MAX) {
|
|
754
|
-
this.mouseBuffer.shift();
|
|
755
|
-
}
|
|
756
|
-
};
|
|
757
|
-
this.handleMouseOut = (e) => {
|
|
758
|
-
const me = e;
|
|
759
|
-
if (this.exitIntentFired) return;
|
|
760
|
-
if (me.clientY > 0) return;
|
|
761
|
-
if (me.relatedTarget !== null) return;
|
|
762
|
-
this.exitIntentFired = true;
|
|
763
|
-
this.push({
|
|
764
|
-
data_type: "exit_intent",
|
|
765
|
-
data: {
|
|
766
|
-
time_on_page_ms: Date.now() - this.startTime,
|
|
767
|
-
timestamp: Date.now()
|
|
768
|
-
},
|
|
769
|
-
page_url: this.pageUrl,
|
|
770
|
-
page_path: this.pagePath
|
|
771
|
-
});
|
|
772
|
-
};
|
|
773
|
-
this.handleCopy = () => {
|
|
774
|
-
const selection = window.getSelection();
|
|
775
|
-
const length = selection?.toString().length ?? 0;
|
|
776
|
-
this.push({
|
|
777
|
-
data_type: "copy",
|
|
778
|
-
data: {
|
|
779
|
-
text_length: length,
|
|
780
|
-
timestamp: Date.now()
|
|
781
|
-
},
|
|
782
|
-
page_url: this.pageUrl,
|
|
783
|
-
page_path: this.pagePath
|
|
784
|
-
});
|
|
785
|
-
};
|
|
786
|
-
this.handleVisibilityChange = () => {
|
|
787
|
-
if (document.visibilityState !== "hidden") return;
|
|
788
|
-
const timeSpent = Date.now() - this.startTime;
|
|
789
|
-
this.push({
|
|
790
|
-
data_type: "page_exit",
|
|
791
|
-
data: {
|
|
792
|
-
time_spent_ms: timeSpent,
|
|
793
|
-
timestamp: Date.now()
|
|
794
|
-
},
|
|
795
|
-
page_url: this.pageUrl,
|
|
796
|
-
page_path: this.pagePath
|
|
797
|
-
});
|
|
798
|
-
this.flushMouseBuffer();
|
|
799
|
-
this.flush();
|
|
800
|
-
};
|
|
801
|
-
this.config = {
|
|
802
|
-
sendBatch: config.sendBatch,
|
|
803
|
-
sessionId: config.sessionId,
|
|
804
|
-
visitorId: config.visitorId,
|
|
805
|
-
flushIntervalMs: config.flushIntervalMs ?? 1e4,
|
|
806
|
-
maxBufferSize: config.maxBufferSize ?? 500
|
|
807
|
-
};
|
|
808
|
-
}
|
|
809
|
-
start() {
|
|
810
|
-
this.startTime = Date.now();
|
|
811
|
-
this.addListener(document, "click", this.handleClick);
|
|
812
|
-
this.addListener(document, "mousemove", this.handleMouseMove);
|
|
813
|
-
this.addListener(document, "mouseout", this.handleMouseOut);
|
|
814
|
-
this.addListener(document, "copy", this.handleCopy);
|
|
815
|
-
this.addListener(document, "visibilitychange", this.handleVisibilityChange);
|
|
816
|
-
this.setupScrollTracking();
|
|
817
|
-
this.setupTimeMilestones();
|
|
818
|
-
this.flushTimer = setInterval(() => this.flush(), this.config.flushIntervalMs);
|
|
819
|
-
}
|
|
820
|
-
stop() {
|
|
821
|
-
for (const [target, event, handler] of this.listeners) {
|
|
822
|
-
target.removeEventListener(event, handler, { capture: true });
|
|
823
|
-
}
|
|
824
|
-
this.listeners = [];
|
|
825
|
-
if (this.flushTimer !== null) {
|
|
826
|
-
clearInterval(this.flushTimer);
|
|
827
|
-
this.flushTimer = null;
|
|
828
|
-
}
|
|
829
|
-
this.clearTimeMilestones();
|
|
830
|
-
this.cleanupScrollTracking();
|
|
831
|
-
this.flushMouseBuffer();
|
|
832
|
-
this.flush();
|
|
833
|
-
}
|
|
834
|
-
setPageContext(url, path) {
|
|
835
|
-
this.flushMouseBuffer();
|
|
836
|
-
this.flush();
|
|
837
|
-
this.pageUrl = url;
|
|
838
|
-
this.pagePath = path;
|
|
839
|
-
this.scrollMilestones.clear();
|
|
840
|
-
this.timeMilestones.clear();
|
|
841
|
-
this.exitIntentFired = false;
|
|
842
|
-
this.startTime = Date.now();
|
|
843
|
-
this.clickHistory = [];
|
|
844
|
-
this.clearTimeMilestones();
|
|
845
|
-
this.cleanupScrollTracking();
|
|
846
|
-
this.setupTimeMilestones();
|
|
847
|
-
requestAnimationFrame(() => this.setupScrollTracking());
|
|
848
|
-
}
|
|
849
|
-
// ---------------------------------------------------------------------------
|
|
850
|
-
// Buffer management
|
|
851
|
-
// ---------------------------------------------------------------------------
|
|
852
|
-
push(event) {
|
|
853
|
-
this.buffer.push(event);
|
|
854
|
-
if (this.buffer.length >= this.config.maxBufferSize) {
|
|
855
|
-
this.flush();
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
flush() {
|
|
859
|
-
if (this.buffer.length === 0) return;
|
|
860
|
-
const batch = {
|
|
861
|
-
session_id: this.config.sessionId,
|
|
862
|
-
visitor_id: this.config.visitorId,
|
|
863
|
-
events: this.buffer
|
|
864
|
-
};
|
|
865
|
-
this.buffer = [];
|
|
866
|
-
this.config.sendBatch(batch).catch(() => {
|
|
867
|
-
});
|
|
868
|
-
}
|
|
869
|
-
addListener(target, event, handler) {
|
|
870
|
-
target.addEventListener(event, handler, { passive: true, capture: true });
|
|
871
|
-
this.listeners.push([target, event, handler]);
|
|
872
|
-
}
|
|
873
|
-
// ---------------------------------------------------------------------------
|
|
874
|
-
// Scroll tracking with IntersectionObserver
|
|
875
|
-
// ---------------------------------------------------------------------------
|
|
876
|
-
setupScrollTracking() {
|
|
877
|
-
if (typeof IntersectionObserver === "undefined") return;
|
|
878
|
-
this.observer = new IntersectionObserver(
|
|
879
|
-
(entries) => {
|
|
880
|
-
for (const entry of entries) {
|
|
881
|
-
if (!entry.isIntersecting) continue;
|
|
882
|
-
const milestone = Number(entry.target.getAttribute("data-scroll-milestone"));
|
|
883
|
-
if (isNaN(milestone) || this.scrollMilestones.has(milestone)) continue;
|
|
884
|
-
this.scrollMilestones.add(milestone);
|
|
885
|
-
this.push({
|
|
886
|
-
data_type: "scroll_depth",
|
|
887
|
-
data: {
|
|
888
|
-
depth_percent: milestone,
|
|
889
|
-
timestamp: Date.now()
|
|
890
|
-
},
|
|
891
|
-
page_url: this.pageUrl,
|
|
892
|
-
page_path: this.pagePath
|
|
893
|
-
});
|
|
894
|
-
}
|
|
895
|
-
},
|
|
896
|
-
{ threshold: 0 }
|
|
897
|
-
);
|
|
898
|
-
const docHeight = document.documentElement.scrollHeight;
|
|
899
|
-
for (const pct of SCROLL_MILESTONES) {
|
|
900
|
-
const sentinel = document.createElement("div");
|
|
901
|
-
sentinel.setAttribute("data-scroll-milestone", String(pct));
|
|
902
|
-
sentinel.style.position = "absolute";
|
|
903
|
-
sentinel.style.left = "0";
|
|
904
|
-
sentinel.style.width = "1px";
|
|
905
|
-
sentinel.style.height = "1px";
|
|
906
|
-
sentinel.style.pointerEvents = "none";
|
|
907
|
-
sentinel.style.opacity = "0";
|
|
908
|
-
sentinel.style.top = `${docHeight * pct / 100 - 1}px`;
|
|
909
|
-
document.body.appendChild(sentinel);
|
|
910
|
-
this.sentinels.push(sentinel);
|
|
911
|
-
this.observer.observe(sentinel);
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
cleanupScrollTracking() {
|
|
915
|
-
if (this.observer) {
|
|
916
|
-
this.observer.disconnect();
|
|
917
|
-
this.observer = null;
|
|
918
|
-
}
|
|
919
|
-
for (const sentinel of this.sentinels) {
|
|
920
|
-
sentinel.remove();
|
|
921
|
-
}
|
|
922
|
-
this.sentinels = [];
|
|
923
|
-
}
|
|
924
|
-
// ---------------------------------------------------------------------------
|
|
925
|
-
// Time milestones
|
|
926
|
-
// ---------------------------------------------------------------------------
|
|
927
|
-
setupTimeMilestones() {
|
|
928
|
-
for (const seconds of TIME_MILESTONES) {
|
|
929
|
-
const timer = setTimeout(() => {
|
|
930
|
-
if (this.timeMilestones.has(seconds)) return;
|
|
931
|
-
this.timeMilestones.add(seconds);
|
|
932
|
-
this.push({
|
|
933
|
-
data_type: "time_on_page",
|
|
934
|
-
data: {
|
|
935
|
-
milestone_seconds: seconds,
|
|
936
|
-
timestamp: Date.now()
|
|
937
|
-
},
|
|
938
|
-
page_url: this.pageUrl,
|
|
939
|
-
page_path: this.pagePath
|
|
940
|
-
});
|
|
941
|
-
}, seconds * 1e3);
|
|
942
|
-
this.timeTimers.push(timer);
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
clearTimeMilestones() {
|
|
946
|
-
for (const timer of this.timeTimers) {
|
|
947
|
-
clearTimeout(timer);
|
|
948
|
-
}
|
|
949
|
-
this.timeTimers = [];
|
|
950
|
-
}
|
|
951
|
-
// ---------------------------------------------------------------------------
|
|
952
|
-
// Rage click detection
|
|
953
|
-
// ---------------------------------------------------------------------------
|
|
954
|
-
detectRageClick(x, y, now2) {
|
|
955
|
-
const windowStart = now2 - RAGE_CLICK_WINDOW_MS;
|
|
956
|
-
const nearby = this.clickHistory.filter((c) => {
|
|
957
|
-
if (c.t < windowStart) return false;
|
|
958
|
-
const dx = c.x - x;
|
|
959
|
-
const dy = c.y - y;
|
|
960
|
-
return Math.sqrt(dx * dx + dy * dy) <= RAGE_CLICK_RADIUS;
|
|
961
|
-
});
|
|
962
|
-
if (nearby.length >= RAGE_CLICK_COUNT) {
|
|
963
|
-
this.push({
|
|
964
|
-
data_type: "rage_click",
|
|
965
|
-
data: {
|
|
966
|
-
x,
|
|
967
|
-
y,
|
|
968
|
-
click_count: nearby.length,
|
|
969
|
-
timestamp: now2
|
|
970
|
-
},
|
|
971
|
-
page_url: this.pageUrl,
|
|
972
|
-
page_path: this.pagePath
|
|
973
|
-
});
|
|
974
|
-
this.clickHistory = [];
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
// ---------------------------------------------------------------------------
|
|
978
|
-
// Mouse buffer flush
|
|
979
|
-
// ---------------------------------------------------------------------------
|
|
980
|
-
flushMouseBuffer() {
|
|
981
|
-
if (this.mouseBuffer.length === 0) return;
|
|
982
|
-
this.push({
|
|
983
|
-
data_type: "mouse_movement",
|
|
984
|
-
data: {
|
|
985
|
-
points: [...this.mouseBuffer],
|
|
986
|
-
timestamp: Date.now()
|
|
987
|
-
},
|
|
988
|
-
page_url: this.pageUrl,
|
|
989
|
-
page_path: this.pagePath
|
|
990
|
-
});
|
|
991
|
-
this.mouseBuffer = [];
|
|
992
|
-
}
|
|
993
|
-
// ---------------------------------------------------------------------------
|
|
994
|
-
// CSS selector helper
|
|
995
|
-
// ---------------------------------------------------------------------------
|
|
996
|
-
getSelector(el) {
|
|
997
|
-
const parts = [];
|
|
998
|
-
let current = el;
|
|
999
|
-
let depth = 0;
|
|
1000
|
-
while (current && depth < 3) {
|
|
1001
|
-
let segment = current.tagName.toLowerCase();
|
|
1002
|
-
if (current.id) {
|
|
1003
|
-
segment += `#${current.id}`;
|
|
1004
|
-
} else if (current.classList.length > 0) {
|
|
1005
|
-
segment += `.${Array.from(current.classList).join(".")}`;
|
|
1006
|
-
}
|
|
1007
|
-
parts.unshift(segment);
|
|
1008
|
-
current = current.parentElement;
|
|
1009
|
-
depth++;
|
|
1010
|
-
}
|
|
1011
|
-
return parts.join(" > ");
|
|
1012
|
-
}
|
|
1013
|
-
};
|
|
1014
|
-
|
|
1015
|
-
// src/react/components/behavioral-tracker.tsx
|
|
1016
689
|
var SESSION_KEY_SUFFIX2 = "-analytics-session";
|
|
1017
690
|
var VISITOR_KEY_SUFFIX2 = "-visitor-id";
|
|
1018
691
|
var MAX_SESSION_WAIT_MS = 1e4;
|
|
@@ -1073,7 +746,7 @@ function BehavioralTrackerComponent({ pathname }) {
|
|
|
1073
746
|
"x-api-key": config.apiKey
|
|
1074
747
|
});
|
|
1075
748
|
};
|
|
1076
|
-
const tracker = new BehavioralTracker({ sendBatch, sessionId, visitorId });
|
|
749
|
+
const tracker = new chunkHOQKBNYB_cjs.BehavioralTracker({ sendBatch, sessionId, visitorId });
|
|
1077
750
|
tracker.start();
|
|
1078
751
|
trackerRef.current = tracker;
|
|
1079
752
|
};
|
|
@@ -2572,7 +2245,26 @@ function SectionRenderer({
|
|
|
2572
2245
|
return null;
|
|
2573
2246
|
}
|
|
2574
2247
|
})();
|
|
2575
|
-
|
|
2248
|
+
const sectionRef = react.useRef(null);
|
|
2249
|
+
react.useEffect(() => {
|
|
2250
|
+
const el2 = sectionRef.current;
|
|
2251
|
+
if (!el2 || typeof IntersectionObserver === "undefined") return;
|
|
2252
|
+
const obs = new IntersectionObserver(
|
|
2253
|
+
([entry]) => {
|
|
2254
|
+
if (entry.isIntersecting) {
|
|
2255
|
+
onEvent?.("section_view", {
|
|
2256
|
+
section_id: section.id,
|
|
2257
|
+
section_type: section.type
|
|
2258
|
+
});
|
|
2259
|
+
obs.disconnect();
|
|
2260
|
+
}
|
|
2261
|
+
},
|
|
2262
|
+
{ threshold: 0.5 }
|
|
2263
|
+
);
|
|
2264
|
+
obs.observe(el2);
|
|
2265
|
+
return () => obs.disconnect();
|
|
2266
|
+
}, [section.id, section.type, onEvent]);
|
|
2267
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: sectionRef, "data-section-id": section.id, "data-section-type": section.type, children: [
|
|
2576
2268
|
el,
|
|
2577
2269
|
showCOA && data?.coa && /* @__PURE__ */ jsxRuntime.jsx(COAModal, { coa: data.coa, theme, onClose: () => setShowCOA(false) })
|
|
2578
2270
|
] });
|
|
@@ -3479,7 +3171,8 @@ function LandingPage({
|
|
|
3479
3171
|
onDataLoaded,
|
|
3480
3172
|
onError,
|
|
3481
3173
|
onEvent,
|
|
3482
|
-
analyticsContext
|
|
3174
|
+
analyticsContext,
|
|
3175
|
+
enableAnalytics = true
|
|
3483
3176
|
}) {
|
|
3484
3177
|
const [state, setState] = react.useState("loading");
|
|
3485
3178
|
const [data, setData] = react.useState(null);
|
|
@@ -3487,6 +3180,13 @@ function LandingPage({
|
|
|
3487
3180
|
react.useEffect(() => {
|
|
3488
3181
|
if (!slug) return;
|
|
3489
3182
|
let cancelled = false;
|
|
3183
|
+
if (typeof window !== "undefined" && window.__LANDING_DATA__) {
|
|
3184
|
+
const json = window.__LANDING_DATA__;
|
|
3185
|
+
setData(json);
|
|
3186
|
+
setState("ready");
|
|
3187
|
+
onDataLoaded?.(json);
|
|
3188
|
+
return;
|
|
3189
|
+
}
|
|
3490
3190
|
async function load() {
|
|
3491
3191
|
try {
|
|
3492
3192
|
const res = await fetch(`${gatewayUrl}/l/${encodeURIComponent(slug)}`);
|
|
@@ -3527,16 +3227,113 @@ function LandingPage({
|
|
|
3527
3227
|
if (state === "expired") return /* @__PURE__ */ jsxRuntime.jsx(DefaultExpired2, {});
|
|
3528
3228
|
if (state === "error") return /* @__PURE__ */ jsxRuntime.jsx(DefaultError2, { message: errorMsg });
|
|
3529
3229
|
if (!data) return null;
|
|
3530
|
-
return /* @__PURE__ */ jsxRuntime.jsx(PageLayout, { data, gatewayUrl, renderSection, onEvent, analyticsContext });
|
|
3230
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PageLayout, { data, gatewayUrl, renderSection, onEvent, analyticsContext, enableAnalytics });
|
|
3231
|
+
}
|
|
3232
|
+
function isSectionVisible(section, urlParams) {
|
|
3233
|
+
const vis = section.config?.visibility;
|
|
3234
|
+
if (!vis?.params) return true;
|
|
3235
|
+
for (const [key, allowed] of Object.entries(vis.params)) {
|
|
3236
|
+
const val = urlParams.get(key);
|
|
3237
|
+
if (!val || !allowed.includes(val)) return false;
|
|
3238
|
+
}
|
|
3239
|
+
return true;
|
|
3531
3240
|
}
|
|
3532
3241
|
function PageLayout({
|
|
3533
3242
|
data,
|
|
3534
3243
|
gatewayUrl,
|
|
3535
3244
|
renderSection,
|
|
3536
3245
|
onEvent,
|
|
3537
|
-
analyticsContext
|
|
3246
|
+
analyticsContext,
|
|
3247
|
+
enableAnalytics
|
|
3538
3248
|
}) {
|
|
3539
3249
|
const { landing_page: lp, store } = data;
|
|
3250
|
+
const trackerRef = react.useRef(null);
|
|
3251
|
+
react.useEffect(() => {
|
|
3252
|
+
if (!enableAnalytics || typeof window === "undefined") return;
|
|
3253
|
+
const analyticsConfig = window.__LANDING_ANALYTICS__;
|
|
3254
|
+
if (!analyticsConfig?.slug) return;
|
|
3255
|
+
let visitorId = localStorage.getItem("wt_vid") || "";
|
|
3256
|
+
if (!visitorId) {
|
|
3257
|
+
visitorId = crypto.randomUUID();
|
|
3258
|
+
localStorage.setItem("wt_vid", visitorId);
|
|
3259
|
+
}
|
|
3260
|
+
let sessionId = sessionStorage.getItem("wt_sid") || "";
|
|
3261
|
+
if (!sessionId) {
|
|
3262
|
+
sessionId = crypto.randomUUID();
|
|
3263
|
+
sessionStorage.setItem("wt_sid", sessionId);
|
|
3264
|
+
}
|
|
3265
|
+
import('../tracker-WYKTEQ4F.cjs').then(({ BehavioralTracker: BehavioralTracker2 }) => {
|
|
3266
|
+
const gwUrl = analyticsConfig.gatewayUrl || gatewayUrl;
|
|
3267
|
+
const slug = analyticsConfig.slug;
|
|
3268
|
+
const utmParams = new URLSearchParams(window.location.search);
|
|
3269
|
+
const tracker = new BehavioralTracker2({
|
|
3270
|
+
sessionId,
|
|
3271
|
+
visitorId,
|
|
3272
|
+
sendBatch: async (batch) => {
|
|
3273
|
+
const events = batch.events.map((e) => ({
|
|
3274
|
+
event_type: e.data_type,
|
|
3275
|
+
event_data: e.data,
|
|
3276
|
+
session_id: batch.session_id,
|
|
3277
|
+
visitor_id: batch.visitor_id,
|
|
3278
|
+
campaign_id: analyticsConfig.campaignId || utmParams.get("utm_campaign_id") || void 0,
|
|
3279
|
+
utm_source: utmParams.get("utm_source") || void 0,
|
|
3280
|
+
utm_medium: utmParams.get("utm_medium") || void 0,
|
|
3281
|
+
utm_campaign: utmParams.get("utm_campaign") || void 0
|
|
3282
|
+
}));
|
|
3283
|
+
const body = JSON.stringify({ events });
|
|
3284
|
+
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
3285
|
+
navigator.sendBeacon(
|
|
3286
|
+
`${gwUrl}/l/${encodeURIComponent(slug)}/events`,
|
|
3287
|
+
new Blob([body], { type: "application/json" })
|
|
3288
|
+
);
|
|
3289
|
+
} else {
|
|
3290
|
+
await fetch(`${gwUrl}/l/${encodeURIComponent(slug)}/events`, {
|
|
3291
|
+
method: "POST",
|
|
3292
|
+
headers: { "Content-Type": "application/json" },
|
|
3293
|
+
body,
|
|
3294
|
+
keepalive: true
|
|
3295
|
+
});
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
});
|
|
3299
|
+
tracker.setPageContext(window.location.href, window.location.pathname);
|
|
3300
|
+
tracker.start();
|
|
3301
|
+
trackerRef.current = tracker;
|
|
3302
|
+
const pageViewBody = JSON.stringify({
|
|
3303
|
+
events: [{
|
|
3304
|
+
event_type: "page_view",
|
|
3305
|
+
event_data: { referrer: document.referrer, url: window.location.href },
|
|
3306
|
+
session_id: sessionId,
|
|
3307
|
+
visitor_id: visitorId,
|
|
3308
|
+
campaign_id: analyticsConfig.campaignId || void 0,
|
|
3309
|
+
utm_source: utmParams.get("utm_source") || void 0,
|
|
3310
|
+
utm_medium: utmParams.get("utm_medium") || void 0,
|
|
3311
|
+
utm_campaign: utmParams.get("utm_campaign") || void 0
|
|
3312
|
+
}]
|
|
3313
|
+
});
|
|
3314
|
+
if (navigator.sendBeacon) {
|
|
3315
|
+
navigator.sendBeacon(
|
|
3316
|
+
`${gwUrl}/l/${encodeURIComponent(slug)}/events`,
|
|
3317
|
+
new Blob([pageViewBody], { type: "application/json" })
|
|
3318
|
+
);
|
|
3319
|
+
} else {
|
|
3320
|
+
fetch(`${gwUrl}/l/${encodeURIComponent(slug)}/events`, {
|
|
3321
|
+
method: "POST",
|
|
3322
|
+
headers: { "Content-Type": "application/json" },
|
|
3323
|
+
body: pageViewBody,
|
|
3324
|
+
keepalive: true
|
|
3325
|
+
}).catch(() => {
|
|
3326
|
+
});
|
|
3327
|
+
}
|
|
3328
|
+
}).catch(() => {
|
|
3329
|
+
});
|
|
3330
|
+
return () => {
|
|
3331
|
+
if (trackerRef.current) {
|
|
3332
|
+
trackerRef.current.stop();
|
|
3333
|
+
trackerRef.current = null;
|
|
3334
|
+
}
|
|
3335
|
+
};
|
|
3336
|
+
}, [enableAnalytics, gatewayUrl]);
|
|
3540
3337
|
const theme = {
|
|
3541
3338
|
bg: lp.background_color || store?.theme?.background || "#050505",
|
|
3542
3339
|
fg: lp.text_color || store?.theme?.foreground || "#fafafa",
|
|
@@ -3548,7 +3345,8 @@ function PageLayout({
|
|
|
3548
3345
|
};
|
|
3549
3346
|
const fontFamily = lp.font_family || theme.fontDisplay || "system-ui, -apple-system, sans-serif";
|
|
3550
3347
|
const logoUrl = store?.logo_url;
|
|
3551
|
-
const
|
|
3348
|
+
const urlParams = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : new URLSearchParams();
|
|
3349
|
+
const sorted = [...lp.sections].sort((a, b) => a.order - b.order).filter((s) => isSectionVisible(s, urlParams));
|
|
3552
3350
|
const sectionData = { ...data, gatewayUrl, landing_page: { slug: lp.slug }, analyticsContext };
|
|
3553
3351
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { minHeight: "100dvh", background: theme.bg, color: theme.fg, fontFamily }, children: [
|
|
3554
3352
|
lp.custom_css && /* @__PURE__ */ jsxRuntime.jsx("style", { children: lp.custom_css }),
|