import React from 'react'; import { Button } from '@/components/ui/button'; import { useConsent } from '@/contexts/consent'; import { useTranslation } from '../i18n/useTranslation'; import { isUploadPath, shouldShowAnalyticsNudge } from '../lib/analyticsConsent'; const PROMPT_STORAGE_KEY = 'fotospiel.guest.analyticsPrompt'; const SNOOZE_MS = 60 * 60 * 1000; const ACTIVE_IDLE_LIMIT_MS = 20_000; type PromptStorage = { snoozedUntil?: number | null; }; function readSnoozedUntil(): number | null { if (typeof window === 'undefined') { return null; } try { const raw = window.localStorage.getItem(PROMPT_STORAGE_KEY); if (!raw) { return null; } const parsed = JSON.parse(raw) as PromptStorage; return typeof parsed.snoozedUntil === 'number' ? parsed.snoozedUntil : null; } catch { return null; } } function writeSnoozedUntil(value: number | null) { if (typeof window === 'undefined') { return; } try { const payload: PromptStorage = { snoozedUntil: value }; window.localStorage.setItem(PROMPT_STORAGE_KEY, JSON.stringify(payload)); } catch { // ignore storage failures } } function randomInt(min: number, max: number): number { const low = Math.ceil(min); const high = Math.floor(max); return Math.floor(Math.random() * (high - low + 1)) + low; } export default function GuestAnalyticsNudge({ enabled, pathname, }: { enabled: boolean; pathname: string; }) { const { t } = useTranslation(); const { decisionMade, preferences, savePreferences } = useConsent(); const analyticsConsent = Boolean(preferences?.analytics); const [thresholdSeconds] = React.useState(() => randomInt(60, 120)); const [thresholdRoutes] = React.useState(() => randomInt(2, 3)); const [activeSeconds, setActiveSeconds] = React.useState(0); const [routeCount, setRouteCount] = React.useState(0); const [isOpen, setIsOpen] = React.useState(false); const [snoozedUntil, setSnoozedUntil] = React.useState(() => readSnoozedUntil()); const lastPathRef = React.useRef(pathname); const lastActivityAtRef = React.useRef(Date.now()); const visibleRef = React.useRef(typeof document === 'undefined' ? true : document.visibilityState === 'visible'); const isUpload = isUploadPath(pathname); React.useEffect(() => { const previousPath = lastPathRef.current; const currentPath = pathname; lastPathRef.current = currentPath; if (previousPath === currentPath) { return; } if (isUploadPath(previousPath) || isUploadPath(currentPath)) { return; } setRouteCount((count) => count + 1); }, [pathname]); React.useEffect(() => { if (typeof window === 'undefined') { return undefined; } const handleActivity = () => { lastActivityAtRef.current = Date.now(); }; const events: Array = [ 'pointerdown', 'pointermove', 'keydown', 'scroll', 'touchstart', ]; events.forEach((event) => window.addEventListener(event, handleActivity, { passive: true })); return () => { events.forEach((event) => window.removeEventListener(event, handleActivity)); }; }, []); React.useEffect(() => { if (typeof document === 'undefined') { return undefined; } const handleVisibility = () => { visibleRef.current = document.visibilityState === 'visible'; }; document.addEventListener('visibilitychange', handleVisibility); return () => document.removeEventListener('visibilitychange', handleVisibility); }, []); React.useEffect(() => { if (typeof window === 'undefined') { return undefined; } const interval = window.setInterval(() => { const now = Date.now(); if (!visibleRef.current) { return; } if (isUploadPath(lastPathRef.current)) { return; } if (now - lastActivityAtRef.current > ACTIVE_IDLE_LIMIT_MS) { return; } setActiveSeconds((seconds) => seconds + 1); }, 1000); return () => window.clearInterval(interval); }, []); React.useEffect(() => { if (!enabled || analyticsConsent || decisionMade) { setIsOpen(false); return; } const shouldOpen = shouldShowAnalyticsNudge({ decisionMade, analyticsConsent, snoozedUntil, now: Date.now(), activeSeconds, routeCount, thresholdSeconds, thresholdRoutes, isUpload, }); if (shouldOpen) { setIsOpen(true); } }, [ enabled, analyticsConsent, decisionMade, snoozedUntil, activeSeconds, routeCount, thresholdSeconds, thresholdRoutes, isUpload, ]); React.useEffect(() => { if (isUpload) { setIsOpen(false); } }, [isUpload]); if (!enabled || decisionMade || analyticsConsent || !isOpen || isUpload) { return null; } const handleSnooze = () => { const until = Date.now() + SNOOZE_MS; setSnoozedUntil(until); writeSnoozedUntil(until); setIsOpen(false); }; const handleAllow = () => { savePreferences({ analytics: true }); writeSnoozedUntil(null); setIsOpen(false); }; return (

{t('consent.analytics.title')}

{t('consent.analytics.body')}

); }