nxtgauge-admin-solid/src/components/AdminSidebar.tsx

143 lines
7.9 KiB
TypeScript
Raw Normal View History

import { A, useLocation } from '@solidjs/router';
import { For, Show, createSignal } from 'solid-js';
import {
LayoutGrid, Building2, Briefcase, Users, ShieldCheck, FileText,
LayoutDashboard, ClipboardList, UserRoundSearch, UserCircle,
Camera, Palette, BookOpen, Code2, BriefcaseBusiness, HandHelping,
WalletCards, CreditCard, Tag, Percent, Receipt, ShoppingCart,
FileCheck, Star, HeadphonesIcon, BarChart3, BookMarked, Bell,
ChevronLeft,
} from 'lucide-solid';
type Item = {
href: string;
label: string;
icon: any;
aliasPrefix?: string;
};
const items: Item[] = [
{ href: '/admin', label: 'Dashboard', icon: LayoutGrid },
{ href: '/admin/department', label: 'Department Management', icon: Building2 },
{ href: '/admin/designation', label: 'Designation Management', icon: Briefcase },
{ href: '/admin/employees', label: 'Internal User Management', icon: Users },
{ href: '/admin/roles', label: 'Internal Role Management', icon: ShieldCheck },
{ href: '/admin/runtime-roles', label: 'External Role Management', icon: ShieldCheck },
{ href: '/admin/onboarding-management', label: 'Onboarding Management', icon: FileText, aliasPrefix: '/admin/onboarding-schemas' },
{ href: '/admin/internal-dashboard-management',label: 'Internal Dashboard Management', icon: LayoutDashboard },
{ href: '/admin/external-dashboard-management',label: 'External Dashboard Management', icon: LayoutDashboard, aliasPrefix: '/admin/role-ui-configs' },
{ href: '/admin/approval', label: 'Approval Management', icon: ClipboardList },
{ href: '/admin/users', label: 'External User Management', icon: UserRoundSearch },
{ href: '/admin/customer', label: 'Customer Management', icon: UserCircle },
{ href: '/admin/company', label: 'Company Management', icon: Building2 },
{ href: '/admin/candidate', label: 'Candidate Management', icon: UserCircle },
{ href: '/admin/photographer', label: 'Photographer Management', icon: Camera },
{ href: '/admin/makeup-artist', label: 'Makeup Artist Management', icon: Palette },
{ href: '/admin/tutors', label: 'Tutor Management', icon: BookOpen },
{ href: '/admin/developers', label: 'Developer Management', icon: Code2 },
{ href: '/admin/jobs', label: 'Jobs Management', icon: BriefcaseBusiness },
{ href: '/admin/leads', label: 'Leads Management', icon: HandHelping },
{ href: '/admin/pricing', label: 'Pricing Management', icon: WalletCards },
{ href: '/admin/credit', label: 'Credit Management', icon: CreditCard },
{ href: '/admin/coupon', label: 'Coupon Management', icon: Tag },
{ href: '/admin/discount', label: 'Discount Management', icon: Percent },
{ href: '/admin/tax', label: 'Tax Management', icon: Receipt },
{ href: '/admin/order', label: 'Order Management', icon: ShoppingCart },
{ href: '/admin/invoice', label: 'Invoice Management', icon: FileCheck },
{ href: '/admin/review', label: 'Review Management', icon: Star },
{ href: '/admin/kb', label: 'Knowledge Base Management', icon: BookMarked },
{ href: '/admin/notifications', label: 'Notifications', icon: Bell },
{ href: '/admin/support', label: 'Support Management', icon: HeadphonesIcon },
{ href: '/admin/report', label: 'Report Management', icon: BarChart3 },
{ href: '/admin/ledger', label: 'Ledger Management', icon: Receipt },
];
export default function AdminSidebar(props: {
collapsed: boolean;
onToggle: () => void;
onNavigate?: () => void;
onLogout?: () => void;
}) {
const location = useLocation();
const active = (item: Item) => {
if (item.href === '/admin') return location.pathname === '/admin';
if (item.aliasPrefix && location.pathname.startsWith(item.aliasPrefix)) return true;
return location.pathname === item.href || location.pathname.startsWith(`${item.href}/`);
};
return (
<aside class={`flex h-full flex-col border-r border-slate-200 bg-[#fcfcfd] transition-all duration-300 ${props.collapsed ? 'w-20' : 'w-64'}`}>
{/* Collapse toggle */}
<div class="flex justify-end px-3 pt-4 pb-3">
<button
type="button"
onClick={() => props.onToggle()}
class="rounded-lg p-2 text-slate-500 transition hover:bg-slate-100 hover:text-slate-700"
>
<ChevronLeft
size={16}
class={`transition-transform duration-300 ${props.collapsed ? 'rotate-180' : ''}`}
/>
</button>
</div>
{/* Nav */}
<nav class="scrollbar min-h-0 flex-1 space-y-1.5 overflow-y-auto px-3 pb-3">
<For each={items}>
{(item) => {
const isActive = () => active(item);
const Icon = item.icon;
return (
<A
href={item.href}
onClick={() => props.onNavigate?.()}
title={props.collapsed ? item.label : undefined}
aria-current={isActive() ? 'page' : undefined}
class={`group relative flex items-center gap-3 rounded-xl border px-3 py-3 text-[15px] leading-5 transition-all ${
props.collapsed ? 'justify-center px-2' : ''
} ${
isActive()
? 'border-orange-200 bg-gradient-to-r from-orange-50 to-orange-100/70 text-slate-900'
: 'border-transparent text-slate-500 hover:border-slate-200 hover:bg-white hover:text-slate-800'
}`}
>
{/* Right orange accent bar */}
<span
class={`absolute right-0 top-2 bottom-2 w-[3px] rounded-l-full bg-orange-500 transition-opacity ${
isActive() ? 'opacity-100' : 'opacity-0'
}`}
/>
<Icon
size={18}
class={`shrink-0 transition-colors ${
isActive() ? 'text-orange-600' : 'text-slate-500 group-hover:text-slate-700'
}`}
/>
<Show when={!props.collapsed}>
<span class={`min-w-0 flex-1 truncate font-medium ${isActive() ? 'text-slate-900' : 'text-slate-600 group-hover:text-slate-800'}`}>
{item.label}
</span>
<Show when={isActive()}>
<span class="ml-auto shrink-0 rounded-full border border-orange-200 bg-orange-100 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-orange-700">
Active
</span>
</Show>
</Show>
{/* Collapsed active dot */}
<Show when={props.collapsed && isActive()}>
<span class="absolute -right-0.5 top-1/2 h-2 w-2 -translate-y-1/2 rounded-full bg-orange-500" />
</Show>
</A>
);
}}
</For>
</nav>
</aside>
);
}