- 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
161 lines
4.5 KiB
TypeScript
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>
|
|
)
|
|
}
|