diff --git a/src/components/CartBadge.tsx b/src/components/CartBadge.tsx index e904b8d..ab18f84 100644 --- a/src/components/CartBadge.tsx +++ b/src/components/CartBadge.tsx @@ -10,7 +10,7 @@ export function CartBadge() { return ( 🛒 diff --git a/src/components/MobileMenuButton.tsx b/src/components/MobileMenuButton.tsx new file mode 100644 index 0000000..58e00eb --- /dev/null +++ b/src/components/MobileMenuButton.tsx @@ -0,0 +1,224 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; +import { signOut } from "next-auth/react"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +type LinkItem = { href: string; label: string }; + +type Props = { + isAuthenticated: boolean; + isOwner: boolean; + isRentalProvider: boolean; + isCeManager: boolean; + isAdmin: boolean; + rentalEnabled: boolean; + ceEnabled: boolean; +}; + +/** + * Bouton hamburger visible uniquement sur mobile (sm:hidden). + * Ouvre un drawer qui rassemble tous les liens de navigation, car en + * mobile les liens du SiteHeader sont masqués pour rester sur 1 ligne. + */ +export function MobileMenuButton({ + isAuthenticated, + isOwner, + isRentalProvider, + isCeManager, + isAdmin, + rentalEnabled, + ceEnabled, +}: Props) { + const [open, setOpen] = useState(false); + const pathname = usePathname(); + // Ferme le menu si on change de page — pathname comparé à la valeur précédente + // dans un effect avec setState, façon "useRef + condition" pour éviter le + // warning react-hooks/set-state-in-effect (setState dans un effect sans + // dépendance externe = anti-pattern). + const lastPathnameRef = useRef(pathname); + useEffect(() => { + if (lastPathnameRef.current !== pathname) { + lastPathnameRef.current = pathname; + // closure ref → reflète bien la dernière valeur ; setOpen est stable + // (renvoyé par useState) donc OK dans deps. + setOpen(false); + } + }, [pathname]); + + // Empêche le scroll sous-jacent quand ouvert + useEffect(() => { + if (!open) return; + const prev = document.body.style.overflow; + document.body.style.overflow = "hidden"; + return () => { + document.body.style.overflow = prev; + }; + }, [open]); + + const publicLinks: LinkItem[] = [ + { href: "/decouvrir", label: "Au fil de l'eau" }, + { href: "/carbets", label: "Catalogue" }, + ...(rentalEnabled ? [{ href: "/materiel", label: "Matériel" }] : []), + ]; + + const userLinks: LinkItem[] = isAuthenticated + ? [ + { href: "/mes-favoris", label: "Favoris" }, + { href: "/mes-reservations", label: "Mes réservations" }, + ...(rentalEnabled ? [{ href: "/mes-locations", label: "Mes locations" }] : []), + { href: "/mon-compte", label: "Mon compte" }, + ] + : []; + + const proLinks: LinkItem[] = isAuthenticated + ? [ + ...(isOwner ? [{ href: "/espace-hote", label: "Espace hôte" }] : []), + ...(isRentalProvider && rentalEnabled + ? [{ href: "/espace-prestataire", label: "Espace prestataire" }] + : []), + ...(isCeManager && ceEnabled ? [{ href: "/espace-ce", label: "Espace CE" }] : []), + ...(isAdmin ? [{ href: "/admin", label: "Admin" }] : []), + ] + : []; + + return ( + <> + + + {open ? ( +
+ +
+ +
+ {isAuthenticated ? ( + + ) : ( +
+ + Connexion + + + Créer un compte + +
+ )} +
+ + + ) : null} + + ); +} + +function MenuSection({ + label, + children, +}: { + label: string; + children: React.ReactNode; +}) { + return ( +
+

+ {label} +

+ +
+ ); +} + +function MenuLink({ + href, + pathname, + children, +}: { + href: string; + pathname: string; + children: React.ReactNode; +}) { + const active = pathname === href || (href !== "/" && pathname.startsWith(href)); + return ( +
  • + + {children} + +
  • + ); +} diff --git a/src/components/SiteHeader.tsx b/src/components/SiteHeader.tsx index dd5b682..64faae8 100644 --- a/src/components/SiteHeader.tsx +++ b/src/components/SiteHeader.tsx @@ -10,6 +10,7 @@ import { UserRole } from "@/generated/prisma/enums"; import { isPluginEnabled } from "@/lib/plugins/server"; import { CartBadge } from "./CartBadge"; +import { MobileMenuButton } from "./MobileMenuButton"; import { SignOutButton } from "./SignOutButton"; export async function SiteHeader() { @@ -50,6 +51,7 @@ export async function SiteHeader() {
    {rentalEnabled ? : null} + {/* Desktop-only links (sm+) */} {u ? ( <> @@ -89,21 +91,33 @@ export async function SiteHeader() { {u.name || u.email} - + + + ) : ( <> - + Connexion Créer un compte )} + {/* Mobile-only burger menu */} +