200 lines
9.1 KiB
TypeScript
200 lines
9.1 KiB
TypeScript
import { A, useLocation } from '@solidjs/router';
|
|
import { For, Show } 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,
|
|
ChevronLeft, BadgeCheck, Activity, Film, Utensils, PenTool,
|
|
Megaphone,
|
|
} from 'lucide-solid';
|
|
|
|
type NavItem = {
|
|
href: string;
|
|
label: string;
|
|
icon: any;
|
|
aliasPrefix?: string;
|
|
};
|
|
|
|
const GROUPS: NavItem[][] = [
|
|
[
|
|
{ href: '/admin', label: 'Dashboard', icon: LayoutGrid },
|
|
],
|
|
[
|
|
{ href: '/admin/department', label: 'Department Management', icon: Building2 },
|
|
{ href: '/admin/designation', label: 'Designation Management', icon: Briefcase },
|
|
{ href: '/admin/roles', label: 'Internal Role Management', icon: ShieldCheck },
|
|
{ href: '/admin/employees', label: 'Employee Management', icon: Users },
|
|
],
|
|
[
|
|
{ href: '/admin/runtime-roles', label: 'External Role Management', icon: ShieldCheck },
|
|
{ href: '/admin/onboarding-management', label: 'External 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/verification-status', label: 'Verification Management', icon: BadgeCheck },
|
|
{ href: '/admin/approval', label: 'Approval Management', icon: ClipboardList },
|
|
],
|
|
[
|
|
{ href: '/admin/users', label: 'Users Management', icon: UserRoundSearch },
|
|
{ href: '/admin/company', label: 'Company Management', icon: Building2 },
|
|
{ href: '/admin/candidate', label: 'Candidate Management', icon: UserCircle },
|
|
{ href: '/admin/customer', label: 'Customer 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: 'Tutors Management', icon: BookOpen },
|
|
{ href: '/admin/developers', label: 'Developers Management', icon: Code2 },
|
|
{ href: '/admin/video-editors', label: 'Video Editor Management', icon: Film },
|
|
{ href: '/admin/fitness-trainers', label: 'Fitness Trainer Management', icon: Activity },
|
|
{ href: '/admin/catering-services', label: 'Catering Services Management', icon: Utensils },
|
|
{ href: '/admin/graphic-designers', label: 'Graphics Designer Management', icon: PenTool },
|
|
{ href: '/admin/social-media-managers', label: 'Social Media Manager Management', icon: Megaphone },
|
|
],
|
|
[
|
|
{ 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/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;
|
|
adminName: string;
|
|
adminInitials: string;
|
|
}) {
|
|
const location = useLocation();
|
|
const isPreview = () => location.search.includes('_preview=1');
|
|
const isDepartmentView = () =>
|
|
location.pathname === '/admin/department' || location.pathname === '/admin/department-management';
|
|
const visibleGroups = () => ((isPreview() || isDepartmentView()) ? GROUPS.slice(0, 3) : GROUPS);
|
|
|
|
const isActive = (item: NavItem) => {
|
|
if (location.pathname === '/admin') return item.href === '/admin';
|
|
if (item.href === '/admin') return false;
|
|
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 bg-white border-r border-[#E5E7EB] transition-all duration-300 ${
|
|
props.collapsed ? 'w-[72px]' : (isDepartmentView() ? 'w-[300px]' : 'w-[272px]')
|
|
}`}
|
|
>
|
|
{/* Logo area */}
|
|
<div class={`relative flex h-[101px] shrink-0 items-center border-b border-[#E5E7EB] ${props.collapsed ? 'justify-center px-3' : 'px-6'}`}>
|
|
<A href="/admin" onClick={props.onNavigate} class="flex items-center">
|
|
<img
|
|
src={props.collapsed ? '/nxtgauge-icon.png' : '/nxtgauge-logo.png'}
|
|
alt="Nxtgauge"
|
|
class={`${props.collapsed ? 'h-8' : 'h-[22px]'} w-auto object-contain`}
|
|
/>
|
|
</A>
|
|
<Show when={!props.collapsed}>
|
|
<button
|
|
type="button"
|
|
onClick={props.onToggle}
|
|
class="absolute right-4 top-1/2 -translate-y-1/2 inline-flex h-7 w-7 items-center justify-center rounded-lg text-[#9CA3AF] transition-colors hover:text-[#374151]"
|
|
aria-label="Collapse sidebar"
|
|
>
|
|
<ChevronLeft size={16} />
|
|
</button>
|
|
</Show>
|
|
<Show when={props.collapsed}>
|
|
<button
|
|
type="button"
|
|
onClick={props.onToggle}
|
|
class="absolute -right-3 top-1/2 z-10 -translate-y-1/2 inline-flex h-6 w-6 items-center justify-center rounded-full border border-[#E5E7EB] bg-white text-[#9CA3AF] transition-colors hover:text-[#374151]"
|
|
aria-label="Expand sidebar"
|
|
>
|
|
<ChevronLeft size={12} class="rotate-180" />
|
|
</button>
|
|
</Show>
|
|
</div>
|
|
|
|
{/* Navigation */}
|
|
<nav class="scrollbar min-h-0 flex-1 overflow-y-auto px-4 py-5">
|
|
<For each={visibleGroups()}>
|
|
{(group, gi) => (
|
|
<>
|
|
<Show when={gi() > 0}>
|
|
<div class="my-3 h-px bg-[#E5E7EB]" />
|
|
</Show>
|
|
<div class="space-y-1">
|
|
<For each={group}>
|
|
{(item) => {
|
|
const active = () => isActive(item);
|
|
const Icon = item.icon;
|
|
return (
|
|
<A
|
|
href={item.href}
|
|
onClick={props.onNavigate}
|
|
title={props.collapsed ? item.label : undefined}
|
|
class={`relative flex h-[48px] w-full items-center rounded-2xl text-[16px] font-medium transition-colors ${
|
|
props.collapsed ? 'justify-center px-0' : 'px-3'
|
|
} ${
|
|
active()
|
|
? 'bg-[#FFF1EB] text-[#FF5E13]'
|
|
: 'text-[#6B7280] hover:bg-[#F3F4F6] hover:text-[#111827]'
|
|
}`}
|
|
aria-current={active() ? 'page' : undefined}
|
|
>
|
|
{/* Active left indicator */}
|
|
<Show when={active() && !props.collapsed}>
|
|
<span class="absolute left-0 top-1/2 h-5 w-[3px] -translate-y-1/2 rounded-r-full bg-[#FF5E13]" />
|
|
</Show>
|
|
<Icon
|
|
size={isDepartmentView() ? 22 : 18}
|
|
class={`shrink-0 ${active() ? 'text-[#FF5E13]' : 'text-[#9CA3AF]'}`}
|
|
strokeWidth={2}
|
|
/>
|
|
<Show when={!props.collapsed}>
|
|
<span class="ml-3 truncate">{item.label}</span>
|
|
</Show>
|
|
</A>
|
|
);
|
|
}}
|
|
</For>
|
|
</div>
|
|
</>
|
|
)}
|
|
</For>
|
|
</nav>
|
|
|
|
{/* User card */}
|
|
<div class="shrink-0 border-t border-[#E5E7EB] p-3">
|
|
<div class={`flex items-center rounded-xl border border-[#E5E7EB] bg-[#F9FAFB] px-3 py-2.5 ${props.collapsed ? 'justify-center' : 'gap-3'}`}>
|
|
<div class="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-gradient-to-br from-[#FF5E13] to-[#ff7a3d] text-[12px] font-bold text-white">
|
|
{props.adminInitials}
|
|
</div>
|
|
<Show when={!props.collapsed}>
|
|
<div class="min-w-0 flex-1">
|
|
<p class="truncate text-[13px] font-semibold leading-5 text-[#111827]">{props.adminName}</p>
|
|
<p class="text-[11px] leading-4 text-[#6B7280]">Super Admin</p>
|
|
</div>
|
|
</Show>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
);
|
|
}
|