style: sidebar improvmetn

This commit is contained in:
ghost2023
2026-07-17 11:15:58 +03:00
parent f769d97135
commit bd81bbfc2c
3 changed files with 237 additions and 231 deletions

View File

@@ -18,6 +18,7 @@ import {
Send, Send,
Settings, Settings,
ShieldCheck, ShieldCheck,
Settings2,
Ship, Ship,
SlidersHorizontal, SlidersHorizontal,
Train, Train,
@@ -142,14 +143,9 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
icon: <LayoutDashboard />, icon: <LayoutDashboard />,
}, },
{ {
label: "Staff", label: "Customers",
href: "/user-management", href: "/dashboard/customers",
icon: <Users />, icon: <Building2 />,
},
{
label: "Bookings",
href: "/dashboard/booking-requests",
icon: <FileText />,
}, },
{ {
label: "Contracts", label: "Contracts",
@@ -157,6 +153,11 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
icon: <FileSignature />, icon: <FileSignature />,
permission: FREIGHT_PERMS.contracts.view, permission: FREIGHT_PERMS.contracts.view,
}, },
{
label: "Bookings",
href: "/dashboard/booking-requests",
icon: <FileText />,
},
// Operations hub: clearance-document review for contracts WITHOUT // Operations hub: clearance-document review for contracts WITHOUT
// customs clearing (contract-level for one-time, per-booking for general). // customs clearing (contract-level for one-time, per-booking for general).
{ {
@@ -165,11 +166,6 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
icon: <ShieldCheck />, icon: <ShieldCheck />,
permission: FREIGHT_PERMS.contracts.opsClearanceReview, permission: FREIGHT_PERMS.contracts.opsClearanceReview,
}, },
{
label: "Customers",
href: "/dashboard/customers",
icon: <Building2 />,
},
{ {
label: "Payments", label: "Payments",
href: "/dashboard/payments", href: "/dashboard/payments",
@@ -186,183 +182,185 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
], ],
}, },
{ {
title: "Operations", // title: "Port & Terminal",
items: [ items: [
{ {
label: "Clearance", label: "Operations",
href: "/dashboard/contracts/clearance", icon: <Settings />,
icon: <ShieldCheck />, children: [
permission: [ {
FREIGHT_PERMS.contracts.clearanceReview, label: "Clearance",
FREIGHT_PERMS.contracts.clearanceEtActions, href: "/dashboard/contracts/clearance",
icon: <ShieldCheck />,
permission: [
FREIGHT_PERMS.contracts.clearanceReview,
FREIGHT_PERMS.contracts.clearanceEtActions,
],
},
{
label: "Shipment Requests",
href: "/dashboard/shipment-requests",
icon: <Send />,
permission: FREIGHT_PERMS.contracts.createBooking,
},
// Operations Path A queue: per-booking self-clearance review for
// GENERAL non-customs booking instances (and legacy self-clear bookings).
{
label: "Self-Clearance Review",
href: "/dashboard/contracts/ops-clearance",
icon: <ShieldCheck />,
permission: FREIGHT_PERMS.contracts.opsClearanceReview,
},
{
label: "GL Djibouti Clearance",
href: "/dashboard/gl-djibouti/clearance",
icon: <Ship />,
permission: FREIGHT_PERMS.contracts.clearanceDjActions,
},
{
label: "Train Schedules",
href: "/dashboard/operations/train-scheduling-v2",
icon: <Train />,
permission: FREIGHT_PERMS.trainScheduling.view,
},
{
label: "Batch Board",
href: "/dashboard/operations/batch-board",
icon: <LayoutGrid />,
permission: FREIGHT_PERMS.trainScheduling.view,
},
{
label: "First Mile",
href: "/dashboard/operations/first-mile",
icon: <Truck />,
permission: FREIGHT_PERMS.firstMile.view,
},
{
label: "Last Mile",
href: "/dashboard/operations/last-mile",
icon: <Truck />,
permission: FREIGHT_PERMS.lastMile.view,
},
], ],
}, },
{ {
label: "Shipment Requests", label: "Fleet Management",
href: "/dashboard/shipment-requests",
icon: <Send />,
permission: FREIGHT_PERMS.contracts.createBooking,
},
// Operations Path A queue: per-booking self-clearance review for
// GENERAL non-customs booking instances (and legacy self-clear bookings).
{
label: "Self-Clearance Review",
href: "/dashboard/contracts/ops-clearance",
icon: <ShieldCheck />,
permission: FREIGHT_PERMS.contracts.opsClearanceReview,
},
{
label: "GL Djibouti Clearance",
href: "/dashboard/gl-djibouti/clearance",
icon: <Ship />,
permission: FREIGHT_PERMS.contracts.clearanceDjActions,
},
{
label: "Train Schedules",
href: "/dashboard/operations/train-scheduling-v2",
icon: <Train />,
permission: FREIGHT_PERMS.trainScheduling.view,
},
{
label: "Batch Board",
href: "/dashboard/operations/batch-board",
icon: <LayoutGrid />,
permission: FREIGHT_PERMS.trainScheduling.view,
},
{
label: "First Mile",
href: "/dashboard/operations/first-mile",
icon: <Truck />, icon: <Truck />,
permission: FREIGHT_PERMS.firstMile.view, children: [
}, {
{ label: "Fleet Dashboard",
label: "Last Mile", href: "/dashboard/fleet-dashboard",
href: "/dashboard/operations/last-mile", icon: <LayoutDashboard />,
icon: <Truck />, permission: FREIGHT_PERMS.fleetDashboard.view,
permission: FREIGHT_PERMS.lastMile.view, },
}, {
], label: "Routes",
}, href: "/dashboard/routes",
{ icon: <Network />,
title: "Fleet Management", permission: FREIGHT_PERMS.fleet.view,
items: [ },
{ {
label: "Fleet Dashboard", label: "Locomotives",
href: "/dashboard/fleet-dashboard", href: "/dashboard/locomotives",
icon: <LayoutDashboard />, icon: <Train />,
permission: FREIGHT_PERMS.fleetDashboard.view, permission: FREIGHT_PERMS.fleet.view,
}, },
{ {
label: "Routes", label: "Train Builder",
href: "/dashboard/routes", href: "/dashboard/train-builder",
icon: <Network />, icon: <Hammer />,
permission: FREIGHT_PERMS.fleet.view, permission: FREIGHT_PERMS.fleet.view,
}, },
{
label: "Locomotives",
href: "/dashboard/locomotives",
icon: <Train />,
permission: FREIGHT_PERMS.fleet.view,
},
{
label: "Train Builder",
href: "/dashboard/train-builder",
icon: <Hammer />,
permission: FREIGHT_PERMS.fleet.view,
},
// { // {
// label: "Wagon types", // label: "Wagon types",
// href: "/dashboard/wagon-types", // href: "/dashboard/wagon-types",
// icon: <Boxes />, // icon: <Boxes />,
// }, // },
{ {
label: "Wagons", label: "Wagons",
href: "/dashboard/wagons", href: "/dashboard/wagons",
icon: <Truck />, icon: <Truck />,
permission: FREIGHT_PERMS.fleet.view, permission: FREIGHT_PERMS.fleet.view,
},
{
label: "Vehicles",
href: "/dashboard/vehicles",
icon: <Truck />,
permission: FREIGHT_PERMS.vehicles.view,
},
{
label: "Drivers",
href: "/dashboard/drivers",
icon: <Users />,
permission: FREIGHT_PERMS.drivers.view,
},
{
label: "Track Vehicles",
href: "/dashboard/tracking",
icon: <MapPin />,
permission: FREIGHT_PERMS.tracking.view,
},
{
label: "Fuel Purchases",
href: "/dashboard/fuel-purchases",
icon: <Truck />,
permission: FREIGHT_PERMS.fuel.view,
},
{
label: "Fuel Analytics",
href: "/dashboard/fuel-stats",
icon: <Truck />,
permission: FREIGHT_PERMS.fuel.view,
},
{
label: "Maintenance",
href: "/dashboard/maintenance",
icon: <Truck />,
permission: FREIGHT_PERMS.maintenance.view,
},
{
label: "Work Orders",
href: "/dashboard/work-orders",
icon: <SlidersHorizontal />,
permission: FREIGHT_PERMS.maintenance.view,
},
{
label: "Compliance & Alerts",
href: "/dashboard/compliance",
icon: <ShieldCheck />,
permission: FREIGHT_PERMS.fleet.view,
},
{
label: "Incidents",
href: "/dashboard/incidents",
icon: <FileText />,
permission: FREIGHT_PERMS.fleet.view,
},
{
label: "Procurement",
href: "/dashboard/procurement",
icon: <Package />,
permission: FREIGHT_PERMS.fleet.view,
},
{
label: "Financial Reports",
href: "/dashboard/financial-reports",
icon: <Wallet />,
permission: FREIGHT_PERMS.fleetReports.view,
},
// {
// label: "Containers",
// href: "/dashboard/containers",
// icon: <Container />,
// },
// {
// label: "Cargoes",
// href: "/dashboard/cargoes",
// icon: <Package />,
// },
],
}, },
{
label: "Vehicles",
href: "/dashboard/vehicles",
icon: <Truck />,
permission: FREIGHT_PERMS.vehicles.view,
},
{
label: "Drivers",
href: "/dashboard/drivers",
icon: <Users />,
permission: FREIGHT_PERMS.drivers.view,
},
{
label: "Track Vehicles",
href: "/dashboard/tracking",
icon: <MapPin />,
permission: FREIGHT_PERMS.tracking.view,
},
{
label: "Fuel Purchases",
href: "/dashboard/fuel-purchases",
icon: <Truck />,
permission: FREIGHT_PERMS.fuel.view,
},
{
label: "Fuel Analytics",
href: "/dashboard/fuel-stats",
icon: <Truck />,
permission: FREIGHT_PERMS.fuel.view,
},
{
label: "Maintenance",
href: "/dashboard/maintenance",
icon: <Truck />,
permission: FREIGHT_PERMS.maintenance.view,
},
{
label: "Work Orders",
href: "/dashboard/work-orders",
icon: <SlidersHorizontal />,
permission: FREIGHT_PERMS.maintenance.view,
},
{
label: "Compliance & Alerts",
href: "/dashboard/compliance",
icon: <ShieldCheck />,
permission: FREIGHT_PERMS.fleet.view,
},
{
label: "Incidents",
href: "/dashboard/incidents",
icon: <FileText />,
permission: FREIGHT_PERMS.fleet.view,
},
{
label: "Procurement",
href: "/dashboard/procurement",
icon: <Package />,
permission: FREIGHT_PERMS.fleet.view,
},
{
label: "Financial Reports",
href: "/dashboard/financial-reports",
icon: <Wallet />,
permission: FREIGHT_PERMS.fleetReports.view,
},
// {
// label: "Containers",
// href: "/dashboard/containers",
// icon: <Container />,
// },
// {
// label: "Cargoes",
// href: "/dashboard/cargoes",
// icon: <Package />,
// },
],
},
{
title: "Port & Terminal",
items: [
{ {
label: "Imports", label: "Imports",
href: "/dashboard/import-warehouse", href: "/dashboard/import-warehouse",
@@ -437,35 +435,37 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
}, },
], ],
}, },
],
},
{
title: "Warehouse Management",
items: [
{ {
label: "Warehouse Dashboard", label: "Warehouse Management",
href: "/dashboard/warehouse-dashboard",
icon: <LayoutDashboard />,
},
{
label: "Warehouses",
href: "/dashboard/warehouses",
icon: <Container />, icon: <Container />,
}, children: [
{ {
label: "Allocation & Fees", label: "Warehouse Dashboard",
href: "/dashboard/warehouse-rules", href: "/dashboard/warehouse-dashboard",
icon: <SlidersHorizontal />, icon: <LayoutDashboard />,
}, },
{ {
label: "Fee Invoices", label: "Warehouses",
href: "/dashboard/warehouse-fee-invoices", href: "/dashboard/warehouses",
icon: <Wallet />, icon: <Container />,
},
{
label: "Allocation & Fees",
href: "/dashboard/warehouse-rules",
icon: <SlidersHorizontal />,
},
{
label: "Fee Invoices",
href: "/dashboard/warehouse-fee-invoices",
icon: <Wallet />,
},
],
}, },
], ],
}, },
{ {
title: "Administration", title: "Freight configuration",
mutedTitle: true,
items: [ items: [
{ {
label: "File settings", label: "File settings",
@@ -485,12 +485,6 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
icon: <ScrollText />, icon: <ScrollText />,
permission: FREIGHT_PERMS.admin, permission: FREIGHT_PERMS.admin,
}, },
],
},
{
title: "Freight configuration",
mutedTitle: true,
items: [
{ {
label: "Configuration", label: "Configuration",
href: "/dashboard/configuration", href: "/dashboard/configuration",
@@ -513,6 +507,12 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
icon: <SlidersHorizontal />, icon: <SlidersHorizontal />,
children: getCategorySidebarChildren("rules"), children: getCategorySidebarChildren("rules"),
}, },
{
label: "Staff",
href: "/user-management",
icon: <Users />,
},
], ],
}, },
]; ];
@@ -599,7 +599,10 @@ const findActiveSidebarLabel = (
): string | undefined => { ): string | undefined => {
const path = pathname.toLowerCase(); const path = pathname.toLowerCase();
const candidates = flattenSidebarItems(sections) const candidates = flattenSidebarItems(sections)
.map(({ href, label }) => ({ label, href: href.split("?")[0].toLowerCase() })) .map(({ href, label }) => ({
label,
href: href.split("?")[0].toLowerCase(),
}))
.sort((a, b) => b.href.length - a.href.length); .sort((a, b) => b.href.length - a.href.length);
return candidates.find( return candidates.find(
@@ -674,10 +677,7 @@ const App = () => {
<Routes> <Routes>
<Route path="/auth" element={<LoginPage />} /> <Route path="/auth" element={<LoginPage />} />
{/* <Route path="/um/*" element={<UserManagementHostPage />} /> */} {/* <Route path="/um/*" element={<UserManagementHostPage />} /> */}
<Route <Route path="um/set-password" element={<SetPassword />} />
path="um/set-password"
element={<SetPassword />}
/>
<Route path="/callback" element={<FaydaCallbackPage />} /> <Route path="/callback" element={<FaydaCallbackPage />} />
<Route path="*" element={<Navigate to="/auth" replace />} /> <Route path="*" element={<Navigate to="/auth" replace />} />
</Routes> </Routes>

View File

@@ -92,7 +92,9 @@ const FreightSidebar = ({
walk(item.children, key); walk(item.children, key);
}); });
}; };
sections.forEach((section) => walk(section.items, section.title)); sections.forEach((section, i) =>
walk(section.items, section?.title ?? "" + i++),
);
return acc; return acc;
}, [sections, isHrefActive, branchActive]); }, [sections, isHrefActive, branchActive]);
@@ -126,6 +128,7 @@ const FreightSidebar = ({
opened={isOpen} opened={isOpen}
classNames={navClassNames(active)} classNames={navClassNames(active)}
onClick={() => toggle(key)} onClick={() => toggle(key)}
childrenOffset="sm"
rightSection={ rightSection={
<Box <Box
component="span" component="span"
@@ -142,7 +145,7 @@ const FreightSidebar = ({
size={16} size={16}
className="text-edr-muted transition-transform duration-200" className="text-edr-muted transition-transform duration-200"
style={{ style={{
transform: isOpen ? "rotate(-180deg)" : "rotate(180deg)", transform: isOpen ? "rotate(-180deg)" : "rotate(0deg)",
}} }}
/> />
</Box> </Box>
@@ -166,6 +169,7 @@ const FreightSidebar = ({
active={active} active={active}
component={Link} component={Link}
classNames={navClassNames(active)} classNames={navClassNames(active)}
onClick={onClose}
to={item.href!} to={item.href!}
/> />
); );
@@ -177,19 +181,21 @@ const FreightSidebar = ({
() => () =>
sections.map((section) => ( sections.map((section) => (
<Box key={section.title}> <Box key={section.title}>
<Text {section.title && (
size="xs" <Text
tt="uppercase" size="xs"
px="sm" tt="uppercase"
mb={6} px="sm"
className={"text-edr-muted!"} mb={6}
style={{ fontWeight: 500, fontSize: 10, letterSpacing: "0.05em" }} className={"text-edr-muted!"}
> style={{ fontWeight: 500, fontSize: 10, letterSpacing: "0.05em" }}
{section.title} >
</Text> {section.title}
</Text>
)}
<Stack gap={2}> <Stack gap={2}>
{section.items.map((item, i) => {section.items.map((item, i) =>
renderItem(item, itemKey(section.title, item, i)), renderItem(item, itemKey(section.title ?? "" + i, item, i)),
)} )}
</Stack> </Stack>
</Box> </Box>
@@ -257,7 +263,7 @@ const FreightSidebar = ({
px="sm" px="sm"
pb="md" pb="md"
> >
<Stack gap="lg">{renderedSections}</Stack> <Stack gap="md">{renderedSections}</Stack>
</AppShell.Section> </AppShell.Section>
</AppShell.Navbar> </AppShell.Navbar>
); );

View File

@@ -12,7 +12,7 @@ export interface SidebarItem {
export interface SidebarSection { export interface SidebarSection {
/** Section label shown above a group of nav items (e.g. "Main menu"). */ /** Section label shown above a group of nav items (e.g. "Main menu"). */
title: string; title?: string;
items: SidebarItem[]; items: SidebarItem[];
/** When true, section title uses muted grey instead of dark text. */ /** When true, section title uses muted grey instead of dark text. */
mutedTitle?: boolean; mutedTitle?: boolean;