"use client"; import Image from "next/image"; import { useEffect, useState, type MouseEvent } from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { auth, clearToken, redirectToLogin } from "@/lib/api"; import { useCurrentUser } from "@/lib/auth-state"; import OrganizationSwitcher from "@/components/OrganizationSwitcher"; import { navigation } from "@/lib/navigation"; import { addPreferencesListener, getStoredPanelName } from "@/lib/preferences"; import { formatRoleLabel, hasMinimumRole } from "@/lib/permissions"; import { LogOut, ChevronLeft, ChevronRight, X } from "lucide-react"; interface SidebarProps { /** Desktop: whether sidebar is in collapsed (icon-only) state */ collapsed: boolean; /** Desktop: called when user clicks the collapse toggle */ onToggle: () => void; /** Mobile: whether screen is narrow */ isMobile: boolean; /** Mobile: whether the drawer is open */ mobileOpen: boolean; /** Mobile: called when user closes the drawer */ onMobileClose: () => void; } export default function Sidebar({ collapsed, onToggle, isMobile, mobileOpen, onMobileClose, }: SidebarProps) { const pathname = usePathname(); const currentUser = useCurrentUser(); const [loggingOut, setLoggingOut] = useState(false); const [pendingHref, setPendingHref] = useState(null); const [panelName, setPanelName] = useState("DOKTAINER"); const visibleNavigation = navigation .map((section) => ({ ...section, items: section.items.filter((item) => hasMinimumRole(currentUser?.role, item.minRole), ), })) .filter((section) => section.items.length > 0); const handleLogout = async () => { if (loggingOut) return; setLoggingOut(true); try { await auth.logout(); } catch { // Best effort server-side logout; local session is cleared regardless. } finally { clearToken(); onMobileClose(); redirectToLogin(); } }; useEffect(() => { const syncPanelName = () => { setPanelName(getStoredPanelName().toUpperCase()); }; syncPanelName(); return addPreferencesListener(syncPanelName); }, []); useEffect(() => { const timeoutId = window.setTimeout(() => { setPendingHref(null); }, 0); return () => window.clearTimeout(timeoutId); }, [pathname]); const handleNavigate = ( event: MouseEvent, href: string, ) => { if ( event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey ) { return; } if (href === pathname) { onMobileClose(); return; } setPendingHref(href); onMobileClose(); }; // On mobile the sidebar is always full-width (never icon-only) const isCollapsed = !isMobile && collapsed; const sidebar = ( ); // ── Mobile: full-screen overlay with slide-in drawer ────────── if (isMobile) { return (
{/* Backdrop */}
{/* Drawer panel */}
{sidebar}
); } // ── Desktop: plain inline flex item ─────────────────────────── return sidebar; }