migrant-web/resources/js/Layouts/AdminLayout.jsx

170 lines
7.9 KiB
JavaScript

import React, { useState } from 'react';
import { Link, usePage } from '@inertiajs/react';
import {
LayoutDashboard,
Users,
Briefcase,
CreditCard,
Megaphone,
Settings,
LogOut,
Menu,
Bell,
Shield,
BadgeDollarSign,
ShieldCheck,
ShieldAlert,
BellRing,
BarChart3,
History,
List,
LifeBuoy,
Heart
} from 'lucide-react';
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
export default function AdminLayout({ children, title = 'Dashboard' }) {
const { url, props } = usePage();
const { auth } = props;
const user = auth?.user || { name: 'Admin Portal', email: 'admin@marketplace.com' };
const [open, setOpen] = useState(false);
const navItems = [
{ name: 'Dashboard', href: '/admin/dashboard', icon: LayoutDashboard },
{ name: 'Worker Profiles', href: '/admin/workers', icon: Users },
{ name: 'Employers', href: '/admin/employers', icon: Briefcase },
{ name: 'OCR Verification', href: '/admin/workers/verifications', icon: ShieldCheck },
{ name: 'Safety & Moderation', href: '/admin/safety', icon: ShieldAlert },
{ name: 'Support Tickets', href: '/admin/tickets', icon: LifeBuoy },
{ name: 'Payments', href: '/admin/payments', icon: BadgeDollarSign },
{ name: 'Campaigns & Alerts', href: '/admin/notifications', icon: BellRing },
{ name: 'Reports & Analytics', href: '/admin/analytics', icon: BarChart3 },
{ name: 'System Audit Logs', href: '/admin/audit-logs', icon: History },
{ name: 'Charity Events', href: '/admin/announcements', icon: Heart },
{ name: 'Skills', href: '/admin/master-data/skills', icon: Settings },
{ name: 'Reason Master', href: '/admin/master-data/reasons', icon: List },
];
const getInitials = (name) => {
return name
?.split(' ')
.map((n) => n[0])
.join('')
.toUpperCase() || 'A';
};
const SidebarContent = ({ isMobile }) => (
<div className="flex flex-col h-full bg-white font-sans select-none">
{/* Top: App Logo + Admin Label */}
<div className="flex items-center space-x-3 px-6 h-16 border-b border-gray-100 flex-shrink-0">
<div className="w-9 h-9 bg-[#0F6E56]/10 rounded-xl flex items-center justify-center shadow-inner">
<Shield className="w-5 h-5 text-[#0F6E56]" />
</div>
<span className="font-semibold text-gray-800 text-lg tracking-tight">Admin Portal</span>
</div>
{/* Nav Items */}
<div className="flex-1 overflow-y-auto px-3 py-4 space-y-1.5">
{navItems.map((item) => {
const Icon = item.icon;
const active = url.startsWith(item.href);
return (
<Link
key={item.name}
href={item.href}
onClick={() => isMobile && setOpen(false)}
className={`flex items-center space-x-3 px-4 py-3 rounded-xl text-sm transition-all duration-200 group ${
active
? 'bg-[#0F6E56] text-white font-bold shadow-lg shadow-teal-900/20 scale-[1.02]'
: 'text-gray-500 hover:bg-gray-50 hover:text-gray-900'
}`}
>
<Icon className={`w-5 h-5 flex-shrink-0 transition-colors ${active ? 'text-white' : 'text-gray-400 group-hover:text-gray-900'}`} />
<span className="tracking-tight">{item.name}</span>
</Link>
);
})}
</div>
{/* Bottom: Admin Avatar, Name, Email, Logout */}
<div className="p-4 border-t border-gray-100 flex-shrink-0">
<div className="flex items-center space-x-3 mb-3 px-2">
<div className="w-9 h-9 rounded-full bg-[#0F6E56] text-white flex items-center justify-center font-medium text-sm flex-shrink-0 shadow-sm">
{getInitials(user.name)}
</div>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-gray-900 truncate">{user.name}</p>
<p className="text-xs text-gray-500 truncate">{user.email}</p>
</div>
</div>
<Link
href="/admin/logout"
method="post"
as="button"
className="w-full flex items-center space-x-3 px-3 py-2 text-sm text-red-600 hover:bg-red-50 rounded-lg transition-colors font-medium justify-start focus:outline-none"
>
<LogOut className="w-5 h-5 flex-shrink-0" />
<span>Log Out</span>
</Link>
</div>
</div>
);
return (
<div className="min-h-screen bg-gray-50 flex font-sans">
{/* Fixed Left Sidebar (Desktop lg+) */}
<aside className="hidden lg:flex lg:flex-col lg:w-[240px] lg:fixed lg:inset-y-0 lg:border-r lg:border-gray-100 lg:bg-white lg:z-30">
<SidebarContent isMobile={false} />
</aside>
{/* Main Content Area */}
<div className="flex-1 flex flex-col min-w-0 lg:ml-[240px]">
{/* Top Bar */}
<header className="h-16 bg-white border-b border-gray-100 flex items-center justify-between px-6 sticky top-0 z-20 shadow-sm">
<div className="flex items-center space-x-4">
{/* Mobile menu trigger */}
<div className="lg:hidden">
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild>
<button
type="button"
className="p-2 text-gray-600 hover:text-gray-900 focus:outline-none rounded-lg hover:bg-gray-50 transition-colors flex items-center justify-center"
>
<Menu className="w-6 h-6" />
</button>
</SheetTrigger>
<SheetContent side="left" className="p-0 w-[240px] bg-white border-r border-gray-100">
<SidebarContent isMobile={true} />
</SheetContent>
</Sheet>
</div>
<h1 className="text-xl font-semibold text-gray-800 tracking-tight">{title}</h1>
</div>
<div className="flex items-center space-x-4">
<button
type="button"
className="p-2 text-gray-500 hover:text-gray-800 rounded-full hover:bg-gray-50 relative focus:outline-none transition-colors"
>
<Bell className="w-5 h-5" />
<span className="absolute top-2 right-2 w-2 h-2 bg-[#0F6E56] rounded-full ring-2 ring-white" />
</button>
<div className="flex items-center space-x-3 border-l border-gray-100 pl-4">
<div className="w-8 h-8 rounded-full bg-[#0F6E56] text-white flex items-center justify-center font-medium text-xs shadow-sm">
{getInitials(user.name)}
</div>
</div>
</div>
</header>
{/* Content Slot */}
<main className="flex-1 p-6 max-w-7xl w-full mx-auto">
{children}
</main>
</div>
</div>
);
}