import { type ReactNode } from "react"; import OdinMark from "../components/odin/OdinMark"; export interface MenuItem { path: string; label: string; end?: boolean; permission?: string | string[]; matchPrefix?: string; matchAlso?: string[]; matchExclude?: string[]; icon: ReactNode; } export interface MenuSection { label: string; items: MenuItem[]; } export const menuSections: MenuSection[] = [ { label: "Přehled", items: [ { path: "/", label: "Přehled", end: true, icon: ( ), }, { path: "/odin", label: "Odin", permission: "ai.use", end: true, icon: , }, ], }, { label: "Docházka", items: [ { path: "/attendance", label: "Záznam", permission: "attendance.record", end: true, icon: ( ), }, { path: "/attendance/history", label: "Moje historie", permission: "attendance.history", icon: ( ), }, { path: "/attendance/requests", label: "Žádosti", permission: "attendance.record", icon: ( ), }, { path: "/attendance/approval", label: "Schvalování", permission: "attendance.approve", icon: ( ), }, { path: "/attendance/admin", label: "Správa", permission: "attendance.manage", matchPrefix: "/attendance/admin", matchAlso: ["/attendance/create", "/attendance/location"], icon: ( ), }, { path: "/attendance/balances", label: "Správa bilancí", permission: "attendance.balances", icon: ( ), }, { path: "/plan-work", label: "Plán prací", permission: ["attendance.manage", "attendance.record"], icon: ( ), }, ], }, { label: "Kniha jízd", items: [ { path: "/trips", label: "Záznam", permission: "trips.record", end: true, icon: ( ), }, { path: "/trips/history", label: "Moje historie", permission: "trips.history", icon: ( ), }, { path: "/trips/admin", label: "Správa", permission: "trips.manage", icon: ( ), }, { path: "/vehicles", label: "Vozidla", permission: "vehicles.manage", icon: ( ), }, ], }, { label: "Administrativa", items: [ { path: "/offers", label: "Nabídky", permission: "offers.view", matchPrefix: "/offers", matchExclude: ["/offers/customers", "/offers/templates"], icon: ( ), }, { path: "/orders", label: "Objednávky", permission: "orders.view", matchPrefix: "/orders", icon: ( ), }, { path: "/invoices", label: "Faktury", permission: "invoices.view", matchPrefix: "/invoices", icon: ( ), }, { path: "/projects", label: "Projekty", permission: "projects.view", matchPrefix: "/projects", icon: ( ), }, { path: "/offers/customers", label: "Zákazníci", permission: "customers.view", icon: ( ), }, ], }, { label: "Sklad", items: [ { path: "/warehouse", label: "Přehled", permission: "warehouse.view", end: true, icon: ( ), }, { path: "/warehouse/items", label: "Položky", permission: "warehouse.view", matchPrefix: "/warehouse/items", icon: ( ), }, { path: "/warehouse/receipts", label: "Příjmy", permission: "warehouse.operate", matchPrefix: "/warehouse/receipts", icon: ( ), }, { path: "/warehouse/issues", label: "Výdeje", permission: "warehouse.operate", matchPrefix: "/warehouse/issues", icon: ( ), }, { path: "/warehouse/reservations", label: "Rezervace", permission: "warehouse.operate", matchPrefix: "/warehouse/reservations", icon: ( ), }, { path: "/warehouse/inventory", label: "Inventura", permission: "warehouse.inventory", matchPrefix: "/warehouse/inventory", icon: ( ), }, { path: "/warehouse/reports", label: "Reporty", permission: "warehouse.view", end: true, icon: ( ), }, { path: "/warehouse/categories", label: "Kategorie", permission: "warehouse.manage", matchPrefix: "/warehouse/categories", icon: ( ), }, { path: "/warehouse/locations", label: "Lokace", permission: "warehouse.manage", matchPrefix: "/warehouse/locations", icon: ( ), }, { path: "/warehouse/suppliers", label: "Dodavatelé", permission: "warehouse.manage", matchPrefix: "/warehouse/suppliers", icon: ( ), }, ], }, { label: "Systém", items: [ { path: "/users", label: "Uživatelé", permission: "users.view", icon: ( ), }, { path: "/settings", label: "Nastavení", permission: [ "settings.company", "settings.banking", "settings.roles", "settings.system", "settings.templates", ], icon: ( ), }, { path: "/audit-log", label: "Audit log", permission: "settings.audit", icon: ( ), }, ], }, ]; /** Active-state matching (mirrors the original Sidebar logic, incl. matchAlso). */ export function isItemActive(item: MenuItem, pathname: string): boolean { if (item.matchPrefix) { let active = pathname.startsWith(item.matchPrefix); if (active && item.matchExclude) { active = !item.matchExclude.some((ex) => pathname.startsWith(ex)); } if (!active && item.matchAlso) { active = item.matchAlso.some((p) => pathname.startsWith(p)); } return active; } if (item.matchAlso && item.matchAlso.some((p) => pathname.startsWith(p))) { return true; } if (item.end) return pathname === item.path; return pathname.startsWith(item.path); } /** Permission check: true if no permission, or any listed permission is held. */ export function hasItemPermission( item: MenuItem, hasPermission: (p: string) => boolean, ): boolean { if (!item.permission) return true; if (Array.isArray(item.permission)) { return item.permission.some((p) => hasPermission(p)); } return hasPermission(item.permission); }