@atmosfer/impressions 0.1.6 → 0.1.7
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/index.js +18 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +18 -25
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -89,14 +89,6 @@ function createTracker(cfg) {
|
|
|
89
89
|
keepalive: true
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
|
-
function beacon(ev) {
|
|
93
|
-
var _a;
|
|
94
|
-
try {
|
|
95
|
-
const blob = new Blob([JSON.stringify(ev)], { type: "application/json" });
|
|
96
|
-
(_a = navigator.sendBeacon) == null ? void 0 : _a.call(navigator, state.endpoint, blob);
|
|
97
|
-
} catch {
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
92
|
function build(eventType, detail) {
|
|
101
93
|
return {
|
|
102
94
|
schema_version: 1,
|
|
@@ -108,21 +100,6 @@ function createTracker(cfg) {
|
|
|
108
100
|
event_detail: { ...baseDetail(anonId), ...detail ?? {} }
|
|
109
101
|
};
|
|
110
102
|
}
|
|
111
|
-
window.addEventListener("pagehide", () => {
|
|
112
|
-
if (state.disabled) return;
|
|
113
|
-
beacon(build("page_view"));
|
|
114
|
-
});
|
|
115
|
-
const origPush = history.pushState;
|
|
116
|
-
history.pushState = function(...args) {
|
|
117
|
-
origPush.apply(history, args);
|
|
118
|
-
void post(build("page_view"));
|
|
119
|
-
};
|
|
120
|
-
const origReplace = history.replaceState;
|
|
121
|
-
history.replaceState = function(...args) {
|
|
122
|
-
origReplace.apply(history, args);
|
|
123
|
-
void post(build("page_view"));
|
|
124
|
-
};
|
|
125
|
-
window.addEventListener("popstate", () => void post(build("page_view")));
|
|
126
103
|
return {
|
|
127
104
|
page: async (detail) => post(build("page_view", detail)),
|
|
128
105
|
track: async (eventType, detail) => post(build(eventType, detail)),
|
|
@@ -147,8 +124,24 @@ function useImpressions(config, options = {}) {
|
|
|
147
124
|
react.useEffect(() => {
|
|
148
125
|
if (options.trackOnMount === false) return;
|
|
149
126
|
if (didTrackMount.current) return;
|
|
150
|
-
|
|
151
|
-
|
|
127
|
+
const sendPageView = () => {
|
|
128
|
+
if (didTrackMount.current) return;
|
|
129
|
+
didTrackMount.current = true;
|
|
130
|
+
void tracker.page();
|
|
131
|
+
};
|
|
132
|
+
if (document.visibilityState === "visible") {
|
|
133
|
+
sendPageView();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const onVisibility = () => {
|
|
137
|
+
if (document.visibilityState !== "visible") return;
|
|
138
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
139
|
+
sendPageView();
|
|
140
|
+
};
|
|
141
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
142
|
+
return () => {
|
|
143
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
144
|
+
};
|
|
152
145
|
}, []);
|
|
153
146
|
return tracker;
|
|
154
147
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tracker.ts","../src/hook.ts"],"names":["useMemo","useRef","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["export type RestaurantId = string;\n\nexport type ImpressionEvent = {\n schema_version: 1;\n event_id: string;\n ts: string;\n\n restaurant_id: RestaurantId;\n table_no?: number | null;\n\n event_type: string;\n event_detail: Record<string, any>;\n};\n\nexport type TrackerConfig = {\n endpoint: string;\n restaurantId: RestaurantId;\n tableNo?: number;\n headers?: Record<string, string>;\n debug?: boolean;\n disable?: boolean;\n anonIdKey?: string;\n};\n\nfunction uuidv4(): string {\n return crypto.randomUUID();\n}\n\nfunction safeGetLS(key: string): string | null {\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n}\nfunction safeSetLS(key: string, val: string) {\n try {\n localStorage.setItem(key, val);\n } catch {}\n}\n\nfunction getAnonId(key: string) {\n const existing = safeGetLS(key);\n if (existing) return existing;\n const id = uuidv4();\n safeSetLS(key, id);\n return id;\n}\n\nfunction parseUtm() {\n const p = new URLSearchParams(location.search);\n const source = p.get(\"utm_source\");\n const medium = p.get(\"utm_medium\");\n const campaign = p.get(\"utm_campaign\");\n if (!source && !medium && !campaign) return undefined;\n return { source, medium, campaign };\n}\n\nfunction deviceType(): \"mobile\" | \"tablet\" | \"desktop\" {\n const w = Math.min(screen.width, screen.height);\n if (w <= 480) return \"mobile\";\n if (w <= 1024) return \"tablet\";\n return \"desktop\";\n}\n\nfunction baseDetail(anonId: string) {\n return {\n path: location.pathname + location.search,\n referrer: document.referrer || undefined,\n utm: parseUtm(),\n anon_id: anonId,\n language: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n device: { type: deviceType() },\n screen: { w: window.innerWidth, h: window.innerHeight },\n page: { title: document.title },\n };\n}\n\nexport type Tracker = {\n page: (detail?: Record<string, any>) => Promise<void>;\n track: (eventType: string, detail?: Record<string, any>) => Promise<void>;\n setContext: (\n ctx: Partial<{ restaurantId: RestaurantId; tableNo: number }>\n ) => void;\n disable: () => void;\n enable: () => void;\n};\n\nexport function createTracker(cfg: TrackerConfig): Tracker {\n const isBrowser =\n typeof window !== \"undefined\" &&\n typeof document !== \"undefined\" &&\n typeof navigator !== \"undefined\" &&\n typeof location !== \"undefined\";\n\n if (!isBrowser) {\n return {\n page: async () => {},\n track: async () => {},\n setContext: () => {},\n disable: () => {},\n enable: () => {},\n };\n }\n\n const anonKey = cfg.anonIdKey ?? \"sa_anon_id\";\n const anonId = getAnonId(anonKey);\n\n const state = {\n endpoint: cfg.endpoint,\n restaurantId: cfg.restaurantId,\n tableNo: cfg.tableNo,\n headers: cfg.headers ?? {},\n disabled: !!cfg.disable,\n debug: !!cfg.debug,\n };\n\n async function post(ev: ImpressionEvent) {\n if (state.disabled) return;\n\n if (state.debug) console.log(\"[impr] sending\", ev);\n\n await fetch(state.endpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", ...state.headers },\n body: JSON.stringify(ev),\n keepalive: true,\n });\n }\n\n function beacon(ev: ImpressionEvent) {\n try {\n const blob = new Blob([JSON.stringify(ev)], { type: \"application/json\" });\n navigator.sendBeacon?.(state.endpoint, blob);\n } catch {}\n }\n\n function build(\n eventType: string,\n detail?: Record<string, any>\n ): ImpressionEvent {\n return {\n schema_version: 1,\n event_id: uuidv4(),\n ts: new Date().toISOString(),\n restaurant_id: state.restaurantId,\n table_no: state.tableNo ?? null,\n event_type: eventType,\n event_detail: { ...baseDetail(anonId), ...(detail ?? {}) },\n };\n }\n\n // Unload best-effort\n window.addEventListener(\"pagehide\", () => {\n if (state.disabled) return;\n beacon(build(\"page_view\"));\n });\n\n // SPA navigation tracking (framework-agnostic)\n const origPush = history.pushState;\n history.pushState = function (...args: any) {\n origPush.apply(history, args as any);\n void post(build(\"page_view\"));\n } as any;\n\n const origReplace = history.replaceState;\n history.replaceState = function (...args: any) {\n origReplace.apply(history, args as any);\n void post(build(\"page_view\"));\n } as any;\n\n window.addEventListener(\"popstate\", () => void post(build(\"page_view\")));\n\n return {\n page: async (detail) => post(build(\"page_view\", detail)),\n track: async (eventType, detail) => post(build(eventType, detail)),\n setContext: (ctx) => {\n if (ctx.restaurantId !== undefined) state.restaurantId = ctx.restaurantId;\n if (ctx.tableNo !== undefined) state.tableNo = ctx.tableNo;\n },\n disable: () => {\n state.disabled = true;\n },\n enable: () => {\n state.disabled = false;\n },\n };\n}\n","import { useEffect, useMemo, useRef } from \"react\";\nimport { createTracker } from \"./tracker\";\nimport type { TrackerConfig } from \"./tracker\";\n\nexport type UseImpressionsOptions = {\n trackOnMount?: boolean;\n};\n\nexport function useImpressions(\n config: TrackerConfig,\n options: UseImpressionsOptions = {}\n) {\n const tracker = useMemo(\n () => createTracker(config),\n [config.endpoint, config.restaurantId, config.tableNo]\n );\n const didTrackMount = useRef(false);\n\n useEffect(() => {\n if (options.trackOnMount === false) return;\n if (didTrackMount.current) return;\n didTrackMount.current = true;\n void tracker.page();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return tracker;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/tracker.ts","../src/hook.ts"],"names":["useMemo","useRef","useEffect"],"mappings":";;;;;AAwBA,SAAS,MAAA,GAAiB;AACxB,EAAA,OAAO,OAAO,UAAA,EAAW;AAC3B;AAEA,SAAS,UAAU,GAAA,EAA4B;AAC7C,EAAA,IAAI;AACF,IAAA,OAAO,YAAA,CAAa,QAAQ,GAAG,CAAA;AAAA,EACjC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AACA,SAAS,SAAA,CAAU,KAAa,GAAA,EAAa;AAC3C,EAAA,IAAI;AACF,IAAA,YAAA,CAAa,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,EAC/B,CAAA,CAAA,MAAQ;AAAA,EAAC;AACX;AAEA,SAAS,UAAU,GAAA,EAAa;AAC9B,EAAA,MAAM,QAAA,GAAW,UAAU,GAAG,CAAA;AAC9B,EAAA,IAAI,UAAU,OAAO,QAAA;AACrB,EAAA,MAAM,KAAK,MAAA,EAAO;AAClB,EAAA,SAAA,CAAU,KAAK,EAAE,CAAA;AACjB,EAAA,OAAO,EAAA;AACT;AAEA,SAAS,QAAA,GAAW;AAClB,EAAA,MAAM,CAAA,GAAI,IAAI,eAAA,CAAgB,QAAA,CAAS,MAAM,CAAA;AAC7C,EAAA,MAAM,MAAA,GAAS,CAAA,CAAE,GAAA,CAAI,YAAY,CAAA;AACjC,EAAA,MAAM,MAAA,GAAS,CAAA,CAAE,GAAA,CAAI,YAAY,CAAA;AACjC,EAAA,MAAM,QAAA,GAAW,CAAA,CAAE,GAAA,CAAI,cAAc,CAAA;AACrC,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,MAAA,IAAU,CAAC,UAAU,OAAO,MAAA;AAC5C,EAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAS;AACpC;AAEA,SAAS,UAAA,GAA8C;AACrD,EAAA,MAAM,IAAI,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,KAAA,EAAO,OAAO,MAAM,CAAA;AAC9C,EAAA,IAAI,CAAA,IAAK,KAAK,OAAO,QAAA;AACrB,EAAA,IAAI,CAAA,IAAK,MAAM,OAAO,QAAA;AACtB,EAAA,OAAO,SAAA;AACT;AAEA,SAAS,WAAW,MAAA,EAAgB;AAClC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA,CAAS,QAAA,GAAW,QAAA,CAAS,MAAA;AAAA,IACnC,QAAA,EAAU,SAAS,QAAA,IAAY,MAAA;AAAA,IAC/B,KAAK,QAAA,EAAS;AAAA,IACd,OAAA,EAAS,MAAA;AAAA,IACT,UAAU,SAAA,CAAU,QAAA;AAAA,IACpB,QAAA,EAAU,IAAA,CAAK,cAAA,EAAe,CAAE,iBAAgB,CAAE,QAAA;AAAA,IAClD,MAAA,EAAQ,EAAE,IAAA,EAAM,UAAA,EAAW,EAAE;AAAA,IAC7B,QAAQ,EAAE,CAAA,EAAG,OAAO,UAAA,EAAY,CAAA,EAAG,OAAO,WAAA,EAAY;AAAA,IACtD,IAAA,EAAM,EAAE,KAAA,EAAO,QAAA,CAAS,KAAA;AAAM,GAChC;AACF;AAYO,SAAS,cAAc,GAAA,EAA6B;AACzD,EAAA,MAAM,SAAA,GACJ,OAAO,MAAA,KAAW,WAAA,IAClB,OAAO,QAAA,KAAa,WAAA,IACpB,OAAO,SAAA,KAAc,WAAA,IACrB,OAAO,QAAA,KAAa,WAAA;AAEtB,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,OAAO;AAAA,MACL,MAAM,YAAY;AAAA,MAAC,CAAA;AAAA,MACnB,OAAO,YAAY;AAAA,MAAC,CAAA;AAAA,MACpB,YAAY,MAAM;AAAA,MAAC,CAAA;AAAA,MACnB,SAAS,MAAM;AAAA,MAAC,CAAA;AAAA,MAChB,QAAQ,MAAM;AAAA,MAAC;AAAA,KACjB;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU,IAAI,SAAA,IAAa,YAAA;AACjC,EAAA,MAAM,MAAA,GAAS,UAAU,OAAO,CAAA;AAEhC,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,UAAU,GAAA,CAAI,QAAA;AAAA,IACd,cAAc,GAAA,CAAI,YAAA;AAAA,IAClB,SAAS,GAAA,CAAI,OAAA;AAAA,IACb,OAAA,EAAS,GAAA,CAAI,OAAA,IAAW,EAAC;AAAA,IACzB,QAAA,EAAU,CAAC,CAAC,GAAA,CAAI,OAAA;AAAA,IAChB,KAAA,EAAO,CAAC,CAAC,GAAA,CAAI;AAAA,GACf;AAEA,EAAA,eAAe,KAAK,EAAA,EAAqB;AACvC,IAAA,IAAI,MAAM,QAAA,EAAU;AAEpB,IAAA,IAAI,KAAA,CAAM,KAAA,EAAO,OAAA,CAAQ,GAAA,CAAI,kBAAkB,EAAE,CAAA;AAEjD,IAAA,MAAM,KAAA,CAAM,MAAM,QAAA,EAAU;AAAA,MAC1B,MAAA,EAAQ,MAAA;AAAA,MACR,SAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,GAAG,MAAM,OAAA,EAAQ;AAAA,MAChE,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,CAAA;AAAA,MACvB,SAAA,EAAW;AAAA,KACZ,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,KAAA,CACP,WACA,MAAA,EACiB;AACjB,IAAA,OAAO;AAAA,MACL,cAAA,EAAgB,CAAA;AAAA,MAChB,UAAU,MAAA,EAAO;AAAA,MACjB,EAAA,EAAA,iBAAI,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAC3B,eAAe,KAAA,CAAM,YAAA;AAAA,MACrB,QAAA,EAAU,MAAM,OAAA,IAAW,IAAA;AAAA,MAC3B,UAAA,EAAY,SAAA;AAAA,MACZ,YAAA,EAAc,EAAE,GAAG,UAAA,CAAW,MAAM,CAAA,EAAG,GAAI,MAAA,IAAU,EAAC;AAAG,KAC3D;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,OAAO,MAAA,KAAW,KAAK,KAAA,CAAM,WAAA,EAAa,MAAM,CAAC,CAAA;AAAA,IACvD,KAAA,EAAO,OAAO,SAAA,EAAW,MAAA,KAAW,KAAK,KAAA,CAAM,SAAA,EAAW,MAAM,CAAC,CAAA;AAAA,IACjE,UAAA,EAAY,CAAC,GAAA,KAAQ;AACnB,MAAA,IAAI,GAAA,CAAI,YAAA,KAAiB,MAAA,EAAW,KAAA,CAAM,eAAe,GAAA,CAAI,YAAA;AAC7D,MAAA,IAAI,GAAA,CAAI,OAAA,KAAY,MAAA,EAAW,KAAA,CAAM,UAAU,GAAA,CAAI,OAAA;AAAA,IACrD,CAAA;AAAA,IACA,SAAS,MAAM;AACb,MAAA,KAAA,CAAM,QAAA,GAAW,IAAA;AAAA,IACnB,CAAA;AAAA,IACA,QAAQ,MAAM;AACZ,MAAA,KAAA,CAAM,QAAA,GAAW,KAAA;AAAA,IACnB;AAAA,GACF;AACF;ACxJO,SAAS,cAAA,CACd,MAAA,EACA,OAAA,GAAiC,EAAC,EAClC;AACA,EAAA,MAAM,OAAA,GAAUA,aAAA;AAAA,IACd,MAAM,cAAc,MAAM,CAAA;AAAA,IAC1B,CAAC,MAAA,CAAO,QAAA,EAAU,MAAA,CAAO,YAAA,EAAc,OAAO,OAAO;AAAA,GACvD;AACA,EAAA,MAAM,aAAA,GAAgBC,aAAO,KAAK,CAAA;AAElC,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAA,CAAQ,iBAAiB,KAAA,EAAO;AACpC,IAAA,IAAI,cAAc,OAAA,EAAS;AAE3B,IAAA,MAAM,eAAe,MAAM;AACzB,MAAA,IAAI,cAAc,OAAA,EAAS;AAC3B,MAAA,aAAA,CAAc,OAAA,GAAU,IAAA;AACxB,MAAA,KAAK,QAAQ,IAAA,EAAK;AAAA,IACpB,CAAA;AAEA,IAAA,IAAI,QAAA,CAAS,oBAAoB,SAAA,EAAW;AAC1C,MAAA,YAAA,EAAa;AACb,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,eAAe,MAAM;AACzB,MAAA,IAAI,QAAA,CAAS,oBAAoB,SAAA,EAAW;AAC5C,MAAA,QAAA,CAAS,mBAAA,CAAoB,oBAAoB,YAAY,CAAA;AAC7D,MAAA,YAAA,EAAa;AAAA,IACf,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA,CAAiB,oBAAoB,YAAY,CAAA;AAC1D,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,oBAAoB,YAAY,CAAA;AAAA,IAC/D,CAAA;AAAA,EAEF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,OAAA;AACT","file":"index.js","sourcesContent":["export type RestaurantId = string;\n\nexport type ImpressionEvent = {\n schema_version: 1;\n event_id: string;\n ts: string;\n\n restaurant_id: RestaurantId;\n table_no?: number | null;\n\n event_type: string;\n event_detail: Record<string, any>;\n};\n\nexport type TrackerConfig = {\n endpoint: string;\n restaurantId: RestaurantId;\n tableNo?: number;\n headers?: Record<string, string>;\n debug?: boolean;\n disable?: boolean;\n anonIdKey?: string;\n};\n\nfunction uuidv4(): string {\n return crypto.randomUUID();\n}\n\nfunction safeGetLS(key: string): string | null {\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n}\nfunction safeSetLS(key: string, val: string) {\n try {\n localStorage.setItem(key, val);\n } catch {}\n}\n\nfunction getAnonId(key: string) {\n const existing = safeGetLS(key);\n if (existing) return existing;\n const id = uuidv4();\n safeSetLS(key, id);\n return id;\n}\n\nfunction parseUtm() {\n const p = new URLSearchParams(location.search);\n const source = p.get(\"utm_source\");\n const medium = p.get(\"utm_medium\");\n const campaign = p.get(\"utm_campaign\");\n if (!source && !medium && !campaign) return undefined;\n return { source, medium, campaign };\n}\n\nfunction deviceType(): \"mobile\" | \"tablet\" | \"desktop\" {\n const w = Math.min(screen.width, screen.height);\n if (w <= 480) return \"mobile\";\n if (w <= 1024) return \"tablet\";\n return \"desktop\";\n}\n\nfunction baseDetail(anonId: string) {\n return {\n path: location.pathname + location.search,\n referrer: document.referrer || undefined,\n utm: parseUtm(),\n anon_id: anonId,\n language: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n device: { type: deviceType() },\n screen: { w: window.innerWidth, h: window.innerHeight },\n page: { title: document.title },\n };\n}\n\nexport type Tracker = {\n page: (detail?: Record<string, any>) => Promise<void>;\n track: (eventType: string, detail?: Record<string, any>) => Promise<void>;\n setContext: (\n ctx: Partial<{ restaurantId: RestaurantId; tableNo: number }>\n ) => void;\n disable: () => void;\n enable: () => void;\n};\n\nexport function createTracker(cfg: TrackerConfig): Tracker {\n const isBrowser =\n typeof window !== \"undefined\" &&\n typeof document !== \"undefined\" &&\n typeof navigator !== \"undefined\" &&\n typeof location !== \"undefined\";\n\n if (!isBrowser) {\n return {\n page: async () => {},\n track: async () => {},\n setContext: () => {},\n disable: () => {},\n enable: () => {},\n };\n }\n\n const anonKey = cfg.anonIdKey ?? \"sa_anon_id\";\n const anonId = getAnonId(anonKey);\n\n const state = {\n endpoint: cfg.endpoint,\n restaurantId: cfg.restaurantId,\n tableNo: cfg.tableNo,\n headers: cfg.headers ?? {},\n disabled: !!cfg.disable,\n debug: !!cfg.debug,\n };\n\n async function post(ev: ImpressionEvent) {\n if (state.disabled) return;\n\n if (state.debug) console.log(\"[impr] sending\", ev);\n\n await fetch(state.endpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", ...state.headers },\n body: JSON.stringify(ev),\n keepalive: true,\n });\n }\n\n function build(\n eventType: string,\n detail?: Record<string, any>\n ): ImpressionEvent {\n return {\n schema_version: 1,\n event_id: uuidv4(),\n ts: new Date().toISOString(),\n restaurant_id: state.restaurantId,\n table_no: state.tableNo ?? null,\n event_type: eventType,\n event_detail: { ...baseDetail(anonId), ...(detail ?? {}) },\n };\n }\n\n return {\n page: async (detail) => post(build(\"page_view\", detail)),\n track: async (eventType, detail) => post(build(eventType, detail)),\n setContext: (ctx) => {\n if (ctx.restaurantId !== undefined) state.restaurantId = ctx.restaurantId;\n if (ctx.tableNo !== undefined) state.tableNo = ctx.tableNo;\n },\n disable: () => {\n state.disabled = true;\n },\n enable: () => {\n state.disabled = false;\n },\n };\n}\n","import { useEffect, useMemo, useRef } from \"react\";\nimport { createTracker } from \"./tracker\";\nimport type { TrackerConfig } from \"./tracker\";\n\nexport type UseImpressionsOptions = {\n trackOnMount?: boolean;\n};\n\nexport function useImpressions(\n config: TrackerConfig,\n options: UseImpressionsOptions = {}\n) {\n const tracker = useMemo(\n () => createTracker(config),\n [config.endpoint, config.restaurantId, config.tableNo]\n );\n const didTrackMount = useRef(false);\n\n useEffect(() => {\n if (options.trackOnMount === false) return;\n if (didTrackMount.current) return;\n\n const sendPageView = () => {\n if (didTrackMount.current) return;\n didTrackMount.current = true;\n void tracker.page();\n };\n\n if (document.visibilityState === \"visible\") {\n sendPageView();\n return;\n }\n\n const onVisibility = () => {\n if (document.visibilityState !== \"visible\") return;\n document.removeEventListener(\"visibilitychange\", onVisibility);\n sendPageView();\n };\n\n document.addEventListener(\"visibilitychange\", onVisibility);\n return () => {\n document.removeEventListener(\"visibilitychange\", onVisibility);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return tracker;\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -87,14 +87,6 @@ function createTracker(cfg) {
|
|
|
87
87
|
keepalive: true
|
|
88
88
|
});
|
|
89
89
|
}
|
|
90
|
-
function beacon(ev) {
|
|
91
|
-
var _a;
|
|
92
|
-
try {
|
|
93
|
-
const blob = new Blob([JSON.stringify(ev)], { type: "application/json" });
|
|
94
|
-
(_a = navigator.sendBeacon) == null ? void 0 : _a.call(navigator, state.endpoint, blob);
|
|
95
|
-
} catch {
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
90
|
function build(eventType, detail) {
|
|
99
91
|
return {
|
|
100
92
|
schema_version: 1,
|
|
@@ -106,21 +98,6 @@ function createTracker(cfg) {
|
|
|
106
98
|
event_detail: { ...baseDetail(anonId), ...detail ?? {} }
|
|
107
99
|
};
|
|
108
100
|
}
|
|
109
|
-
window.addEventListener("pagehide", () => {
|
|
110
|
-
if (state.disabled) return;
|
|
111
|
-
beacon(build("page_view"));
|
|
112
|
-
});
|
|
113
|
-
const origPush = history.pushState;
|
|
114
|
-
history.pushState = function(...args) {
|
|
115
|
-
origPush.apply(history, args);
|
|
116
|
-
void post(build("page_view"));
|
|
117
|
-
};
|
|
118
|
-
const origReplace = history.replaceState;
|
|
119
|
-
history.replaceState = function(...args) {
|
|
120
|
-
origReplace.apply(history, args);
|
|
121
|
-
void post(build("page_view"));
|
|
122
|
-
};
|
|
123
|
-
window.addEventListener("popstate", () => void post(build("page_view")));
|
|
124
101
|
return {
|
|
125
102
|
page: async (detail) => post(build("page_view", detail)),
|
|
126
103
|
track: async (eventType, detail) => post(build(eventType, detail)),
|
|
@@ -145,8 +122,24 @@ function useImpressions(config, options = {}) {
|
|
|
145
122
|
useEffect(() => {
|
|
146
123
|
if (options.trackOnMount === false) return;
|
|
147
124
|
if (didTrackMount.current) return;
|
|
148
|
-
|
|
149
|
-
|
|
125
|
+
const sendPageView = () => {
|
|
126
|
+
if (didTrackMount.current) return;
|
|
127
|
+
didTrackMount.current = true;
|
|
128
|
+
void tracker.page();
|
|
129
|
+
};
|
|
130
|
+
if (document.visibilityState === "visible") {
|
|
131
|
+
sendPageView();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const onVisibility = () => {
|
|
135
|
+
if (document.visibilityState !== "visible") return;
|
|
136
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
137
|
+
sendPageView();
|
|
138
|
+
};
|
|
139
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
140
|
+
return () => {
|
|
141
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
142
|
+
};
|
|
150
143
|
}, []);
|
|
151
144
|
return tracker;
|
|
152
145
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tracker.ts","../src/hook.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["export type RestaurantId = string;\n\nexport type ImpressionEvent = {\n schema_version: 1;\n event_id: string;\n ts: string;\n\n restaurant_id: RestaurantId;\n table_no?: number | null;\n\n event_type: string;\n event_detail: Record<string, any>;\n};\n\nexport type TrackerConfig = {\n endpoint: string;\n restaurantId: RestaurantId;\n tableNo?: number;\n headers?: Record<string, string>;\n debug?: boolean;\n disable?: boolean;\n anonIdKey?: string;\n};\n\nfunction uuidv4(): string {\n return crypto.randomUUID();\n}\n\nfunction safeGetLS(key: string): string | null {\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n}\nfunction safeSetLS(key: string, val: string) {\n try {\n localStorage.setItem(key, val);\n } catch {}\n}\n\nfunction getAnonId(key: string) {\n const existing = safeGetLS(key);\n if (existing) return existing;\n const id = uuidv4();\n safeSetLS(key, id);\n return id;\n}\n\nfunction parseUtm() {\n const p = new URLSearchParams(location.search);\n const source = p.get(\"utm_source\");\n const medium = p.get(\"utm_medium\");\n const campaign = p.get(\"utm_campaign\");\n if (!source && !medium && !campaign) return undefined;\n return { source, medium, campaign };\n}\n\nfunction deviceType(): \"mobile\" | \"tablet\" | \"desktop\" {\n const w = Math.min(screen.width, screen.height);\n if (w <= 480) return \"mobile\";\n if (w <= 1024) return \"tablet\";\n return \"desktop\";\n}\n\nfunction baseDetail(anonId: string) {\n return {\n path: location.pathname + location.search,\n referrer: document.referrer || undefined,\n utm: parseUtm(),\n anon_id: anonId,\n language: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n device: { type: deviceType() },\n screen: { w: window.innerWidth, h: window.innerHeight },\n page: { title: document.title },\n };\n}\n\nexport type Tracker = {\n page: (detail?: Record<string, any>) => Promise<void>;\n track: (eventType: string, detail?: Record<string, any>) => Promise<void>;\n setContext: (\n ctx: Partial<{ restaurantId: RestaurantId; tableNo: number }>\n ) => void;\n disable: () => void;\n enable: () => void;\n};\n\nexport function createTracker(cfg: TrackerConfig): Tracker {\n const isBrowser =\n typeof window !== \"undefined\" &&\n typeof document !== \"undefined\" &&\n typeof navigator !== \"undefined\" &&\n typeof location !== \"undefined\";\n\n if (!isBrowser) {\n return {\n page: async () => {},\n track: async () => {},\n setContext: () => {},\n disable: () => {},\n enable: () => {},\n };\n }\n\n const anonKey = cfg.anonIdKey ?? \"sa_anon_id\";\n const anonId = getAnonId(anonKey);\n\n const state = {\n endpoint: cfg.endpoint,\n restaurantId: cfg.restaurantId,\n tableNo: cfg.tableNo,\n headers: cfg.headers ?? {},\n disabled: !!cfg.disable,\n debug: !!cfg.debug,\n };\n\n async function post(ev: ImpressionEvent) {\n if (state.disabled) return;\n\n if (state.debug) console.log(\"[impr] sending\", ev);\n\n await fetch(state.endpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", ...state.headers },\n body: JSON.stringify(ev),\n keepalive: true,\n });\n }\n\n function beacon(ev: ImpressionEvent) {\n try {\n const blob = new Blob([JSON.stringify(ev)], { type: \"application/json\" });\n navigator.sendBeacon?.(state.endpoint, blob);\n } catch {}\n }\n\n function build(\n eventType: string,\n detail?: Record<string, any>\n ): ImpressionEvent {\n return {\n schema_version: 1,\n event_id: uuidv4(),\n ts: new Date().toISOString(),\n restaurant_id: state.restaurantId,\n table_no: state.tableNo ?? null,\n event_type: eventType,\n event_detail: { ...baseDetail(anonId), ...(detail ?? {}) },\n };\n }\n\n // Unload best-effort\n window.addEventListener(\"pagehide\", () => {\n if (state.disabled) return;\n beacon(build(\"page_view\"));\n });\n\n // SPA navigation tracking (framework-agnostic)\n const origPush = history.pushState;\n history.pushState = function (...args: any) {\n origPush.apply(history, args as any);\n void post(build(\"page_view\"));\n } as any;\n\n const origReplace = history.replaceState;\n history.replaceState = function (...args: any) {\n origReplace.apply(history, args as any);\n void post(build(\"page_view\"));\n } as any;\n\n window.addEventListener(\"popstate\", () => void post(build(\"page_view\")));\n\n return {\n page: async (detail) => post(build(\"page_view\", detail)),\n track: async (eventType, detail) => post(build(eventType, detail)),\n setContext: (ctx) => {\n if (ctx.restaurantId !== undefined) state.restaurantId = ctx.restaurantId;\n if (ctx.tableNo !== undefined) state.tableNo = ctx.tableNo;\n },\n disable: () => {\n state.disabled = true;\n },\n enable: () => {\n state.disabled = false;\n },\n };\n}\n","import { useEffect, useMemo, useRef } from \"react\";\nimport { createTracker } from \"./tracker\";\nimport type { TrackerConfig } from \"./tracker\";\n\nexport type UseImpressionsOptions = {\n trackOnMount?: boolean;\n};\n\nexport function useImpressions(\n config: TrackerConfig,\n options: UseImpressionsOptions = {}\n) {\n const tracker = useMemo(\n () => createTracker(config),\n [config.endpoint, config.restaurantId, config.tableNo]\n );\n const didTrackMount = useRef(false);\n\n useEffect(() => {\n if (options.trackOnMount === false) return;\n if (didTrackMount.current) return;\n didTrackMount.current = true;\n void tracker.page();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return tracker;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/tracker.ts","../src/hook.ts"],"names":[],"mappings":";;;AAwBA,SAAS,MAAA,GAAiB;AACxB,EAAA,OAAO,OAAO,UAAA,EAAW;AAC3B;AAEA,SAAS,UAAU,GAAA,EAA4B;AAC7C,EAAA,IAAI;AACF,IAAA,OAAO,YAAA,CAAa,QAAQ,GAAG,CAAA;AAAA,EACjC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AACA,SAAS,SAAA,CAAU,KAAa,GAAA,EAAa;AAC3C,EAAA,IAAI;AACF,IAAA,YAAA,CAAa,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,EAC/B,CAAA,CAAA,MAAQ;AAAA,EAAC;AACX;AAEA,SAAS,UAAU,GAAA,EAAa;AAC9B,EAAA,MAAM,QAAA,GAAW,UAAU,GAAG,CAAA;AAC9B,EAAA,IAAI,UAAU,OAAO,QAAA;AACrB,EAAA,MAAM,KAAK,MAAA,EAAO;AAClB,EAAA,SAAA,CAAU,KAAK,EAAE,CAAA;AACjB,EAAA,OAAO,EAAA;AACT;AAEA,SAAS,QAAA,GAAW;AAClB,EAAA,MAAM,CAAA,GAAI,IAAI,eAAA,CAAgB,QAAA,CAAS,MAAM,CAAA;AAC7C,EAAA,MAAM,MAAA,GAAS,CAAA,CAAE,GAAA,CAAI,YAAY,CAAA;AACjC,EAAA,MAAM,MAAA,GAAS,CAAA,CAAE,GAAA,CAAI,YAAY,CAAA;AACjC,EAAA,MAAM,QAAA,GAAW,CAAA,CAAE,GAAA,CAAI,cAAc,CAAA;AACrC,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,MAAA,IAAU,CAAC,UAAU,OAAO,MAAA;AAC5C,EAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAS;AACpC;AAEA,SAAS,UAAA,GAA8C;AACrD,EAAA,MAAM,IAAI,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,KAAA,EAAO,OAAO,MAAM,CAAA;AAC9C,EAAA,IAAI,CAAA,IAAK,KAAK,OAAO,QAAA;AACrB,EAAA,IAAI,CAAA,IAAK,MAAM,OAAO,QAAA;AACtB,EAAA,OAAO,SAAA;AACT;AAEA,SAAS,WAAW,MAAA,EAAgB;AAClC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA,CAAS,QAAA,GAAW,QAAA,CAAS,MAAA;AAAA,IACnC,QAAA,EAAU,SAAS,QAAA,IAAY,MAAA;AAAA,IAC/B,KAAK,QAAA,EAAS;AAAA,IACd,OAAA,EAAS,MAAA;AAAA,IACT,UAAU,SAAA,CAAU,QAAA;AAAA,IACpB,QAAA,EAAU,IAAA,CAAK,cAAA,EAAe,CAAE,iBAAgB,CAAE,QAAA;AAAA,IAClD,MAAA,EAAQ,EAAE,IAAA,EAAM,UAAA,EAAW,EAAE;AAAA,IAC7B,QAAQ,EAAE,CAAA,EAAG,OAAO,UAAA,EAAY,CAAA,EAAG,OAAO,WAAA,EAAY;AAAA,IACtD,IAAA,EAAM,EAAE,KAAA,EAAO,QAAA,CAAS,KAAA;AAAM,GAChC;AACF;AAYO,SAAS,cAAc,GAAA,EAA6B;AACzD,EAAA,MAAM,SAAA,GACJ,OAAO,MAAA,KAAW,WAAA,IAClB,OAAO,QAAA,KAAa,WAAA,IACpB,OAAO,SAAA,KAAc,WAAA,IACrB,OAAO,QAAA,KAAa,WAAA;AAEtB,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,OAAO;AAAA,MACL,MAAM,YAAY;AAAA,MAAC,CAAA;AAAA,MACnB,OAAO,YAAY;AAAA,MAAC,CAAA;AAAA,MACpB,YAAY,MAAM;AAAA,MAAC,CAAA;AAAA,MACnB,SAAS,MAAM;AAAA,MAAC,CAAA;AAAA,MAChB,QAAQ,MAAM;AAAA,MAAC;AAAA,KACjB;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU,IAAI,SAAA,IAAa,YAAA;AACjC,EAAA,MAAM,MAAA,GAAS,UAAU,OAAO,CAAA;AAEhC,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,UAAU,GAAA,CAAI,QAAA;AAAA,IACd,cAAc,GAAA,CAAI,YAAA;AAAA,IAClB,SAAS,GAAA,CAAI,OAAA;AAAA,IACb,OAAA,EAAS,GAAA,CAAI,OAAA,IAAW,EAAC;AAAA,IACzB,QAAA,EAAU,CAAC,CAAC,GAAA,CAAI,OAAA;AAAA,IAChB,KAAA,EAAO,CAAC,CAAC,GAAA,CAAI;AAAA,GACf;AAEA,EAAA,eAAe,KAAK,EAAA,EAAqB;AACvC,IAAA,IAAI,MAAM,QAAA,EAAU;AAEpB,IAAA,IAAI,KAAA,CAAM,KAAA,EAAO,OAAA,CAAQ,GAAA,CAAI,kBAAkB,EAAE,CAAA;AAEjD,IAAA,MAAM,KAAA,CAAM,MAAM,QAAA,EAAU;AAAA,MAC1B,MAAA,EAAQ,MAAA;AAAA,MACR,SAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,GAAG,MAAM,OAAA,EAAQ;AAAA,MAChE,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,CAAA;AAAA,MACvB,SAAA,EAAW;AAAA,KACZ,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,KAAA,CACP,WACA,MAAA,EACiB;AACjB,IAAA,OAAO;AAAA,MACL,cAAA,EAAgB,CAAA;AAAA,MAChB,UAAU,MAAA,EAAO;AAAA,MACjB,EAAA,EAAA,iBAAI,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAC3B,eAAe,KAAA,CAAM,YAAA;AAAA,MACrB,QAAA,EAAU,MAAM,OAAA,IAAW,IAAA;AAAA,MAC3B,UAAA,EAAY,SAAA;AAAA,MACZ,YAAA,EAAc,EAAE,GAAG,UAAA,CAAW,MAAM,CAAA,EAAG,GAAI,MAAA,IAAU,EAAC;AAAG,KAC3D;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,OAAO,MAAA,KAAW,KAAK,KAAA,CAAM,WAAA,EAAa,MAAM,CAAC,CAAA;AAAA,IACvD,KAAA,EAAO,OAAO,SAAA,EAAW,MAAA,KAAW,KAAK,KAAA,CAAM,SAAA,EAAW,MAAM,CAAC,CAAA;AAAA,IACjE,UAAA,EAAY,CAAC,GAAA,KAAQ;AACnB,MAAA,IAAI,GAAA,CAAI,YAAA,KAAiB,MAAA,EAAW,KAAA,CAAM,eAAe,GAAA,CAAI,YAAA;AAC7D,MAAA,IAAI,GAAA,CAAI,OAAA,KAAY,MAAA,EAAW,KAAA,CAAM,UAAU,GAAA,CAAI,OAAA;AAAA,IACrD,CAAA;AAAA,IACA,SAAS,MAAM;AACb,MAAA,KAAA,CAAM,QAAA,GAAW,IAAA;AAAA,IACnB,CAAA;AAAA,IACA,QAAQ,MAAM;AACZ,MAAA,KAAA,CAAM,QAAA,GAAW,KAAA;AAAA,IACnB;AAAA,GACF;AACF;ACxJO,SAAS,cAAA,CACd,MAAA,EACA,OAAA,GAAiC,EAAC,EAClC;AACA,EAAA,MAAM,OAAA,GAAU,OAAA;AAAA,IACd,MAAM,cAAc,MAAM,CAAA;AAAA,IAC1B,CAAC,MAAA,CAAO,QAAA,EAAU,MAAA,CAAO,YAAA,EAAc,OAAO,OAAO;AAAA,GACvD;AACA,EAAA,MAAM,aAAA,GAAgB,OAAO,KAAK,CAAA;AAElC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAA,CAAQ,iBAAiB,KAAA,EAAO;AACpC,IAAA,IAAI,cAAc,OAAA,EAAS;AAE3B,IAAA,MAAM,eAAe,MAAM;AACzB,MAAA,IAAI,cAAc,OAAA,EAAS;AAC3B,MAAA,aAAA,CAAc,OAAA,GAAU,IAAA;AACxB,MAAA,KAAK,QAAQ,IAAA,EAAK;AAAA,IACpB,CAAA;AAEA,IAAA,IAAI,QAAA,CAAS,oBAAoB,SAAA,EAAW;AAC1C,MAAA,YAAA,EAAa;AACb,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,eAAe,MAAM;AACzB,MAAA,IAAI,QAAA,CAAS,oBAAoB,SAAA,EAAW;AAC5C,MAAA,QAAA,CAAS,mBAAA,CAAoB,oBAAoB,YAAY,CAAA;AAC7D,MAAA,YAAA,EAAa;AAAA,IACf,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA,CAAiB,oBAAoB,YAAY,CAAA;AAC1D,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,oBAAoB,YAAY,CAAA;AAAA,IAC/D,CAAA;AAAA,EAEF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,OAAA;AACT","file":"index.mjs","sourcesContent":["export type RestaurantId = string;\n\nexport type ImpressionEvent = {\n schema_version: 1;\n event_id: string;\n ts: string;\n\n restaurant_id: RestaurantId;\n table_no?: number | null;\n\n event_type: string;\n event_detail: Record<string, any>;\n};\n\nexport type TrackerConfig = {\n endpoint: string;\n restaurantId: RestaurantId;\n tableNo?: number;\n headers?: Record<string, string>;\n debug?: boolean;\n disable?: boolean;\n anonIdKey?: string;\n};\n\nfunction uuidv4(): string {\n return crypto.randomUUID();\n}\n\nfunction safeGetLS(key: string): string | null {\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n}\nfunction safeSetLS(key: string, val: string) {\n try {\n localStorage.setItem(key, val);\n } catch {}\n}\n\nfunction getAnonId(key: string) {\n const existing = safeGetLS(key);\n if (existing) return existing;\n const id = uuidv4();\n safeSetLS(key, id);\n return id;\n}\n\nfunction parseUtm() {\n const p = new URLSearchParams(location.search);\n const source = p.get(\"utm_source\");\n const medium = p.get(\"utm_medium\");\n const campaign = p.get(\"utm_campaign\");\n if (!source && !medium && !campaign) return undefined;\n return { source, medium, campaign };\n}\n\nfunction deviceType(): \"mobile\" | \"tablet\" | \"desktop\" {\n const w = Math.min(screen.width, screen.height);\n if (w <= 480) return \"mobile\";\n if (w <= 1024) return \"tablet\";\n return \"desktop\";\n}\n\nfunction baseDetail(anonId: string) {\n return {\n path: location.pathname + location.search,\n referrer: document.referrer || undefined,\n utm: parseUtm(),\n anon_id: anonId,\n language: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n device: { type: deviceType() },\n screen: { w: window.innerWidth, h: window.innerHeight },\n page: { title: document.title },\n };\n}\n\nexport type Tracker = {\n page: (detail?: Record<string, any>) => Promise<void>;\n track: (eventType: string, detail?: Record<string, any>) => Promise<void>;\n setContext: (\n ctx: Partial<{ restaurantId: RestaurantId; tableNo: number }>\n ) => void;\n disable: () => void;\n enable: () => void;\n};\n\nexport function createTracker(cfg: TrackerConfig): Tracker {\n const isBrowser =\n typeof window !== \"undefined\" &&\n typeof document !== \"undefined\" &&\n typeof navigator !== \"undefined\" &&\n typeof location !== \"undefined\";\n\n if (!isBrowser) {\n return {\n page: async () => {},\n track: async () => {},\n setContext: () => {},\n disable: () => {},\n enable: () => {},\n };\n }\n\n const anonKey = cfg.anonIdKey ?? \"sa_anon_id\";\n const anonId = getAnonId(anonKey);\n\n const state = {\n endpoint: cfg.endpoint,\n restaurantId: cfg.restaurantId,\n tableNo: cfg.tableNo,\n headers: cfg.headers ?? {},\n disabled: !!cfg.disable,\n debug: !!cfg.debug,\n };\n\n async function post(ev: ImpressionEvent) {\n if (state.disabled) return;\n\n if (state.debug) console.log(\"[impr] sending\", ev);\n\n await fetch(state.endpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", ...state.headers },\n body: JSON.stringify(ev),\n keepalive: true,\n });\n }\n\n function build(\n eventType: string,\n detail?: Record<string, any>\n ): ImpressionEvent {\n return {\n schema_version: 1,\n event_id: uuidv4(),\n ts: new Date().toISOString(),\n restaurant_id: state.restaurantId,\n table_no: state.tableNo ?? null,\n event_type: eventType,\n event_detail: { ...baseDetail(anonId), ...(detail ?? {}) },\n };\n }\n\n return {\n page: async (detail) => post(build(\"page_view\", detail)),\n track: async (eventType, detail) => post(build(eventType, detail)),\n setContext: (ctx) => {\n if (ctx.restaurantId !== undefined) state.restaurantId = ctx.restaurantId;\n if (ctx.tableNo !== undefined) state.tableNo = ctx.tableNo;\n },\n disable: () => {\n state.disabled = true;\n },\n enable: () => {\n state.disabled = false;\n },\n };\n}\n","import { useEffect, useMemo, useRef } from \"react\";\nimport { createTracker } from \"./tracker\";\nimport type { TrackerConfig } from \"./tracker\";\n\nexport type UseImpressionsOptions = {\n trackOnMount?: boolean;\n};\n\nexport function useImpressions(\n config: TrackerConfig,\n options: UseImpressionsOptions = {}\n) {\n const tracker = useMemo(\n () => createTracker(config),\n [config.endpoint, config.restaurantId, config.tableNo]\n );\n const didTrackMount = useRef(false);\n\n useEffect(() => {\n if (options.trackOnMount === false) return;\n if (didTrackMount.current) return;\n\n const sendPageView = () => {\n if (didTrackMount.current) return;\n didTrackMount.current = true;\n void tracker.page();\n };\n\n if (document.visibilityState === \"visible\") {\n sendPageView();\n return;\n }\n\n const onVisibility = () => {\n if (document.visibilityState !== \"visible\") return;\n document.removeEventListener(\"visibilitychange\", onVisibility);\n sendPageView();\n };\n\n document.addEventListener(\"visibilitychange\", onVisibility);\n return () => {\n document.removeEventListener(\"visibilitychange\", onVisibility);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return tracker;\n}\n"]}
|