Files
gridpilot.gg/apps/website/components/admin/AdminLayout.tsx
2026-01-12 01:01:49 +01:00

180 lines
6.1 KiB
TypeScript

'use client';
import { ReactNode, useState } from 'react';
import {
LayoutDashboard,
Users,
Settings,
LogOut,
Shield,
Activity
} from 'lucide-react';
import { useRouter, usePathname } from 'next/navigation';
import { logoutAction } from '@/app/actions/logoutAction';
interface AdminLayoutProps {
children: ReactNode;
}
type AdminTab = 'dashboard' | 'users';
export function AdminLayout({ children }: AdminLayoutProps) {
const router = useRouter();
const pathname = usePathname();
const [isSidebarOpen, setIsSidebarOpen] = useState(true);
// Determine current tab from pathname
const getCurrentTab = (): AdminTab => {
if (pathname === '/admin') return 'dashboard';
if (pathname === '/admin/users') return 'users';
return 'dashboard';
};
const currentTab = getCurrentTab();
const navigation = [
{
id: 'dashboard',
label: 'Dashboard',
icon: LayoutDashboard,
href: '/admin',
description: 'Overview and statistics'
},
{
id: 'users',
label: 'User Management',
icon: Users,
href: '/admin/users',
description: 'Manage all users'
},
{
id: 'settings',
label: 'Settings',
icon: Settings,
href: '/admin/settings',
description: 'System configuration',
disabled: true
}
];
const handleNavigation = (href: string, disabled?: boolean) => {
if (!disabled) {
router.push(href);
}
};
return (
<div className="flex h-screen bg-deep-graphite overflow-hidden">
{/* Sidebar */}
<aside className={`${isSidebarOpen ? 'w-64' : 'w-20'} bg-iron-gray border-r border-charcoal-outline transition-all duration-300 flex flex-col`}>
{/* Logo/Header */}
<div className="p-4 border-b border-charcoal-outline">
<div className="flex items-center gap-2">
<Shield className="w-6 h-6 text-primary-blue" />
{isSidebarOpen && (
<span className="font-bold text-white text-lg">Admin Panel</span>
)}
</div>
{isSidebarOpen && (
<p className="text-xs text-gray-400 mt-1">System Administration</p>
)}
</div>
{/* Navigation */}
<nav className="flex-1 p-2 space-y-1 overflow-y-auto">
{navigation.map((item) => {
const Icon = item.icon;
const isActive = currentTab === item.id;
const isDisabled = item.disabled;
return (
<button
key={item.id}
onClick={() => handleNavigation(item.href, isDisabled)}
disabled={isDisabled}
className={`
w-full flex items-center gap-3 px-3 py-3 rounded-lg
transition-all duration-200 text-left
${isActive
? 'bg-primary-blue/20 text-primary-blue border border-primary-blue/30'
: 'text-gray-300 hover:bg-iron-gray/50 hover:text-white'
}
${isDisabled ? 'opacity-50 cursor-not-allowed' : ''}
`}
>
<Icon className={`w-5 h-5 flex-shrink-0 ${isActive ? 'text-primary-blue' : 'text-gray-400'}`} />
{isSidebarOpen && (
<div className="flex-1 min-w-0">
<div className="font-medium text-sm">{item.label}</div>
<div className="text-xs text-gray-500">{item.description}</div>
</div>
)}
</button>
);
})}
</nav>
{/* Footer */}
<div className="p-2 border-t border-charcoal-outline space-y-1">
<button
onClick={() => setIsSidebarOpen(!isSidebarOpen)}
className="w-full flex items-center gap-3 px-3 py-2 rounded-lg text-gray-300 hover:bg-iron-gray/50 hover:text-white transition-colors"
>
<Activity className="w-5 h-5" />
{isSidebarOpen && <span className="text-sm">Toggle Sidebar</span>}
</button>
{/* Use form with server action for logout */}
<form action={logoutAction}>
<button
type="submit"
className="w-full flex items-center gap-3 px-3 py-2 rounded-lg text-racing-red hover:bg-racing-red/10 transition-colors"
>
<LogOut className="w-5 h-5" />
{isSidebarOpen && <span className="text-sm">Logout</span>}
</button>
</form>
</div>
</aside>
{/* Main Content */}
<main className="flex-1 flex flex-col overflow-hidden">
{/* Top Bar */}
<header className="bg-iron-gray border-b border-charcoal-outline px-6 py-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<div className="p-2 bg-primary-blue/20 rounded-lg">
<Shield className="w-5 h-5 text-primary-blue" />
</div>
<div>
<h2 className="text-lg font-semibold text-white">
{navigation.find(n => n.id === currentTab)?.label || 'Admin'}
</h2>
<p className="text-xs text-gray-400">
{navigation.find(n => n.id === currentTab)?.description}
</p>
</div>
</div>
<div className="flex items-center gap-4">
<div className="flex items-center gap-2 px-3 py-1.5 bg-deep-graphite rounded-lg border border-charcoal-outline">
<Shield className="w-4 h-4 text-purple-500" />
<span className="text-xs font-medium text-purple-400">Super Admin</span>
</div>
<div className="text-right hidden sm:block">
<div className="text-sm font-medium text-white">System Administrator</div>
<div className="text-xs text-gray-400">Full Access</div>
</div>
</div>
</div>
</header>
{/* Content Area */}
<div className="flex-1 overflow-y-auto bg-deep-graphite">
{children}
</div>
</main>
</div>
);
}