feat: mis cursos agrupados por plan de estudios

This commit is contained in:
Nurfog committed 2026-09-28 13:35:38 -03:00
1 parent e6d283e184
commit 2232ff2763
2 files changed
+46 -19

No files matched your search

+7
View File
@@ -41,6 +41,13 @@ export interface Curso {
nombreCurso: string; nombreCurso: string;
nivelCurso?: number; nivelCurso?: number;
duracion?: number; duracion?: number;
idPlanDeEstudios?: number;
planNombre?: string;
}
export interface Plan {
idPlanDeEstudios: number;
nombre: string;
nCursos: number;
} }
export interface Alumno { export interface Alumno {
idAlumno: string; idAlumno: string;
+39 -19
View File
@@ -1,12 +1,13 @@
"use client"; "use client";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import SamShell from "./components/SamShell"; import SamShell from "./components/SamShell";
import { apiGet, nombreCompleto, useMisCursos, type Asignacion, type Template } from "./lib/mis"; import { apiGet, nombreCompleto, useMisCursos, type Asignacion, type Curso, type Template } from "./lib/mis";
import { useSession } from "./lib/session"; import { useSession } from "./lib/session";
export default function Home() { export default function Home() {
const { user } = useSession(); const { user } = useSession();
const [templates, setTemplates] = useState<Template[]>([]); const [templates, setTemplates] = useState<Template[]>([]);
const [cursosTodos, setCursosTodos] = useState<Curso[]>([]);
const [asignaciones, setAsignaciones] = useState<Record<number, Asignacion[]>>({}); const [asignaciones, setAsignaciones] = useState<Record<number, Asignacion[]>>({});
const { cursos, loading, error } = useMisCursos(); const { cursos, loading, error } = useMisCursos();
@@ -14,6 +15,13 @@ export default function Home() {
apiGet("/templates").then(setTemplates).catch(() => {}); apiGet("/templates").then(setTemplates).catch(() => {});
}, []); }, []);
useEffect(() => {
if (!user) return;
apiGet(`/cursos/${user.origen === "SAM" ? "sam" : "empresa"}`)
.then(setCursosTodos)
.catch(() => {});
}, [user]);
useEffect(() => { useEffect(() => {
if (!user || cursos.length === 0) return; if (!user || cursos.length === 0) return;
cursos.forEach((c) => { cursos.forEach((c) => {
@@ -24,31 +32,43 @@ export default function Home() {
}, [user, cursos]); }, [user, cursos]);
const tplNombre = (id: string) => templates.find((t) => t.id === id)?.nombre ?? "Prueba"; const tplNombre = (id: string) => templates.find((t) => t.id === id)?.nombre ?? "Prueba";
const planDe = (id: number) => cursosTodos.find((c) => c.idCursos === id)?.planNombre ?? "Otros";
const total = Object.values(asignaciones).reduce((s, as) => s + as.length, 0); const total = Object.values(asignaciones).reduce((s, as) => s + as.length, 0);
const grupos = new Map<string, typeof cursos>();
cursos.forEach((c) => {
const p = planDe(c.idCursos);
if (!grupos.has(p)) grupos.set(p, []);
grupos.get(p)!.push(c);
});
return ( return (
<SamShell title="Mis cursos" subtitle={user ? `${nombreCompleto(user)} · ${user.origen === "SAM" ? "Plan central" : "Empresas"}` : ""} icon="bx-home" activeHref="/"> <SamShell title="Mis cursos" subtitle={user ? `${nombreCompleto(user)} · ${user.origen === "SAM" ? "Plan central" : "Empresas"}` : ""} icon="bx-home" activeHref="/">
{loading && <div className="spinner-border" role="status" />} {loading && <div className="spinner-border" role="status" />}
{error && <div className="alert alert-danger">{error}</div>} {error && <div className="alert alert-danger">{error}</div>}
<div className="row row-cards"> {[...grupos.entries()].map(([plan, cs]) => (
{cursos.map((c) => ( <div key={plan} className="mb-3">
<div className="col-md-6" key={c.idCursos}> <div className="section-header mb-2"><i className="bx bx-book me-1" /> {plan} <span className="badge bg-light text-dark">{cs.length}</span></div>
<div className="app-card p-3 h-100"> <div className="row row-cards">
<h6><i className="bx bx-book me-1" /> {c.nombreCurso}</h6> {cs.map((c) => (
{(asignaciones[c.idCursos] ?? []).length === 0 ? ( <div className="col-md-6" key={c.idCursos}>
<p className="text-muted mb-0">Sin pruebas asignadas por ahora.</p> <div className="app-card p-3 h-100">
) : ( <h6>{c.nombreCurso}</h6>
<ul className="mb-2"> {(asignaciones[c.idCursos] ?? []).length === 0 ? (
{(asignaciones[c.idCursos] ?? []).map((a) => ( <p className="text-muted mb-0">Sin pruebas asignadas por ahora.</p>
<li key={a.id}>{tplNombre(a.templateId)}</li> ) : (
))} <ul className="mb-2">
</ul> {(asignaciones[c.idCursos] ?? []).map((a) => (
)} <li key={a.id}>{tplNombre(a.templateId)}</li>
<a href="/rendir" className="btn btn-success btn-sm">Rendir</a> ))}
</div> </ul>
)}
<a href="/rendir" className="btn btn-success btn-sm">Rendir</a>
</div>
</div>
))}
</div> </div>
))} </div>
</div> ))}
{cursos.length > 0 && ( {cursos.length > 0 && (
<p className="text-muted">Tienes {total} prueba(s) asignada(s) en {cursos.length} curso(s) con matrícula activa.</p> <p className="text-muted">Tienes {total} prueba(s) asignada(s) en {cursos.length} curso(s) con matrícula activa.</p>
)} )}