import { Direction, EventMapKeys } from '../types'; import Api from './api'; import type { AnalyticsPayload } from '../types/api'; import { Helpers } from './helpers'; import { AnalyticsConsent } from './analyticsConsent'; import { Identity } from './identity'; export interface AnalyticsEventData { event_widget_id: string; event_post_id?: string; event_product_id?: string; event_direction?: Direction; event_position?: number; } export class Analytics { private static eventQueue: AnalyticsPayload[] = []; private static batchTimer: ReturnType | null = null; private static readonly BATCH_INTERVAL_MS = 5000; private static readonly IMMEDIATE_FLUSH_EVENTS: Set = new Set([ 'packshotClicked', 'productClicked', ]); public static async trackEvent(params: { eventName: K; data: AnalyticsEventData; }): Promise { const { eventName, data } = params; const hasConsent = AnalyticsConsent.has(); const identity = hasConsent ? Identity.getIdentity() : null; if (hasConsent && identity) { Identity.touchSession(); } const payload: AnalyticsPayload = { eventName: eventName as string, widgetId: data.event_widget_id, postId: data.event_post_id, productId: data.event_product_id, direction: data.event_direction, position: data.event_position, timestamp: new Date().toISOString(), userAgent: navigator.userAgent, referrer: document.referrer || undefined, pageLocation: window.location?.href || undefined, pageTitle: document.title || undefined, deviceCategory: Helpers.isMobileDevice() ? 'mobile' : 'desktop', consent: hasConsent, identity: hasConsent && identity ? { visitor_id: identity.visitorId, session_id: identity.sessionId, } : undefined, }; this.eventQueue.push(payload); if (this.IMMEDIATE_FLUSH_EVENTS.has(eventName)) { await this.flushImmediately(); return; } if (!this.batchTimer) { this.batchTimer = setTimeout(() => { this.sendBatch(); }, this.BATCH_INTERVAL_MS); } } private static clearBatchTimer(): void { if (this.batchTimer) { clearTimeout(this.batchTimer); this.batchTimer = null; } } private static async flushImmediately(): Promise { this.clearBatchTimer(); await this.sendBatch(); } private static async sendBatch(): Promise { if (this.eventQueue.length === 0) return; const events = [...this.eventQueue]; this.eventQueue = []; this.batchTimer = null; try { await Api.trackAnalyticsBatch(events); } catch (error) { console.warn('Failed to send analytics batch:', error); } } }