Le dépôt sortait 7 erreurs eslint au début de cette série de correctifs, dont certaines antérieures. Il n'en reste aucune. - Dashboard et Users appelaient setState de façon synchrone dans un effet, ce qui provoque des rendus en cascade. Le chargement initial passe par une fonction asynchrone qui n'écrit qu'après l'await, avec annulation au démontage. Sur le Dashboard, l'indicateur de chargement est allumé par les gestionnaires d'événement, et le bouton Actualiser relance l'effet via un compteur plutôt qu'en appelant le chargement. - L'import ExternalLink de Documentation.jsx n'était pas utilisé. - AuthContext.jsx exportait à la fois un composant, le contexte et un hook, ce qui désactivait le rafraîchissement à chaud de Vite pour ce fichier. Le contexte et le hook vivent désormais dans leurs propres modules ; les 5 fichiers concernés sont mis à jour.
99 lines
3.0 KiB
React
99 lines
3.0 KiB
React
/* Barre de navigation latérale fixe */
|
|
|
|
import { NavLink } from 'react-router-dom';
|
|
import {
|
|
LayoutGrid,
|
|
Layers,
|
|
Clock,
|
|
Settings,
|
|
Users,
|
|
List,
|
|
Book,
|
|
Shield,
|
|
FileText,
|
|
ScrollText,
|
|
} from 'lucide-react';
|
|
import { useAuth } from '../../context/useAuth';
|
|
import styles from './Sidebar.module.css';
|
|
|
|
/* Un lien de navigation avec icône */
|
|
function NavItem({ to, icon: Icon, label }) {
|
|
return (
|
|
<NavLink
|
|
to={to}
|
|
className={({ isActive }) =>
|
|
`${styles.navItem} ${isActive ? styles.active : ''}`
|
|
}
|
|
aria-current={undefined}
|
|
>
|
|
<Icon size={16} aria-hidden="true" />
|
|
<span>{label}</span>
|
|
</NavLink>
|
|
);
|
|
}
|
|
|
|
export default function Sidebar({ isOpen, onClose }) {
|
|
const { user } = useAuth();
|
|
const isAdmin = user?.role === 'Admin';
|
|
|
|
return (
|
|
<>
|
|
{/* Overlay mobile pour fermer la sidebar */}
|
|
{isOpen && (
|
|
<div
|
|
className={styles.overlay}
|
|
onClick={onClose}
|
|
role="presentation"
|
|
aria-hidden="true"
|
|
/>
|
|
)}
|
|
|
|
<aside
|
|
id="sidebar"
|
|
className={`${styles.sidebar} ${isOpen ? styles.open : ''}`}
|
|
aria-label="Navigation principale"
|
|
>
|
|
<nav className={styles.nav} aria-label="Menu de navigation">
|
|
{/* Navigation principale */}
|
|
<div className={styles.section} role="group" aria-label="Monitoring">
|
|
<NavItem to="/dashboard" icon={LayoutGrid} label="Dashboard" />
|
|
<NavItem to="/consolidee" icon={Layers} label="Vue consolidée" />
|
|
<NavItem to="/contrat" icon={List} label="Contrat" />
|
|
<NavItem to="/fournisseur" icon={Users} label="Fournisseur" />
|
|
<NavItem to="/historique" icon={Clock} label="Historique" />
|
|
</div>
|
|
|
|
{/* Section administration : réservée aux administrateurs */}
|
|
{isAdmin && (
|
|
<>
|
|
<div className={styles.separator} role="separator" />
|
|
<div className={styles.sectionLabel} aria-hidden="true">ADMIN</div>
|
|
<div className={styles.section} role="group" aria-label="Administration">
|
|
<NavItem to="/admin" icon={Settings} label="Nomenclature" />
|
|
<NavItem to="/utilisateurs" icon={Users} label="Utilisateurs" />
|
|
<NavItem to="/journal" icon={ScrollText} label="Journal d'audit" />
|
|
</div>
|
|
</>
|
|
)}
|
|
</nav>
|
|
|
|
{/* Liens de pied de sidebar */}
|
|
<nav className={styles.footer} aria-label="Liens utiles">
|
|
<NavLink to="/documentation" className={styles.footerLink}>
|
|
<Book size={13} aria-hidden="true" />
|
|
Documentation
|
|
</NavLink>
|
|
<NavLink to="/mentions-legales" className={styles.footerLink}>
|
|
<Shield size={13} aria-hidden="true" />
|
|
Mentions légales
|
|
</NavLink>
|
|
<NavLink to="/cgu" className={styles.footerLink}>
|
|
<FileText size={13} aria-hidden="true" />
|
|
CGU
|
|
</NavLink>
|
|
</nav>
|
|
</aside>
|
|
</>
|
|
);
|
|
}
|