mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
- Updated API documentation and summaries to reflect support for both USD and ETB invoices. - Modified data structures to include trade direction for invoices. - Adjusted UI components to accommodate manual payment confirmations and display relevant information. - Implemented filtering options for currency in the manual payments worklist.
1223 lines
41 KiB
TypeScript
1223 lines
41 KiB
TypeScript
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 (
|
|
<FreightDashboardLayout
|
|
sidebarSections={sidebarSections}
|
|
activeHref={location.pathname}
|
|
onNavigate={navigate}
|
|
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>
|
|
);
|
|
}
|
|
|
|
const landingPath = resolveLandingPath(user);
|
|
|
|
return (
|
|
<Routes>
|
|
{UserManagementRoutes()}
|
|
{/* <Route path="/um/*" element={<UserManagementHostPage />} /> */}
|
|
<Route path="/health" element={<HealthCheck />} />
|
|
<Route path="/fayda/callback" element={<FaydaCallbackPage />} />
|
|
<Route path={NO_ACCESS_PATH} element={<NoAccessPage />} />
|
|
{/* Landing is per-user: /dashboard/overview is gated on overview:view, so
|
|
a fixed target strands anyone without that key on a blank page. */}
|
|
<Route path="/" element={<Navigate to={landingPath} replace />} />
|
|
<Route
|
|
path="/dashboard"
|
|
element={<Navigate to={landingPath} replace />}
|
|
/>
|
|
<Route path="/dashboard" element={<DashboardShell />}>
|
|
<Route
|
|
path="overview"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.overview.view}>
|
|
<OverviewPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
{/* 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) => (
|
|
<Route
|
|
key={domain.key}
|
|
path={`overview/${domain.key}`}
|
|
element={
|
|
<RequirePermission permission={domain.permission}>
|
|
<OverviewDomainPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
))}
|
|
<Route
|
|
path="reports"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.reports.view}>
|
|
<ReportsIndexRedirect />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="reports/:reportKey"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.reports.view}>
|
|
<ReportPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="audit-logs"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.auditLog.view}>
|
|
<AuditLogsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
{/* Dev/testing page for the mock AI booking assistant. */}
|
|
<Route
|
|
path="ai-booking-mock-test"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.bookings.view}>
|
|
<AiBookingMockTestPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route path="profile" element={<MyProfilePage />} />
|
|
|
|
<Route
|
|
path="booking-requests"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.bookings.view}>
|
|
<BookingRequestsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
{/* Payments used to be its own page; it's now the "payments" tab on
|
|
the merged Invoices hub. Old bookmarks/links still land there. */}
|
|
<Route
|
|
path="payments"
|
|
element={<Navigate to="/dashboard/invoices?tab=payments" replace />}
|
|
/>
|
|
<Route
|
|
path="support"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.support.agentView}>
|
|
<SupportInboxPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<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>
|
|
}
|
|
/>
|
|
{/* Merged Invoices / Payments / USD Payments hub — tabs switch via
|
|
?tab=invoices|payments|manual-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. */}
|
|
<Route
|
|
path="shipping-lines"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.shippingLines.view}>
|
|
<ShippingLineCompaniesPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="shipping-line-credits"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.shippingLineCredits.view}
|
|
>
|
|
<ShippingLineCreditsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="invoices"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.invoices.view,
|
|
FREIGHT_PERMS.payments.view,
|
|
]}
|
|
>
|
|
<FinanceHubPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="usd-payments"
|
|
element={<Navigate to="/dashboard/invoices?tab=manual-payments" replace />}
|
|
/>
|
|
<Route
|
|
path="invoices/:id"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.invoices.view}>
|
|
<InvoiceDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="booking-requests/new"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.bookings.view}>
|
|
<NewBookingPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="wagon-cancellations"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.bookings.wagonCancellationView}
|
|
>
|
|
<WagonCancellationsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="booking-requests/:id"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.bookings.view}>
|
|
<BookingRequestDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="booking-requests/:id/contract"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.bookings.view}>
|
|
<BookingContractPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
{/* 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={CLEARANCE_DETAIL_PERMS}>
|
|
<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={CLEARANCE_DETAIL_PERMS}>
|
|
<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={
|
|
<RequirePermission permission={FREIGHT_PERMS.warehouses.view}>
|
|
<WarehouseListPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="warehouses/:id"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.warehouses.view}>
|
|
<WarehouseDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="warehouse-inventory"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<WarehouseInventoryPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="import-warehouse"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<ImportWarehouseFlowPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="export-warehouse"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<ExportWarehouseFlowPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="arrival-queue"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<ArrivalQueuePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="loading-queue"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<LoadingQueuePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="intercity"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<IntercityPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="trucks-on-site"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<TrucksOnSitePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="import-trucks"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<ImportTrucksPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="container-returns"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<ContainerReturnsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="loaded-inventory"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<LoadedInventoryPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="dispatch-queue"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<DispatchQueuePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="export-djibouti-unloading"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<ExportDjiboutiUnloadingQueuePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="interchange-documents"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.interchangeDocuments.view}
|
|
>
|
|
<InterchangeDocumentsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="inventory-inquiry"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseInventory.view}
|
|
>
|
|
<InventoryInquiryPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="warehouse-rules"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.warehouseAllocationRules.view,
|
|
FREIGHT_PERMS.warehouseFeeRules.view,
|
|
]}
|
|
>
|
|
<WarehouseRulesPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="warehouse-fee-invoices"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseFeeInvoices.view}
|
|
>
|
|
<WarehouseInvoicesPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="warehouse-dashboard"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.warehouseDashboard.view}
|
|
>
|
|
<WarehouseDashboardPage />
|
|
</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/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}>
|
|
<RoutesPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="locomotives"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.locomotives.view}>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="trains"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trains.view}>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="trains/:id"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trains.view}>
|
|
<TrainDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="train-builder"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trains.view}>
|
|
<TrainBuilderListPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="train-builder/:id"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.trains.view}>
|
|
<TrainBuilderDetailPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="wagons"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.wagons.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}>
|
|
<FleetResourcePage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="cargoes"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.cargoes.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="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.compliance.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.procurement.view}>
|
|
<ProcurementPage />
|
|
</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.settings.fileUpload.view}
|
|
>
|
|
<FileUploadSettingsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="dropdown-settings"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.settings.dropdown.view}
|
|
>
|
|
<DropdownSettingsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
{/*
|
|
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.
|
|
*/}
|
|
<Route
|
|
path="stamp-settings"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.settings.stamp.view}>
|
|
<CompanyStampSettingsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
{/* Old URL kept alive so existing links/bookmarks do not 404. */}
|
|
<Route
|
|
path="invoice-stamp-settings"
|
|
element={<Navigate to="/dashboard/stamp-settings" replace />}
|
|
/>
|
|
{/* The ONE company logo, shown in the header of every generated document. */}
|
|
<Route
|
|
path="logo-settings"
|
|
element={
|
|
<RequirePermission permission={FREIGHT_PERMS.settings.logo.view}>
|
|
<LogoSettingsPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="contract-templates"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.settings.contractTemplates.view}
|
|
>
|
|
<ContractTemplatesPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="contract-templates/:code"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.settings.contractTemplates.view}
|
|
>
|
|
<ContractTemplateEditorPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="portal-content"
|
|
element={
|
|
<RequirePermission
|
|
permission={[
|
|
FREIGHT_PERMS.settings.supportContent.view,
|
|
FREIGHT_PERMS.settings.supportContent.manage,
|
|
]}
|
|
>
|
|
<PortalContentPage />
|
|
</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.tradeAccess.view}>
|
|
<TradeAccessPage />
|
|
</RequirePermission>
|
|
}
|
|
/>
|
|
<Route
|
|
path="configuration/exchange-rate"
|
|
element={
|
|
<RequirePermission
|
|
permission={FREIGHT_PERMS.settings.exchangeRate.view}
|
|
>
|
|
<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>
|
|
|
|
{/* Post-login landing: the browser is still on /auth, which matches
|
|
nothing here, so this is what actually decides where users start. */}
|
|
<Route path="*" element={<Navigate to={landingPath} 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;
|