Louis Mazin 7875f21b4d nice
2026-09-21 14:18:14 +02:00

313 lines
7.4 KiB
JavaScript

import React, { useEffect, useRef } from 'react';
import { Link, NavLink } from 'react-router-dom';
import { useAuth } from '../context/useAuth';
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
useSidebar,
} from '@/components/ui/sidebar';
import {
User,
Clock,
CalendarDays,
Users,
LogOut,
Wheat,
} from 'lucide-react';
const NavBar = () => {
const { user, logout } = useAuth();
const { isMobile, toggleSidebar, setOpen } = useSidebar();
const closeTimeout = useRef(null);
useEffect(() => {
return () => {
if (closeTimeout.current) {
clearTimeout(closeTimeout.current);
}
};
}, []);
if (!user) {
return null;
}
const handleMouseEnter = () => {
if (isMobile) return;
if (closeTimeout.current) {
clearTimeout(closeTimeout.current);
closeTimeout.current = null;
}
setOpen(true);
};
const handleMouseLeave = () => {
if (isMobile) return;
closeTimeout.current = setTimeout(() => {
setOpen(false);
}, 150);
};
const handleCloseMenu = () => {
if (isMobile) {
toggleSidebar();
}
};
const navigation = [
{
title: 'Profil',
href: '/profile',
icon: User,
},
{
title: 'Résumé hebdomadaire',
href: '/weekly-summary',
icon: Clock,
},
{
title: 'Pointage',
href: '/pointage',
icon: CalendarDays,
},
];
/*
* Hauteur d'une ligne de navigation.
*
* Le SidebarMenuButton natif fait 32px.
* On lui donne une ligne de 48px et on le centre.
*
* Le header de groupe fait lui aussi 32px.
* En mode plié, il est remplacé visuellement par
* une séparation, mais conserve exactement ses 32px.
*/
const menuItemClass = 'h-12 min-h-12 flex items-center';
const buttonClass = `
w-full
h-8
min-h-8
group-data-[collapsible=icon]:size-8!
group-data-[collapsible=icon]:p-2!
`;
const linkClass = `
flex
h-full
w-full
items-center
gap-2
text-base
`;
/*
* Header de groupe :
*
* Déplié :
* [ Navigation ] 32px
*
* Plié :
* [ ---------------------- ] 32px
*
* Même hauteur dans les deux cas.
*/
const GroupHeader = ({ children }) => (
<div
className="
flex
h-8
min-h-8
w-full
items-center
px-2
"
>
{/* Nom du groupe */}
<span
className="
truncate
text-lg
font-medium
group-data-[collapsible=icon]:hidden
"
>
{children}
</span>
{/* Séparation en mode plié */}
<div
className="
hidden
w-full
border-t
border-sidebar-border
group-data-[collapsible=icon]:block
"
/>
</div>
);
return (
<Sidebar
className="border-0"
collapsible="icon"
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{/* Logo / nom de la boulangerie */}
<SidebarHeader className="h-16 p-2 pl-0">
<SidebarMenu>
<SidebarMenuItem className="h-12 flex items-center">
<SidebarMenuButton
size="lg"
className="
h-12
w-full
group-data-[collapsible=icon]:h-8!
group-data-[collapsible=icon]:w-10!
group-data-[collapsible=icon]:p-2!
"
render={
<Link
to="/"
className="flex w-full items-center gap-2"
>
<div className="flex aspect-square size-8 shrink-0 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
<Wheat className="size-4" />
</div>
<div className="grid min-w-0 flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">
Le Fournil du Bocage
</span>
<span className="truncate text-xs">
Gestion
</span>
</div>
</Link>
}
/>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
<SidebarContent>
{/* Navigation */}
<SidebarGroup className="p-2">
<GroupHeader>
Navigation
</GroupHeader>
<SidebarGroupContent>
<SidebarMenu>
{navigation.map((item) => {
const Icon = item.icon;
return (
<SidebarMenuItem
key={item.href}
className={menuItemClass}
>
<SidebarMenuButton
tooltip={item.title}
onClick={handleCloseMenu}
className={buttonClass}
render={
<NavLink
to={item.href}
className={linkClass}
>
<Icon className="size-6 shrink-0" />
<span className="truncate text-base">
{item.title}
</span>
</NavLink>
}
/>
</SidebarMenuItem>
);
})}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
{/* Administration */}
{user.is_admin && (
<SidebarGroup className="p-2">
<GroupHeader>
Administration
</GroupHeader>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem className={menuItemClass}>
<SidebarMenuButton
tooltip="Comptes existants"
onClick={handleCloseMenu}
className={buttonClass}
render={
<NavLink
to="/users"
className={linkClass}
>
<Users className="size-6 shrink-0" />
<span className="truncate text-base">
Comptes existants
</span>
</NavLink>
}
/>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
)}
</SidebarContent>
{/* Déconnexion */}
<SidebarFooter>
<SidebarMenu>
<SidebarMenuItem className={menuItemClass}>
<SidebarMenuButton
tooltip="Déconnexion"
onClick={handleCloseMenu}
className={buttonClass}
render={
<button
type="button"
onClick={logout}
className={linkClass}
>
<LogOut className="size-6 shrink-0" />
<span className="truncate text-base">
Déconnexion
</span>
</button>
}
/>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
</Sidebar>
);
};
export default NavBar;