"use client";
import React, { useEffect, useState } from "react";
import { useRouter, usePathname } from "next/navigation";
import Link from "next/link";
import {
LayoutDashboard,
Users,
Clock,
FileSpreadsheet,
Settings,
Monitor,
LogOut,
Menu,
X,
ChevronRight,
Scan,
History,
Sun,
Moon
} from "lucide-react";
import { getAccessToken, getUserProfile, clearTokens } from "@/app/utils/api";
const navItems = [
{ name: "Dashboard", href: "/dashboard", icon: LayoutDashboard },
{ name: "Attendance", href: "/attendance", icon: Clock },
{ name: "Employees", href: "/employees", icon: Users },
{ name: "Reports", href: "/reports", icon: FileSpreadsheet },
{ name: "Audit Logs", href: "/audit", icon: History },
{ name: "Settings", href: "/settings", icon: Settings },
];
function NavLink({
item,
isActive,
isCollapsed,
onClick
}: {
item: typeof navItems[0],
isActive: boolean,
isCollapsed: boolean,
onClick?: () => void
}) {
const Icon = item.icon;
return (
{/* Active indicator */}
{isActive && (
)}
{!isCollapsed && (
)}
{isActive && !isCollapsed && }
);
}
export default function SidebarLayout({ children }: { children: React.ReactNode }) {
const router = useRouter();
const pathname = usePathname();
const [sidebarOpen, setSidebarOpen] = useState(false);
const [isCollapsed, setIsCollapsed] = useState(false);
const [user, setUser] = useState(null);
const [authorized, setAuthorized] = useState(false);
const [theme, setTheme] = useState<"light" | "dark">("light");
// Load theme and sidebar state from localStorage on client side
useEffect(() => {
const saved = localStorage.getItem("sidebar_collapsed");
if (saved === "true") {
setIsCollapsed(true);
}
const savedTheme = localStorage.getItem("theme");
const systemPrefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
const initialTheme = (savedTheme as "light" | "dark") || (systemPrefersDark ? "dark" : "light");
setTheme(initialTheme);
if (initialTheme === "dark") {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
}, []);
const toggleTheme = () => {
const nextTheme = theme === "dark" ? "light" : "dark";
setTheme(nextTheme);
localStorage.setItem("theme", nextTheme);
if (nextTheme === "dark") {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
};
const toggleCollapse = () => {
const nextVal = !isCollapsed;
setIsCollapsed(nextVal);
localStorage.setItem("sidebar_collapsed", String(nextVal));
};
useEffect(() => {
const token = getAccessToken();
const profile = getUserProfile();
if (!token || !profile) {
clearTokens();
router.push("/");
} else {
setUser(profile);
setAuthorized(true);
}
}, [router]);
if (!authorized) {
return (
);
}
const handleLogout = () => {
clearTokens();
router.push("/");
};
const initials = user?.email ? user.email[0].toUpperCase() : "A";
return (
{/* Ambient background */}
{/* ─── Desktop Sidebar ─── */}
{/* ─── Mobile Top Bar ─── */}
{/* Theme Toggle Mobile */}
{/* ─── Mobile Drawer ─── */}
{sidebarOpen && (
setSidebarOpen(false)}
>
)}
{/* ─── Main Content ─── */}
{/* Desktop Top Navbar */}
{children}
);
}