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