Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | import { Outlet, useLocation } from 'react-router-dom'
import { useState, useEffect, useRef } from 'react'
import Navigation from './Navigation'
import AppHeader from './AppHeader'
import { useAuth } from '../contexts/AuthContext'
import { useOrganizationInitialization } from '../hooks/useOrganizationInitialization'
import { useOrganizationStore } from '../store/organizationStore'
import { frontofficeNavigation } from '../config/frontofficeNavigation'
const DESKTOP_QUERY = '(min-width: 1024px)'
function Layout() {
// Sidebar ouverte par défaut sur desktop, fermée sur mobile (drawer).
const [menuOpen, setMenuOpen] = useState(
() => typeof window !== 'undefined' && window.matchMedia(DESKTOP_QUERY).matches,
)
const isDesktopRef = useRef(typeof window !== 'undefined' && window.matchMedia(DESKTOP_QUERY).matches)
const location = useLocation()
const { isAuthenticated } = useAuth()
const { currentOrganization } = useOrganizationStore()
useOrganizationInitialization()
useEffect(() => {
const mql = window.matchMedia(DESKTOP_QUERY)
const onChange = (e) => { isDesktopRef.current = e.matches }
mql.addEventListener('change', onChange)
return () => mql.removeEventListener('change', onChange)
}, [])
useEffect(() => {
window.scrollTo(0, 0)
if (!isDesktopRef.current) setMenuOpen(false) // ferme le drawer mobile à la navigation
}, [location.pathname])
const orgId = currentOrganization?.id
const hasOrg = !!orgId
const closeOnMobile = () => { if (!isDesktopRef.current) setMenuOpen(false) }
const nav = (
<Navigation
sections={frontofficeNavigation}
theme="light"
collapsed={false}
isAuthenticated={isAuthenticated}
className="p-2 overflow-y-auto flex-1"
basePath={hasOrg ? `/${orgId}` : '/'}
onItemClick={closeOnMobile}
/>
)
return (
<div className="min-h-screen bg-gray-50">
{/* Backdrop — mobile uniquement */}
{menuOpen && (
<div className="fixed inset-0 z-[35] bg-gray-900/50 lg:hidden" onClick={() => setMenuOpen(false)} />
)}
{/* Sidebar : persistante (ouvrable/fermable) sur desktop, drawer sur mobile */}
<aside
className={`fixed top-16 bottom-0 left-0 z-[36] w-72 bg-white border-r border-gray-200 overflow-y-auto flex flex-col transition-transform duration-200 ${
menuOpen ? 'translate-x-0' : '-translate-x-full'
}`}
>
{nav}
</aside>
<div className="min-h-screen flex flex-col">
<AppHeader mode="frontoffice" onOpenSidebar={() => setMenuOpen((v) => !v)} />
{/* Page content — décalé de la sidebar sur desktop quand elle est ouverte */}
<main className={`flex-1 transition-all duration-200 ${menuOpen ? 'lg:pl-72' : 'lg:pl-0'}`}>
<Outlet context={{ navOpen: menuOpen }} />
</main>
</div>
</div>
)
}
export default Layout
|