Correxion en los tipos de datos

This commit is contained in:
santiago
2025-10-18 14:21:12 -06:00
parent 11c9143367
commit c2e67afd16
32 changed files with 513 additions and 402 deletions
@@ -2,7 +2,8 @@
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import axios from 'axios';
import { axiosInstance } from '@/api/config';
import { isAxiosError } from 'axios';
import BotonRegresar from '@/components/boton-regresar';
import InformacionCasoEspecial from '@/components/administrador/informacion-caso-especial';
import LiberarCasoEspecial from '@/components/administrador/liberar-caso-especial';
@@ -40,18 +41,26 @@ export default function CasoEspecialPage() {
const [alumno, setAlumno] = useState<Alumno>({ Usuario: {}, Carrera: {}, Status: {} });
// Funciones de dialogo
const imprimirError = (err: any = {}, title = '¡Hubo un error!', onConfirm = () => {}) => {
const imprimirError = (err: unknown = {}, title = '¡Hubo un error!', onConfirm = () => {}) => {
let message = 'Ocurrió un error';
if (typeof err === 'string') message = err;
else if (err instanceof Error) message = err.message;
else if (isAxiosError(err) && err.response?.data?.message) message = String(err.response.data.message);
MySwal.fire({
title,
text: err.message || 'Ocurrió un error',
text: message,
icon: 'error',
confirmButtonText: 'Entendido',
}).then(() => onConfirm());
if (err.err === 'token error') {
localStorage.clear();
router.push('/');
try {
const anyErr = err as { err?: string };
if (anyErr.err === 'token error') {
localStorage.clear();
router.push('/');
}
} catch (_) {}
};
const imprimirMensaje = (message: string, title = '¡Felicidades!', onConfirm = () => {}) => {
@@ -102,15 +111,12 @@ export default function CasoEspecialPage() {
updateIsLoading(true);
try {
const res = await axios.get(
`${process.env.api}/caso_especial?idCasoEspecial=${idCasoEspecial}`,
{
headers: { token: admin.token },
}
);
const res = await axiosInstance.get(`/caso_especial?idCasoEspecial=${idCasoEspecial}`, { headers: { token: admin.token } });
setAlumno(res.data);
} catch (err: any) {
imprimirError(err.response?.data || err.message);
} catch (err: unknown) {
if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
else if (err instanceof Error) imprimirError(err.message);
else imprimirError();
} finally {
updateIsLoading(false);
}
@@ -1,14 +1,16 @@
"use client"
import BotonRegresar from "@/components/boton-regresar";
import InformacionResponsable from "@/components/administrador/infomracion-responsable";
import { useState } from "react";
import { useState, useEffect } from "react";
export default function Responsable() {
const [loading, setIsLoading] = useState(false);
// Simulamos el objeto admin con el token desde localStorage o desde login
const admin = {
token: localStorage.getItem('token') || '',
};
// admin token (read on client only)
const [admin, setAdmin] = useState<{ token?: string }>({});
useEffect(() => {
const token = typeof window !== 'undefined' ? localStorage.getItem('token') || '' : '';
setAdmin({ token });
}, []);
// Función para imprimir errores
const imprimirError = (msg: string) => {
+16 -9
View File
@@ -23,18 +23,22 @@ export default function Page() {
const updateIsLoading = (v: boolean) => setIsLoading(v);
const imprimirError = (err: unknown = {}, title = '¡Hubo un error!', onConfirm: () => void = () => {}) => {
// Usamos alert como reemplazo simple de Buefy dialog en la vista
// Los componentes hijos pueden mostrar mensajes más ricos si lo desean
// err puede ser objeto o string
const msg = typeof err === 'string' ? err : (err && typeof (err as any).message === 'string' ? (err as any).message : JSON.stringify(err));
let msg = typeof err === 'string' ? err : JSON.stringify(err);
if (typeof err === 'object' && err !== null) {
const anyErr = err as { message?: unknown; err?: unknown };
if (typeof anyErr.message === 'string') msg = anyErr.message;
}
// Mostrar alerta simple
// eslint-disable-next-line no-alert
alert(`${title}\n\n${msg}`);
onConfirm();
// comportamiento original: limpiar token y redirigir si token error
if (typeof err === 'object' && err !== null && (err as any).err === 'token error') {
try { localStorage.clear(); } catch (_) {}
router.push('/');
if (typeof err === 'object' && err !== null) {
const anyErr = err as { err?: unknown };
if (anyErr.err === 'token error') {
try { localStorage.clear(); } catch (_) {}
router.push('/');
}
}
};
@@ -71,8 +75,11 @@ export default function Page() {
if (res.data.idCuestionarioPrograma) router.push('/responsable');
} catch (err: unknown) {
updateIsLoading(false);
if ((err as any)?.response?.data) imprimirError((err as any).response.data);
else if (err instanceof Error) imprimirError(err.message);
if (typeof err === 'object' && err !== null && 'response' in err) {
const anyErr = err as { response?: { data?: unknown } };
if (anyErr.response?.data) imprimirError(anyErr.response.data);
else imprimirError(err);
} else if (err instanceof Error) imprimirError(err.message);
else imprimirError(String(err));
}
};
+12 -5
View File
@@ -14,14 +14,21 @@ export default function Page() {
const updateIsLoading = (booleanValue: boolean) => setIsLoading(booleanValue);
const imprimirError = (err: unknown = {}, title = '¡Hubo un error!', onConfirm: () => void = () => {}) => {
const msg = typeof err === 'string' ? err : (err && typeof (err as any).message === 'string' ? (err as any).message : JSON.stringify(err));
const imprimirError = (err: unknown = {}, title = '\u00a1Hubo un error!', onConfirm: () => void = () => {}) => {
let msg = typeof err === 'string' ? err : JSON.stringify(err);
if (typeof err === 'object' && err !== null) {
const anyErr = err as { message?: unknown; err?: unknown };
if (typeof anyErr.message === 'string') msg = anyErr.message;
}
// eslint-disable-next-line no-alert
alert(`${title}\n\n${msg}`);
onConfirm();
if (typeof err === 'object' && err !== null && (err as any).err === 'token error') {
try { localStorage.clear(); } catch (_) {}
router.push('/');
if (typeof err === 'object' && err !== null) {
const anyErr = err as { err?: unknown };
if (anyErr.err === 'token error') {
try { localStorage.clear(); } catch (_) {}
router.push('/');
}
}
};
+6 -3
View File
@@ -24,9 +24,12 @@ export default function Page() {
// Mostrar diálogo simple (puedes sustituir por un modal personalizado si lo deseas)
// Mantener la misma semántica: si es token error, limpiar y redirigir
alert(`${title}: ${message}`);
if (typeof err !== 'string' && (err as any).err === 'token error') {
localStorage.clear();
router.push('/');
if (typeof err !== 'string' && typeof err === 'object' && err !== null) {
const anyErr = err as { err?: unknown };
if (anyErr.err === 'token error') {
localStorage.clear();
router.push('/');
}
}
onConfirm();
};
+7 -5
View File
@@ -2,7 +2,9 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
import axios, { AxiosResponse } from "axios";
import { axiosInstance } from '@/api/config';
import { isAxiosError } from 'axios';
import type { AxiosResponse } from 'axios';
interface Status {
idStatus: number;
@@ -99,7 +101,7 @@ export default function VerDocumento({
imprimirMensaje(res.data.data.message);
router.push("/administrador");
} catch (err: unknown) {
if (axios.isAxiosError(err)) {
if (isAxiosError(err)) {
imprimirError(err.response?.data || err.message);
} else {
imprimirError(err);
@@ -110,13 +112,13 @@ export default function VerDocumento({
};
const rechazarCartaAceptacion = (data: RechazarData) =>
axios.put(`${process.env.NEXT_PUBLIC_API}/servicio/rechazar_aceptacion`, data, admin.token);
axiosInstance.put(`/servicio/rechazar_aceptacion`, data, admin.token);
const rechazarCartaTermino = (data: RechazarData) =>
axios.put(`${process.env.NEXT_PUBLIC_API}/servicio/rechazar_termino`, data, admin.token);
axiosInstance.put(`/servicio/rechazar_termino`, data, admin.token);
const rechazarInformeGlobal = (data: RechazarData) =>
axios.put(`${process.env.NEXT_PUBLIC_API}/servicio/rechazar_informe`, data, admin.token);
axiosInstance.put(`/servicio/rechazar_informe`, data, admin.token);
return (
<div className="mb-4">
@@ -1,7 +1,8 @@
"use client";
import { useState } from "react";
import axios from "axios";
import { axiosInstance } from '@/api/config';
import { isAxiosError } from 'axios';
import { useRouter } from "next/navigation";
interface Status {
@@ -20,7 +21,7 @@ interface Props {
idServicio: number;
admin: Admin;
alumno: Alumno;
imprimirError: (err: any) => void;
imprimirError: (err: unknown) => void;
imprimirMensaje: (msg: string) => void;
imprimirWarning: (msg: string, onConfirm: () => void) => void;
updateIsLoading: (value: boolean) => void;
@@ -49,13 +50,15 @@ export default function CancelarServicio({
try {
updateIsLoading(true);
const res = await axios.put(`${process.env.NEXT_PUBLIC_API}/servicio/cancelar`, data, admin.token);
const res = await axiosInstance.put(`/servicio/cancelar`, data, admin.token);
localStorage.removeItem("idServicio");
imprimirMensaje(res.data.message);
router.push("/admin");
} catch (err: any) {
imprimirError(err.response?.data || err);
} finally {
} catch (err: unknown) {
if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
else if (err instanceof Error) imprimirError(err.message);
else imprimirError(err);
} finally {
updateIsLoading(false);
}
};
@@ -1,5 +1,7 @@
import { useState } from "react";
import axios, { AxiosResponse } from "axios";
import { isAxiosError } from 'axios';
import { axiosInstance } from '@/api/config';
import type { AxiosResponse } from 'axios';
import { useRouter } from "next/navigation";
interface Status {
@@ -69,7 +71,7 @@ export default function ConfirmarServicio({
imprimirMensaje(res.data.message);
router.push("/admin");
} catch (err: unknown) {
if (axios.isAxiosError(err)) {
if (isAxiosError(err)) {
imprimirError(err.response?.data || err.message);
} else {
imprimirError(err);
@@ -80,15 +82,11 @@ export default function ConfirmarServicio({
};
const confirmarPreRegistro = (data: ConfirmarData) =>
axios.put<ApiResponse>(`${process.env.NEXT_PUBLIC_API}/servicio/registro`, data, admin.token);
axiosInstance.put<ApiResponse>(`/servicio/registro`, data, admin.token);
const confirmarLiberacion = (data: ConfirmarData) => {
if (vistoBuenoAcatlan) data.vistoBuenoAcatlan = vistoBuenoAcatlan;
return axios.put<ApiResponse>(
`${process.env.NEXT_PUBLIC_API}/servicio/liberacion`,
data,
admin.token
);
return axiosInstance.put<ApiResponse>(`/servicio/liberacion`, data, admin.token);
};
return (
@@ -30,10 +30,10 @@ export default function Cuestionario({ years, admin, updateIsLoading }: Props) {
setSelectedCuestionario("");
setVersion("");
//updateIsLoading(false);
} catch (err: any) {
//updateIsLoading(false);
//imprimirError(err.response?.data || "Error al descargar");
}
} catch (err: unknown) {
//updateIsLoading(false);
// optional: handle error, e.g. console.error(err)
}
};
return (
@@ -1,7 +1,8 @@
"use client";
import { useState, useMemo } from "react";
import axios from "axios";
import { axiosInstance } from "@/api/config";
import { isAxiosError } from "axios";
import moment from "moment";
import validator from "validator";
import DatePicker from "react-datepicker";
@@ -30,7 +31,7 @@ interface Props {
viejo: Viejo;
imprimirMensaje: (msg: string) => void;
imprimirWarning: (msg: string, onConfirm: () => void) => void;
imprimirError: (err: any) => void;
imprimirError: (err: unknown) => void;
updateIsLoading: (value: boolean) => void;
}
@@ -83,7 +84,7 @@ export default function EditarAlumno({
};
const actualizar = async () => {
const data: Record<string, any> = { idCasoEspecial };
const data: Record<string, unknown> = { idCasoEspecial };
if (nuevo.direccion) data.direccion = nuevo.direccion;
if (nuevo.correo) data.correo = nuevo.correo;
@@ -98,15 +99,17 @@ export default function EditarAlumno({
try {
updateIsLoading(true);
const res = await axios.put(
`${process.env.NEXT_PUBLIC_API}/caso_especial/update`,
data,
admin.token
);
const res = await axiosInstance.put(`/caso_especial/update`, data, admin.token);
imprimirMensaje(res.data.message);
router.push("/admin/casos_especiales/caso_especial");
} catch (err: any) {
imprimirError(err.response?.data || err);
} catch (err: unknown) {
let msg: unknown = err;
if (isAxiosError(err) && err.response?.data) {
msg = err.response.data;
} else if (err instanceof Error) {
msg = err.message;
}
imprimirError(msg);
} finally {
updateIsLoading(false);
}
@@ -1,7 +1,8 @@
"use client";
import { useState } from "react";
import axios from "axios";
import { axiosInstance } from "@/api/config";
import { isAxiosError } from "axios";
import validator from "validator";
import { useRouter } from "next/navigation";
@@ -18,7 +19,7 @@ interface Admin {
interface Props {
admin: Admin;
responsable: Responsable;
imprimirError: (err: any) => void;
imprimirError: (err: unknown) => void;
imprimirMensaje: (msg: string) => void;
imprimirWarning: (msg: string, onConfirm: () => void) => void;
updateIsLoading: (value: boolean) => void;
@@ -47,21 +48,23 @@ export default function EditarResponsable({
// Actualizar información del responsable
const actualizar = async () => {
const data: Record<string, any> = { idUsuario: responsable.idUsuario };
const data: Record<string, unknown> = { idUsuario: responsable.idUsuario };
if (nuevo.correo) data.correo = nuevo.correo;
if (nuevo.nombre) data.nombre = nuevo.nombre;
try {
updateIsLoading(true);
const res = await axios.put(
`${process.env.NEXT_PUBLIC_API}/usuario/responsable/update`,
data,
admin.token
);
const res = await axiosInstance.put(`/usuario/responsable/update`, data, admin.token);
imprimirMensaje(res.data.message);
router.push("/admin/responsables/responsable");
} catch (err: any) {
imprimirError(err.response?.data || err);
} catch (err: unknown) {
let msg: unknown = err;
if (isAxiosError(err) && err.response?.data) {
msg = err.response.data;
} else if (err instanceof Error) {
msg = err.message;
}
imprimirError(msg);
} finally {
updateIsLoading(false);
}
@@ -73,15 +76,17 @@ export default function EditarResponsable({
try {
updateIsLoading(true);
const res = await axios.put(
`${process.env.NEXT_PUBLIC_API}/usuario/new_password_responsable`,
data,
admin.token
);
const res = await axiosInstance.put(`/usuario/new_password_responsable`, data, admin.token);
imprimirMensaje(res.data.message);
router.push("/admin/responsables/responsable");
} catch (err: any) {
imprimirError(err.response?.data || err);
} catch (err: unknown) {
let msg: unknown = err;
if (isAxiosError(err) && err.response?.data) {
msg = err.response.data;
} else if (err instanceof Error) {
msg = err.message;
}
imprimirError(msg);
} finally {
updateIsLoading(false);
}
@@ -1,7 +1,8 @@
"use client";
import { useState, useEffect } from "react";
import axios from "axios";
import { axiosInstance } from "@/api/config";
import { isAxiosError } from 'axios';
import moment from "moment";
import validator from "validator";
import DatePicker from "react-datepicker";
@@ -23,7 +24,7 @@ interface Props {
token: { headers: { token: string } };
tokenArchivo: { headers: Record<string, string> };
};
imprimirError: (err: any) => void;
imprimirError: (err: unknown) => void;
imprimirMensaje: (msg: string) => void;
imprimirWarning: (msg: string, onConfirm: () => void) => void;
updateIsLoading: (value: boolean) => void;
@@ -67,10 +68,7 @@ export default function EditarAlumno({
const obtenerRegistro = async () => {
try {
updateIsLoading(true);
const res = await axios.get(
`${process.env.NEXT_PUBLIC_API}/servicio/admin?idServicio=${idServicio}`,
admin.token
);
const res = await axiosInstance.get(`/servicio/admin?idServicio=${idServicio}`, admin.token);
const data = res.data;
setServicio(data);
@@ -86,16 +84,21 @@ export default function EditarAlumno({
setFechaNacimiento(new Date(data.fechaNacimiento));
updateIsLoading(false);
} catch (err: any) {
updateIsLoading(false);
imprimirError(err.response?.data || err);
}
} catch (err: unknown) {
updateIsLoading(false);
let msg: unknown = err;
if (typeof err === 'object' && err !== null && 'response' in err) {
const anyErr = err as { response?: { data?: unknown } };
if (anyErr.response?.data) msg = anyErr.response.data;
} else if (err instanceof Error) msg = err.message;
imprimirError(msg);
}
};
// Actualizar datos del alumno
const actualizar = async () => {
const formData = new FormData();
const data: Record<string, any> = { idServicio };
const data: Record<string, unknown> = { idServicio };
if (cartaAceptacion) formData.append("cartaAceptacion", cartaAceptacion);
if (cartaTermino) formData.append("cartaTermino", cartaTermino);
@@ -111,18 +114,16 @@ export default function EditarAlumno({
try {
updateIsLoading(true);
const res = await axios.put(
`${process.env.NEXT_PUBLIC_API}/servicio/update`,
formData,
admin.tokenArchivo
);
const res = await axiosInstance.put(`/servicio/update`, formData, admin.tokenArchivo);
imprimirMensaje(res.data.message);
updateIsLoading(false);
router.push("/admin/servicio");
} catch (err: any) {
updateIsLoading(false);
imprimirError(err.response?.data || err);
}
} catch (err: unknown) {
updateIsLoading(false);
if (isAxiosError(err)) imprimirError(err.response?.data ?? err.message);
else if (err instanceof Error) imprimirError(err.message);
else imprimirError(err);
}
};
// Cambiar contraseña
@@ -131,18 +132,16 @@ export default function EditarAlumno({
try {
updateIsLoading(true);
const res = await axios.put(
`${process.env.NEXT_PUBLIC_API}/usuario/new_password_alumno`,
data,
admin.token
);
const res = await axiosInstance.put(`/usuario/new_password_alumno`, data, admin.token);
imprimirMensaje(res.data.message);
updateIsLoading(false);
router.push("/admin");
} catch (err: any) {
updateIsLoading(false);
imprimirError(err.response?.data || err);
}
} catch (err: unknown) {
updateIsLoading(false);
if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
else if (err instanceof Error) imprimirError(err.message);
else imprimirError(err);
}
};
// Mostrar botón activo o no
@@ -2,6 +2,7 @@
import { useState } from "react";
import { Col, FormGroup, FormLabel, FormSelect, InputGroup, Button } from "react-bootstrap";
import { axiosInstance } from "@/api/config"; // tu config de axios
import { isAxiosError } from 'axios';
//import fileDownload from "js-file-download";
interface Props {
@@ -36,10 +37,12 @@ export default function GustavoBazPrada({
setSelectedYear("");
updateIsLoading?.(false);
} catch (err: any) {
updateIsLoading?.(false);
imprimirError?.(err.response?.data || "Error al descargar");
}
} catch (err: unknown) {
updateIsLoading?.(false);
if (isAxiosError(err)) imprimirError?.(String(err.response?.data) || err.message || 'Error al descargar');
else if (err instanceof Error) imprimirError?.(err.message);
else imprimirError?.('Error al descargar');
}
};
return (
@@ -2,10 +2,11 @@
import React, { useEffect, useState } from 'react';
import { axiosInstance } from '@/api/config';
import { isAxiosError } from 'axios';
import { useRouter } from 'next/navigation';
interface Admin {
token: string;
token?: string;
}
interface Programa {
@@ -47,8 +48,10 @@ export default function InformacionResponsable({ admin, imprimirError, updateIsL
});
setResponsable(res.data);
obtenerProgramas();
} catch (err: any) {
imprimirError(err.response?.data || 'Error al obtener responsable');
} catch (err: unknown) {
if (isAxiosError(err)) imprimirError(String(err.response?.data) || err.message || 'Error al obtener responsable');
else if (err instanceof Error) imprimirError(err.message);
else imprimirError('Error al obtener responsable');
} finally {
updateIsLoading(false);
}
@@ -61,9 +64,11 @@ export default function InformacionResponsable({ admin, imprimirError, updateIsL
headers: { Authorization: admin.token },
});
setProgramas(res.data);
} catch (err: any) {
imprimirError(err.response?.data || 'Error al obtener programas');
}
} catch (err: unknown) {
if (isAxiosError(err)) imprimirError(String(err.response?.data) || err.message || 'Error al obtener programas');
else if (err instanceof Error) imprimirError(err.message);
else imprimirError('Error al obtener programas');
}
};
// Cargar al montar
@@ -1,12 +1,12 @@
'use client';
import { useRouter } from 'next/navigation';
import axios from 'axios';
import { axiosInstance } from '@/api/config';
interface Props {
idCasoEspecial: number;
admin: { token: string };
imprimirError: (msg: any) => void;
imprimirError: (err: unknown) => void;
imprimirMensaje: (msg: string) => void;
imprimirWarning: (msg: string, callback: () => void) => void;
updateIsLoading: (loading: boolean) => void;
@@ -27,19 +27,16 @@ export default function LiberarCasoEspecial({
try {
updateIsLoading(true);
const res = await axios.put(
`${process.env.api}/caso_especial/liberacion`,
data,
{
headers: {
Authorization: `Bearer ${admin.token}`,
},
}
);
const res = await axiosInstance.put(`/caso_especial/liberacion`, data, { headers: { Authorization: `Bearer ${admin.token}` } });
imprimirMensaje(res.data.message);
router.push('/admin/casos_especiales');
} catch (err: any) {
imprimirError(err.response?.data || err.message);
} catch (err: unknown) {
let msg: unknown = 'Error';
if (typeof err === 'object' && err !== null && 'response' in err) {
const anyErr = err as { response?: { data?: unknown } };
if (anyErr.response?.data) msg = anyErr.response.data;
} else if (err instanceof Error) msg = err.message;
imprimirError(msg);
} finally {
updateIsLoading(false);
}
@@ -1,13 +1,14 @@
"use client";
import { useState } from "react";
import axios from "axios";
import { axiosInstance } from "@/api/config";
import { isAxiosError } from 'axios';
import { useRouter } from "next/navigation";
interface Props {
admin: { token: { headers: { token: string } } };
responsable: { idUsuario: number; usuario: string };
imprimirError: (err: any) => void;
imprimirError: (err: unknown) => void;
imprimirMensaje: (msg: string) => void;
imprimirWarning: (msg: string, onConfirm: () => void) => void;
updateIsLoading: (value: boolean) => void;
@@ -42,18 +43,16 @@ export default function ReasignacionProgramas({
try {
updateIsLoading(true);
const res = await axios.put(
`${process.env.NEXT_PUBLIC_API}/programa/reasignar_programas`,
data,
admin.token
);
const res = await axiosInstance.put(`/programa/reasignar_programas`, data, admin.token);
updateIsLoading(false);
imprimirMensaje(res.data.message);
router.push("/admin/responsables/responsable");
} catch (err: any) {
updateIsLoading(false);
imprimirError(err.response?.data || err);
}
} catch (err: unknown) {
updateIsLoading(false);
if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
else if (err instanceof Error) imprimirError(err.message);
else imprimirError(err);
}
};
return (
+4 -4
View File
@@ -48,10 +48,10 @@ export default function Reporte({ admin }: Props) {
setSelectedInicio(null);
setSelectedFin(null);
//updateIsLoading(false);
} catch (err: any) {
//updateIsLoading(false);
//imprimirError(err.response?.data || "Error al descargar");
}
} catch (err: unknown) {
//updateIsLoading(false);
// optional: handle error
}
};
return (
@@ -1,7 +1,9 @@
"use client";
import { useEffect, useState } from "react";
import axios, { AxiosResponse } from "axios";
import { axiosInstance } from '@/api/config';
import { isAxiosError } from 'axios';
import type { AxiosResponse } from 'axios';
import { Button, Form, Spinner } from "react-bootstrap";
import ServicioSocialTabla from "../servicio-social-tabla";
@@ -20,7 +22,7 @@ interface ServicioEspecial {
numeroCuenta: string;
nombre: string;
idStatus: number;
[key: string]: any; // Si hay más campos dinámicos, opcional
[key: string]: Record<string, unknown> | string | number | boolean | undefined; // campos dinámicos
}
interface Props {
@@ -80,16 +82,13 @@ export default function TablaCasosEspeciales({ admin, imprimirError }: Props) {
if (search.numeroCuenta) query += `&numeroCuenta=${search.numeroCuenta}`;
try {
const res: AxiosResponse<CasosEspecialesResponse> = await axios.get(
`${process.env.NEXT_PUBLIC_API}/caso_especial/servicios_especiales?pagina=${pagina}${query}`,
// { headers: { Authorization: `Bearer ${admin?.token}` } }
);
const res: AxiosResponse<CasosEspecialesResponse> = await axiosInstance.get(`/caso_especial/servicios_especiales?pagina=${pagina}${query}`);
setData(res.data.serviciosEspeciales);
setTotal(res.data.count);
} catch (err: unknown) {
if (imprimirError) {
if (axios.isAxiosError(err)) {
imprimirError(err.response?.data?.toString() || err.message);
if (isAxiosError(err)) {
imprimirError(String(err.response?.data) || err.message);
} else if (err instanceof Error) {
imprimirError(err.message);
} else {
@@ -103,16 +102,13 @@ export default function TablaCasosEspeciales({ admin, imprimirError }: Props) {
const obtenerCatalogoStatus = async () => {
try {
const res: AxiosResponse<Status[]> = await axios.get(
`${process.env.NEXT_PUBLIC_API}/status`
// { headers: { Authorization: `Bearer ${admin?.token}` } }
);
const res: AxiosResponse<Status[]> = await axiosInstance.get(`/status`);
setStatus(res.data);
obtenerCasosEspeciales();
} catch (err: unknown) {
if (imprimirError) {
if (axios.isAxiosError(err)) {
imprimirError(err.response?.data?.toString() || err.message);
if (isAxiosError(err)) {
imprimirError(String(err.response?.data) || err.message);
} else if (err instanceof Error) {
imprimirError(err.message);
} else {
@@ -3,7 +3,9 @@
import React, { useState } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import axios, { AxiosResponse } from "axios";
import { axiosInstance } from '@/api/config';
import { isAxiosError } from 'axios';
import type { AxiosResponse } from 'axios';
import moment from "moment";
interface Alumno {
@@ -57,15 +59,11 @@ export default function CompletarDatosPersonales({
try {
updateIsLoading(true);
const res: AxiosResponse<ApiResponse> = await axios.put(
`${process.env.NEXT_PUBLIC_API}/servicio/registro_validado`,
data,
alumno.token
);
const res: AxiosResponse<ApiResponse> = await axiosInstance.put(`/servicio/registro_validado`, data, alumno.token);
imprimirMensaje(res.data.data.message);
obtenerServicio();
} catch (err: unknown) {
if (axios.isAxiosError(err)) {
if (isAxiosError(err)) {
imprimirError(err.response?.data || err.message);
} else {
imprimirError(err);
+14 -3
View File
@@ -75,9 +75,20 @@ export default function CuestionarioD({ onChange }: Props) {
const setRadioArray = (key: "p14" | "p15" | "p17", index: number, value: "s" | "n" | number | null) => {
setAnswers((prev) => {
const newArr = [...prev[key]];
newArr[index] = value as any; // TS sabe que es correcto según key
return { ...prev, [key]: newArr };
if (key === "p14") {
const newArr = [...prev.p14];
newArr[index] = value as "s" | "n";
return { ...prev, p14: newArr };
}
if (key === "p15") {
const newArr = [...prev.p15];
newArr[index] = value as "s" | "n";
return { ...prev, p15: newArr };
}
// p17
const newArr = [...prev.p17];
newArr[index] = value as number | null;
return { ...prev, p17: newArr };
});
};
@@ -24,7 +24,7 @@ interface Answers {
p14: (string | null)[];
p15: (string | null)[];
p16: string | null;
p17: any[]; // puede ajustarse según la estructura
p17: string[]; // puede ajustarse según la estructura
p18: string;
p19: string;
p20: string;
@@ -1,7 +1,7 @@
'use client';
import React, { useEffect, useMemo, useState } from 'react';
import axios from 'axios';
import { axiosInstance } from '@/api/config';
interface Pregunta {
id: string;
@@ -325,7 +325,7 @@ export default function FormularioCuestionario() {
const sortedItems = useMemo(() => {
const items: (Pregunta | Tabla)[] = [...formulario.preguntas, ...formulario.tablas];
return items.sort((a: any, b: any) => {
return items.sort((a: { numeroPregunta: number; idTabla?: number }, b: { numeroPregunta: number; idTabla?: number }) => {
if (a.numeroPregunta === b.numeroPregunta) {
return (a.idTabla || 0) - (b.idTabla || 0);
}
@@ -439,7 +439,7 @@ export default function FormularioCuestionario() {
};
const formatearRespuestas = (resps: Respuestas) => {
const resultado: Record<string, any> = {};
const resultado: Record<string, string | string[] | number | null | undefined> = {};
for (const key in resps) {
const esTabla = !isNaN(Number(key));
@@ -454,7 +454,7 @@ export default function FormularioCuestionario() {
if (coincidencia) subLetra = coincidencia[1];
}
const respuestasTabla = resps[key] as Record<string, any>;
const respuestasTabla = resps[key] as Record<string, string | null>;
for (const idRenglon in respuestasTabla) {
const valor = respuestasTabla[idRenglon];
let clave = `p${numPregunta}_${idRenglon}`;
@@ -466,7 +466,13 @@ export default function FormularioCuestionario() {
if (!preguntaDef) continue;
const numPregunta = preguntaDef.numeroPregunta;
const clave = `p${numPregunta}`;
resultado[clave] = resps[key];
const val = resps[key];
if (typeof val === 'string' || typeof val === 'number' || Array.isArray(val) || val === null) {
resultado[clave] = val as string | string[] | number | null;
} else {
// fallback to stringified value
resultado[clave] = String(val);
}
}
}
@@ -487,16 +493,20 @@ export default function FormularioCuestionario() {
};
try {
const apiUrl = (process.env as any).api || (process.env as any).NEXT_PUBLIC_API || '';
await axios.post(`${apiUrl}/cuestionario_alumno`, data);
await axiosInstance.post(`/cuestionario_alumno`, data);
window.alert('Se enviaron los datos correctamente');
if (typeof window !== 'undefined') {
localStorage.removeItem('idCuestionarioAlumno');
// navegar a /alumno si existe history
window.location.href = '/alumno';
}
} catch (error: any) {
window.alert(error?.response?.data?.message || 'Error al enviar el formulario');
} catch (error: unknown) {
let msg = 'Error al enviar el formulario';
if (typeof error === 'object' && error !== null && 'response' in error) {
const anyErr = error as { response?: { data?: unknown } };
if (anyErr.response?.data && typeof (anyErr.response.data as { message?: unknown }).message === 'string') msg = (anyErr.response.data as { message?: unknown }).message as string;
} else if (error instanceof Error) msg = error.message;
window.alert(msg);
}
};
@@ -1,7 +1,8 @@
"use client";
import React, { useEffect, useMemo, useState } from "react";
import axios from "axios";
import { axiosInstance } from "@/api/config";
import { isAxiosError } from "axios";
type PreguntaDef = {
id: string;
@@ -30,7 +31,7 @@ type FormularioDef = {
tablas: TablaDef[];
};
type Respuestas = { [key: string]: any };
type Respuestas = Record<string, string | string[] | Record<number, string | null> | null>;
export default function FullCuestionarioNewBad2() {
const [isLoading, setIsLoading] = useState(false);
@@ -447,15 +448,15 @@ export default function FullCuestionarioNewBad2() {
// Inicializa las respuestas
useEffect(() => {
const initial: Respuestas = {};
const initial = {} as Respuestas;
formulario.preguntas.forEach((p) => {
if (p.tipo === "seleccionMultiple") initial[p.id] = [];
else initial[p.id] = "";
});
formulario.tablas.forEach((t) => {
initial[t.idTabla] = {};
initial[t.idTabla] = {} as Record<number, string | null>;
t.renglones.forEach((r) => {
initial[t.idTabla][r.idRenglon] = null;
(initial[t.idTabla] as Record<number, string | null>)[r.idRenglon] = null;
});
});
setRespuestas(initial);
@@ -465,15 +466,19 @@ export default function FullCuestionarioNewBad2() {
const isMobile = () => typeof window !== "undefined" && window.innerWidth < 576;
const sortedItems = useMemo(() => {
const items: any[] = [...formulario.preguntas, ...formulario.tablas];
const items: (PreguntaDef | TablaDef)[] = [...formulario.preguntas, ...formulario.tablas];
return items.sort((a, b) => {
if (a.numeroPregunta === b.numeroPregunta) return (a.idTabla || 0) - (b.idTabla || 0);
if (a.numeroPregunta === b.numeroPregunta) {
const aIdx = 'idTabla' in a ? (a.idTabla ?? 0) : 0;
const bIdx = 'idTabla' in b ? (b.idTabla ?? 0) : 0;
return aIdx - bIdx;
}
return a.numeroPregunta - b.numeroPregunta;
});
}, [formulario]);
const isItemVisible = (item: any) => {
if (item.condicional) {
const isItemVisible = (item: PreguntaDef | TablaDef) => {
if ('condicional' in item && item.condicional) {
return respuestas[item.condicional.preguntaId] === item.condicional.valor;
}
return true;
@@ -486,11 +491,13 @@ export default function FullCuestionarioNewBad2() {
const ans = respuestas[p.id];
let answered = false;
if (p.tipo === "seleccionMultiple") answered = Array.isArray(ans) && ans.length > 0;
else answered = ans !== null && ans !== "";
else if (typeof ans === 'string') answered = ans !== null && ans !== "";
else answered = ans !== null && ans !== undefined;
if (!answered) missing.push(`Pregunta ${p.numeroPregunta}`);
});
formulario.tablas.forEach((t) => {
const allAnswered = t.renglones.every((r) => respuestas[t.idTabla] && respuestas[t.idTabla][r.idRenglon] !== null);
const tablaResp = respuestas[t.idTabla] as Record<number, string | null> | undefined;
const allAnswered = t.renglones.every((r) => tablaResp && tablaResp[r.idRenglon] !== null && tablaResp[r.idRenglon] !== undefined);
if (!allAnswered) missing.push(`Tabla ${t.numeroPregunta}`);
});
return missing;
@@ -510,7 +517,7 @@ export default function FullCuestionarioNewBad2() {
});
};
const updateRespuestas = (id: string, valor: any) => setRespuestas((prev) => ({ ...prev, [id]: valor }));
const updateRespuestas = (id: string, valor: string | string[] | Record<number, string | null> | null) => setRespuestas((prev) => ({ ...prev, [id]: valor }));
const handleTableResponse = (tablaId: number, renglonId: number, valor: string) => {
setRespuestas((prev) => ({ ...prev, [tablaId]: { ...(prev[tablaId] || {}), [renglonId]: valor } }));
@@ -521,22 +528,22 @@ export default function FullCuestionarioNewBad2() {
if (!isItemVisible(pregunta)) continue;
const resp = respuestas[pregunta.id];
if (pregunta.tipo === "seleccionMultiple") {
if (!resp || resp.length === 0) {
if (!Array.isArray(resp) || resp.length === 0) {
window.alert(`Por favor, selecciona al menos una opción en la pregunta ${pregunta.numeroPregunta}.`);
return false;
}
} else if (pregunta.tipo === "texto") {
if (!resp || resp === "") {
if (typeof resp !== 'string' || resp === "") {
window.alert(`Por favor, responde la pregunta ${pregunta.numeroPregunta}.`);
return false;
}
const limite = pregunta.limite || 500;
if (typeof resp === "string" && resp.length > limite) {
if (resp.length > limite) {
window.alert(`La respuesta de la pregunta ${pregunta.numeroPregunta} excede el límite de ${limite} caracteres.`);
return false;
}
} else {
if (resp === null || resp === "") {
if (resp === null || resp === "" || resp === undefined) {
window.alert(`Por favor, responde la pregunta ${pregunta.numeroPregunta}.`);
return false;
}
@@ -544,9 +551,10 @@ export default function FullCuestionarioNewBad2() {
}
for (const tabla of formulario.tablas) {
const tablaResp = respuestas[tabla.idTabla] as Record<number, string | null> | undefined;
for (const renglon of tabla.renglones) {
const resp = respuestas[tabla.idTabla]?.[renglon.idRenglon];
if (resp === null) {
const resp = tablaResp ? tablaResp[renglon.idRenglon] : null;
if (resp === null || resp === undefined) {
window.alert(`Por favor, responde la tabla ${tabla.numeroPregunta}, fila "${renglon.textoRenglon}".`);
return false;
}
@@ -557,7 +565,7 @@ export default function FullCuestionarioNewBad2() {
};
const formatearRespuestas = (resps: Respuestas) => {
const resultado: Record<string, any> = {};
const resultado: Record<string, unknown> = {};
for (const key in resps) {
const esTabla = !isNaN(Number(key));
if (esTabla) {
@@ -571,11 +579,14 @@ export default function FullCuestionarioNewBad2() {
if (m) subLetra = m[1];
}
const respuestasTabla = resps[key];
for (const idR in respuestasTabla) {
const val = respuestasTabla[idR];
let clave = `p${num}_${idR}`;
if (subLetra) clave = `p${num}_${subLetra}_${idR}`;
resultado[clave] = val;
if (respuestasTabla && typeof respuestasTabla === 'object' && !Array.isArray(respuestasTabla)) {
const tablaMap = respuestasTabla as Record<string, string | null>;
for (const idR in tablaMap) {
const val = tablaMap[idR];
let clave = `p${num}_${idR}`;
if (subLetra) clave = `p${num}_${subLetra}_${idR}`;
resultado[clave] = val;
}
}
} else {
const pregDef = formulario.preguntas.find((p) => p.id === key);
@@ -591,15 +602,15 @@ export default function FullCuestionarioNewBad2() {
setIsLoading(true);
try {
const data = { ...formatearRespuestas(respuestas), idServicio: typeof window !== 'undefined' ? localStorage.getItem('idServicio') : null };
const apiUrl = (process.env as any).api || (process.env as any).NEXT_PUBLIC_API || '';
await axios.post(`${apiUrl}/cuestionario_alumno`, data);
await axiosInstance.post(`/cuestionario_alumno`, data);
window.alert('Se enviaron los datos correctamente');
if (typeof window !== 'undefined') {
localStorage.removeItem('idCuestionarioAlumno');
window.location.href = '/alumno';
}
} catch (err: any) {
window.alert(err?.response?.data?.message || 'Error al enviar el formulario');
} catch (err: unknown) {
const message = isAxiosError(err) && err.response?.data?.message ? String(err.response.data.message) : (err instanceof Error ? err.message : 'Error al enviar el formulario');
window.alert(message);
} finally {
setIsLoading(false);
}
@@ -622,74 +633,82 @@ export default function FullCuestionarioNewBad2() {
)}
<div>
{sortedItems.map((item: any, index: number) => {
{sortedItems.map((item, index: number) => {
if (!isItemVisible(item)) return null;
const key = item.id || item.idTabla;
return (
<div key={key} className="mb-6">
{/* Preguntas */}
{item.tipo ? (
// Distinguish between pregunta and tabla
const isPregunta = 'tipo' in item && (item as PreguntaDef).numeroPregunta !== undefined;
if (isPregunta) {
const pregunta = item as PreguntaDef;
const key = pregunta.id;
const resp = respuestas[pregunta.id];
return (
<div key={key} className="mb-6">
<div className="mt-6">
<label className="form-label">{item.numeroPregunta}. {item.texto}</label>
{item.tipo === 'seleccionUnica' && (
<label className="form-label">{pregunta.numeroPregunta}. {pregunta.texto}</label>
{pregunta.tipo === 'seleccionUnica' && pregunta.opciones && (
<div>
{item.opciones.map((op: string) => (
{pregunta.opciones.map((op: string) => (
<div key={op} className="SINO">
<label style={{ display: 'block' }}>
<input type="radio" name={item.id} checked={respuestas[item.id] === op} onChange={() => updateRespuestas(item.id, op)} /> {op}
<input type="radio" name={pregunta.id} checked={resp === op} onChange={() => updateRespuestas(pregunta.id, op)} /> {op}
</label>
</div>
))}
</div>
)}
{item.tipo === 'seleccionMultiple' && (
{pregunta.tipo === 'seleccionMultiple' && pregunta.opciones && (
<div>
{item.opciones.map((op: string) => (
{pregunta.opciones.map((op: string) => (
<div key={op} className="SINO">
<label style={{ display: 'block' }}>
<input className="checkb" type="checkbox" value={op} checked={Array.isArray(respuestas[item.id]) && respuestas[item.id].includes(op)} onChange={() => toggleSelection(item.id, op)} /> {op}
<input className="checkb" type="checkbox" value={op} checked={Array.isArray(resp) && (resp as string[]).includes(op)} onChange={() => toggleSelection(pregunta.id, op)} /> {op}
</label>
</div>
))}
</div>
)}
{item.tipo === 'texto' && (
{pregunta.tipo === 'texto' && (
<div>
<input className="form-control" type="text" value={respuestas[item.id] || ''} onChange={(e) => updateRespuestas(item.id, e.target.value)} maxLength={item.limite || 500} />
<input className="form-control" type="text" value={typeof resp === 'string' ? resp : ''} onChange={(e) => updateRespuestas(pregunta.id, e.target.value)} maxLength={pregunta.limite || 500} />
</div>
)}
</div>
) : (
/* Tablas */
<div className="table-responsive">
{(index === 0 || item.numeroPregunta !== sortedItems[index - 1].numeroPregunta) && (
<h3 className="mb-3">{item.numeroPregunta}. {item.preguntaTabla}</h3>
)}
{item.subPreguntaTabla && <h5 className="mb-3">{item.subPreguntaTabla}</h5>}
<table className="table table-bordered text-center">
<thead>
<tr>
<th></th>
{item.renglones[0].opciones.map((op: string) => (
<th key={op}>{op}</th>
</div>
);
}
const tabla = item as TablaDef;
const key = tabla.idTabla;
const tablaResp = respuestas[tabla.idTabla] as Record<number, string | null> | undefined;
return (
<div key={String(key)} className="mb-6">
<div className="table-responsive">
{(index === 0 || tabla.numeroPregunta !== (sortedItems[index - 1] as TablaDef).numeroPregunta) && (
<h3 className="mb-3">{tabla.numeroPregunta}. {tabla.preguntaTabla}</h3>
)}
{tabla.subPreguntaTabla && <h5 className="mb-3">{tabla.subPreguntaTabla}</h5>}
<table className="table table-bordered text-center">
<thead>
<tr>
<th></th>
{tabla.renglones[0].opciones.map((op: string) => (
<th key={op}>{op}</th>
))}
</tr>
</thead>
<tbody>
{tabla.renglones.map((r: RenglonDef) => (
<tr key={r.idRenglon}>
<td>{r.textoRenglon}</td>
{r.opciones.map((op: string) => (
<td key={op}>
<input type="radio" name={`tabla-${tabla.idTabla}-renglon-${r.idRenglon}`} value={op} checked={!!(tablaResp && tablaResp[r.idRenglon] === op)} onChange={() => handleTableResponse(tabla.idTabla, r.idRenglon, op)} />
</td>
))}
</tr>
</thead>
<tbody>
{item.renglones.map((r: any) => (
<tr key={r.idRenglon}>
<td>{r.textoRenglon}</td>
{r.opciones.map((op: string) => (
<td key={op}>
<input type="radio" name={`tabla-${item.idTabla}-renglon-${r.idRenglon}`} value={op} checked={respuestas[item.idTabla] && respuestas[item.idTabla][r.idRenglon] === op} onChange={() => handleTableResponse(item.idTabla, r.idRenglon, op)} />
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
)}
))}
</tbody>
</table>
</div>
</div>
);
})}
@@ -1,7 +1,7 @@
"use client";
import React, { useEffect, useMemo, useState } from "react";
import axios from "axios";
import { axiosInstance } from "@/api/config";
type Pregunta = {
id: string;
@@ -26,7 +26,7 @@ type Tabla = {
type Formulario = { titulo?: string; descripcion?: string; preguntas: Pregunta[]; tablas: Tabla[] };
export default function FullCuestionario() {
const [respuestas, setRespuestas] = useState<Record<string, any>>({});
const [respuestas, setRespuestas] = useState<Record<string, string | string[] | Record<number, string | null> | null>>({});
const [isLoading, setIsLoading] = useState(false);
const formulario: Formulario = useMemo(
@@ -83,14 +83,15 @@ export default function FullCuestionario() {
// inicializar respuestas
useEffect(() => {
const initial: Record<string, any> = {};
const initial: Record<string, string | string[] | Record<number, string | null> | null> = {};
formulario.preguntas.forEach((p) => {
if (p.tipo === "seleccionMultiple") initial[p.id] = [];
else initial[p.id] = null;
});
formulario.tablas.forEach((t) => {
initial[t.idTabla] = {};
t.renglones.forEach((r) => (initial[t.idTabla][r.idRenglon] = null));
const tablaObj: Record<number, string | null> = {};
t.renglones.forEach((r) => (tablaObj[r.idRenglon] = null));
initial[String(t.idTabla)] = tablaObj;
});
setRespuestas(initial);
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -99,16 +100,21 @@ export default function FullCuestionario() {
const isMobile = () => typeof window !== 'undefined' && window.innerWidth < 576;
const sortedItems = useMemo(() => {
const items: any[] = [...formulario.preguntas, ...formulario.tablas];
const items: (Pregunta | Tabla)[] = [...formulario.preguntas, ...formulario.tablas];
return items.sort((a, b) => {
if (a.numeroPregunta === b.numeroPregunta) return (a.idTabla || 0) - (b.idTabla || 0);
if (a.numeroPregunta === b.numeroPregunta) {
const aId = 'idTabla' in a ? a.idTabla ?? 0 : 0;
const bId = 'idTabla' in b ? b.idTabla ?? 0 : 0;
return aId - bId;
}
return a.numeroPregunta - b.numeroPregunta;
});
}, [formulario]);
const isItemVisible = (item: any) => {
if (item.condicional) {
return respuestas[item.condicional.preguntaId] === item.condicional.valor;
const isItemVisible = (item: Pregunta | Tabla) => {
if ('condicional' in item && item.condicional) {
const cond = item.condicional;
return respuestas[cond.preguntaId] === cond.valor;
}
return true;
};
@@ -120,15 +126,16 @@ export default function FullCuestionario() {
const answer = respuestas[p.id];
let answered = false;
if (p.tipo === 'seleccionMultiple') {
if (p.id === 'criterios') answered = Array.isArray(answer) && answer.length === 3;
else answered = Array.isArray(answer) && answer.length > 0;
if (p.id === 'criterios') answered = Array.isArray(answer) && (answer as string[]).length === 3;
else answered = Array.isArray(answer) && (answer as string[]).length > 0;
} else {
answered = answer !== null && answer !== '';
answered = answer !== null && String(answer) !== '';
}
if (!answered) missing.push(`Pregunta ${p.numeroPregunta}`);
});
formulario.tablas.forEach((t) => {
const allAnswered = t.renglones.every((r) => respuestas[t.idTabla] && respuestas[t.idTabla][r.idRenglon] !== null);
const tablaResp = respuestas[String(t.idTabla)] as Record<number, string | null> | undefined;
const allAnswered = t.renglones.every((r) => !!tablaResp && tablaResp[r.idRenglon] !== null && tablaResp[r.idRenglon] !== undefined && tablaResp[r.idRenglon] !== '');
if (!allAnswered) missing.push(`Tabla ${t.numeroPregunta}`);
});
return missing;
@@ -151,7 +158,7 @@ export default function FullCuestionario() {
});
};
const updateRespuestas = (id: string, valor: any) => setRespuestas((prev) => ({ ...prev, [id]: valor }));
const updateRespuestas = (id: string, valor: string | string[] | Record<number, string | null> | null) => setRespuestas((prev) => ({ ...prev, [id]: valor }));
const handleTableResponse = (tablaId: number, renglonId: number, valor: string) => {
setRespuestas((prev) => ({ ...prev, [tablaId]: { ...(prev[tablaId] || {}), [renglonId]: valor } }));
@@ -163,12 +170,12 @@ export default function FullCuestionario() {
const resp = respuestas[pregunta.id];
if (pregunta.tipo === 'seleccionMultiple') {
if (pregunta.id === 'criterios') {
if (!resp || resp.length !== 3) {
if (!Array.isArray(resp) || (resp as string[]).length !== 3) {
window.alert(`Por favor, selecciona exactamente 3 opciones en la pregunta ${pregunta.numeroPregunta}.`);
return false;
}
} else {
if (!resp || resp.length === 0) {
if (!Array.isArray(resp) || (resp as string[]).length === 0) {
window.alert(`Por favor, selecciona al menos una opción en la pregunta ${pregunta.numeroPregunta}.`);
return false;
}
@@ -199,8 +206,8 @@ export default function FullCuestionario() {
return true;
};
const formatearRespuestas = (resps: Record<string, any>) => {
const resultado: Record<string, any> = {};
const formatearRespuestas = (resps: Record<string, string | string[] | Record<number, string | null> | null>) => {
const resultado: Record<string, string | string[]> = {};
for (const key in resps) {
const esTabla = !isNaN(Number(key));
if (esTabla) {
@@ -213,17 +220,19 @@ export default function FullCuestionario() {
const m = tablaDef.subPreguntaTabla.match(/^([A-E])\./);
if (m) subLetra = m[1];
}
const respuestasTabla = resps[key];
const respuestasTabla = resps[key] as Record<number, string | null> | undefined;
if (!respuestasTabla) continue;
for (const idR in respuestasTabla) {
const valor = respuestasTabla[idR];
const valor = respuestasTabla[idR as unknown as number] ?? '';
let clave = `p${numPregunta}_${idR}`;
if (subLetra) clave = `p${numPregunta}_${subLetra}_${idR}`;
resultado[clave] = valor;
resultado[clave] = String(valor);
}
} else {
const preguntaDef = formulario.preguntas.find((p) => p.id === key);
if (!preguntaDef) continue;
resultado[`p${preguntaDef.numeroPregunta}`] = resps[key];
const val = resps[key];
resultado[`p${preguntaDef.numeroPregunta}`] = Array.isArray(val) ? (val as string[]).join(',') : String(val ?? '');
}
}
return resultado;
@@ -234,15 +243,19 @@ export default function FullCuestionario() {
setIsLoading(true);
try {
const data = { ...formatearRespuestas(respuestas), idServicio: typeof window !== 'undefined' ? localStorage.getItem('idServicio') : null };
const apiUrl = (process.env as any).api || (process.env as any).NEXT_PUBLIC_API || '';
await axios.post(`${apiUrl}/cuestionario_alumno`, data);
await axiosInstance.post(`/cuestionario_alumno`, data);
window.alert('Se enviaron los datos correctamente');
if (typeof window !== 'undefined') {
localStorage.removeItem('idCuestionarioAlumno');
window.location.href = '/alumno';
}
} catch (err: any) {
window.alert(err?.response?.data?.message || 'Error al enviar el formulario');
} catch (err: unknown) {
let message = 'Error al enviar el formulario';
if (typeof err === 'object' && err !== null && 'response' in err) {
const anyErr = err as { response?: { data?: { message?: unknown } } };
if (anyErr.response?.data?.message) message = String(anyErr.response.data.message);
} else if (err instanceof Error) message = err.message;
window.alert(message);
} finally {
setIsLoading(false);
}
@@ -265,71 +278,75 @@ export default function FullCuestionario() {
)}
<div className="container mt-5">
{sortedItems.map((item: any, index: number) => {
{sortedItems.map((item, index) => {
if (!isItemVisible(item)) return null;
if ('tipo' in item && item.tipo) {
const p = item as Pregunta;
return (
<div key={p.id} className="mb-4 mt-6">
<label htmlFor={p.id} className="form-label">{p.numeroPregunta}. {p.texto}</label>
{p.tipo === 'seleccionUnica' && (
<div>
{p.opciones?.map((op) => (
<div key={p.id + '-' + op} className="SINO">
<label>
<input type="radio" name={p.id} checked={respuestas[p.id] === op} onChange={() => updateRespuestas(p.id, op)} /> {op}
</label>
</div>
))}
</div>
)}
{p.tipo === 'seleccionMultiple' && (
<div>
{p.opciones?.map((op) => (
<div key={op} className="SINO">
<label>
<input className="checkb" type="checkbox" value={op} checked={Array.isArray(respuestas[p.id]) && (respuestas[p.id] as string[]).includes(op)} onChange={(e) => toggleSelection(p.id, op, e)} /> {op}
</label>
</div>
))}
</div>
)}
{p.tipo === 'texto' && (
<div>
<input id={p.id} className="form-control" type="text" value={(respuestas[p.id] as string) || ''} onChange={(e) => updateRespuestas(p.id, e.target.value)} maxLength={p.limite || 200} placeholder="Escribe tu respuesta aquí" />
</div>
)}
</div>
);
}
const t = item as Tabla;
const tablaResp = respuestas[String(t.idTabla)] as Record<number, string | null> | undefined;
return (
<div key={item.id || item.idTabla} className="mb-4 mt-6">
{item.tipo ? (
<div>
<label htmlFor={item.id} className="form-label">{item.numeroPregunta}. {item.texto}</label>
{item.tipo === 'seleccionUnica' && (
<div>
{item.opciones.map((op: string) => (
<div key={item.id + '-' + op} className="SINO">
<label>
<input type="radio" name={item.id} checked={respuestas[item.id] === op} onChange={() => updateRespuestas(item.id, op)} /> {op}
</label>
</div>
<div key={t.idTabla} className="mb-4 mt-6">
{(index === 0 || t.numeroPregunta !== (sortedItems[index - 1] as Tabla).numeroPregunta) && (
<h3 className="mb-3">{t.numeroPregunta}. {t.preguntaTabla}</h3>
)}
{t.subPreguntaTabla && <h5 className="mb-3">{t.subPreguntaTabla}</h5>}
<div className="table-responsive">
<table className="table table-bordered text-center">
<thead>
<tr>
<th></th>
{t.renglones[0].opciones.map((op) => (
<th key={op}>{op}</th>
))}
</div>
)}
{item.tipo === 'seleccionMultiple' && (
<div>
{item.opciones.map((op: string) => (
<div key={op} className="SINO">
<label>
<input className="checkb" type="checkbox" value={op} checked={Array.isArray(respuestas[item.id]) && respuestas[item.id].includes(op)} onChange={(e) => toggleSelection(item.id, op, e)} /> {op}
</label>
</div>
))}
</div>
)}
{item.tipo === 'texto' && (
<div>
<input id={item.id} className="form-control" type="text" value={respuestas[item.id] || ''} onChange={(e) => updateRespuestas(item.id, e.target.value)} maxLength={item.limite || 200} placeholder="Escribe tu respuesta aquí" />
</div>
)}
</div>
) : (
<div className="table-responsive">
{(index === 0 || item.numeroPregunta !== sortedItems[index - 1].numeroPregunta) && (
<h3 className="mb-3">{item.numeroPregunta}. {item.preguntaTabla}</h3>
)}
{item.subPreguntaTabla && <h5 className="mb-3">{item.subPreguntaTabla}</h5>}
<table className="table table-bordered text-center">
<thead>
<tr>
<th></th>
{item.renglones[0].opciones.map((op: string) => (
<th key={op}>{op}</th>
</tr>
</thead>
<tbody>
{t.renglones.map((r) => (
<tr key={r.idRenglon}>
<td>{r.textoRenglon}</td>
{r.opciones.map((op) => (
<td key={op}>
<input type="radio" name={`tabla-${t.idTabla}-renglon-${r.idRenglon}`} value={op} checked={Boolean(tablaResp && tablaResp[r.idRenglon] === op)} onChange={() => handleTableResponse(t.idTabla, r.idRenglon, op)} />
</td>
))}
</tr>
</thead>
<tbody>
{item.renglones.map((r: any) => (
<tr key={r.idRenglon}>
<td>{r.textoRenglon}</td>
{r.opciones.map((op: string) => (
<td key={op}>
<input type="radio" name={`tabla-${item.idTabla}-renglon-${r.idRenglon}`} value={op} checked={respuestas[item.idTabla] && respuestas[item.idTabla][r.idRenglon] === op} onChange={() => handleTableResponse(item.idTabla, r.idRenglon, op)} />
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
)}
))}
</tbody>
</table>
</div>
</div>
);
})}
+6 -9
View File
@@ -1,7 +1,8 @@
"use client";
import { useState, useEffect } from "react";
import axios, { AxiosResponse } from "axios";
import { axiosInstance } from "@/api/config";
import { isAxiosError } from 'axios';
interface Alumno {
tokenArchivo: string;
@@ -19,7 +20,7 @@ interface Props {
servicio: Servicio;
imprimirMensaje: (msg: string) => void;
imprimirWarning: (msg: string, callback: () => void) => void;
imprimirError: (err: any) => void;
imprimirError: (err: unknown) => void;
obtenerServicio: () => void;
updateIsLoading: (loading: boolean) => void;
}
@@ -53,17 +54,13 @@ export default function PreTermino({
try {
updateIsLoading(true);
const res: AxiosResponse<{ message: string }> = await axios.put(
`${process.env.api}/servicio/informe_global`,
formData,
{ headers: { "Content-Type": "multipart/form-data", Authorization: alumno.tokenArchivo } }
);
const res = await axiosInstance.put(`/servicio/informe_global`, formData, { headers: { "Content-Type": "multipart/form-data", Authorization: alumno.tokenArchivo } });
imprimirMensaje(res.data.message);
obtenerServicio();
setFile(null);
} catch (err: unknown) {
if (axios.isAxiosError(err)) {
imprimirError(err.response?.data || err.message);
if (isAxiosError(err)) {
imprimirError((err.response?.data) || err.message);
} else {
imprimirError(err);
}
@@ -1,7 +1,7 @@
'use client';
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { axiosInstance } from '@/api/config';
import moment from 'moment';
import 'bootstrap/dist/css/bootstrap.min.css';
@@ -97,16 +97,19 @@ export default function CasoEspecialForm({
const buscarAlumno = async (): Promise<void> => {
try {
updateIsLoading(true);
const res = await axios.get(
`${process.env.NEXT_PUBLIC_API_URL}/usuario/escolares?numeroCuenta=${numeroCuenta}`,
responsable.token
);
const res = await axiosInstance.get(`/usuario/escolares?numeroCuenta=${numeroCuenta}`, responsable.token);
resetear();
setAlumno(res.data);
} catch (err: any) {
} catch (err: unknown) {
resetear();
setNumeroCuenta('');
imprimirError(err.response?.data || { message: 'Error al buscar alumno.' });
let msg = { message: 'Error al buscar alumno.' };
if (typeof err === 'object' && err !== null && 'response' in err) {
const anyErr = err as { response?: { data?: { message?: unknown } } };
const m = anyErr.response?.data as { message?: unknown } | undefined;
msg = { message: m?.message ? String(m.message) : msg.message };
} else if (err instanceof Error) msg = { message: err.message };
imprimirError(msg);
} finally {
updateIsLoading(false);
}
@@ -139,16 +142,24 @@ export default function CasoEspecialForm({
try {
updateIsLoading(true);
const res = await axios.post(
`${process.env.NEXT_PUBLIC_API_URL}/caso_especial/nuevo`,
formData,
responsable.tokenArchivo
);
const res = await axiosInstance.post(`/caso_especial/nuevo`, formData, responsable.tokenArchivo);
resetear();
setNumeroCuenta('');
imprimirMensaje(res.data.message);
} catch (err: any) {
imprimirError(err.response?.data || { message: 'Error al enviar formulario.' });
} catch (err: unknown) {
let msg: { message: string } = { message: 'Error al enviar formulario.' };
if (typeof err === 'object' && err !== null && 'response' in err) {
const anyErr = err as { response?: { data?: unknown } };
if (anyErr.response && typeof anyErr.response.data === 'object' && anyErr.response.data !== null) {
const d = anyErr.response.data as { message?: unknown } | unknown;
if (d && typeof d === 'object' && 'message' in d && typeof (d as { message?: unknown }).message === 'string') {
msg = { message: (d as { message?: unknown }).message as string };
}
}
} else if (err instanceof Error) {
msg = { message: err.message };
}
imprimirError(msg);
} finally {
updateIsLoading(false);
}
@@ -1,7 +1,7 @@
"use client";
import React, { useEffect, useState, useCallback } from "react";
import axios from "axios";
import { axiosInstance } from "@/api/config";
import ServicioSocialTabla from "../servicio-social-tabla";
interface Responsable {
@@ -69,19 +69,21 @@ export default function LiberarCasoEspecial({ responsable, imprimirError }: Prop
if (search.nombre) query += `&nombre=${search.nombre}`;
if (search.numeroCuenta) query += `&numeroCuenta=${search.numeroCuenta}`;
const res = await axios.get(
`${process.env.NEXT_PUBLIC_API_URL}/caso_especial/servicios_especiales?pagina=${page}${query}`,
{
const res = await axiosInstance.get(`/caso_especial/servicios_especiales?pagina=${page}${query}`, {
headers: {
Authorization: `Bearer ${responsable.token}`,
},
}
);
});
setData(res.data.serviciosEspeciales);
setTotal(res.data.count);
} catch (err: any) {
imprimirError(err.response?.data || "Error al obtener los casos especiales");
} catch (err: unknown) {
let msg = 'Error al obtener los casos especiales';
if (typeof err === 'object' && err !== null && 'response' in err) {
const anyErr = err as { response?: { data?: unknown } };
msg = String((anyErr.response?.data as { message?: unknown })?.message || msg);
} else if (err instanceof Error) msg = err.message;
imprimirError(msg);
} finally {
setIsLoading(false);
}
@@ -90,15 +92,20 @@ export default function LiberarCasoEspecial({ responsable, imprimirError }: Prop
// Obtener catálogo de status
const obtenerCatalogoStatus = useCallback(async () => {
try {
const res = await axios.get(`${process.env.NEXT_PUBLIC_API_URL}/status`, {
headers: {
Authorization: `Bearer ${responsable.token}`,
},
});
setStatus(res.data);
obtenerCasosEspeciales();
} catch (err: any) {
imprimirError(err.response?.data || "Error al obtener el catálogo de status");
const res = await axiosInstance.get(`/status`, {
headers: {
Authorization: `Bearer ${responsable.token}`,
},
});
setStatus(res.data);
obtenerCasosEspeciales();
} catch (err: unknown) {
let msg = 'Error al obtener el catálogo de status';
if (typeof err === 'object' && err !== null && 'response' in err) {
const anyErr = err as { response?: { data?: { message?: unknown } } };
msg = String(anyErr.response?.data?.message || msg);
} else if (err instanceof Error) msg = err.message;
imprimirError(msg);
}
}, [responsable.token, obtenerCasosEspeciales, imprimirError]);
@@ -128,7 +128,7 @@ export default function CuestionarioResponsbale2({
const sortedItems = useMemo(() => {
const items: (Pregunta | Tabla)[] = [...formulario.preguntas, ...formulario.tablas];
return items.sort((a: any, b: any) => {
return items.sort((a: { numeroPregunta: number; idTabla?: number }, b: { numeroPregunta: number; idTabla?: number }) => {
if (a.numeroPregunta === b.numeroPregunta) return (a.idTabla || 0) - (b.idTabla || 0);
return a.numeroPregunta - b.numeroPregunta;
});
@@ -258,8 +258,14 @@ export default function CuestionarioResponsbale2({
try { localStorage.removeItem('idCuestionarioAlumno'); } catch (_) {}
if (typeof window !== 'undefined') window.location.href = '/alumno';
} catch (err: unknown) {
const axiosErr = err as any;
imprimirError(axiosErr?.response?.data?.message || 'Error al enviar el formulario');
if (typeof err === 'object' && err !== null && 'response' in err) {
const anyErr = err as { response?: { data?: { message?: unknown } } };
imprimirError(String(anyErr.response?.data?.message) || 'Error al enviar el formulario');
} else if (err instanceof Error) {
imprimirError(err.message);
} else {
imprimirError('Error al enviar el formulario');
}
} finally {
updateIsLoading(false);
setIsLoading(false);
@@ -279,7 +285,7 @@ export default function CuestionarioResponsbale2({
)}
<div>
{sortedItems.map((item: any, index: number) => {
{sortedItems.map((item: Pregunta | Tabla, index: number) => {
if (!isItemVisible(item)) return null;
if ((item as Pregunta).tipo) {
const p = item as Pregunta;
@@ -319,7 +325,7 @@ export default function CuestionarioResponsbale2({
const t = item as Tabla;
return (
<div key={t.idTabla} className="mb-6 table-responsive">
{(index === 0 || t.numeroPregunta !== (sortedItems[index - 1] as any).numeroPregunta) && (
{(index === 0 || t.numeroPregunta !== (sortedItems[index - 1] as Tabla).numeroPregunta) && (
<h3 className="mb-3">{t.numeroPregunta}. {t.preguntaTabla}</h3>
)}
{t.subPreguntaTabla && <h5 className="mb-3">{t.subPreguntaTabla}</h5>}
@@ -201,7 +201,7 @@ export default function NuevoServicio({
<div className="mb-3">
<label className="form-label">Carrera</label>
<p className="input">{(alumno as Alumno).nombre ? (alumno as any).carrera : ''}</p>
<p className="input">{alumno.idCarrera ? String(alumno.idCarrera) : ''}</p>
</div>
<div className="mb-3">
@@ -42,7 +42,7 @@ export default function UploadArchivo({
try {
const headers = responsable?.tokenArchivo ? { Authorization: `Bearer ${responsable.tokenArchivo}`, 'Content-Type': 'multipart/form-data' } : { 'Content-Type': 'multipart/form-data' };
const res = await axiosInstance.put(`/servicio/${path}`, formData, { headers });
try { localStorage.removeItem('idServicio'); } catch (_) {}
try { localStorage.removeItem('idServicio'); } catch (error) {}
updateIsLoading(false);
imprimirMensaje(res.data?.message || 'Archivo subido');
if (typeof window !== 'undefined') window.location.href = '/responsable';
+3 -3
View File
@@ -44,7 +44,7 @@ export default function TablaServiciosSociales({
const month = (d.getMonth() + 1).toString().padStart(2, '0');
const year = d.getFullYear();
return `${day}/${month}/${year}`;
} catch (_) {
} catch (error) {
return String(date);
}
};
@@ -83,7 +83,7 @@ export default function TablaServiciosSociales({
const addPointer = () => (idTipoUsuario === 1 ? 'pointer' : '');
const responsableUpdate = (servicio: ServicioSocialResponse, p: string) => {
try { localStorage.setItem('idServicio', String(servicio.idServicio ?? servicio.id ?? '')); } catch (_) {}
try { localStorage.setItem('idServicio', String(servicio.idServicio ?? servicio.id ?? '')); } catch (error) {}
if (path) router.push(`/responsable/${p}`);
};
@@ -123,7 +123,7 @@ export default function TablaServiciosSociales({
<tr key={index} className={addPointer()} onClick={() => {
setServicioSelected(item);
if (idTipoUsuario === 1 && path) {
try { localStorage.setItem('idServicio', String(item.idServicio ?? item.id ?? '')); } catch (_) {}
try { localStorage.setItem('idServicio', String(item.idServicio ?? item.id ?? '')); } catch (error) {}
router.push(path);
}
}}>
+6 -6
View File
@@ -25,12 +25,12 @@ export interface Usuario {
export interface OtraTabla {
title: string;
admin: object;
alumno: object;
imprimirError?: (...args: any[]) => void;
imprimirMensaje?: (...args: any[]) => void;
imprimirWairning?: (...args: any[]) => void;
updateIsLoading?: (...args: any[]) => void;
admin: Record<string, unknown>;
alumno: Record<string, unknown>;
imprimirError?: (...args: unknown[]) => void;
imprimirMensaje?: (...args: unknown[]) => void;
imprimirWairning?: (...args: unknown[]) => void;
updateIsLoading?: (...args: unknown[]) => void;
}
export interface Carrera {