"use client"; import { useEffect, useState } from "react"; import SamShell from "../components/SamShell"; import { apiGet, apiPost, apiPut, AUTO_TYPES, parseJSON, useMisCursos, type Asignacion, type Pregunta, type Template } from "../lib/mis"; import { useSession } from "../lib/session"; type Fase = "seleccion" | "rindiendo" | "resultado"; export default function Rendir() { const { user } = useSession(); const { cursos } = useMisCursos(); const [templates, setTemplates] = useState([]); const [asignaciones, setAsignaciones] = useState<(Asignacion & { cursoNombre: string })[]>([]); const [asignacionId, setAsignacionId] = useState(""); const [preguntas, setPreguntas] = useState([]); const [respuestas, setRespuestas] = useState>({}); const [rendicionId, setRendicionId] = useState(""); const [fase, setFase] = useState("seleccion"); const [nota, setNota] = useState<{ ob: number; mx: number; ap: boolean } | null>(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); useEffect(() => { apiGet("/templates").then(setTemplates).catch(() => {}); }, []); useEffect(() => { if (!user || cursos.length === 0) return; (async () => { const todas: (Asignacion & { cursoNombre: string })[] = []; for (const c of cursos) { try { const as: Asignacion[] = await apiGet(`/asignaciones?origen=${user.origen}&idCursos=${c.idCursos}`); as.forEach((a) => todas.push({ ...a, cursoNombre: c.nombreCurso })); } catch { /* sin asignaciones */ } } setAsignaciones(todas); })(); }, [user, cursos]); const asig = asignaciones.find((a) => a.id === asignacionId); const tpl = templates.find((t) => t.id === asig?.templateId); async function iniciar(e: React.FormEvent) { e.preventDefault(); setError(""); if (!user || !asig || !tpl) return; setLoading(true); try { const r = await apiPost("/rendiciones/iniciar", { asignacionId, idAlumno: user.idAlumno, respuestas: "[]" }); setRendicionId(r.id); setPreguntas(await apiGet(`/templates/${tpl.id}/preguntas`)); setRespuestas({}); setFase("rindiendo"); } catch (err: any) { setError(err.message); } finally { setLoading(false); } } function esCorrecta(p: Pregunta, val: string): boolean | null { if (p.tipoPregunta === "multiple-choice") { return val !== "" && Number(val) === Number(parseJSON(p.respuestaCorrecta)); } if (p.tipoPregunta === "true-false") { const exp = parseJSON(p.respuestaCorrecta); return val !== "" && (val === "true") === (exp === true || exp === "true"); } if (p.tipoPregunta === "short-answer") { const exp = (parseJSON(p.respuestaCorrecta) ?? p.respuestaCorrecta ?? "").toString().trim().toLowerCase(); return val.trim() !== "" && val.trim().toLowerCase() === exp; } return null; } async function entregar() { setError(""); const auto = preguntas.filter((p) => AUTO_TYPES.includes(p.tipoPregunta)); let ob = 0; const mx = auto.reduce((s, p) => s + p.puntaje, 0); const detalle = preguntas.map((p) => { const v = respuestas[p.id] ?? ""; const c = esCorrecta(p, v); if (c === true) ob += p.puntaje; return { preguntaId: p.id, tipo: p.tipoPregunta, respuesta: v, correcta: c }; }); try { await apiPut(`/rendiciones/${rendicionId}/cerrar`, { puntajeObtenido: ob, puntajeMaximo: mx, respuestas: JSON.stringify(detalle) }); const umbral = tpl?.puntajeAprobacion ?? 70; setNota({ ob, mx, ap: mx > 0 ? ob >= (mx * umbral) / 100 : true }); setFase("resultado"); } catch (err: any) { setError(err.message); } } function renderPregunta(p: Pregunta) { const v = respuestas[p.id] ?? ""; const set = (val: string) => setRespuestas({ ...respuestas, [p.id]: val }); if (p.tipoPregunta === "multiple-choice") { const opts = (parseJSON(p.opciones) as string[]) ?? []; return (
{opts.map((o, idx) => (
set(String(idx))} />
))}
); } if (p.tipoPregunta === "true-false") { return (
{(["true", "false"] as const).map((b) => (
set(b)} />
))}
); } if (p.tipoPregunta === "short-answer") { return set(e.target.value)} placeholder="Tu respuesta" />; } return