140 lines
5.8 KiB
TypeScript
140 lines
5.8 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from "react";
|
|
import { useRouter, usePathname } from "next/navigation";
|
|
import Link from "next/link";
|
|
import {
|
|
LogOut,
|
|
LayoutDashboard,
|
|
Activity,
|
|
ShieldCheck,
|
|
Settings2,
|
|
CalendarDays
|
|
} from "lucide-react";
|
|
|
|
export default function AdminLayout({ children }: { children: React.ReactNode }) {
|
|
const router = useRouter();
|
|
const pathname = usePathname();
|
|
const [user, setUser] = useState<any>(null);
|
|
|
|
// 1. TAMBAHAN BARU: Gembok Loading untuk mencegah glitch redirect
|
|
const [isAuthorized, setIsAuthorized] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const userData = localStorage.getItem("user");
|
|
|
|
if (!userData) {
|
|
router.push("/login");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const parsed = JSON.parse(userData);
|
|
|
|
// 2. PERBAIKAN: Baca role dengan aman, ubah semua ke huruf kecil
|
|
const userRole = parsed.role || parsed.Role || "";
|
|
|
|
if (userRole.toLowerCase() !== 'admin') {
|
|
router.push("/dashboard");
|
|
} else {
|
|
setUser(parsed);
|
|
setIsAuthorized(true); // Buka gembok karena dia benar-benar admin!
|
|
}
|
|
} catch (error) {
|
|
console.error("Gagal membaca data user", error);
|
|
router.push("/login");
|
|
}
|
|
}, [router]);
|
|
|
|
const handleLogout = () => {
|
|
localStorage.clear();
|
|
router.push("/login");
|
|
};
|
|
|
|
// 3. CEGATAN RENDER: Jika belum divalidasi, jangan render apapun selain layar loading
|
|
if (!isAuthorized) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-white">
|
|
<div className="text-blue-600 font-bold animate-pulse">Memverifikasi Otoritas Admin...</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-white flex flex-col font-sans">
|
|
|
|
{/* HEADER ADMIN */}
|
|
<header className="bg-[#e5e7eb] flex items-center justify-between px-6 py-4 shadow-sm z-20 relative">
|
|
<div>
|
|
<h2 className="text-blue-600 text-sm font-medium mb-1">Admin Panel,</h2>
|
|
<h1 className="text-blue-600 text-3xl font-bold">S-CLASS</h1>
|
|
</div>
|
|
<div className="flex items-center gap-8">
|
|
<div className="flex items-center gap-3">
|
|
<div className="bg-slate-800 text-white rounded-full h-10 w-10 flex items-center justify-center text-lg font-bold shadow-sm">
|
|
{user?.full_name ? user.full_name.charAt(0).toUpperCase() : "A"}
|
|
</div>
|
|
<div className="hidden sm:flex flex-col">
|
|
<span className="font-semibold text-gray-800 text-sm">{user?.full_name || "Administrator"}</span>
|
|
<span className="font-medium text-blue-600 text-xs uppercase tracking-wider">System Controller</span>
|
|
</div>
|
|
</div>
|
|
<button onClick={handleLogout} className="flex items-center gap-2 text-red-500 font-medium hover:text-red-600 transition-colors">
|
|
Log Out <LogOut size={20} />
|
|
</button>
|
|
</div>
|
|
</header>
|
|
|
|
<div className="flex flex-1 overflow-hidden relative">
|
|
|
|
{/* SIDEBAR ADMIN (Lebar Permanen: w-64) */}
|
|
<aside className="bg-[#b0c4d9] w-64 flex flex-col py-10 shadow-inner z-10">
|
|
<nav className="flex flex-col gap-6 px-4">
|
|
|
|
<Link href="/admin" className={`flex items-center gap-4 font-semibold transition-colors group ${pathname === '/admin' ? 'text-blue-700' : 'text-gray-800 hover:text-blue-700'}`}>
|
|
<div className={`p-2 rounded-lg transition-colors ${pathname === '/admin' ? 'bg-white/60 shadow-sm' : 'bg-white/30 group-hover:bg-white/50'}`}>
|
|
<LayoutDashboard size={22} />
|
|
</div>
|
|
<span>Dashboard</span>
|
|
</Link>
|
|
|
|
<Link href="/admin/monitoring" className={`flex items-center gap-4 font-semibold transition-colors group ${pathname === '/admin/monitoring' ? 'text-blue-700' : 'text-gray-800 hover:text-blue-700'}`}>
|
|
<div className={`p-2 rounded-lg transition-colors ${pathname === '/admin/monitoring' ? 'bg-white/60 shadow-sm' : 'bg-white/30 group-hover:bg-white/50'}`}>
|
|
<Activity size={22} />
|
|
</div>
|
|
<span>Power Monitoring</span>
|
|
</Link>
|
|
|
|
<Link href="/admin/approvals" className={`flex items-center gap-4 font-semibold transition-colors group ${pathname === '/admin/approvals' ? 'text-blue-700' : 'text-gray-800 hover:text-blue-700'}`}>
|
|
<div className={`p-2 rounded-lg transition-colors ${pathname === '/admin/approvals' ? 'bg-white/60 shadow-sm' : 'bg-white/30 group-hover:bg-white/50'}`}>
|
|
<ShieldCheck size={22} />
|
|
</div>
|
|
<span>Approvals</span>
|
|
</Link>
|
|
|
|
<Link href="/admin/rooms" className={`flex items-center gap-4 font-semibold transition-colors group ${pathname === '/admin/rooms' ? 'text-blue-700' : 'text-gray-800 hover:text-blue-700'}`}>
|
|
<div className={`p-2 rounded-lg transition-colors ${pathname === '/admin/rooms' ? 'bg-white/60 shadow-sm' : 'bg-white/30 group-hover:bg-white/50'}`}>
|
|
<Settings2 size={22} />
|
|
</div>
|
|
<span>Manage Rooms</span>
|
|
</Link>
|
|
|
|
<Link href="/admin/schedules" className={`flex items-center gap-4 font-semibold transition-colors group ${pathname === '/admin/schedules' ? 'text-blue-700' : 'text-gray-800 hover:text-blue-700'}`}>
|
|
<div className={`p-2 rounded-lg transition-colors ${pathname === '/admin/schedules' ? 'bg-white/60 shadow-sm' : 'bg-white/30 group-hover:bg-white/50'}`}>
|
|
<CalendarDays size={22} />
|
|
</div>
|
|
<span>Edit Jadwal</span>
|
|
</Link>
|
|
|
|
</nav>
|
|
</aside>
|
|
|
|
{/* KONTEN UTAMA */}
|
|
<main className="flex-1 overflow-y-auto bg-[#f8fafc] p-8">
|
|
{children}
|
|
</main>
|
|
|
|
</div>
|
|
</div>
|
|
);
|
|
} |