import React, { createContext, useCallback, useContext, useEffect, useMemo, useState, } from 'react'; const CONSENT_STORAGE_KEY = 'fotospiel.consent'; const CONSENT_VERSION = '2025-10-17-1'; export type ConsentCategory = 'functional' | 'analytics'; export type ConsentPreferences = Record; interface StoredConsent { version: string; preferences: ConsentPreferences; decisionMade: boolean; updatedAt: string | null; } const defaultPreferences: ConsentPreferences = { functional: true, analytics: false, }; const defaultState: StoredConsent = { version: CONSENT_VERSION, preferences: { ...defaultPreferences }, decisionMade: false, updatedAt: null, }; interface ConsentContextValue { preferences: ConsentPreferences; decisionMade: boolean; showBanner: boolean; acceptAll: () => void; rejectAll: () => void; savePreferences: (preferences: Partial) => void; hasConsent: (category: ConsentCategory) => boolean; openPreferences: () => void; closePreferences: () => void; isPreferencesOpen: boolean; } const ConsentContext = createContext(undefined); function normalizeState(state: StoredConsent | null): StoredConsent { if (!state || state.version !== CONSENT_VERSION) { return { ...defaultState }; } return { version: CONSENT_VERSION, decisionMade: state.decisionMade ?? false, updatedAt: state.updatedAt ?? null, preferences: { ...defaultPreferences, ...state.preferences, functional: true, }, }; } function getInitialState(): StoredConsent { if (typeof window === 'undefined') { return { ...defaultState }; } try { const raw = window.localStorage.getItem(CONSENT_STORAGE_KEY); if (!raw) { return { ...defaultState }; } const parsed = JSON.parse(raw) as StoredConsent; return normalizeState(parsed); } catch { return { ...defaultState }; } } export const ConsentProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [state, setState] = useState(() => getInitialState()); const [isPreferencesOpen, setPreferencesOpen] = useState(false); useEffect(() => { if (typeof window === 'undefined') { return; } window.localStorage.setItem(CONSENT_STORAGE_KEY, JSON.stringify(state)); }, [state]); const acceptAll = useCallback(() => { setState({ version: CONSENT_VERSION, preferences: { functional: true, analytics: true }, decisionMade: true, updatedAt: new Date().toISOString(), }); setPreferencesOpen(false); }, []); const rejectAll = useCallback(() => { setState({ version: CONSENT_VERSION, preferences: { functional: true, analytics: false }, decisionMade: true, updatedAt: new Date().toISOString(), }); setPreferencesOpen(false); }, []); const savePreferences = useCallback((preferences: Partial) => { setState((prev) => ({ version: CONSENT_VERSION, preferences: { ...defaultPreferences, ...prev.preferences, ...preferences, functional: true, }, decisionMade: true, updatedAt: new Date().toISOString(), })); setPreferencesOpen(false); }, []); const hasConsent = useCallback( (category: ConsentCategory) => { return Boolean(state.preferences?.[category]); }, [state.preferences], ); const openPreferences = useCallback(() => { setPreferencesOpen(true); }, []); const closePreferences = useCallback(() => { setPreferencesOpen(false); }, []); const value = useMemo( () => ({ preferences: state.preferences, decisionMade: state.decisionMade, showBanner: !state.decisionMade, acceptAll, rejectAll, savePreferences, hasConsent, openPreferences, closePreferences, isPreferencesOpen, }), [ state.preferences, state.decisionMade, acceptAll, rejectAll, savePreferences, hasConsent, openPreferences, closePreferences, isPreferencesOpen, ], ); return {children}; }; export const useConsent = (): ConsentContextValue => { const context = useContext(ConsentContext); if (!context) { throw new Error('useConsent must be used within a ConsentProvider'); } return context; };