/** * Layout applicatif — enveloppe toutes les routes privées. * * Desktop (≥ 1024px) : Sidebar fixe 230px + Topbar sticky + zone contenu. * Mobile (< 1024px) : Topbar avec hamburger + drawer slide-in + BottomNav fixe. * * Le drawer mobile se ferme automatiquement à chaque changement de route * (useEffect sur location.pathname). * * Règle L : tokens du design system exclusivement. * Règle H : aucune logique métier — plan lu depuis le cache TanStack Query. */ import { useState, useEffect } from 'react' import { useLocation } from 'react-router-dom' import { Sidebar } from './Sidebar' import { Topbar } from './Topbar' import { BottomNav } from './BottomNav' import { usePlan } from '@/features/dashboard/hooks/usePlan' import { cn } from '@/shared/lib/utils' import type { Plan } from '@/entities/user/lib' interface AppLayoutProps { children: React.ReactNode } export function AppLayout({ children }: AppLayoutProps) { const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false) const location = useLocation() const { data } = usePlan() const plan: Plan = data?.plan ?? 'free' // Ferme le drawer à chaque changement de route. useEffect(() => { // eslint-disable-next-line react-hooks/set-state-in-effect setIsMobileMenuOpen(false) }, [location.pathname]) const mainBackground = ` radial-gradient(ellipse at 35% 0%, var(--color-gradient-a), transparent 55%), radial-gradient(ellipse at 80% 100%, var(--color-gradient-b), transparent 50%), var(--color-canvas) ` return (