141 lines
3.4 KiB
TypeScript
141 lines
3.4 KiB
TypeScript
// Cliente del backend SAM: GET /api/sam-pruebas/* (repo ICHN/sam, prod desplegado).
|
|
const API_BASE = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:5000";
|
|
const B = `${API_BASE}/api/sam-pruebas`;
|
|
|
|
async function req(path: string, init?: RequestInit) {
|
|
const r = await fetch(B + path, { cache: "no-store", ...init });
|
|
if (!r.ok) {
|
|
const t = await r.text().catch(() => "");
|
|
throw new Error(t.slice(0, 300) || `HTTP ${r.status}`);
|
|
}
|
|
if (r.status === 204) return null;
|
|
return r.json();
|
|
}
|
|
|
|
export const apiGet = (path: string) => req(path);
|
|
export const apiPost = (path: string, body: unknown) =>
|
|
req(path, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) });
|
|
export const apiPut = (path: string, body: unknown) =>
|
|
req(path, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) });
|
|
|
|
/** JSON.parse tolerante (columnas ::text que pueden venir null o malformadas). */
|
|
export function parseJSON(s: string | null | undefined): any {
|
|
if (!s) return null;
|
|
try {
|
|
return JSON.parse(s);
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export interface Creador {
|
|
idUsuario: string;
|
|
nombres: string;
|
|
apPaterno: string;
|
|
apMaterno?: string;
|
|
email: string;
|
|
tipo?: string;
|
|
}
|
|
export interface Curso {
|
|
idCursos: number;
|
|
nombreCurso: string;
|
|
nivelCurso?: number;
|
|
duracion?: number;
|
|
idPlanDeEstudios?: number;
|
|
planNombre?: string;
|
|
}
|
|
export interface Plan {
|
|
idPlanDeEstudios: number;
|
|
nombre: string;
|
|
nCursos: number;
|
|
}
|
|
export interface Alumno {
|
|
idAlumno: string;
|
|
nombres: string;
|
|
apPaterno: string;
|
|
apMaterno?: string;
|
|
email: string;
|
|
idCursoAbierto: number;
|
|
idCursos: number;
|
|
nombreCurso: string;
|
|
}
|
|
export interface Template {
|
|
id: string;
|
|
nombre: string;
|
|
descripcion?: string;
|
|
idCursos?: number;
|
|
nivel?: string;
|
|
tipoCurso: string;
|
|
tipoPrueba: string;
|
|
duracionMin: number;
|
|
puntajeAprobacion: number;
|
|
puntajeTotal: number;
|
|
instrucciones?: string;
|
|
usoCount: number;
|
|
creadoPor?: string;
|
|
}
|
|
export interface Pregunta {
|
|
id: string;
|
|
templateId: string;
|
|
sectionId?: string;
|
|
orden: number;
|
|
tipoPregunta: string;
|
|
pregunta: string;
|
|
opciones?: string;
|
|
respuestaCorrecta?: string;
|
|
explicacion?: string;
|
|
puntaje: number;
|
|
metadata?: string;
|
|
}
|
|
export interface BancoItem {
|
|
id: string;
|
|
pregunta: string;
|
|
tipoPregunta: string;
|
|
puntaje: number;
|
|
dificultad: string;
|
|
skill?: string;
|
|
activo: boolean;
|
|
usoCount: number;
|
|
}
|
|
export interface Asignacion {
|
|
id: string;
|
|
templateId: string;
|
|
origen: string;
|
|
idCursos?: number;
|
|
idCursoAbierto?: number;
|
|
fechaInicio?: string;
|
|
fechaFin?: string;
|
|
activo: boolean;
|
|
asignadoPor?: string;
|
|
}
|
|
export interface Rendicion {
|
|
id: string;
|
|
asignacionId: string;
|
|
idAlumno: string;
|
|
intento: number;
|
|
puntajeObtenido?: number;
|
|
puntajeMaximo?: number;
|
|
aprobado?: boolean;
|
|
inicio: string;
|
|
termino?: string;
|
|
respuestas: string;
|
|
}
|
|
|
|
export const TIPOS_PRUEBA = ["CA", "MWT", "MOT", "FOT", "FWT"];
|
|
export const TIPOS_PREGUNTA = [
|
|
"multiple-choice",
|
|
"true-false",
|
|
"short-answer",
|
|
"essay",
|
|
"matching",
|
|
"ordering",
|
|
"fill-in-the-blanks",
|
|
"audio-response"
|
|
];
|
|
/** Tipos con corrección automática en el frontend. */
|
|
export const AUTO_TYPES = ["multiple-choice", "true-false", "short-answer"];
|
|
|
|
export function nombreCompleto(a: { nombres: string; apPaterno: string; apMaterno?: string }) {
|
|
return `${a.nombres} ${a.apPaterno}${a.apMaterno ? " " + a.apMaterno : ""}`;
|
|
}
|