// 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; } 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 : ""}`; }