245 lines
5.7 KiB
TypeScript
245 lines
5.7 KiB
TypeScript
'use client';
|
|
|
|
import Link from 'next/link';
|
|
import { usePathname } from 'next/navigation';
|
|
import { cn } from '@/lib/utils';
|
|
import { getUserRole } from '@/lib/api';
|
|
import { useState, useEffect } from 'react';
|
|
import { useSidebar } from '@/lib/SidebarContext';
|
|
import ThemeToggle from './ThemeToggle';
|
|
|
|
interface NavItem {
|
|
label: string;
|
|
href: string;
|
|
icon: string;
|
|
roles?: string[];
|
|
children?: { label: string; href: string }[];
|
|
}
|
|
|
|
const navItems: NavItem[] = [
|
|
{
|
|
label: 'Dashboard',
|
|
href: '/admin/dashboard',
|
|
icon: '📊',
|
|
},
|
|
{
|
|
label: 'Benefactors',
|
|
href: '/admin/benefactors',
|
|
icon: '👥',
|
|
roles: ['super-admin', 'admin'],
|
|
},
|
|
{
|
|
label: 'Agents',
|
|
href: '/admin/agents',
|
|
icon: '🤝',
|
|
roles: ['super-admin', 'admin'],
|
|
},
|
|
{
|
|
label: 'Kind Boxes',
|
|
href: '/admin/kind-boxes',
|
|
icon: '📦',
|
|
roles: ['super-admin', 'admin'],
|
|
children: [
|
|
{ label: 'All Boxes', href: '/admin/kind-boxes' },
|
|
{ label: 'Create', href: '/admin/kind-boxes/create' },
|
|
],
|
|
},
|
|
{
|
|
label: 'Kind Box Requests',
|
|
href: '/admin/kind-box-requests',
|
|
icon: '📋',
|
|
roles: ['super-admin', 'admin'],
|
|
children: [
|
|
{ label: 'All Requests', href: '/admin/kind-box-requests' },
|
|
{ label: 'Create', href: '/admin/kind-box-requests/create' },
|
|
],
|
|
},
|
|
{
|
|
label: 'Refer Times',
|
|
href: '/admin/refer-times',
|
|
icon: '⏰',
|
|
roles: ['super-admin', 'admin'],
|
|
},
|
|
{
|
|
label: 'My Kind Boxes',
|
|
href: '/benefactor/kind-boxes',
|
|
icon: '📦',
|
|
roles: ['benefactor'],
|
|
},
|
|
{
|
|
label: 'My Requests',
|
|
href: '/benefactor/kind-box-requests',
|
|
icon: '📋',
|
|
roles: ['benefactor'],
|
|
},
|
|
{
|
|
label: 'My Addresses',
|
|
href: '/benefactor/addresses',
|
|
icon: '📍',
|
|
roles: ['benefactor'],
|
|
},
|
|
{
|
|
label: 'Refer Times',
|
|
href: '/benefactor/refer-times',
|
|
icon: '⏰',
|
|
roles: ['benefactor'],
|
|
},
|
|
{
|
|
label: 'Agent Dashboard',
|
|
href: '/agent/dashboard',
|
|
icon: '🎯',
|
|
roles: ['agent'],
|
|
},
|
|
{
|
|
label: 'Return Awaiting',
|
|
href: '/agent/kind-boxes',
|
|
icon: '📥',
|
|
roles: ['agent'],
|
|
},
|
|
{
|
|
label: 'Delivery Awaiting',
|
|
href: '/agent/kind-box-requests',
|
|
icon: '📤',
|
|
roles: ['agent'],
|
|
},
|
|
{
|
|
label: 'Products',
|
|
href: '/products',
|
|
icon: '🛍️',
|
|
},
|
|
{
|
|
label: 'Cart',
|
|
href: '/cart',
|
|
icon: '🛒',
|
|
},
|
|
{
|
|
label: 'Orders',
|
|
href: '/orders',
|
|
icon: '📦',
|
|
},
|
|
{
|
|
label: 'Campaigns',
|
|
href: '/campaigns',
|
|
icon: '🎯',
|
|
},
|
|
{
|
|
label: 'Wallet',
|
|
href: '/wallet',
|
|
icon: '💳',
|
|
},
|
|
{
|
|
label: 'Patients',
|
|
href: '/patients',
|
|
icon: '🏥',
|
|
roles: ['super-admin', 'admin'],
|
|
},
|
|
{
|
|
label: 'Drivers',
|
|
href: '/drivers',
|
|
icon: '🚗',
|
|
roles: ['super-admin', 'admin'],
|
|
},
|
|
{
|
|
label: 'Staff',
|
|
href: '/staff',
|
|
icon: '👔',
|
|
roles: ['super-admin', 'admin'],
|
|
},
|
|
{
|
|
label: 'Sales Reports',
|
|
href: '/sales-reports',
|
|
icon: '📈',
|
|
roles: ['super-admin', 'admin'],
|
|
},
|
|
{
|
|
label: 'Gamification',
|
|
href: '/gamification',
|
|
icon: '🏆',
|
|
roles: ['super-admin', 'admin'],
|
|
},
|
|
];
|
|
|
|
export default function Sidebar() {
|
|
const pathname = usePathname();
|
|
const [role, setRole] = useState<string | null>(null);
|
|
const { collapsed, toggle } = useSidebar();
|
|
|
|
useEffect(() => {
|
|
setRole(getUserRole());
|
|
}, []);
|
|
|
|
// Don't render sidebar on login or landing page
|
|
if (pathname === '/login' || pathname === '/') {
|
|
return null;
|
|
}
|
|
|
|
const filteredItems = navItems.filter((item) => {
|
|
if (!item.roles || item.roles.length === 0) return true;
|
|
return role && item.roles.includes(role);
|
|
});
|
|
|
|
const isActive = (href: string) => {
|
|
return pathname.startsWith(href);
|
|
};
|
|
|
|
return (
|
|
<aside
|
|
className={cn(
|
|
'fixed left-0 top-0 h-screen bg-white dark:bg-gray-900 border-r border-gray-200 dark:border-gray-700 z-30 transition-all duration-300 flex flex-col',
|
|
collapsed ? 'w-[60px]' : 'w-[260px]'
|
|
)}
|
|
>
|
|
{/* Logo */}
|
|
<div className="flex items-center gap-3 px-4 h-16 border-b border-gray-200 dark:border-gray-700">
|
|
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center text-white font-bold text-sm shrink-0">
|
|
N
|
|
</div>
|
|
{!collapsed && (
|
|
<>
|
|
<span className="font-bold text-lg bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent flex-1">
|
|
Niki
|
|
</span>
|
|
<ThemeToggle />
|
|
</>
|
|
)}
|
|
{collapsed && (
|
|
<div className="flex-1 flex justify-center">
|
|
<ThemeToggle />
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Navigation */}
|
|
<nav className="flex-1 overflow-y-auto p-3 space-y-1">
|
|
{filteredItems.map((item) => {
|
|
const active = isActive(item.href);
|
|
return (
|
|
<div key={item.href}>
|
|
<Link
|
|
href={item.href}
|
|
className={cn(
|
|
'sidebar-link',
|
|
active && 'active',
|
|
collapsed && 'justify-center px-2'
|
|
)}
|
|
title={collapsed ? item.label : undefined}
|
|
>
|
|
<span className="text-lg shrink-0">{item.icon}</span>
|
|
{!collapsed && <span>{item.label}</span>}
|
|
</Link>
|
|
</div>
|
|
);
|
|
})}
|
|
</nav>
|
|
|
|
{/* Collapse toggle */}
|
|
<button
|
|
onClick={toggle}
|
|
className="p-3 border-t border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors flex items-center justify-center text-gray-400"
|
|
>
|
|
<span className="text-sm">{collapsed ? '→' : '←'}</span>
|
|
</button>
|
|
</aside>
|
|
);
|
|
}
|