import React, { useMemo, useState } from 'react';
import {
LayoutDashboard,
Tag,
MapPin,
Users,
Package,
FileText,
HelpCircle,
LogOut,
ChevronDown,
ChevronRight,
Layers,
Type,
FileBox,
Settings
} from 'lucide-react';
import { cn } from '../ui/utils';
import { ScrollArea } from '../ui/scroll-area';
import logo from "figma:asset/773f0c39e1986271e9144596caac519f934a6ae6.png";
import type { CurrentUserMenuNodeDto } from '../../types/authSession';
interface SidebarProps {
currentView: string;
setCurrentView: (view: string) => void;
menus?: CurrentUserMenuNodeDto[];
onLogout?: () => void;
}
const FALLBACK_ICONS = {
Dashboard: LayoutDashboard,
Labeling: Tag,
Labels: Tag,
"Label Categories": Layers,
"Label Types": Type,
"Label Templates": FileBox,
"Multiple Option Sets": Settings,
"Multiple Options": Settings,
"Location Manager": MapPin,
"Account Management": Users,
"Menu Management": Package,
"System Menu": Settings,
Reports: FileText,
Support: HelpCircle,
"Log Out": LogOut,
} as const;
function normalizeLabel(name: string) {
return name.trim() || "N/A";
}
function displayMenuLabel(name: string) {
const s = normalizeLabel(name);
if (s === "Multiple Options") return "Multiple Option Sets";
return s;
}
function pickIconKeyFromNode(node: CurrentUserMenuNodeDto, label: string): keyof typeof FALLBACK_ICONS | null {
const raw = String((node as any)?.menuIcon ?? (node as any)?.MenuIcon ?? "").trim();
if (raw && raw in FALLBACK_ICONS) return raw as keyof typeof FALLBACK_ICONS;
if (label in FALLBACK_ICONS) return label as keyof typeof FALLBACK_ICONS;
return null;
}
function MenuNode({
node,
level,
currentKey,
onSelect,
}: {
node: CurrentUserMenuNodeDto;
level: number;
currentKey: string;
onSelect: (key: string) => void;
}) {
const [open, setOpen] = React.useState(true);
const children = node.children ?? [];
const isDir = (node.menuType ?? 0) === 0 || children.length > 0;
const label = normalizeLabel(String(node.menuName ?? node.routerName ?? node.routeUrl ?? node.id ?? ""));
const viewKey = label === "Multiple Options" ? "Multiple Option Sets" : label;
const active = currentKey === viewKey;
const iconKey = pickIconKeyFromNode(node, viewKey);
const Icon = iconKey ? FALLBACK_ICONS[iconKey] : null;
if (isDir) {
return (
{open && children.length > 0 && (
{children.map((c) => (
))}
)}
);
}
return (
);
}
export function Sidebar({ currentView, setCurrentView, menus, onLogout }: SidebarProps) {
const [labelingOpen, setLabelingOpen] = useState(true);
const fallbackMenuItems = [
{ name: 'Dashboard', icon: LayoutDashboard, type: 'item' },
{ type: 'header', name: 'MODULES' },
{
name: 'Labeling',
icon: Tag,
type: 'sub',
isOpen: labelingOpen,
toggle: () => setLabelingOpen(!labelingOpen),
children: [
{ name: 'Labels', icon: Tag },
{ name: 'Label Categories', icon: Layers },
{ name: 'Label Types', icon: Type },
{ name: 'Label Templates', icon: FileBox },
{ name: 'Multiple Option Sets', icon: Settings },
]
},
{ type: 'header', name: 'MANAGEMENT' },
{ name: 'Account Management', icon: Users, type: 'item' },
{ name: 'Menu Management', icon: Package, type: 'item' },
{ name: 'System Menu', icon: Settings, type: 'item' },
{ name: 'Reports', icon: FileText, type: 'item' },
{ name: 'Support', icon: HelpCircle, type: 'item' },
{ name: 'Log Out', icon: LogOut, type: 'item' },
];
const hasRemoteMenus = (menus?.length ?? 0) > 0;
const logoutHandler = () => (onLogout ? onLogout() : setCurrentView("Log Out"));
const remoteMenuNodes = useMemo(() => menus ?? [], [menus]);
const { moduleMenus, accountMenus } = useMemo(() => {
const ACCOUNT_LABELS = new Set([
"Location Manager",
"Account Management",
"Menu Management",
"System Menu",
"Reports",
"Support",
]);
const roots = remoteMenuNodes;
const moduleMenus: CurrentUserMenuNodeDto[] = [];
const accountMenus: CurrentUserMenuNodeDto[] = [];
for (const n of roots) {
const label = normalizeLabel(String(n.menuName ?? n.routerName ?? n.routeUrl ?? n.id ?? ""));
if (label === "Management") {
const children = n.children ?? [];
for (const c of children) {
const cl = normalizeLabel(String(c.menuName ?? c.routerName ?? c.routeUrl ?? c.id ?? ""));
if (ACCOUNT_LABELS.has(cl)) accountMenus.push(c);
else moduleMenus.push(c);
}
continue;
}
if (ACCOUNT_LABELS.has(label)) {
accountMenus.push(n);
continue;
}
moduleMenus.push(n);
}
return { moduleMenus, accountMenus };
}, [remoteMenuNodes]);
return (
{hasRemoteMenus ? (
<>
MODULES
{moduleMenus.map((n) => (
))}
MANAGEMENT
{accountMenus.map((n) => (
))}
>
) : (
fallbackMenuItems.map((item, index) => {
if (item.type === 'header') {
return (
{item.name}
);
}
if (item.type === 'sub') {
const Icon = item.icon;
return (
{item.isOpen && (
{item.children?.map((child, childIndex) => (
))}
)}
);
}
const Icon = item.icon;
return (
);
}))}
);
}