feat: implement dashboard with KPIs, recent activity, and health metrics

- Added dashboard route with loader fetching KPIs, recent plans and subjects, and health metrics.
- Created visual components for displaying KPIs and recent activity.
- Implemented gradient background and user greeting based on role.
- Added input for global search and quick links for creating new plans and subjects.

refactor: update facultad progress ring rendering

- Fixed rendering of progress ring in facultad detail view.

fix: remove unnecessary link to subjects in plan detail view

- Removed link to view subjects from the plan detail page for cleaner UI.

feat: add create plan dialog in planes route

- Introduced a dialog for creating new plans with form validation and role-based field visibility.
- Integrated Supabase for creating plans and handling user roles.

feat: enhance user management with create user dialog

- Added functionality to create new users with role and claims management.
- Implemented password generation and input handling for user creation.

fix: update login redirect to dashboard

- Changed default redirect after login from /planes to /dashboard for better user experience.
This commit is contained in:
2025-08-22 14:32:43 -06:00
parent 9727f4c691
commit ca3fed69b2
16 changed files with 2274 additions and 118 deletions

View File

@@ -16,9 +16,12 @@ import { Route as AuthenticatedUsuariosRouteImport } from './routes/_authenticat
import { Route as AuthenticatedPlanesRouteImport } from './routes/_authenticated/planes'
import { Route as AuthenticatedFacultadesRouteImport } from './routes/_authenticated/facultades'
import { Route as AuthenticatedDashboardRouteImport } from './routes/_authenticated/dashboard'
import { Route as AuthenticatedAsignaturasRouteImport } from './routes/_authenticated/asignaturas'
import { Route as AuthenticatedArchivosRouteImport } from './routes/_authenticated/archivos'
import { Route as AuthenticatedPlanPlanIdRouteImport } from './routes/_authenticated/plan/$planId'
import { Route as AuthenticatedFacultadFacultadIdRouteImport } from './routes/_authenticated/facultad/$facultadId'
import { Route as AuthenticatedAsignaturasPlanIdRouteImport } from './routes/_authenticated/asignaturas/$planId'
import { Route as AuthenticatedAsignaturaAsignaturaIdRouteImport } from './routes/_authenticated/asignatura/$asignaturaId'
const LoginRoute = LoginRouteImport.update({
id: '/login',
@@ -54,6 +57,17 @@ const AuthenticatedDashboardRoute = AuthenticatedDashboardRouteImport.update({
path: '/dashboard',
getParentRoute: () => AuthenticatedRoute,
} as any)
const AuthenticatedAsignaturasRoute =
AuthenticatedAsignaturasRouteImport.update({
id: '/asignaturas',
path: '/asignaturas',
getParentRoute: () => AuthenticatedRoute,
} as any)
const AuthenticatedArchivosRoute = AuthenticatedArchivosRouteImport.update({
id: '/archivos',
path: '/archivos',
getParentRoute: () => AuthenticatedRoute,
} as any)
const AuthenticatedPlanPlanIdRoute = AuthenticatedPlanPlanIdRouteImport.update({
id: '/plan/$planId',
path: '/plan/$planId',
@@ -67,18 +81,27 @@ const AuthenticatedFacultadFacultadIdRoute =
} as any)
const AuthenticatedAsignaturasPlanIdRoute =
AuthenticatedAsignaturasPlanIdRouteImport.update({
id: '/asignaturas/$planId',
path: '/asignaturas/$planId',
id: '/$planId',
path: '/$planId',
getParentRoute: () => AuthenticatedAsignaturasRoute,
} as any)
const AuthenticatedAsignaturaAsignaturaIdRoute =
AuthenticatedAsignaturaAsignaturaIdRouteImport.update({
id: '/asignatura/$asignaturaId',
path: '/asignatura/$asignaturaId',
getParentRoute: () => AuthenticatedRoute,
} as any)
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/login': typeof LoginRoute
'/archivos': typeof AuthenticatedArchivosRoute
'/asignaturas': typeof AuthenticatedAsignaturasRouteWithChildren
'/dashboard': typeof AuthenticatedDashboardRoute
'/facultades': typeof AuthenticatedFacultadesRoute
'/planes': typeof AuthenticatedPlanesRoute
'/usuarios': typeof AuthenticatedUsuariosRoute
'/asignatura/$asignaturaId': typeof AuthenticatedAsignaturaAsignaturaIdRoute
'/asignaturas/$planId': typeof AuthenticatedAsignaturasPlanIdRoute
'/facultad/$facultadId': typeof AuthenticatedFacultadFacultadIdRoute
'/plan/$planId': typeof AuthenticatedPlanPlanIdRoute
@@ -86,10 +109,13 @@ export interface FileRoutesByFullPath {
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/login': typeof LoginRoute
'/archivos': typeof AuthenticatedArchivosRoute
'/asignaturas': typeof AuthenticatedAsignaturasRouteWithChildren
'/dashboard': typeof AuthenticatedDashboardRoute
'/facultades': typeof AuthenticatedFacultadesRoute
'/planes': typeof AuthenticatedPlanesRoute
'/usuarios': typeof AuthenticatedUsuariosRoute
'/asignatura/$asignaturaId': typeof AuthenticatedAsignaturaAsignaturaIdRoute
'/asignaturas/$planId': typeof AuthenticatedAsignaturasPlanIdRoute
'/facultad/$facultadId': typeof AuthenticatedFacultadFacultadIdRoute
'/plan/$planId': typeof AuthenticatedPlanPlanIdRoute
@@ -99,10 +125,13 @@ export interface FileRoutesById {
'/': typeof IndexRoute
'/_authenticated': typeof AuthenticatedRouteWithChildren
'/login': typeof LoginRoute
'/_authenticated/archivos': typeof AuthenticatedArchivosRoute
'/_authenticated/asignaturas': typeof AuthenticatedAsignaturasRouteWithChildren
'/_authenticated/dashboard': typeof AuthenticatedDashboardRoute
'/_authenticated/facultades': typeof AuthenticatedFacultadesRoute
'/_authenticated/planes': typeof AuthenticatedPlanesRoute
'/_authenticated/usuarios': typeof AuthenticatedUsuariosRoute
'/_authenticated/asignatura/$asignaturaId': typeof AuthenticatedAsignaturaAsignaturaIdRoute
'/_authenticated/asignaturas/$planId': typeof AuthenticatedAsignaturasPlanIdRoute
'/_authenticated/facultad/$facultadId': typeof AuthenticatedFacultadFacultadIdRoute
'/_authenticated/plan/$planId': typeof AuthenticatedPlanPlanIdRoute
@@ -112,10 +141,13 @@ export interface FileRouteTypes {
fullPaths:
| '/'
| '/login'
| '/archivos'
| '/asignaturas'
| '/dashboard'
| '/facultades'
| '/planes'
| '/usuarios'
| '/asignatura/$asignaturaId'
| '/asignaturas/$planId'
| '/facultad/$facultadId'
| '/plan/$planId'
@@ -123,10 +155,13 @@ export interface FileRouteTypes {
to:
| '/'
| '/login'
| '/archivos'
| '/asignaturas'
| '/dashboard'
| '/facultades'
| '/planes'
| '/usuarios'
| '/asignatura/$asignaturaId'
| '/asignaturas/$planId'
| '/facultad/$facultadId'
| '/plan/$planId'
@@ -135,10 +170,13 @@ export interface FileRouteTypes {
| '/'
| '/_authenticated'
| '/login'
| '/_authenticated/archivos'
| '/_authenticated/asignaturas'
| '/_authenticated/dashboard'
| '/_authenticated/facultades'
| '/_authenticated/planes'
| '/_authenticated/usuarios'
| '/_authenticated/asignatura/$asignaturaId'
| '/_authenticated/asignaturas/$planId'
| '/_authenticated/facultad/$facultadId'
| '/_authenticated/plan/$planId'
@@ -201,6 +239,20 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AuthenticatedDashboardRouteImport
parentRoute: typeof AuthenticatedRoute
}
'/_authenticated/asignaturas': {
id: '/_authenticated/asignaturas'
path: '/asignaturas'
fullPath: '/asignaturas'
preLoaderRoute: typeof AuthenticatedAsignaturasRouteImport
parentRoute: typeof AuthenticatedRoute
}
'/_authenticated/archivos': {
id: '/_authenticated/archivos'
path: '/archivos'
fullPath: '/archivos'
preLoaderRoute: typeof AuthenticatedArchivosRouteImport
parentRoute: typeof AuthenticatedRoute
}
'/_authenticated/plan/$planId': {
id: '/_authenticated/plan/$planId'
path: '/plan/$planId'
@@ -217,30 +269,56 @@ declare module '@tanstack/react-router' {
}
'/_authenticated/asignaturas/$planId': {
id: '/_authenticated/asignaturas/$planId'
path: '/asignaturas/$planId'
path: '/$planId'
fullPath: '/asignaturas/$planId'
preLoaderRoute: typeof AuthenticatedAsignaturasPlanIdRouteImport
parentRoute: typeof AuthenticatedAsignaturasRoute
}
'/_authenticated/asignatura/$asignaturaId': {
id: '/_authenticated/asignatura/$asignaturaId'
path: '/asignatura/$asignaturaId'
fullPath: '/asignatura/$asignaturaId'
preLoaderRoute: typeof AuthenticatedAsignaturaAsignaturaIdRouteImport
parentRoute: typeof AuthenticatedRoute
}
}
}
interface AuthenticatedAsignaturasRouteChildren {
AuthenticatedAsignaturasPlanIdRoute: typeof AuthenticatedAsignaturasPlanIdRoute
}
const AuthenticatedAsignaturasRouteChildren: AuthenticatedAsignaturasRouteChildren =
{
AuthenticatedAsignaturasPlanIdRoute: AuthenticatedAsignaturasPlanIdRoute,
}
const AuthenticatedAsignaturasRouteWithChildren =
AuthenticatedAsignaturasRoute._addFileChildren(
AuthenticatedAsignaturasRouteChildren,
)
interface AuthenticatedRouteChildren {
AuthenticatedArchivosRoute: typeof AuthenticatedArchivosRoute
AuthenticatedAsignaturasRoute: typeof AuthenticatedAsignaturasRouteWithChildren
AuthenticatedDashboardRoute: typeof AuthenticatedDashboardRoute
AuthenticatedFacultadesRoute: typeof AuthenticatedFacultadesRoute
AuthenticatedPlanesRoute: typeof AuthenticatedPlanesRoute
AuthenticatedUsuariosRoute: typeof AuthenticatedUsuariosRoute
AuthenticatedAsignaturasPlanIdRoute: typeof AuthenticatedAsignaturasPlanIdRoute
AuthenticatedAsignaturaAsignaturaIdRoute: typeof AuthenticatedAsignaturaAsignaturaIdRoute
AuthenticatedFacultadFacultadIdRoute: typeof AuthenticatedFacultadFacultadIdRoute
AuthenticatedPlanPlanIdRoute: typeof AuthenticatedPlanPlanIdRoute
}
const AuthenticatedRouteChildren: AuthenticatedRouteChildren = {
AuthenticatedArchivosRoute: AuthenticatedArchivosRoute,
AuthenticatedAsignaturasRoute: AuthenticatedAsignaturasRouteWithChildren,
AuthenticatedDashboardRoute: AuthenticatedDashboardRoute,
AuthenticatedFacultadesRoute: AuthenticatedFacultadesRoute,
AuthenticatedPlanesRoute: AuthenticatedPlanesRoute,
AuthenticatedUsuariosRoute: AuthenticatedUsuariosRoute,
AuthenticatedAsignaturasPlanIdRoute: AuthenticatedAsignaturasPlanIdRoute,
AuthenticatedAsignaturaAsignaturaIdRoute:
AuthenticatedAsignaturaAsignaturaIdRoute,
AuthenticatedFacultadFacultadIdRoute: AuthenticatedFacultadFacultadIdRoute,
AuthenticatedPlanPlanIdRoute: AuthenticatedPlanPlanIdRoute,
}