Analytics: queued events, once-per-order revenue, heatmap on product pages (#17)
build / build (push) Failing after 8s
build / build (push) Failing after 8s
Analytics: queued events, once-per-order revenue, heatmap on product pages (#17)
Co-authored-by: Michael Czechowski <mail@librete.ch>
(cherry picked from commit d5dd109c63)
This commit is contained in:
4 files changed
+145
-14
No files matched your search
+46
-3
@@ -6,8 +6,51 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
export const trackEvent = (event: string, data?: Record<string, unknown>) => {
|
||||
if (import.meta.client && window.umami) {
|
||||
window.umami.track(event, data);
|
||||
type Pending = { event: string; data?: Record<string, unknown>; onSent?: () => void };
|
||||
|
||||
// Events fired during page setup (onMounted) often run before the deferred
|
||||
// Umami script has loaded; they used to be dropped silently. Queue them and
|
||||
// flush once the tracker exists. If it never appears (blocked, offline),
|
||||
// they are discarded after ~10 s without throwing.
|
||||
const queue: Pending[] = [];
|
||||
let timer: ReturnType<typeof setInterval> | null = null;
|
||||
let attempts = 0;
|
||||
const MAX_ATTEMPTS = 40;
|
||||
const INTERVAL_MS = 250;
|
||||
|
||||
function send(item: Pending) {
|
||||
try {
|
||||
window.umami!.track(item.event, item.data);
|
||||
item.onSent?.();
|
||||
} catch {
|
||||
// tracking must never break the shop
|
||||
}
|
||||
}
|
||||
|
||||
function flush() {
|
||||
if (window.umami) {
|
||||
while (queue.length) send(queue.shift()!);
|
||||
}
|
||||
if (window.umami || ++attempts >= MAX_ATTEMPTS) {
|
||||
queue.length = 0;
|
||||
if (timer) clearInterval(timer);
|
||||
timer = null;
|
||||
attempts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
export const trackEvent = (event: string, data?: Record<string, unknown>, onSent?: () => void) => {
|
||||
if (typeof window === "undefined") return;
|
||||
const item = { event, data, onSent };
|
||||
if (window.umami) return send(item);
|
||||
queue.push(item);
|
||||
if (!timer) timer = setInterval(flush, INTERVAL_MS);
|
||||
};
|
||||
|
||||
// Test hook: reset module state between cases.
|
||||
export const __resetTrackQueue = () => {
|
||||
queue.length = 0;
|
||||
if (timer) clearInterval(timer);
|
||||
timer = null;
|
||||
attempts = 0;
|
||||
};
|
||||
Reference in new issue
Block a user