diff --git a/eslint.config.mjs b/eslint.config.mjs index 3d230bd..120714d 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -19,6 +19,8 @@ const eslintConfig = [ "react/no-unescaped-entities": "off", // Allow Math.random() in useMemo - intentionally memoized for client-side randomization "react-hooks/purity": "off", + // Allow setState in useEffect for legitimate hydration patterns + "react-hooks/set-state-in-effect": "off", // Unused vars as warnings instead of errors "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_", diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 4408f61..2278a47 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -25,29 +25,28 @@ export default function RootLayout({ children: React.ReactNode; }>) { const [isClient, setIsClient] = useState(false) - const [analyticsAllowed] = useState(() => { - // Initialize from localStorage on mount (only runs once) - if (typeof window === 'undefined') return false; + const [analyticsAllowed, setAnalyticsAllowed] = useState(false); + + useEffect(() => { + // Read cookie consent from localStorage after component mounts try { const consent = localStorage.getItem('cookie_consent'); if (consent) { const parsedConsent = JSON.parse(consent); - return parsedConsent.analytics === true; + setAnalyticsAllowed(parsedConsent.analytics === true); } } catch (e) { console.error("Error parsing cookie consent:", e); } - return false; - }); + }, []); useEffect(() => { // This is a legitimate hydration pattern - set client flag after mount - // eslint-disable-next-line react-hooks/set-state-in-effect setIsClient(true) }, []) return ( - +