Files
SIG-CM2.0/src/web/src/router.tsx
dmolinari 2e2d4543ad feat(web): router wiring completo + nav link usuarios + MustChangePasswordGate integration [UDT-008]
- Agrega ProtectedPage helper que combina ProtectedRoute + MustChangePasswordGate + ProtectedLayout
- Rutas nuevas: /usuarios, /usuarios/:id, /usuarios/:id/editar con permisos RBAC
- /perfil/contrasena sin MustChangePasswordGate (evita redirect loop)
- Sidebar: sección "Mi cuenta" con cambio de contraseña; link Usuarios en sección admin
2026-04-15 18:12:54 -03:00

161 lines
4.5 KiB
TypeScript

import { Navigate, Route, Routes } from 'react-router-dom'
import { useAuthStore } from './stores/authStore'
import { ProtectedRoute } from './components/routing/ProtectedRoute'
import { MustChangePasswordGate } from './components/routing/MustChangePasswordGate'
import { LoginPage } from './features/auth/pages/LoginPage'
import { CreateUserPage } from './features/users/pages/CreateUserPage'
import { UsersListPage } from './features/users/pages/UsersListPage'
import { UserDetailPage } from './features/users/pages/UserDetailPage'
import { UserEditPage } from './features/users/pages/UserEditPage'
import { ChangeMyPasswordPage } from './features/profile/pages/ChangeMyPasswordPage'
import { RolesPage } from './features/roles/pages/RolesPage'
import { NewRolPage } from './features/roles/pages/NewRolPage'
import { EditRolPage } from './features/roles/pages/EditRolPage'
import { RolPermisosPage } from './features/permisos/pages/RolPermisosPage'
import { HomePage } from './pages/HomePage'
import { PublicLayout } from './layouts/PublicLayout'
import { ProtectedLayout } from './layouts/ProtectedLayout'
function PublicRoute({ children }: { children: React.ReactNode }) {
const user = useAuthStore((s) => s.user)
if (user) {
return <Navigate to="/" replace />
}
return <>{children}</>
}
/**
* Wraps a protected route with ProtectedLayout + MustChangePasswordGate.
* The gate forces users with mustChangePassword=true to /perfil/contrasena.
*/
function ProtectedPage({
children,
requiredPermissions,
}: {
children: React.ReactNode
requiredPermissions?: string[]
}) {
return (
<ProtectedRoute requiredPermissions={requiredPermissions}>
<MustChangePasswordGate>
<ProtectedLayout>{children}</ProtectedLayout>
</MustChangePasswordGate>
</ProtectedRoute>
)
}
export function AppRoutes() {
return (
<Routes>
{/* Public routes */}
<Route
path="/login"
element={
<PublicRoute>
<PublicLayout>
<LoginPage />
</PublicLayout>
</PublicRoute>
}
/>
{/* Change password — protected but NO MustChangePasswordGate (avoids redirect loop) */}
<Route
path="/perfil/contrasena"
element={
<ProtectedRoute>
<ProtectedLayout>
<ChangeMyPasswordPage />
</ProtectedLayout>
</ProtectedRoute>
}
/>
{/* Protected routes — all wrapped with MustChangePasswordGate */}
<Route
path="/"
element={<ProtectedPage><HomePage /></ProtectedPage>}
/>
<Route
path="/usuarios"
element={
<ProtectedPage requiredPermissions={['administracion:usuarios:gestionar']}>
<UsersListPage />
</ProtectedPage>
}
/>
<Route
path="/usuarios/nuevo"
element={
<ProtectedPage requiredPermissions={['administracion:usuarios:gestionar']}>
<CreateUserPage />
</ProtectedPage>
}
/>
<Route
path="/usuarios/:id"
element={
<ProtectedPage requiredPermissions={['administracion:usuarios:gestionar']}>
<UserDetailPage />
</ProtectedPage>
}
/>
<Route
path="/usuarios/:id/editar"
element={
<ProtectedPage requiredPermissions={['administracion:usuarios:gestionar']}>
<UserEditPage />
</ProtectedPage>
}
/>
<Route
path="/admin/roles"
element={
<ProtectedPage requiredPermissions={['administracion:roles:gestionar']}>
<RolesPage />
</ProtectedPage>
}
/>
<Route
path="/admin/roles/nuevo"
element={
<ProtectedPage requiredPermissions={['administracion:roles:gestionar']}>
<NewRolPage />
</ProtectedPage>
}
/>
<Route
path="/admin/roles/:codigo/editar"
element={
<ProtectedPage requiredPermissions={['administracion:roles:gestionar']}>
<EditRolPage />
</ProtectedPage>
}
/>
<Route
path="/admin/permisos"
element={
<ProtectedPage
requiredPermissions={[
'administracion:roles_permisos:gestionar',
'administracion:permisos:ver',
]}
>
<RolPermisosPage />
</ProtectedPage>
}
/>
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
)
}