import type { ReactElement } from "react"; import { Navigate, Outlet, Route } from "react-router-dom"; import { useAuth } from "@/auth/useAuth"; import { NO_ACCESS_PATH, resolveLandingPath } from "@/lib/landing"; import { FREIGHT_PERMS, isSuperAdmin } from "@/lib/permissions"; import { WithPermission } from "@/shared/hooks/useHas"; import PendingExternalUsers from "@/super-admin/components/externalUsers/PendingExternalUsers"; import TemplatePage from "@/super-admin/components/templates/components/templates"; import CreatePositionPage from "./pages/position-management/create"; import EditPositionPage from "./pages/position-management/edit"; import PositionManagementPage from "./pages/position-management"; import MigratedDataManagementPage from "./pages/position-management/MigratedDataManagementPage"; import UserPositionApprovalPage from "./pages/UserPositionApprovalPage"; import ViewMigratedDataPage from "./components/MigratedRecords/ViewMigratedDataPage"; import AllRecordsPage from "./all-records/pages/AllRecordsPage"; import AllRecordDetailsPage from "./all-records/pages/AllRecordDetailsPage"; import Branding from "./web-Management/Branding/Branding"; import { AppLayout } from "./Applayout"; import ActivityLogPage from "@/pages/ActivityLogPage"; import AdminRegistrationPage from "@/pages/Organizations/AdminRegistrationPage"; import OrganizationAdminsPage from "@/pages/OrganizationAdminsPage"; import OrgAdminPermissionsPage from "@/super-admin/components/org-admins/OrgAdminPermissionsPage"; import UserProfileEditPage from "@/pages/UserProfileEditPage"; import UploadedDocumentViewPage from "@/pages/UploadedDocumentViewPage"; import EditOrganizationPage from "@/pages/Organizations/EditOrganizationPage"; import NewOrganizationPage from "@/pages/Organizations/NewOrganizationPage"; import OrganizationDetailPage from "@/pages/Organizations/OrganizationDetailPage"; import OrganizationsPage from "@/pages/Organizations/OrganizationsPage"; import DashboardPage from "@/pages/DashboardPage"; import AddSitePage from "@/pages/AddSitePage"; import SuperAdminArchivedPage from "@/pages/SuperAdminArchivedPage"; import SuperAdminArchiveUsersPage from "@/pages/SuperAdminArchiveUsersPage"; import SettingsPage from "@/pages/SettingsPage"; import OrgAdminDashboard from "@/pages/OrgAdminDashboard"; import ContentManagementPage from "@/pages/ContentManagementPage"; import BulkUploadPage from "@/pages/BulkUploadPage"; import WebManagement from "@/pages/WebManagementPage"; import ArchiveUsersPage from "@/pages/ArchiveUsersPage"; import SectorReportsPage from "@/record-management/pages/User/sectorReports"; import ArchivedUnitsPositionsPage from "@/pages/ArchivedUnitsPositionsPage"; import ConfigurationPage from "@/pages/ConfigurationPage"; import { SidebarProvider } from "@/shared/common/ui/sidebar"; import { AuthProvider as UmAuthProvider } from "@/shared/context/AuthContext"; import { PermissionProvider } from "@/shared/context/PermissionContext"; import UserManagementPage from "@/pages/UserManagementPage"; import { RequirePermission } from "@/components/auth/RequirePermission"; import UploadTeeterAndSignature from "@/record-management/components/Settings/uploadTeeterandSingature"; /** * Provider shell for the vendored IAM UI. Feeds its Auth + Permission contexts * from the real freight session so AppMenuTabs / pages see the signed-in user * and their permission keys (otherwise both are null/empty). Wraps AppLayout in * SidebarProvider (its useSidebar dependency). */ function UmShell(): ReactElement { const { user } = useAuth(); return ( ); } /** * Layout wrapper for the user-management route subtree. Self-contained (the * original vendored AppLayout was removed when the folder was re-copied and it * pulled the un-migrated @/record-management chrome). Just renders the matched * child route; swap in the real IAM shell later if desired. */ /** * Role gate for the nested super-admin / org-admin route groups. Renders child * routes via only when the user holds an allowed role (super admins * always pass); otherwise bounces to the overview. */ function PrivateRoute({ allowedRoles }: { allowedRoles: string[] }): ReactElement { const { user } = useAuth(); const roleKeys = (user?.roles ?? []) .map((r) => r.key) .filter((k): k is string => Boolean(k)); const allowed = isSuperAdmin(user) || allowedRoles.some((r) => roleKeys.includes(r)); return allowed ? : ; } export const UserManagementRedirect = () => { const { user } = useAuth(); const roles = user?.roles?.map((r) => r.key) || []; if (roles.includes("super_admin")) { return ; } if (roles.includes("admin") || roles.includes("unit_admin")) { return ; } // No IAM role: "/" resolves back here for anyone whose only sidebar entry is // Staff, so bounce to the terminal page instead of ping-ponging. return ; }; /** * Placeholder for user-management pages present in the source IAM app's route * map but not yet migrated into this backoffice. Keeps the route live and * honest instead of failing the build. See the `TODO(um-migration)` markers. */ /** * User-management route subtree. Mount inside the app's : * {UserManagementRoutes()} * Child paths are relative (RRv6 forbids absolute paths on nested routes), so * they serve at /user-management/* under the app root. */ export function UserManagementRoutes(): ReactElement { return ( } > } /> } /> } /> {/* The per-officer teeter (ማህተም) + signature upload. This is NOT the company stamp: it is the individual approval stamp a record officer applies to records, locale-aware (am/en) and genuinely per-person. It used to sit at /dashboard/stamp-settings under Settings, next to the single global company stamp, which read as duplication. Gated by settings:teeter:*, split out of settings:stamp:* when the two were untangled — settings:stamp:* now means the company stamp, so anyone who held it for the teeter needs the new key granted. */} } /> } /> } /> } /> {/* Super Admin */} } > } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> {/* Org Admin */} } > } /> } /> } // > // } /> } > } /> } > } /> } /> } /> } /> } /> } /> } /> } /> ); }