@@ -786,6 +954,7 @@ export default function OrdersPage() {
+ {/* Customize dialog */}
{openCustomize && (
>
);
-}
+}
\ No newline at end of file
diff --git a/src/app/component/layout/AppShell.tsx b/src/app/component/layout/AppShell.tsx
index 9d7cb34..bdf9fdc 100644
--- a/src/app/component/layout/AppShell.tsx
+++ b/src/app/component/layout/AppShell.tsx
@@ -1,17 +1,78 @@
+// src/app/component/layout/AppShell.tsx
"use client";
import { ReactNode, useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import type { UserSession } from "@/types/auth";
+import type { NavItem as ServerNavItem, IconKey } from "@/lib/nav";
-type NavItem = { label: string; href: string; icon?: React.ReactNode; match?: RegExp };
-type Props = { user: UserSession; nav: NavItem[]; children: ReactNode };
+import type { LucideIcon } from "lucide-react";
+import {
+ // groups
+ Home, Settings, Megaphone, Warehouse as WarehouseIcon, Wrench, ShoppingCart,
+ Bell, BarChart3, CircleDollarSign,
+ // pages/common
+ LayoutDashboard, Users, UserRound, PhoneCall, MessageSquare, Headset,
+ BookOpen, Newspaper, Bot,
+ // sales & catalog
+ Package, Boxes, Tag, FileText, Repeat,
+ // services
+ CalendarClock, Route, Calendar, UserCog, ClipboardList, Timer, FileSignature, Box, BadgeCheck,
+ // procurement & warehouse
+ Store, Inbox, Truck, ClipboardCheck,
+ // marketing
+ BadgePercent, Gift,
+ // finance
+ Receipt, CreditCard, Calculator, PiggyBank, ListChecks,
+ // admin/integrations
+ PlugZap, Webhook, KeyRound, FileSearch, Building2, Activity, CodeSquare, Smile,
+ // chrome
+ Menu, PanelLeftOpen, PanelLeftClose,
+} from "lucide-react";
+
+type Props = {
+ user: UserSession;
+ nav: ServerNavItem[];
+ children: ReactNode; // <<<< เพิ่ม children ลงใน Props
+};
+
+// map string key -> actual Lucide icon
+const ICONS: Record
= {
+ // groups
+ home: Home, sales: ShoppingCart, services: Wrench, procurement: Store, warehouse: WarehouseIcon,
+ support: Headset, marketing: Megaphone, finance: CircleDollarSign, analytics: BarChart3, admin: Settings,
+ // common
+ dashboard: LayoutDashboard, myTasks: ClipboardCheck, notifications: Bell,
+ // sales & catalog
+ customers: Users, contacts: UserRound, leads: PhoneCall, orders: ShoppingCart, quotes: FileText,
+ subscriptions: Repeat, products: Package, bundles: Boxes, pricing: Tag, returns: Repeat,
+ // services
+ serviceCatalog: Tag, servicePricing: Tag, serviceOrders: Wrench, dispatchBoard: Route,
+ schedule: Calendar, resources: UserCog, projects: ClipboardList, timesheets: Timer,
+ contracts: FileSignature, installedBase: Box, warrantyClaims: BadgeCheck,
+ // procurement & warehouse
+ suppliers: Store, purchaseOrders: ClipboardCheck, grn: Inbox,
+ inventory: Boxes, receiving: Inbox, picking: ClipboardList, packing: Package, shipments: Truck,
+ // support & knowledge
+ tickets: MessageSquare, sla: Timer, csat: Smile, aiChat: Bot, knowledgeBase: BookOpen,
+ // marketing
+ campaigns: Megaphone, coupons: BadgePercent, loyalty: Gift, news: Newspaper, pages: FileText,
+ // finance
+ invoices: Receipt, payments: CreditCard, refunds: Repeat, generalLedger: PiggyBank, reconciliation: ListChecks,
+ // analytics
+ reports: BarChart3, dashboards: LayoutDashboard,
+ // admin & system
+ users: Users, rolesPermissions: UserCog, tenants: Building2, settings: Settings,
+ flashExpress: Truck, tiktokShop: PlugZap, psp: CreditCard, webhooks: Webhook, apiKeys: KeyRound,
+ compliance: CircleDollarSign, documents: FileText, eSign: FileSignature, auditTrail: FileSearch,
+ systemHealth: Activity, logs: ListChecks, developerSandbox: CodeSquare,
+ // misc
+ kms: BookOpen, chat: Bot,
+};
export default function AppShell({ user, nav, children }: Props) {
- // เดสก์ท็อป: พับ/กางไซด์บาร์
const [sidebarOpen, setSidebarOpen] = useState(true);
- // มือถือ: เปิด/ปิด drawer
const [mobileOpen, setMobileOpen] = useState(false);
const pathname = usePathname();
@@ -23,23 +84,23 @@ export default function AppShell({ user, nav, children }: Props) {
}, [user?.email]);
const year = new Date().getFullYear();
- const isActive = (item: NavItem): boolean =>
- Boolean((item.match && item.match.test(pathname)) || pathname === item.href);
- // ปิด drawer อัตโนมัติเมื่อเปลี่ยนหน้า
- useEffect(() => {
- setMobileOpen(false);
- }, [pathname]);
+ const isActive = (item: ServerNavItem): boolean => {
+ if (item.match) {
+ try { return new RegExp(item.match).test(pathname); }
+ catch { return pathname.startsWith(item.match); }
+ }
+ return pathname === item.href;
+ };
+
+ useEffect(() => { setMobileOpen(false); }, [pathname]);
- // ล็อกสกอลล์หน้าเมื่อ drawer เปิด (กันเลื่อนพื้นหลัง)
useEffect(() => {
const el = document.documentElement;
if (mobileOpen) {
const prev = el.style.overflow;
el.style.overflow = "hidden";
- return () => {
- el.style.overflow = prev;
- };
+ return () => { el.style.overflow = prev; };
}
}, [mobileOpen]);
@@ -75,10 +136,7 @@ export default function AppShell({ user, nav, children }: Props) {
{/* Tenant pill */}
@@ -94,6 +152,7 @@ export default function AppShell({ user, nav, children }: Props) {