mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
1722 lines
56 KiB
TypeScript
1722 lines
56 KiB
TypeScript
import {
|
|
ArrowLeftRight,
|
|
Boxes,
|
|
Building2,
|
|
BarChart3,
|
|
Container,
|
|
FileSignature,
|
|
FileText,
|
|
Hammer,
|
|
History,
|
|
LayoutDashboard,
|
|
LayoutGrid,
|
|
MapPin,
|
|
Network,
|
|
Package,
|
|
PackageCheck,
|
|
PackageOpen,
|
|
Paperclip,
|
|
Receipt,
|
|
ScrollText,
|
|
Send,
|
|
Settings,
|
|
ShieldCheck,
|
|
Ship,
|
|
SlidersHorizontal,
|
|
Train,
|
|
Truck,
|
|
Users,
|
|
Wallet,
|
|
LifeBuoy,
|
|
TrainFront,
|
|
} from "lucide-react";
|
|
import { useEffect } from "react";
|
|
import {
|
|
Navigate,
|
|
Outlet,
|
|
Route,
|
|
Routes,
|
|
useLocation,
|
|
useNavigate,
|
|
useParams,
|
|
} from "react-router-dom";
|
|
|
|
import {
|
|
FreightDashboardLayout,
|
|
type SidebarItem,
|
|
type SidebarSection,
|
|
} from "@/components/layout";
|
|
import { useAuth } from "./auth/useAuth";
|
|
import LoadingScreen from "./components/LoadingScreen";
|
|
import LoginPage from "./pages/auth/LoginPage";
|
|
import ForgotPasswordPage from "./pages/auth/ForgotPasswordPage";
|
|
import BookingContractPage from "./pages/bookings/BookingContractPage";
|
|
import BookingRequestDetailPage from "./pages/bookings/BookingRequestDetailPage";
|
|
import BookingRequestsPage from "./pages/bookings/BookingRequestsPage";
|
|
import NewBookingPage from "./pages/bookings/NewBookingPage";
|
|
import ContractRequestsPage from "./pages/contracts/ContractRequestsPage";
|
|
import ContractRequestDetailPage from "./pages/contracts/ContractRequestDetailPage";
|
|
import ContractViewPage from "./pages/contracts/ContractViewPage";
|
|
import ContractClearanceListPage from "./pages/contracts/ContractClearanceListPage";
|
|
import ContractClearanceDetailPage from "./pages/contracts/ContractClearanceDetailPage";
|
|
import ClearanceDocumentsPage from "./pages/contracts/ClearanceDocumentsPage";
|
|
import GlDjiboutiClearanceListPage from "./pages/contracts/GlDjiboutiClearanceListPage";
|
|
import GlClearanceDetailPage from "./pages/contracts/GlClearanceDetailPage";
|
|
import ShipmentRequestsPage from "./pages/contracts/ShipmentRequestsPage";
|
|
import ShipmentRequestDetailPage from "./pages/contracts/ShipmentRequestDetailPage";
|
|
import GlCreateBookingForm from "./components/contracts/GlCreateBookingForm";
|
|
import DocumentClearanceDetailPage from "./pages/bookings/DocumentClearanceDetailPage";
|
|
import DocumentClearanceListPage from "./pages/bookings/DocumentClearanceListPage";
|
|
import CustomerDetailPage from "./pages/customers/CustomerDetailPage";
|
|
import CustomersPage from "./pages/customers/CustomersPage";
|
|
import InvoiceDetailPage from "./pages/invoices/InvoiceDetailPage";
|
|
import InvoicesPage from "./pages/invoices/InvoicesPage";
|
|
import MyProfilePage from "./pages/dashboard/MyProfilePage";
|
|
import OverviewPage from "./pages/dashboard/OverviewPage";
|
|
import ReportsHubPage from "./pages/reports/ReportsHubPage";
|
|
import ReportPage from "./pages/reports/ReportPage";
|
|
import AiBookingMockTestPage from "./pages/ai/AiBookingMockTestPage";
|
|
import PaymentsPage from "./pages/payments/PaymentsPage";
|
|
import AuditLogsPage from "./pages/audit/AuditLogsPage";
|
|
//import EmployeesPage from "./pages/dashboard/user-management/EmployeesPage";
|
|
import { RequirePermission } from "./components/auth/RequirePermission";
|
|
import {
|
|
FREIGHT_PERMS,
|
|
hasPermission as hasFreightPermission,
|
|
isDjiboutiGl,
|
|
isEthiopianGl,
|
|
isSuperAdmin,
|
|
} from "./lib/permissions";
|
|
import FileUploadSettingsPage from "./pages/documents/FileUploadSettingsPage";
|
|
import DropdownSettingsPage from "./pages/dropdown_settings/DropdownSettingsPage";
|
|
import ContractTemplatesPage from "./pages/contract_templates/ContractTemplatesPage";
|
|
import ContractTemplateEditorPage from "./pages/contract_templates/ContractTemplateEditorPage";
|
|
import FleetResourcePage from "./pages/fleet/FleetResourcePage";
|
|
import WagonTransfersPage from "./pages/wagons/WagonTransfersPage";
|
|
import VehicleDetailPage from "./pages/fleet/VehicleDetailPage";
|
|
import DriverDetailPage from "./pages/fleet/DriverDetailPage";
|
|
import RoutesPage from "./pages/fleet/RoutesPage";
|
|
import FuelPurchasePage from "./pages/fleet/FuelPurchasePage";
|
|
import FuelStatsPage from "./pages/fleet/FuelStatsPage";
|
|
import { MaintenancePage } from "./pages/fleet/MaintenancePage";
|
|
import { FinancialReportsPage } from "./pages/fleet/FinancialReportsPage";
|
|
import { FleetDashboard } from "./pages/fleet/FleetDashboard";
|
|
import { TrackingPage } from "./pages/fleet/TrackingPage";
|
|
import CompliancePage from "./pages/fleet/CompliancePage";
|
|
import IncidentsPage from "./pages/fleet/IncidentsPage";
|
|
import WorkOrdersPage from "./pages/fleet/WorkOrdersPage";
|
|
import ProcurementPage from "./pages/fleet/ProcurementPage";
|
|
import { getCategorySidebarChildren } from "./pages/ruleEngine/config/resources";
|
|
import RuleEngineLegacyRedirect from "./pages/ruleEngine/RuleEngineLegacyRedirect";
|
|
import RuleEngineResourcePage from "./pages/ruleEngine/RuleEngineResourcePage";
|
|
import CargoTypesPage from "./pages/ruleEngine/CargoTypesPage";
|
|
import TrainScheduleV2ListPage from "./pages/trainScheduling/TrainScheduleV2ListPage";
|
|
import BatchBoardPage from "./pages/trainScheduling/BatchBoardPage";
|
|
import BatchScheduleDetailPage from "./pages/trainScheduling/BatchScheduleDetailPage";
|
|
import TrainScheduleV2DetailPage from "./pages/trainScheduling/TrainScheduleV2DetailPage";
|
|
import TrainScheduleTrackPage from "./pages/trainScheduling/TrainScheduleTrackPage";
|
|
import TrainSchedulingGlobalRulesPage from "./pages/trainScheduling/TrainSchedulingGlobalRulesPage";
|
|
import TradeAccessPage from "./pages/configuration/TradeAccessPage";
|
|
import ExchangeRateSettingsCard from "./pages/settings/ExchangeRateSettingsCard";
|
|
import ContractValidityPeriodsPage from "./pages/configuration/ContractValidityPeriodsPage";
|
|
import FirstMilePage from "./pages/operations/FirstMilePage";
|
|
import LastMilePage from "./pages/operations/LastMilePage";
|
|
import TrainDetailPage from "./pages/trains/TrainDetailPage";
|
|
import TrainBuilderDetailPage from "./pages/trainBuilder/TrainBuilderDetailPage";
|
|
import TrainBuilderListPage from "./pages/trainBuilder/TrainBuilderListPage";
|
|
import ArrivalQueuePage from "./pages/warehouses/ArrivalQueuePage";
|
|
import EDRLastMileReturnsPage from "./pages/warehouses/EDRLastMileReturnsPage";
|
|
import ContainerReturnsPage from "./pages/warehouses/ContainerReturnsPage";
|
|
import DispatchQueuePage from "./pages/warehouses/DispatchQueuePage";
|
|
import ExportDjiboutiUnloadingQueuePage from "./pages/warehouses/ExportDjiboutiUnloadingQueuePage";
|
|
import ExportWarehouseFlowPage from "./pages/warehouses/ExportWarehouseFlowPage";
|
|
import ImportTrucksPage from "./pages/warehouses/ImportTrucksPage";
|
|
import ImportWarehouseFlowPage from "./pages/warehouses/ImportWarehouseFlowPage";
|
|
import InterchangeDocumentsPage from "./pages/warehouses/InterchangeDocumentsPage";
|
|
import InventoryInquiryPage from "./pages/warehouses/InventoryInquiryPage";
|
|
import LoadedInventoryPage from "./pages/warehouses/LoadedInventoryPage";
|
|
import LoadingQueuePage from "./pages/warehouses/LoadingQueuePage";
|
|
import IntercityPage from "./pages/warehouses/IntercityPage";
|
|
import TrucksOnSitePage from "./pages/warehouses/TrucksOnSitePage";
|
|
import WarehouseDashboardPage from "./pages/warehouses/WarehouseDashboardPage";
|
|
import WarehouseDetailPage from "./pages/warehouses/WarehouseDetailPage";
|
|
import WarehouseInventoryPage from "./pages/warehouses/WarehouseInventoryPage";
|
|
import WarehouseInvoicesPage from "./pages/warehouses/WarehouseInvoicesPage";
|
|
import WarehouseListPage from "./pages/warehouses/WarehouseListPage";
|
|
import WarehouseRulesPage from "./pages/warehouses/WarehouseRulesPage";
|
|
import { HealthCheck } from "./features/health/HealthCheck";
|
|
import FaydaCallbackPage from "./pages/FaydaCallbackPage";
|
|
import { UserManagementRoutes } from "./user-management/route";
|
|
import SetPassword from "./shared/components/SetPassword";
|
|
import SupportInboxPage from "./pages/support/SupportInboxPage";
|
|
|
|
const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
|
|
{
|
|
title: "Main menu",
|
|
items: [
|
|
{
|
|
label: "Overview",
|
|
href: "/dashboard/overview",
|
|
icon: <LayoutDashboard />,
|
|
permission: FREIGHT_PERMS.overview.view,
|
|
},
|
|
{
|
|
label: "Reports",
|
|
href: "/dashboard/reports",
|
|
icon: <BarChart3 />,
|
|
permission: FREIGHT_PERMS.bookings.view,
|
|
},
|
|
{
|
|
label: "Customers",
|
|
href: "/dashboard/customers",
|
|
icon: <Building2 />,
|
|
permission: FREIGHT_PERMS.customers.view,
|
|
},
|
|
{
|
|
label: "Contracts",
|
|
href: "/dashboard/contract-requests",
|
|
icon: <FileSignature />,
|
|
permission: FREIGHT_PERMS.contracts.view,
|
|
},
|
|
{
|
|
label: "Bookings",
|
|
href: "/dashboard/booking-requests",
|
|
icon: <FileText />,
|
|
permission: FREIGHT_PERMS.bookings.view,
|
|
},
|
|
// Operations hub: per-shipment clearance-document review for services
|
|
// WITHOUT customs clearing (self-clearance) — bookings only.
|
|
{
|
|
label: "Clearance Documents",
|
|
href: "/dashboard/contracts/clearance-documents",
|
|
icon: <ShieldCheck />,
|
|
permission: FREIGHT_PERMS.contracts.opsClearanceReview,
|
|
},
|
|
{
|
|
label: "Payments",
|
|
href: "/dashboard/payments",
|
|
icon: <Wallet />,
|
|
permission: FREIGHT_PERMS.bookings.view,
|
|
},
|
|
{
|
|
label: "Invoices",
|
|
href: "/dashboard/invoices",
|
|
icon: <Receipt />,
|
|
permission: FREIGHT_PERMS.bookings.view,
|
|
},
|
|
{
|
|
label: "Support",
|
|
href: "/dashboard/support",
|
|
icon: <LifeBuoy />,
|
|
permission: FREIGHT_PERMS.support.view,
|
|
},
|
|
...demoItems,
|
|
],
|
|
},
|
|
{
|
|
// title: "Port & Terminal",
|
|
items: [
|
|
{
|
|
label: "Operations",
|
|
icon: <Settings />,
|
|
children: [
|
|
{
|
|
label: "Clearance",
|
|
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: "Fleet Management",
|
|
icon: <Truck />,
|
|
children: [
|
|
{
|
|
label: "Fleet Dashboard",
|
|
href: "/dashboard/fleet-dashboard",
|
|
icon: <LayoutDashboard />,
|
|
permission: FREIGHT_PERMS.fleetDashboard.view,
|
|
},
|
|
{
|
|
label: "Routes",
|
|
href: "/dashboard/routes",
|
|
icon: <Network />,
|
|
permission: [FREIGHT_PERMS.routes.view, FREIGHT_PERMS.fleet.view],
|
|
},
|
|
{
|
|
label: "Locomotives",
|
|
href: "/dashboard/locomotives",
|
|
icon: <Train />,
|
|
permission: [
|
|
FREIGHT_PERMS.locomotives.view,
|
|
FREIGHT_PERMS.fleet.view,
|
|
],
|
|
},
|
|
{
|
|
label: "Train Builder",
|
|
href: "/dashboard/train-builder",
|
|
icon: <Hammer />,
|
|
permission: [FREIGHT_PERMS.trains.view, FREIGHT_PERMS.fleet.view],
|
|
},
|
|
|
|
// {
|
|
// label: "Wagon types",
|
|
// href: "/dashboard/wagon-types",
|
|
// icon: <Boxes />,
|
|
// },
|
|
{
|
|
label: "Wagons",
|
|
href: "/dashboard/wagons",
|
|
icon: <Truck />,
|
|
permission: [FREIGHT_PERMS.wagons.view, FREIGHT_PERMS.fleet.view],
|
|
},
|
|
{
|
|
label: "Wagon Transfers",
|
|
href: "/dashboard/wagon-transfers",
|
|
icon: <ArrowLeftRight />,
|
|
permission: [
|
|
FREIGHT_PERMS.wagons.transferView,
|
|
FREIGHT_PERMS.wagons.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: "Imports",
|
|
href: "/dashboard/import-warehouse",
|
|
icon: <PackageOpen />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
children: [
|
|
{
|
|
label: "Import Overview",
|
|
href: "/dashboard/import-warehouse",
|
|
icon: <PackageOpen />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
{
|
|
label: "Arrival Queue",
|
|
href: "/dashboard/arrival-queue",
|
|
icon: <PackageOpen />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
{
|
|
label: "Import Trucks",
|
|
href: "/dashboard/import-trucks",
|
|
icon: <Truck />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
{
|
|
label: "EDR Last Mile Returns",
|
|
href: "/dashboard/edr-last-mile-returns",
|
|
icon: <Container />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
{
|
|
label: "Container Returns",
|
|
href: "/dashboard/container-returns",
|
|
icon: <Container />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
{
|
|
label: "Terminal Inventory",
|
|
href: "/dashboard/warehouse-inventory?direction=IMPORT",
|
|
icon: <Package />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
{
|
|
label: "Inventory Inquiry",
|
|
href: "/dashboard/inventory-inquiry",
|
|
icon: <Boxes />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
label: "Exports",
|
|
href: "/dashboard/export-warehouse",
|
|
icon: <Truck />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
children: [
|
|
{
|
|
label: "Export Overview",
|
|
href: "/dashboard/export-warehouse",
|
|
icon: <Truck />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
{
|
|
label: "Loading Queue",
|
|
href: "/dashboard/loading-queue",
|
|
icon: <Truck />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
{
|
|
label: "Loaded Inventory",
|
|
href: "/dashboard/loaded-inventory",
|
|
icon: <PackageCheck />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
{
|
|
label: "Dispatch Queue",
|
|
href: "/dashboard/dispatch-queue",
|
|
icon: <Send />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
{
|
|
label: "Djibouti Unloading",
|
|
href: "/dashboard/export-djibouti-unloading",
|
|
icon: <PackageOpen />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
{
|
|
label: "Interchange Documents",
|
|
href: "/dashboard/interchange-documents",
|
|
icon: <FileText />,
|
|
permission: FREIGHT_PERMS.interchangeDocuments.view,
|
|
},
|
|
{
|
|
label: "Terminal Inventory",
|
|
href: "/dashboard/warehouse-inventory?direction=EXPORT",
|
|
icon: <Package />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
label: "Intercity",
|
|
href: "/dashboard/intercity",
|
|
icon: <TrainFront />,
|
|
permission: FREIGHT_PERMS.trainScheduling.view,
|
|
children: [
|
|
{
|
|
label: "Intercity Cargo",
|
|
href: "/dashboard/intercity",
|
|
icon: <TrainFront />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
label: "Warehouse Management",
|
|
icon: <Container />,
|
|
children: [
|
|
{
|
|
label: "Warehouse Dashboard",
|
|
href: "/dashboard/warehouse-dashboard",
|
|
icon: <LayoutDashboard />,
|
|
permission: FREIGHT_PERMS.warehouseDashboard.view,
|
|
},
|
|
{
|
|
// Yard-wide, not per-direction: the gate sees import and export
|
|
// trucks at the same barrier.
|
|
label: "Trucks on Site",
|
|
href: "/dashboard/trucks-on-site",
|
|
icon: <Truck />,
|
|
permission: FREIGHT_PERMS.warehouseInventory.view,
|
|
},
|
|
{
|
|
label: "Warehouses",
|
|
href: "/dashboard/warehouses",
|
|
icon: <Container />,
|
|
permission: FREIGHT_PERMS.warehouses.view,
|
|
},
|
|
{
|
|
label: "Allocation & Fees",
|
|
href: "/dashboard/warehouse-rules",
|
|
icon: <SlidersHorizontal />,
|
|
permission: [
|
|
FREIGHT_PERMS.warehouseAllocationRules.view,
|
|
FREIGHT_PERMS.warehouseFeeRules.view,
|
|
],
|
|
},
|
|
{
|
|
label: "Fee Invoices",
|
|
href: "/dashboard/warehouse-fee-invoices",
|
|
icon: <Wallet />,
|
|
permission: FREIGHT_PERMS.warehouseFeeInvoices.view,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: "Freight configuration",
|
|
mutedTitle: true,
|
|
items: [
|
|
{
|
|
label: "File settings",
|
|
href: "/dashboard/file-settings",
|
|
icon: <Paperclip />,
|
|
permission: FREIGHT_PERMS.admin,
|
|
},
|
|
{
|
|
label: "Dropdown settings",
|
|
href: "/dashboard/dropdown-settings",
|
|
icon: <Settings />,
|
|
permission: FREIGHT_PERMS.admin,
|
|
},
|
|
{
|
|
label: "Contract templates",
|
|
href: "/dashboard/contract-templates",
|
|
icon: <ScrollText />,
|
|
permission: FREIGHT_PERMS.admin,
|
|
},
|
|
{
|
|
label: "Audit logs",
|
|
href: "/dashboard/audit-logs",
|
|
icon: <History />,
|
|
permission: FREIGHT_PERMS.audit.view,
|
|
},
|
|
{
|
|
label: "Configuration",
|
|
href: "/dashboard/configuration",
|
|
icon: <Boxes />,
|
|
children: [
|
|
...getCategorySidebarChildren("configuration"),
|
|
{
|
|
label: "Train scheduling rules",
|
|
href: "/dashboard/configuration/train-scheduling-rules",
|
|
permission: FREIGHT_PERMS.trainScheduling.rulesManage,
|
|
},
|
|
{
|
|
label: "Trade access",
|
|
href: "/dashboard/configuration/trade-access",
|
|
permission: FREIGHT_PERMS.admin,
|
|
},
|
|
{
|
|
label: "Exchange rate",
|
|
href: "/dashboard/configuration/exchange-rate",
|
|
permission: FREIGHT_PERMS.admin,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
label: "Rules",
|
|
href: "/dashboard/rules",
|
|
icon: <SlidersHorizontal />,
|
|
children: getCategorySidebarChildren("rules"),
|
|
},
|
|
|
|
{
|
|
label: "Staff",
|
|
href: "/user-management",
|
|
icon: <Users />,
|
|
permission: [
|
|
FREIGHT_PERMS.admin,
|
|
FREIGHT_PERMS.staff.roles.view,
|
|
FREIGHT_PERMS.staff.employeeRegistration.view,
|
|
FREIGHT_PERMS.staff.roleAssignment.view,
|
|
],
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
/** Hrefs of the two document-clearance menu items (stable identifiers). */
|
|
const ET_CLEARANCE_HREF = "/dashboard/contracts/clearance";
|
|
const DJ_CLEARANCE_HREF = "/dashboard/gl-djibouti/clearance";
|
|
|
|
// Routes a GL officer may reach beyond their clearance hub. Path B booking is
|
|
// part of their job (create/rebook under a cleared contract, then view that
|
|
// booking's clearance), but those routes live outside the clearance prefix —
|
|
// without this allowlist the single-prefix lock bounces them out of their own
|
|
// workflow. Matched against location.pathname (no query string).
|
|
const GL_WORKFLOW_PATH_PATTERNS: RegExp[] = [
|
|
/^\/dashboard\/contracts\/[^/]+\/create-booking(\/|$)/,
|
|
/^\/dashboard\/bookings\/[^/]+\/clearance(\/|$)/,
|
|
];
|
|
|
|
const isEtClearanceItem = (item: SidebarItem): boolean =>
|
|
item.href === ET_CLEARANCE_HREF;
|
|
const isDjClearanceItem = (item: SidebarItem): boolean =>
|
|
item.href === DJ_CLEARANCE_HREF;
|
|
const isClearanceItem = (item: SidebarItem): boolean =>
|
|
isEtClearanceItem(item) || isDjClearanceItem(item);
|
|
|
|
/**
|
|
* Keep only items the user is permitted to see; drop now-empty sections.
|
|
*
|
|
* Position-scoped visibility (super_admin sees everything):
|
|
* - Super Admin → sees all items (all permissions pass, all tabs visible)
|
|
* - Ethiopian GL → sees ONLY the ET document-clearance page.
|
|
* - Djibouti GL → sees ONLY the DJ clearance page.
|
|
* - Everyone else → sees everything they have permission for, EXCEPT the two
|
|
* clearance pages (those are GL-only).
|
|
*/
|
|
const filterSidebarByPermission = (
|
|
sections: SidebarSection[],
|
|
user: ReturnType<typeof useAuth>["user"],
|
|
): SidebarSection[] => {
|
|
// Superadmin sees every section and item — no permission filtering.
|
|
if (isSuperAdmin(user)) return sections;
|
|
|
|
const etGl = isEthiopianGl(user);
|
|
const djGl = isDjiboutiGl(user);
|
|
|
|
const permissionAllowed = (item: SidebarItem): boolean => {
|
|
if (!item.permission) return true;
|
|
const keys = Array.isArray(item.permission)
|
|
? item.permission
|
|
: [item.permission];
|
|
return keys.some((key) => hasFreightPermission(user, key));
|
|
};
|
|
|
|
// Recursive: children are filtered first; a group (item with children) stays
|
|
// only while it still has visible children — so parents without their own
|
|
// permission key never leak a whole subtree the user cannot open.
|
|
const filterItems = (items: SidebarItem[]): SidebarItem[] =>
|
|
items
|
|
.map((item) =>
|
|
item.children
|
|
? { ...item, children: filterItems(item.children) }
|
|
: item,
|
|
)
|
|
.filter((item) => {
|
|
if (etGl || djGl) {
|
|
// GL positions are locked to their single clearance page (parents
|
|
// survive only as the path to that page).
|
|
const isTarget = etGl ? isEtClearanceItem : isDjClearanceItem;
|
|
return isTarget(item) || (item.children?.length ?? 0) > 0;
|
|
}
|
|
// Everyone else: hide the GL-only clearance pages entirely.
|
|
if (isClearanceItem(item)) return false;
|
|
if (!permissionAllowed(item)) return false;
|
|
if (item.children) return item.children.length > 0;
|
|
return true;
|
|
});
|
|
|
|
return sections
|
|
.map((section) => ({
|
|
...section,
|
|
items: filterItems(section.items),
|
|
}))
|
|
.filter((section) => section.items.length > 0);
|
|
};
|
|
|
|
const APP_TITLE = "EDR Freight Backoffice";
|
|
|
|
/** Flatten sidebar sections (incl. nested children) into {href, label} pairs. */
|
|
const flattenSidebarItems = (
|
|
sections: SidebarSection[],
|
|
): { href: string; label: string }[] =>
|
|
sections.flatMap((section) =>
|
|
section.items.flatMap((item) => [
|
|
...(item.href ? [{ href: item.href, label: item.label }] : []),
|
|
...(item.children ?? [])
|
|
.filter((child): child is SidebarItem & { href: string } =>
|
|
Boolean(child.href),
|
|
)
|
|
.map((child) => ({ href: child.href, label: child.label })),
|
|
]),
|
|
);
|
|
|
|
/** Find the sidebar label whose href matches (exactly or as a prefix of) the current path. */
|
|
const findActiveSidebarLabel = (
|
|
pathname: string,
|
|
sections: SidebarSection[],
|
|
): string | undefined => {
|
|
const path = pathname.toLowerCase();
|
|
const candidates = flattenSidebarItems(sections)
|
|
.map(({ href, label }) => ({
|
|
label,
|
|
href: href.split("?")[0].toLowerCase(),
|
|
}))
|
|
.sort((a, b) => b.href.length - a.href.length);
|
|
|
|
return candidates.find(
|
|
({ href }) => path === href || path.startsWith(`${href}/`),
|
|
)?.label;
|
|
};
|
|
|
|
const DashboardShell = () => {
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
const { user, logout } = useAuth();
|
|
|
|
const demoItems: SidebarItem[] = [];
|
|
|
|
const sidebarSections = filterSidebarByPermission(
|
|
buildSidebarSections(demoItems),
|
|
user,
|
|
);
|
|
const displayName = user?.name?.en || user?.username || user?.email || "User";
|
|
|
|
// GL positions are locked to their single clearance page: if they navigate
|
|
// (or deep-link) anywhere else, send them back to their clearance hub.
|
|
// Super admin is exempt. Allow the clearance path + its detail sub-routes.
|
|
const superAdmin = isSuperAdmin(user);
|
|
const glClearanceHome = !superAdmin
|
|
? isEthiopianGl(user)
|
|
? ET_CLEARANCE_HREF
|
|
: isDjiboutiGl(user)
|
|
? DJ_CLEARANCE_HREF
|
|
: null
|
|
: null;
|
|
|
|
useEffect(() => {
|
|
const activeLabel = findActiveSidebarLabel(
|
|
location.pathname,
|
|
sidebarSections,
|
|
);
|
|
document.title = activeLabel ? `${activeLabel} | ${APP_TITLE}` : APP_TITLE;
|
|
}, [location.pathname, sidebarSections]);
|
|
|
|
if (
|
|
glClearanceHome &&
|
|
!location.pathname.startsWith(glClearanceHome) &&
|
|
!GL_WORKFLOW_PATH_PATTERNS.some((re) => re.test(location.pathname))
|
|
) {
|
|
return <Navigate to={glClearanceHome} replace />;
|
|
}
|
|
|
|
return (
|
|
<FreightDashboardLayout
|
|
sidebarSections={sidebarSections}
|
|
// GL Ethiopia / GL Djibouti are locked to a single clearance page — no
|
|
// sidebar (or mobile burger) at all; the page renders full width.
|
|
hideSidebar={Boolean(glClearanceHome)}
|
|
activeHref={location.pathname}
|
|
onNavigate={navigate}
|
|
enableThemeToggle
|
|
userName={displayName}
|
|
userEmail={user?.email}
|
|
onLogout={logout}
|
|
>
|
|
<Outlet />
|
|
</FreightDashboardLayout>
|
|
);
|
|
};
|
|
|
|
const App = () => {
|
|
const { user, loading } = useAuth();
|
|
|
|
if (loading) {
|
|
return <LoadingScreen />;
|
|
}
|
|
|
|
if (!user) {
|
|
return (
|
|
<Routes>
|
|
<Route path="/auth" element={<LoginPage />} />
|
|
<Route path="/forgot-password" element={<ForgotPasswordPage />} />
|
|
{/* <Route path="/um/*" element={<UserManagementHostPage />} /> */}
|
|
<Route path="um/set-password" element={<SetPassword />} />
|
|
<Route path="/fayda/callback" element={<FaydaCallbackPage />} />
|
|
<Route path="*" element={<Navigate to="/auth" replace />} />
|
|
</Routes>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Routes>
|
|
{UserManagementRoutes()}
|
|
{/* <Route path="/um/*" element={<UserManagementHostPage />} /> */}
|
|
<Route path="/health" element={<HealthCheck />} />
|
|
<Route path="/fayda/callback" element={<FaydaCallbackPage />} />
|
|
<Route path="/" element={<Navigate to="/dashboard/overview" replace />} />
|
|
<Route
|
|
path="/dashboard"
|
|
element={<Navigate to="/dashboard/overview" replace />}
|
|
/>
|
|
<Route path="/dashboard" element={<DashboardShell />}>
|
|
<Route path="overview" element={<OverviewPage />} />
|
|
<Route path="reports" element={<ReportsHubPage />} />
|
|
<Route path="reports/:reportKey" element={<ReportPage />} />
|
|
{/* Dev/testing page for the mock AI booking assistant. */}
|
|
<Route
|
|
path="ai-booking-mock-test"
|
|
element={<AiBookingMockTestPage />}
|
|
/>
|
|
<Route path="profile" element={<MyProfilePage />} />
|
|
|
|
<Route path="booking-requests" element={<BookingRequestsPage />} />
|
|
<Route
|
|
path="payments"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.bookings.view}>
|
|
<PaymentsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route path="support" element={<SupportInboxPage />} />
|
|
<Route
|
|
path="customers"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.customers.view}>
|
|
<CustomersPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="customers/:id"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.customers.view}>
|
|
<CustomerDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="invoices"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.bookings.view}>
|
|
<InvoicesPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="invoices/:id"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.bookings.view}>
|
|
<InvoiceDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route path="booking-requests/new" element={<NewBookingPage />} />
|
|
<Route
|
|
path="booking-requests/:id"
|
|
element={<BookingRequestDetailPage />}
|
|
/>
|
|
<Route
|
|
path="booking-requests/:id/contract"
|
|
element={<BookingContractPage />}
|
|
/>
|
|
{/* Legacy booking-based clearance URLs → the contract clearance hub. */}
|
|
<Route
|
|
path="clearance"
|
|
element={<Navigate to="/dashboard/contracts/clearance" replace />}
|
|
/>
|
|
<Route
|
|
path="clearance/:id"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.bookings.clearanceView}
|
|
>
|
|
<DocumentClearanceDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
|
|
{/* Contracts (Path A/B) */}
|
|
<Route
|
|
path="contract-requests"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.contracts.view}>
|
|
<ContractRequestsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="contract-requests/:id"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.contracts.view}>
|
|
<ContractRequestDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="contract-requests/:id/view"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.contracts.view}>
|
|
<ContractViewPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="bookings/:bookingId/clearance"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.bookings.clearanceView}
|
|
>
|
|
<DocumentClearanceDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="shipment-requests"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.contracts.createBooking}
|
|
>
|
|
<ShipmentRequestsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="shipment-requests/:id"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.contracts.createBooking}
|
|
>
|
|
<ShipmentRequestDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
{/* Operations hub: clearance documents for non-customs contracts —
|
|
Contracts tab (contract-level) + General tab (per-booking). */}
|
|
<Route
|
|
path="contracts/clearance-documents"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.contracts.opsClearanceReview}
|
|
>
|
|
<ClearanceDocumentsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="contracts/clearance-documents/:id"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.contracts.opsClearanceReview}
|
|
>
|
|
<ContractClearanceDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
{/* GL (Path B) contract clearance review hub */}
|
|
<Route
|
|
path="contracts/clearance"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.contracts.clearanceReview,
|
|
FREIGHT_PERMS.contracts.clearanceEtActions,
|
|
]}
|
|
>
|
|
<ContractClearanceListPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="contracts/clearance/:id"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.contracts.clearanceReview,
|
|
FREIGHT_PERMS.contracts.clearanceEtActions,
|
|
]}
|
|
>
|
|
<ContractClearanceDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="gl-ethiopia/clearance"
|
|
element={<LegacyGlEthiopiaClearanceRedirect />}
|
|
/>
|
|
<Route
|
|
path="gl-ethiopia/clearance/:id"
|
|
element={<LegacyGlEthiopiaClearanceRedirect />}
|
|
/>
|
|
<Route
|
|
path="gl-djibouti/clearance"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.contracts.clearanceDjActions}
|
|
>
|
|
<GlDjiboutiClearanceListPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="gl-djibouti/clearance/:id"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.contracts.clearanceDjActions}
|
|
>
|
|
<GlClearanceDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
{/* Path A — Operations reviews per-booking self-clearance documents
|
|
(GENERAL contracts without customs). */}
|
|
<Route
|
|
path="contracts/ops-clearance"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.contracts.opsClearanceReview}
|
|
>
|
|
<DocumentClearanceListPage opsMode />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="contracts/:id/create-booking"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.contracts.createBooking}
|
|
>
|
|
<GlCreateBookingForm />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
{/* Completion of an initiated (bare) instance after per-booking
|
|
clearance — same form, submits to the complete endpoint. */}
|
|
<Route
|
|
path="contracts/:id/bookings/:bookingId/complete"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.contracts.createBooking}
|
|
>
|
|
<GlCreateBookingForm />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="bookings/:id/milestones"
|
|
element={<BookingMilestonesRedirect />}
|
|
/>
|
|
<Route path="warehouses" element={<WarehouseListPage />} />
|
|
<Route path="warehouses/:id" element={<WarehouseDetailPage />} />
|
|
<Route
|
|
path="warehouse-inventory"
|
|
element={<WarehouseInventoryPage />}
|
|
/>
|
|
<Route path="import-warehouse" element={<ImportWarehouseFlowPage />} />
|
|
<Route path="export-warehouse" element={<ExportWarehouseFlowPage />} />
|
|
<Route path="arrival-queue" element={<ArrivalQueuePage />} />
|
|
<Route path="loading-queue" element={<LoadingQueuePage />} />
|
|
<Route path="intercity" element={<IntercityPage />} />
|
|
<Route path="trucks-on-site" element={<TrucksOnSitePage />} />
|
|
<Route path="import-trucks" element={<ImportTrucksPage />} />
|
|
<Route
|
|
path="edr-last-mile-returns"
|
|
element={<EDRLastMileReturnsPage />}
|
|
/>
|
|
<Route path="container-returns" element={<ContainerReturnsPage />} />
|
|
<Route path="loaded-inventory" element={<LoadedInventoryPage />} />
|
|
<Route path="dispatch-queue" element={<DispatchQueuePage />} />
|
|
<Route
|
|
path="export-djibouti-unloading"
|
|
element={<ExportDjiboutiUnloadingQueuePage />}
|
|
/>
|
|
<Route
|
|
path="interchange-documents"
|
|
element={<InterchangeDocumentsPage />}
|
|
/>
|
|
<Route path="inventory-inquiry" element={<InventoryInquiryPage />} />
|
|
<Route path="warehouse-rules" element={<WarehouseRulesPage />} />
|
|
<Route
|
|
path="warehouse-fee-invoices"
|
|
element={<WarehouseInvoicesPage />}
|
|
/>
|
|
<Route
|
|
path="warehouse-dashboard"
|
|
element={<WarehouseDashboardPage />}
|
|
/>
|
|
|
|
<Route
|
|
path="operations/train-scheduling"
|
|
element={
|
|
<Navigate to="/dashboard/operations/train-scheduling-v2" replace />
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/batch-board"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}>
|
|
<BatchBoardPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/first-mile"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.firstMile.view}>
|
|
<FirstMilePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/last-mile"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.lastMile.view}>
|
|
<LastMilePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/batch-board/:scheduleId"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}>
|
|
<BatchScheduleDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/train-scheduling-v2"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}>
|
|
<TrainScheduleV2ListPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/train-scheduling-v2/:scheduleId"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}>
|
|
<TrainScheduleV2DetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/train-scheduling-v2/:scheduleId/track"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}>
|
|
<TrainScheduleTrackPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="routes"
|
|
element={
|
|
<RequirePermission
|
|
permission={[FREIGHT_PERMS.routes.view, FREIGHT_PERMS.fleet.view]}
|
|
>
|
|
<RoutesPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="locomotives"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.locomotives.view,
|
|
FREIGHT_PERMS.fleet.view,
|
|
]}
|
|
>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="trains"
|
|
element={
|
|
<RequirePermission
|
|
permission={[FREIGHT_PERMS.trains.view, FREIGHT_PERMS.fleet.view]}
|
|
>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="trains/:id"
|
|
element={
|
|
<RequirePermission
|
|
permission={[FREIGHT_PERMS.trains.view, FREIGHT_PERMS.fleet.view]}
|
|
>
|
|
<TrainDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="train-builder"
|
|
element={
|
|
<RequirePermission
|
|
permission={[FREIGHT_PERMS.trains.view, FREIGHT_PERMS.fleet.view]}
|
|
>
|
|
<TrainBuilderListPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="train-builder/:id"
|
|
element={
|
|
<RequirePermission
|
|
permission={[FREIGHT_PERMS.trains.view, FREIGHT_PERMS.fleet.view]}
|
|
>
|
|
<TrainBuilderDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="wagons"
|
|
element={
|
|
<RequirePermission
|
|
permission={[FREIGHT_PERMS.wagons.view, FREIGHT_PERMS.fleet.view]}
|
|
>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="wagon-transfers"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.wagons.transferView,
|
|
FREIGHT_PERMS.wagons.view,
|
|
]}
|
|
>
|
|
<WagonTransfersPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="containers"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.containers.view,
|
|
FREIGHT_PERMS.fleet.view,
|
|
]}
|
|
>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="cargoes"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.cargoes.view,
|
|
FREIGHT_PERMS.fleet.view,
|
|
]}
|
|
>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="vehicles"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.vehicles.view}>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="vehicles/:id"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.vehicles.view}>
|
|
<VehicleDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="drivers"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.drivers.view}>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="drivers/:id"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.drivers.view}>
|
|
<DriverDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/train-scheduling"
|
|
element={
|
|
<Navigate to="/dashboard/operations/train-scheduling-v2" replace />
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/batch-board"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}>
|
|
<BatchBoardPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/batch-board/:scheduleId"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}>
|
|
<BatchScheduleDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/train-scheduling-v2"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}>
|
|
<TrainScheduleV2ListPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/train-scheduling-v2/:scheduleId"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}>
|
|
<TrainScheduleV2DetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="operations/train-scheduling-v2/:scheduleId/track"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}>
|
|
<TrainScheduleTrackPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="routes"
|
|
element={
|
|
<RequirePermission
|
|
permission={[FREIGHT_PERMS.routes.view, FREIGHT_PERMS.fleet.view]}
|
|
>
|
|
<RoutesPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="fuel-purchases"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.fuel.view}>
|
|
<FuelPurchasePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="fuel-stats"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.fuel.view}>
|
|
<FuelStatsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="maintenance"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.maintenance.view}>
|
|
<MaintenancePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="financial-reports"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.fleetReports.view}>
|
|
<FinancialReportsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="fleet-dashboard"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.fleetDashboard.view}>
|
|
<FleetDashboard />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="tracking"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.tracking.view}>
|
|
<TrackingPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="compliance"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.fleet.view}>
|
|
<CompliancePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="incidents"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.fleet.view}>
|
|
<IncidentsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="work-orders"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.maintenance.view}>
|
|
<WorkOrdersPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="procurement"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.fleet.view}>
|
|
<ProcurementPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="locomotives"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.locomotives.view,
|
|
FREIGHT_PERMS.fleet.view,
|
|
]}
|
|
>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="trains"
|
|
element={
|
|
<RequirePermission
|
|
permission={[FREIGHT_PERMS.trains.view, FREIGHT_PERMS.fleet.view]}
|
|
>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="trains/:id"
|
|
element={
|
|
<RequirePermission
|
|
permission={[FREIGHT_PERMS.trains.view, FREIGHT_PERMS.fleet.view]}
|
|
>
|
|
<TrainDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="train-builder"
|
|
element={
|
|
<RequirePermission
|
|
permission={[FREIGHT_PERMS.trains.view, FREIGHT_PERMS.fleet.view]}
|
|
>
|
|
<TrainBuilderListPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="train-builder/:id"
|
|
element={
|
|
<RequirePermission
|
|
permission={[FREIGHT_PERMS.trains.view, FREIGHT_PERMS.fleet.view]}
|
|
>
|
|
<TrainBuilderDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="wagons"
|
|
element={
|
|
<RequirePermission
|
|
permission={[FREIGHT_PERMS.wagons.view, FREIGHT_PERMS.fleet.view]}
|
|
>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="wagon-transfers"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.wagons.transferView,
|
|
FREIGHT_PERMS.wagons.view,
|
|
]}
|
|
>
|
|
<WagonTransfersPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="containers"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.containers.view,
|
|
FREIGHT_PERMS.fleet.view,
|
|
]}
|
|
>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="cargoes"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.cargoes.view,
|
|
FREIGHT_PERMS.fleet.view,
|
|
]}
|
|
>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
|
|
{/* Legacy embedded user management routes */}
|
|
{/* <Route path="user-management" element={<UserManagementPage />} />
|
|
<Route path="user-management/users" element={<UsersPage />} />
|
|
<Route
|
|
path="user-management/position-types"
|
|
element={<PositionTypesPage />}
|
|
/> */}
|
|
{/* <Route path="user-management/employees" element={<EmployeesPage />} /> */}
|
|
{/* <Route
|
|
path="user-management/permissions"
|
|
element={<PermissionsPage />}
|
|
/>
|
|
<Route path="user-management/roles" element={<RolesPage />} /> */}
|
|
|
|
<Route
|
|
path="file-settings"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.admin}>
|
|
<FileUploadSettingsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="dropdown-settings"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.admin}>
|
|
<DropdownSettingsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="audit-logs"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.audit.view}>
|
|
<AuditLogsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="contract-templates"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.admin}>
|
|
<ContractTemplatesPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="contract-templates/:code"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.admin}>
|
|
<ContractTemplateEditorPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
|
|
<Route
|
|
path="configuration"
|
|
element={
|
|
<Navigate to="/dashboard/configuration/cargo-types" replace />
|
|
}
|
|
/>
|
|
<Route
|
|
path="configuration/train-scheduling-rules"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}>
|
|
<TrainSchedulingGlobalRulesPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="configuration/trade-access"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.admin}>
|
|
<TradeAccessPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="configuration/exchange-rate"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.admin}>
|
|
<div className="p-4">
|
|
<ExchangeRateSettingsCard />
|
|
</div>
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
{/* <Route
|
|
path="configuration/contract-validity-periods"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.admin}>
|
|
<ContractValidityPeriodsPage />
|
|
</RequirePermission>
|
|
}
|
|
/> */}
|
|
<Route path="configuration/cargo-types" element={<CargoTypesPage />} />
|
|
<Route
|
|
path="configuration/cargo-types/:id"
|
|
element={<CargoTypesPage />}
|
|
/>
|
|
<Route
|
|
path="configuration/:resource"
|
|
element={<RuleEngineResourcePage />}
|
|
/>
|
|
|
|
<Route
|
|
path="rules"
|
|
element={<Navigate to="/dashboard/rules/priority-configs" replace />}
|
|
/>
|
|
<Route path="rules/:resource" element={<RuleEngineResourcePage />} />
|
|
|
|
<Route
|
|
path="rule-engine"
|
|
element={
|
|
<Navigate to="/dashboard/configuration/cargo-types" replace />
|
|
}
|
|
/>
|
|
<Route
|
|
path="rule-engine/:resource"
|
|
element={<RuleEngineLegacyRedirect />}
|
|
/>
|
|
<Route path="org-structure" element={<Navigate to="/um" replace />} />
|
|
<Route path="org-structure/*" element={<Navigate to="/um" replace />} />
|
|
</Route>
|
|
|
|
<Route path="*" element={<Navigate to="/dashboard/overview" replace />} />
|
|
</Routes>
|
|
);
|
|
};
|
|
|
|
/** Redirect removed milestones page to document clearance. */
|
|
function BookingMilestonesRedirect() {
|
|
const { id } = useParams();
|
|
return <Navigate to={`/dashboard/bookings/${id}/clearance`} replace />;
|
|
}
|
|
|
|
/** Redirect legacy GL Ethiopia clearance URLs to the unified document clearance hub. */
|
|
function LegacyGlEthiopiaClearanceRedirect() {
|
|
const { id } = useParams();
|
|
if (id) {
|
|
return <Navigate to={`/dashboard/contracts/clearance/${id}`} replace />;
|
|
}
|
|
return <Navigate to="/dashboard/contracts/clearance" replace />;
|
|
}
|
|
|
|
export default App;
|