diff --git a/src/observability/analytics/loader.tsx b/src/observability/analytics/loader.tsx new file mode 100644 index 00000000..a48fe8c4 --- /dev/null +++ b/src/observability/analytics/loader.tsx @@ -0,0 +1,52 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; +import type { ReactNode } from "react"; +import type { Analytics, AnalyticsProviders } from "./types.js"; +import type { Logger } from "@/observability/logger/types"; +import { createAnalytics } from "./facade.js"; +import { AnalyticsContext } from "./provider.js"; + +export interface AnalyticsLoaderProps { + enabled: AnalyticsProviders; + consent: { analytics: boolean; telemetry: boolean }; + logger: Logger; + children: ReactNode; +} + +/** + * Mounts in the root layout. Waits for idle callback, then initializes + * analytics adapters and provides the Analytics instance to the tree. + */ +export function AnalyticsLoader({ + enabled, + consent, + logger, + children, +}: AnalyticsLoaderProps): JSX.Element { + const [analytics, setAnalytics] = useState(null); + const initRef = useRef(false); + + useEffect(() => { + if (initRef.current) return; + initRef.current = true; + + const init = () => { + const instance = createAnalytics({ enabled, consent, logger }); + setAnalytics(instance); + }; + + if (typeof window !== "undefined" && "requestIdleCallback" in window) { + (window as unknown as { requestIdleCallback: (cb: () => void) => void }).requestIdleCallback(init); + } else { + // Fallback for environments without requestIdleCallback + setTimeout(init, 1); + } + }, [enabled, consent, logger]); + + return ( + + {children} + + ); +}