import type { ReactNode } from 'react'; import { createBrowserRouter, RouterProvider, Navigate, } from 'react-router-dom'; import { LoginPage, ForgotPasswordPage, SetPasswordPage, OTPVerificationPage, RequirePermission, LICENSE_PERMISSIONS as P, } from '@ema-platform/auth'; import { ThemeGallery } from '@ema-platform/ui'; import { AuthLayout } from '../layouts/AuthLayout'; import { BackofficeLayout } from '../layouts/BackofficeLayout'; import { ProtectedRoute } from './ProtectedRoute'; import { LandingRoute } from './LandingRoute'; import { DashboardPage } from '../features/dashboard/pages/DashboardPage'; import UserManagementPage from '../features/user-management/UserManagementPage'; import { ProfilePage } from '../features/profile/pages/ProfilePage'; import { ConfigurationPage } from '../features/configuration/pages/ConfigurationPage'; import { AnalyticsPage } from '../features/analytics/pages/AnalyticsPage'; import { ApplicationReviewPage } from '../features/applications/pages/ApplicationReviewPage'; import { MedicalVerificationPage, SeaServiceVerificationPage, } from '../features/medical-verification/pages/MedicalVerificationPage'; import { PaymentConfigPage } from '../features/payment-config/pages/PaymentConfigPage'; import { PickupDeskPage } from '../features/pickup/pages/PickupDeskPage'; import { PickupOfficesPage } from '../features/pickup/pages/PickupOfficesPage'; import { SeafarerRegistryPage } from '../features/seafarer-registry/pages/SeafarerRegistryPage'; import { SeafarerRegistrationQueuePage } from '../features/seafarer-registration-review/pages/SeafarerRegistrationQueuePage'; import { SeafarerRegistrationReviewPage } from '../features/seafarer-registration-review/pages/SeafarerRegistrationReviewPage'; import { BtcQueuePage, SeamanBookQueuePage } from '../features/seafarer-document-review/pages/SeafarerDocumentQueuePage'; import { SeafarerDocumentReviewPage } from '../features/seafarer-document-review/pages/SeafarerDocumentReviewPage'; import { QuestionPage } from '../features/question/pages/QuestionPage'; import { ExamPage } from '../features/exam/pages/ExamPage'; import { ExamDetailPage } from '../features/exam/pages/ExamDetailPage'; import { ResultPage } from '../features/result/pages/ResultPage'; import { ExamAppealsPage } from '../features/result/pages/ExamAppealsPage'; import { VesselRegistrationQueuePage } from '../features/vessel-registration/pages/VesselRegistrationQueuePage'; import { VesselRegistrationReviewPage } from '../features/vessel-registration/pages/VesselRegistrationReviewPage'; import { VesselRegistrationReportPage } from '../features/vessel-registration/pages/VesselRegistrationReportPage'; import { VesselRegistrationFormBuilderPage } from '../features/vessel-registration/pages/VesselRegistrationFormBuilderPage'; import { LicenseQueuePage } from '../features/license-review/pages/LicenseQueuePage'; import { LicenseRegisterPage } from '../features/license-register/pages/LicenseRegisterPage'; import { LicenseReviewPage } from '../features/license-review/pages/LicenseReviewPage'; import { LogisticsHeadDashboardPage } from '../features/logistics-head/pages/LogisticsHeadDashboardPage'; import { CertificateDesignerPage } from '../features/certificate-designer/pages/CertificateDesignerPage'; import { CertificateRequirementsPage } from '../features/certificate-requirements/pages/CertificateRequirementsPage'; import { BiometricEnrollmentPage } from '../features/biometric-enrollment/pages/BiometricEnrollmentPage'; /** Any-of gate shared by every licence-type queue and its review workspace. */ const APPLICATION_QUEUE = [P.VIEW_APPLICATION_QUEUE, P.VIEW_APPLICATIONS]; const BIOMETRIC_ENROLLMENT = [ P.ENROLL_BIOMETRICS, P.VIEW_BIOMETRICS, P.VIEW_SEAFARER_REGISTRY, ]; /** Route gate: same keys as the route's nav item in nav-config.ts. */ const guard = (anyOf: string[], element: ReactNode) => ( {element} ); const router = createBrowserRouter([ { element: , children: [ { path: '/login', element: }, { path: '/forgot-password', element: }, { path: '/set-password', element: }, { path: '/reset-password', element: }, { path: '/otp-verify', element: }, ], }, { path: '/um/*', element: }, // Theme visual-regression surface. Unauthenticated by design — it renders // only static primitives, so it needs no API and cannot flake. { path: '/__gallery', element: }, { path: '/', element: }, { path: '/profile-setup', element: }, { element: , children: [ { element: , children: [ { path: 'dashboard', element: }, { path: 'logistics-head-dashboard', element: guard(APPLICATION_QUEUE, ) }, { path: 'profile', element: }, { path: 'configuration', element: guard([P.VIEW_LICENSE_TYPES, P.VIEW_TEMPLATES], ) }, { path: 'analytics', element: }, { path: 'applications/:id', element: guard(APPLICATION_QUEUE, ) }, // CoC/CoP review happens in the config-driven licence queue. { path: 'coc-queue', element: }, { path: 'coc-queue/:id', element: }, // Endorsement review happens in the config-driven licence queue. // CoC and GOC endorsement now share one combined type; the two old // type queues (ENDORSEMENT_COC / ENDORSEMENT_GOC) are left routing // through the generic `:typeCode` queue below rather than redirected, // so an application filed before the switch stays reachable there. { path: 'endorsement-queue', element: }, { path: 'endorsement-queue/:id', element: }, { path: 'medical-verification', element: guard([P.VERIFY_SEAFARER_RECORDS], ) }, { path: 'sea-service-verification', element: guard([P.VERIFY_SEAFARER_RECORDS], ) }, { path: 'payment-config', element: guard([P.VIEW_PAYMENTS], ) }, { path: 'pickup-desk', element: guard([P.MANAGE_PICKUP_DESK], ) }, { path: 'pickup-offices', element: guard([P.CONFIGURE_PICKUP_OFFICES], ) }, { path: 'seafarer-registry', element: guard([P.VIEW_SEAFARER_REGISTRY], ) }, { path: 'biometric-enrollment', element: guard(BIOMETRIC_ENROLLMENT, ) }, // Seafarer registration is not a licence: own queue, own review. { path: 'seafarer-registrations', element: guard(APPLICATION_QUEUE, ) }, { path: 'seafarer-registrations/:id', element: guard(APPLICATION_QUEUE, ) }, { path: 'licence-review/type/SEAFARER_REGISTRATION', element: }, // Seaman Book and BTC are not licences: own queues, own review. { path: 'seaman-book-queue', element: guard(APPLICATION_QUEUE, ) }, { path: 'btc-queue', element: guard(APPLICATION_QUEUE, ) }, { path: 'seafarer-documents/:id', element: guard(APPLICATION_QUEUE, ) }, { path: 'licence-review/type/SEAMAN_BOOK', element: }, { path: 'licence-review/type/BTC_BASIC_TRAINING', element: }, { path: 'questions', element: guard([P.APPROVE_QUESTION, P.AUTHOR_QUESTION], ) }, { path: 'exams', element: guard([P.MANAGE_EXAMS, P.RECORD_EXAM_ATTENDANCE, P.MANAGE_EXAM_INCIDENTS, P.PUBLISH_EXAM_RESULT], ) }, { path: 'exams/:id', element: guard([P.MANAGE_EXAMS, P.RECORD_EXAM_ATTENDANCE, P.MANAGE_EXAM_INCIDENTS, P.PUBLISH_EXAM_RESULT], ) }, { path: 'exam-results', element: guard([P.RECORD_EXAM_RESULT, P.MODERATE_EXAM_RESULT, P.APPROVE_EXAM_RESULT, P.PUBLISH_EXAM_RESULT], ) }, { path: 'exam-appeals', element: guard([P.DECIDE_EXAM_APPEAL], ) }, { path: 'vessel-registration-queue', element: guard([P.VIEW_VESSEL_REGISTRY], ) }, { path: 'vessel-registration-queue/new', element: guard([P.VIEW_VESSEL_REGISTRY], ) }, // { path: 'vessel-registration-queue/:id', element: }, { path: 'vessel-registration-report', element: guard([P.VIEW_VESSEL_REGISTRY], ) }, { path: 'vessel-ownership-transfer', element: }, { path: 'vessel-ownership-transfer/:id', element: }, // Config-driven review workspace, shared by every licence type. { path: 'certificate-designer', element: guard([P.VIEW_TEMPLATES], ) }, // Form schema + document requirement authoring, shared by every licence type. { path: 'certificate-requirements', element: guard([P.VIEW_LICENSE_TYPES], ) }, { path: 'licence-review', element: guard(APPLICATION_QUEUE, ) }, { path: 'licence-register', element: guard([P.VIEW_LICENSES], ) }, // Deep link into the grid with the type facet pinned, so "Freight // Forwarder" in the nav is a filtered view rather than a page. { path: 'licence-review/type/:typeCode', element: guard(APPLICATION_QUEUE, ) }, { path: 'licence-review/:id', element: guard(APPLICATION_QUEUE, ) }, { path: 'freight-forwarder-license', element: }, { path: 'freight-forwarder-license/:id', element: }, { path: 'shipping-agent-license', element: }, { path: 'shipping-agent-license/:id', element: }, { path: 'combined-license', element: }, { path: 'combined-license/:id', element: }, { path: 'joint-investment-license', element: }, { path: 'joint-investment-license/:id', element: }, { path: 'mto-license', element: }, { path: 'mto-license/:id', element: }, // Waivers are seeded licence types, so their queue is the licence // queue filtered by type and their review is the licence review. { path: 'waiver', element: }, { path: 'waiver/:id', element: }, ], }, ], }, { path: '/404', element:
Page not found
}, { path: '*', element: }, ]); export function AppRouter() { return ; }