()
| 49 | ]; |
| 50 | |
| 51 | export function Sidebar() { |
| 52 | const pathname = usePathname(); |
| 53 | const router = useRouter(); |
| 54 | const [isOpen, setIsOpen] = useState(false); |
| 55 | const [isMobile, setIsMobile] = useState(false); |
| 56 | |
| 57 | // Check if mobile on mount and resize |
| 58 | useEffect(() => { |
| 59 | const checkMobile = () => { |
| 60 | setIsMobile(window.innerWidth < 768); |
| 61 | if (window.innerWidth >= 768) { |
| 62 | setIsOpen(false); |
| 63 | } |
| 64 | }; |
| 65 | |
| 66 | checkMobile(); |
| 67 | window.addEventListener("resize", checkMobile); |
| 68 | return () => window.removeEventListener("resize", checkMobile); |
| 69 | }, []); |
| 70 | |
| 71 | // Close sidebar when navigating on mobile |
| 72 | useEffect(() => { |
| 73 | if (isMobile) { |
| 74 | setIsOpen(false); |
| 75 | } |
| 76 | }, [pathname, isMobile]); |
| 77 | |
| 78 | // Prevent scroll when sidebar is open on mobile |
| 79 | useEffect(() => { |
| 80 | if (isOpen && isMobile) { |
| 81 | document.body.style.overflow = "hidden"; |
| 82 | } else { |
| 83 | document.body.style.overflow = ""; |
| 84 | } |
| 85 | return () => { |
| 86 | document.body.style.overflow = ""; |
| 87 | }; |
| 88 | }, [isOpen, isMobile]); |
| 89 | |
| 90 | const handleLogout = async () => { |
| 91 | await fetch("/api/auth/logout", { method: "POST" }); |
| 92 | router.push("/login"); |
| 93 | router.refresh(); |
| 94 | }; |
| 95 | |
| 96 | const toggleSidebar = () => setIsOpen(!isOpen); |
| 97 | const closeSidebar = () => setIsOpen(false); |
| 98 | |
| 99 | return ( |
| 100 | <> |
| 101 | {/* Mobile hamburger button */} |
| 102 | <button |
| 103 | onClick={toggleSidebar} |
| 104 | className="mobile-menu-button" |
| 105 | aria-label="Toggle menu" |
| 106 | style={{ |
| 107 | position: "fixed", |
| 108 | top: "1rem", |
nothing calls this directly
no test coverage detected