niki-frontend/src/components/Sidebar.tsx

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>
);
}