204 lines
5.7 KiB
TypeScript
204 lines
5.7 KiB
TypeScript
import { lazy, Suspense, useEffect } from 'react'
|
|
import { createRouter, createRootRoute, createRoute, redirect, Outlet, useNavigate, useRouterState } from '@tanstack/react-router'
|
|
import { WorkspacePageWithBoundary } from '@/features/workspace/WorkspacePage'
|
|
import { ImportPage } from '@/features/import/ImportPage'
|
|
import { LibraryPage } from '@/features/library/LibraryPage'
|
|
import { SettingsPage } from '@/features/settings/SettingsPage'
|
|
import { ResourceCatalogPage } from '@/features/resources/ResourceCatalogPage'
|
|
import { LoginPage } from '@/features/login/LoginPage'
|
|
import { ResetPasswordPage } from '@/features/auth/ResetPasswordPage'
|
|
import { ConfirmInvitePage } from '@/features/auth/ConfirmInvitePage'
|
|
import { AdminLayout } from '@/features/admin/AdminLayout'
|
|
import { OrganizationsPage } from '@/features/admin/OrganizationsPage'
|
|
import { OrganizationDetailPage } from '@/features/admin/OrganizationDetailPage'
|
|
import { UsersPage } from '@/features/admin/UsersPage'
|
|
import { useAuth } from '@/auth/AuthContext'
|
|
import { Loader2 } from 'lucide-react'
|
|
|
|
const ReportPage = lazy(() =>
|
|
import('@/features/report/ReportPage').then((m) => ({ default: m.ReportPage }))
|
|
)
|
|
|
|
function ReportPageWithSuspense() {
|
|
return (
|
|
<Suspense fallback={
|
|
<div className="min-h-screen flex flex-col items-center justify-center gap-3 bg-slate-50">
|
|
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
|
<p className="text-sm text-slate-400">Cargando reporte…</p>
|
|
</div>
|
|
}>
|
|
<ReportPage />
|
|
</Suspense>
|
|
)
|
|
}
|
|
|
|
const PUBLIC_PATHS = ['/login', '/reset-password', '/auth/confirm']
|
|
|
|
function RootComponent() {
|
|
const { user, loading, pendingPasswordReset } = useAuth()
|
|
const navigate = useNavigate()
|
|
const pathname = useRouterState({ select: (s) => s.location.pathname })
|
|
|
|
useEffect(() => {
|
|
if (loading) return
|
|
// Usuario con PASSWORD_RECOVERY activo → forzar /reset-password
|
|
if (user && pendingPasswordReset && pathname !== '/reset-password') {
|
|
void navigate({ to: '/reset-password' })
|
|
return
|
|
}
|
|
if (!user && !PUBLIC_PATHS.includes(pathname)) {
|
|
void navigate({ to: '/login' })
|
|
} else if (user && !pendingPasswordReset && pathname === '/login') {
|
|
void navigate({ to: '/' })
|
|
}
|
|
}, [user, loading, pathname, navigate, pendingPasswordReset])
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center">
|
|
<Loader2 className="h-8 w-8 animate-spin" style={{ color: '#F59845' }} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (!user && !PUBLIC_PATHS.includes(pathname)) return (
|
|
<div className="min-h-screen flex items-center justify-center">
|
|
<Loader2 className="h-8 w-8 animate-spin" style={{ color: '#F59845' }} />
|
|
</div>
|
|
)
|
|
|
|
return <Outlet />
|
|
}
|
|
|
|
// Redirect /admin → /admin/organizations
|
|
function AdminIndexRedirect() {
|
|
const navigate = useNavigate()
|
|
useEffect(() => { void navigate({ to: '/admin/organizations' }) }, [navigate])
|
|
return null
|
|
}
|
|
|
|
const rootRoute = createRootRoute({ component: RootComponent })
|
|
|
|
const loginRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: '/login',
|
|
component: LoginPage,
|
|
})
|
|
|
|
const resetPasswordRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: '/reset-password',
|
|
component: ResetPasswordPage,
|
|
})
|
|
|
|
const confirmInviteRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: '/auth/confirm',
|
|
component: ConfirmInvitePage,
|
|
})
|
|
|
|
const indexRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: '/',
|
|
component: LibraryPage,
|
|
})
|
|
|
|
const libraryRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: '/library',
|
|
component: LibraryPage,
|
|
})
|
|
|
|
const importRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: '/import',
|
|
component: ImportPage,
|
|
})
|
|
|
|
const workspaceRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: '/workspace/$processId',
|
|
component: WorkspacePageWithBoundary,
|
|
})
|
|
|
|
const reportRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: '/report/$processId',
|
|
component: ReportPageWithSuspense,
|
|
})
|
|
|
|
const settingsRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: '/settings',
|
|
component: SettingsPage,
|
|
beforeLoad: ({ context }) => {
|
|
const role = (context as { auth?: { user?: { platformRole?: string } } }).auth?.user?.platformRole
|
|
if (role === 'client_editor' || role === 'client_viewer') {
|
|
throw redirect({ to: '/library' })
|
|
}
|
|
},
|
|
})
|
|
|
|
const resourcesRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: '/recursos',
|
|
component: ResourceCatalogPage,
|
|
})
|
|
|
|
// ─── Admin routes (guard de platform_admin en AdminLayout) ────────────────────
|
|
|
|
const adminLayoutRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
path: '/admin',
|
|
component: AdminLayout,
|
|
})
|
|
|
|
const adminIndexRoute = createRoute({
|
|
getParentRoute: () => adminLayoutRoute,
|
|
path: '/',
|
|
component: AdminIndexRedirect,
|
|
})
|
|
|
|
const adminOrgsRoute = createRoute({
|
|
getParentRoute: () => adminLayoutRoute,
|
|
path: '/organizations',
|
|
component: OrganizationsPage,
|
|
})
|
|
|
|
const adminOrgDetailRoute = createRoute({
|
|
getParentRoute: () => adminLayoutRoute,
|
|
path: '/organizations/$orgId',
|
|
component: OrganizationDetailPage,
|
|
})
|
|
|
|
const adminUsersRoute = createRoute({
|
|
getParentRoute: () => adminLayoutRoute,
|
|
path: '/users',
|
|
component: UsersPage,
|
|
})
|
|
|
|
const routeTree = rootRoute.addChildren([
|
|
loginRoute,
|
|
resetPasswordRoute,
|
|
confirmInviteRoute,
|
|
indexRoute,
|
|
libraryRoute,
|
|
importRoute,
|
|
workspaceRoute,
|
|
reportRoute,
|
|
settingsRoute,
|
|
resourcesRoute,
|
|
adminLayoutRoute.addChildren([
|
|
adminIndexRoute,
|
|
adminOrgsRoute,
|
|
adminOrgDetailRoute,
|
|
adminUsersRoute,
|
|
]),
|
|
])
|
|
|
|
export const router = createRouter({ routeTree })
|
|
|
|
declare module '@tanstack/react-router' {
|
|
interface Register { router: typeof router }
|
|
}
|