import { useEffect, useMemo } from "react"; import { useQuery } from "@tanstack/react-query"; import { Navigate, Outlet, Route, Routes, useLocation, useNavigate, useParams, } from "react-router-dom"; import { FreightDashboardLayout, type SidebarItem } from "@/components/layout"; import { api } from "@/services/api"; 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 WagonCancellationsPage from "./pages/bookings/WagonCancellationsPage"; 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 ShippingLineCompaniesPage from "./pages/shipping-lines/ShippingLineCompaniesPage"; import ShippingLineCreditsPage from "./pages/shipping-lines/ShippingLineCreditsPage"; import InvoiceDetailPage from "./pages/invoices/InvoiceDetailPage"; import FinanceHubPage from "./pages/invoices/FinanceHubPage"; import MyProfilePage from "./pages/dashboard/MyProfilePage"; import OverviewPage from "./pages/dashboard/OverviewPage"; import OverviewDomainPage from "./pages/dashboard/OverviewDomainPage"; import { OVERVIEW_DOMAINS } from "./components/overview/overview-domains.config"; import ReportsIndexRedirect from "./pages/reports/ReportsIndexRedirect"; import ReportPage from "./pages/reports/ReportPage"; import AuditLogsPage from "./pages/AuditLogsPage"; import AiBookingMockTestPage from "./pages/ai/AiBookingMockTestPage"; //import EmployeesPage from "./pages/dashboard/user-management/EmployeesPage"; import { RequirePermission } from "./components/auth/RequirePermission"; import { FREIGHT_PERMS } from "./lib/permissions"; import { NO_ACCESS_PATH, resolveLandingPath } from "./lib/landing"; import NoAccessPage from "./pages/NoAccessPage"; import FileUploadSettingsPage from "./pages/documents/FileUploadSettingsPage"; import DropdownSettingsPage from "./pages/dropdown_settings/DropdownSettingsPage"; import CompanyStampSettingsPage from "./pages/settings/CompanyStampSettingsPage"; import LogoSettingsPage from "./pages/settings/LogoSettingsPage"; import ContractTemplatesPage from "./pages/contract_templates/ContractTemplatesPage"; import PortalContentPage from "./pages/portal_content/PortalContentPage"; 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 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 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 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"; import { APP_TITLE, buildSidebarSections, filterSidebarByPermission, findActiveSidebarLabel, } from "@/components/layout/sidebar-sections"; /** * The per-shipment clearance detail page is the shared destination of three * hubs (Operations → Clearance, Clearance Documents, Self-Clearance Review), * none of which are gated on `bookings:clearance_view`. Gating the detail on * that key alone bounced reviewers back to their landing page (Bookings) the * moment they opened a row, so accept any key that can reach a hub. */ const CLEARANCE_DETAIL_PERMS = [ FREIGHT_PERMS.bookings.clearanceView, FREIGHT_PERMS.contracts.clearanceReview, FREIGHT_PERMS.contracts.clearanceEtActions, FREIGHT_PERMS.contracts.opsClearanceReview, ]; const DashboardShell = () => { const navigate = useNavigate(); const location = useLocation(); const { user, logout } = useAuth(); const demoItems: SidebarItem[] = []; const { data: reportCatalog } = useQuery(api.reports.catalog.queryOptions()); const reportItems: SidebarItem[] = useMemo( () => (reportCatalog ?? []).map((report) => ({ label: report.title, href: `/dashboard/reports/${report.key}`, })), [reportCatalog], ); const sidebarSections = filterSidebarByPermission( buildSidebarSections(demoItems, reportItems), user, ); const displayName = user?.name?.en || user?.username || user?.email || "User"; useEffect(() => { const activeLabel = findActiveSidebarLabel( location.pathname, sidebarSections, ); document.title = activeLabel ? `${activeLabel} | ${APP_TITLE}` : APP_TITLE; }, [location.pathname, sidebarSections]); return ( ); }; const App = () => { const { user, loading } = useAuth(); if (loading) { return ; } if (!user) { return ( } /> } /> {/* } /> */} } /> } /> } /> ); } const landingPath = resolveLandingPath(user); return ( {UserManagementRoutes()} {/* } /> */} } /> } /> } /> {/* Landing is per-user: /dashboard/overview is gated on overview:view, so a fixed target strands anyone without that key on a blank page. */} } /> } /> }> } /> {/* One drill-down route per overview domain — the old per-tab charts, now each on its own page. Single source of truth for the permission gate is OVERVIEW_DOMAINS, shared with the summary page's "View all" links. */} {OVERVIEW_DOMAINS.map((domain) => ( } /> ))} } /> } /> } /> {/* Dev/testing page for the mock AI booking assistant. */} } /> } /> } /> {/* Payments used to be its own page; it's now the "payments" tab on the merged Invoices hub. Old bookmarks/links still land there. */} } /> } /> } /> } /> {/* Merged Invoices / Payments / USD Payments hub — tabs switch via ?tab=invoices|payments|usd-payments (default invoices). Access is OR'd across both keys so a user with just one still gets in; each tab hides itself if the user lacks the permission it used to be routed on. */} } /> } /> } /> } /> } /> } /> } /> } /> } /> {/* Legacy booking-based clearance URLs → the contract clearance hub. */} } /> } /> {/* Contracts (Path A/B) */} } /> } /> } /> } /> } /> } /> {/* Operations hub: clearance documents for non-customs contracts — Contracts tab (contract-level) + General tab (per-booking). */} } /> } /> {/* GL (Path B) contract clearance review hub */} } /> } /> } /> } /> } /> } /> {/* Path A — Operations reviews per-booking self-clearance documents (GENERAL contracts without customs). */} } /> } /> {/* Completion of an initiated (bare) instance after per-booking clearance — same form, submits to the complete endpoint. */} } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> {/* Legacy embedded user management routes */} {/* } /> } /> } /> */} {/* } /> */} {/* } /> } /> */} } /> } /> {/* The ONE company stamp, for every generated document. The per-officer teeter (ማህተም) that used to sit beside it at /dashboard/stamp-settings now lives at /user-management/teeter-and-signature — it is a different thing (an individual's approval stamp), and pairing the two here was the duplication. */} } /> {/* Old URL kept alive so existing links/bookmarks do not 404. */} } /> {/* The ONE company logo, shown in the header of every generated document. */} } /> } /> } /> } /> } /> } /> } />
} /> {/* } /> */} } /> } /> } /> } /> } /> } /> } /> } /> } /> {/* Post-login landing: the browser is still on /auth, which matches nothing here, so this is what actually decides where users start. */} } />
); }; /** Redirect removed milestones page to document clearance. */ function BookingMilestonesRedirect() { const { id } = useParams(); return ; } /** Redirect legacy GL Ethiopia clearance URLs to the unified document clearance hub. */ function LegacyGlEthiopiaClearanceRedirect() { const { id } = useParams(); if (id) { return ; } return ; } export default App;