'use client' import { useEffect, useRef, useCallback } from 'react' interface AuditTrackerOptions { investorId: string | null currentSlide: string enabled: boolean } export function useAuditTracker({ investorId, currentSlide, enabled }: AuditTrackerOptions) { const lastSlide = useRef('') const slideTimestamps = useRef>(new Map()) const pendingEvents = useRef; slide_id?: string }>>([]) const flushTimer = useRef(null) const flush = useCallback(async () => { if (pendingEvents.current.length === 0) return const events = [...pendingEvents.current] pendingEvents.current = [] // Send events one at a time (they're debounced so there shouldn't be many) for (const event of events) { try { await fetch('/api/audit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(event), }) } catch { // Silently fail - audit should not block UX } } }, []) const track = useCallback((action: string, details: Record = {}, slideId?: string) => { if (!enabled || !investorId) return pendingEvents.current.push({ action, details, slide_id: slideId }) // Debounce flush by 500ms if (flushTimer.current) clearTimeout(flushTimer.current) flushTimer.current = setTimeout(flush, 500) }, [enabled, investorId, flush]) // Track slide views useEffect(() => { if (!enabled || !investorId || !currentSlide) return if (currentSlide === lastSlide.current) return const now = Date.now() const prevTimestamp = slideTimestamps.current.get(lastSlide.current) const dwellTime = prevTimestamp ? now - prevTimestamp : 0 lastSlide.current = currentSlide slideTimestamps.current.set(currentSlide, now) track('slide_viewed', { slide_id: currentSlide, previous_dwell_ms: dwellTime, }, currentSlide) }, [currentSlide, enabled, investorId, track]) // Flush on unmount useEffect(() => { return () => { if (flushTimer.current) clearTimeout(flushTimer.current) flush() } }, [flush]) return { track } }