// ============================================================ // Product analytics + error capture (Phase 2) // // - OpenPanel (@openpanel/web): funnels/usage — initialized only when // VITE_OPENPANEL_URL and VITE_OPENPANEL_CLIENT_ID are set (build args), // so local dev and air-gapped environments stay silent. // - GlitchTip (@sentry/react): frontend exception capture, only when // VITE_SENTRY_DSN is set. // // Both are no-ops without configuration; every helper is safe to call // unconditionally from anywhere in the app. // ============================================================ import * as Sentry from "@sentry/react"; type Props = Record; declare global { interface Window { op?: (...args: unknown[]) => void; } } const OPENPANEL_URL = (import.meta.env?.VITE_OPENPANEL_URL as string | undefined)?.trim(); const OPENPANEL_CLIENT_ID = (import.meta.env?.VITE_OPENPANEL_CLIENT_ID as string | undefined)?.trim(); const SENTRY_DSN = (import.meta.env?.VITE_SENTRY_DSN as string | undefined)?.trim(); export function initAnalytics(): void { if (SENTRY_DSN) { Sentry.init({ dsn: SENTRY_DSN, environment: (import.meta.env?.MODE as string | undefined) ?? "production", // Frontend traces are expensive and rarely needed — errors only. tracesSampleRate: 0, }); } if (OPENPANEL_URL && OPENPANEL_CLIENT_ID) { try { window.op?.("init", { apiUrl: OPENPANEL_URL, clientId: OPENPANEL_CLIENT_ID, trackScreenViews: true, // pageview → which pages users visit }); } catch { /* analytics must never break the app */ } } } /** Attach the ERP user identity to analytics (after login / app load). */ export function identifyUser(profile: { id?: string; name?: string; role?: string | null; }): void { if (!profile.id) return; try { window.op?.("identify", { profileId: profile.id, firstName: profile.name || undefined, data: { role: profile.role ?? undefined }, }); track("user_identified", { role: profile.role ?? undefined }); } catch { /* ignore */ } } export function track(event: string, properties?: Props): void { try { window.op?.("track", event, properties ?? {}); } catch { /* ignore */ } } export function captureError(err: unknown): void { if (SENTRY_DSN) Sentry.captureException(err); } export const analyticsEnabled = Boolean(OPENPANEL_URL && OPENPANEL_CLIENT_ID);