feat: mis cursos agrupados por plan de estudios
This commit is contained in:
1 parent
e6d283e184
commit
2232ff2763
2 files changed
+46
-19
No files matched your search
@@ -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
@@ -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>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in new issue
Block a user