22 Commits

Author SHA1 Message Date
santiago 801e1b4205 Se modificaron varias cosas en el fetching de los datos asi como los nombres y estilos de algunas vistas 2025-12-09 09:05:57 -06:00
Patriots01 3de2f08ed2 Se modificaron las rutas de las peticiones 2025-11-27 23:31:06 +00:00
Patriots01 bbb0b0f795 Modificaiones en la fomrma de renderizar la info 2025-11-27 20:29:44 +00:00
Patriots01 6ff9641761 Se modifico el fechind de los datos en la vista de responsable 2025-11-26 22:00:35 +00:00
Patriots01 99adfdebb5 Modificaciones 2025-11-26 21:13:28 +00:00
Patriots01 ac1fd05638 Modificacinoes en los endpoint asi como los metodos 2025-11-25 22:00:20 +00:00
Patriots01 8b27cbd425 Se modificaron cosas de nombres a la hora de renderizar la informacion y se cambiaron los losnmbres de los endpoint asi como tambien las direcciones de algunos endpoint 2025-11-25 21:54:49 +00:00
Patriots01 82b5b1fc50 Modificaciones 2025-11-25 19:54:57 +00:00
Patriots01 e27b1fb643 Modificaciones 2025-11-25 19:03:57 +00:00
Patriots01 da73df3e7d Modificaciones 2025-11-25 17:55:39 +00:00
Patriots01 5a0fe4edde errores corregidos en login 2025-11-24 22:21:57 +00:00
santiago b1bafec1be Modificacines 2025-11-14 21:23:32 +01:00
santiago 763c017ce9 Se agrego la funcionalidad de descargar los reportes en la vista administrador/registro 2025-11-14 17:44:49 +01:00
santiago 36ef050f47 Nuevos estilos y correcion de errores 2025-11-11 20:56:21 +01:00
santiago d58283674d Correcion de error en la visyta de alumno 2025-11-10 22:16:33 +01:00
santiago 41e65d313b Nuevos estilos y se agrego la vista de alumno 2025-11-10 22:13:04 +01:00
santiago ca119f4d25 Modificaciones en la vista 2025-11-08 00:54:06 +01:00
santiago fec91b02c0 Nuevos estilos en las vistas 2025-11-07 00:56:04 +01:00
santiago 5c3556d6c3 Modificaciones en la vista de administrador/caso_especial, se agregaron los status 2025-11-06 18:02:23 +01:00
santiago c35358398e Nuevos estilos en las diferentes vistas 2025-11-05 21:02:02 +01:00
santiago 6500e41fbf Nuevos estilos en las diferentes vistas 2025-11-05 19:51:26 +01:00
santiago b089acca0c Se agregaron nuevos estilos en la vista de responsable/editar 2025-11-05 17:54:14 +01:00
48 changed files with 1764 additions and 1042 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

+1
View File
@@ -0,0 +1 @@
correo,nombre,institucion,dependencia,programa,clave
1 correo nombre institucion dependencia programa clave
+2 -2
View File
@@ -39,8 +39,8 @@ axiosInstance.interceptors.response.use(
if (error.response.status === 401) {
console.warn('Sesión expirada o token inválido.');
if (typeof window !== 'undefined') {
localStorage.clear();
window.location.href = '/'; // redirige automáticamente
//localStorage.clear();
//window.location.href = '/'; // redirige automáticamente
}
}
@@ -27,9 +27,9 @@ interface Status {
}
interface Alumno {
Usuario?: object;
Carrera?: object;
Status?: Status;
usuario?: object;
carrera?: object;
status?: Status;
}
export default function CasoEspecialPage() {
@@ -38,7 +38,7 @@ export default function CasoEspecialPage() {
const [isLoading, setIsLoading] = useState(false);
const [idCasoEspecial, setIdCasoEspecial] = useState<number | null>(null);
const [admin, setAdmin] = useState<Admin>({});
const [alumno, setAlumno] = useState<Alumno>({ Usuario: {}, Carrera: {}, Status: {} });
const [alumno, setAlumno] = useState<Alumno>({ usuario: {}, carrera: {}, status: {} });
// Funciones de dialogo
const imprimirError = (err: unknown = {}, title = '¡Hubo un error!', onConfirm = () => {}) => {
@@ -111,8 +111,11 @@ export default function CasoEspecialPage() {
updateIsLoading(true);
try {
const res = await axiosInstance.get(`/caso_especial?idCasoEspecial=${idCasoEspecial}`, { headers: { token: admin.token } });
setAlumno(res.data);
const res = await axiosInstance.get(`/caso-especial/caso_especial/${idCasoEspecial}`);
setAlumno(res.data.data);
console.log("Respuesta del servidor", res.data)
} catch (err: unknown) {
if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
else if (err instanceof Error) imprimirError(err.message);
@@ -148,7 +151,7 @@ export default function CasoEspecialPage() {
<InformacionCasoEspecial alumno={alumno} />
{(alumno.Status?.idStatus === 11 || alumno.Status?.idStatus === 12) && (
{(alumno.status?.idStatus === 11 || alumno.status?.idStatus === 12) && (
<LiberarCasoEspecial
idCasoEspecial={idCasoEspecial!}
admin={{ token: admin.token! }}
@@ -1,12 +1,23 @@
'use client'
import TablaCasosEspeciales from "@/components/administrador/tabla-casos-especiales";
import BotonRegresar from "@/components/boton-regresar";
import { useEffect, useState } from "react";
export default function CasosEspeciales() {
const [admin, setAdmin] = useState<{ idTipoUsuario: number; token?: string } | null>(null);
useEffect(() => {
const idTipoUsuario = Number(localStorage.getItem('idTipoUsuario') ?? 0);
const token = localStorage.getItem('token') ?? undefined;
if (!idTipoUsuario) return; // no logueado
setAdmin({ idTipoUsuario, token });
}, []);
return(
<section className="container px-2 pb-5">
<BotonRegresar />
<TablaCasosEspeciales />
<TablaCasosEspeciales admin={admin ?? undefined}/>
</section>
);
}
+24 -6
View File
@@ -1,20 +1,36 @@
'use client'
import Cuestionario from "@/components/administrador/cuestionario";
import GustavoBazPrada from "@/components/administrador/gustavo-baz-prada";
import Reporte from "@/components/administrador/reporte";
import BotonRegresar from "@/components/boton-regresar";
import { type } from "node:os";
import { useEffect } from "react";
export default function Registro() {
const years = [2020, 2021, 2022, 2023, 2024, 2025];
//const years = [2020, 2021, 2022, 2023, 2024, 2025];
const admin = { token: "mi_token_de_prueba" };
const obtenerYears = () => {
const years1 = [];
const fechaActual = new Date();
for( let i = 2020; i <= fechaActual.getFullYear(); i++) {
years1.push(i)
}
return years1
}
//const updateIsLoading = (loading: boolean) => {
// console.log("Loading:", loading);
//};
const years = obtenerYears()
useEffect(() => {
console.log("Estos son los datos de years", years)
console.log("Este es el tipo de datos de years", typeof(years))
}, [years]);
return (
<section className="container px-2 pb-5">
<BotonRegresar />
<h2 className="title mb-4">Reportes</h2>
<h2 className="title mb-4 fw-bold">Reportes</h2>
<Cuestionario
years={years}
admin={admin}
@@ -23,7 +39,9 @@ export default function Registro() {
<Reporte admin={admin}/>
<GustavoBazPrada />
<GustavoBazPrada
years={years}
/>
</section>
);
}
@@ -49,7 +49,7 @@ export default function Editar() {
try {
updateIsLoading(true)
const res = await axiosInstance.get(`usuario/responsable?idUsuario=${idUsuario}`)
const res = await axiosInstance.get(`usuario/responsable/${idUsuario}`)
//imprimirMensaje(res.data.message)
setData(res.data)
} catch (error) {
@@ -63,33 +63,35 @@ export default function Editar() {
}, []);
return (
<section>
<BotonRegresar />
<section className="container px-2 pb-5">
<div className="pt-4">
<BotonRegresar />
</div>
<EditarResponsable
<EditarResponsable
responsable={data}
imprimirError={imprimirError}
imprimirMensaje={imprimirMensaje}
imprimirWarning={imprimirWarning}
updateIsLoading={updateIsLoading}
/>
<ReasignacionProgramas
responsable={data}
imprimirError={imprimirError}
imprimirMensaje={imprimirMensaje}
imprimirWarning={imprimirWarning}
updateIsLoading={updateIsLoading}
/>
<ReasignacionProgramas
responsable={data}
imprimirError={imprimirError}
imprimirMensaje={imprimirMensaje}
imprimirWarning={imprimirWarning}
updateIsLoading={updateIsLoading}
/>
{/*
<EditarResponsable
token={token ?? undefined}
imprimirError={imprimirError}
imprimirMensaje={imprimirMensaje}
imprimirWarning={imprimirWarning}
updateIsLoading={updateIsLoading}
/>
*/}
{/*
<EditarResponsable
token={token ?? undefined}
imprimirError={imprimirError}
imprimirMensaje={imprimirMensaje}
imprimirWarning={imprimirWarning}
updateIsLoading={updateIsLoading}
/>
*/}
</section>
);
}
@@ -46,7 +46,7 @@ export default function Servicio() {
}, []);
return (
<section>
<section className="container">
<BotonRegresar />
{/* <EditarServicio admin={}/> */}
<EditarServicio
+13 -11
View File
@@ -78,10 +78,10 @@ Programa: { Usuario: {} },
//Interface
interface Datos {
Programa?: Programa;
Carrera?: Carrera;
Usuario?: Usuario;
Status?: Status;
programa?: Programa;
carrera?: Carrera;
usuario?: Usuario;
status?: Status;
creditos?: string;
correo?: string;
fechaRegistro?: string;
@@ -190,10 +190,10 @@ export default function Servicio() {
const obtenerRegistro = async (adminInfo: AdminInfo, idServicioVal: number) => {
try {
updateIsLoading(true);
const res = await axiosInstance.get(`/servicio/admin?idServicio=${idServicioVal}`); //, adminInfo.token
const res = await axiosInstance.get(`/servicio/admin/${idServicioVal}`); //, adminInfo.token
console.log('Respuesta del servicio:', res.data);
setDatos(res.data);
console.log('Programa obtenido:', datos.Status);
console.log('Programa obtenido:', datos.status);
} catch (error) {
//imprimirError(error.response?.data || { message: 'Error al obtener el registro' });
console.log('Error al obtener el registro:', error);
@@ -239,7 +239,7 @@ export default function Servicio() {
<section className="container px-2 pb-6">
<BotonRegresar />
<h3 className="title">{datos.Status?.status}</h3>
<h3 className="container fw-bold title">{datos.status?.status}</h3>
<InformacionServicio
datos={datos}
@@ -248,7 +248,7 @@ export default function Servicio() {
updateIsLoading={updateIsLoading}
/>
<TituloStatus status={datos.Status}/>
<TituloStatus status={datos.status}/>
{/* Para mostrar si tiene la carta y poder ver los diferentes archivos */}
{datos.cartaAceptacion && (
@@ -265,7 +265,7 @@ export default function Servicio() {
{datos.cartaTermino && (
<Archivo
title={datos.cartaTermino ? "carta de término" : ""}
title={datos.cartaTermino ? "carta de termino" : ""}
datos={datos}
admin={admin}
imprimirMensaje={imprimirMensaje}
@@ -287,7 +287,7 @@ export default function Servicio() {
/>
)}
<div>
<div className='container'>
{datos.idCuestionarioPrograma || datos.idCuestionarioPrograma2 ? (
<p className="my-4">
<strong>Cuenta con cuestionario de programa resuelto.</strong>
@@ -373,7 +373,9 @@ export default function Servicio() {
*/}
<BotonRegresar />
<div className='container mt-4'>
<BotonRegresar />
</div>
{isLoading && (
<div className="loading-overlay">
+20 -2
View File
@@ -8,8 +8,26 @@ import FullCuestionario from '@/components/alumno/cuestionario2/full-cuestionari
export default function Page() {
return (
<div className='bg-light'>
<BotonRegresar />
<div className='container bg-light'>
<div className='mt-4'>
<BotonRegresar />
</div>
<div className='my-1'>
<h1 className='is-size-2'>2025 evaluación del universitario(a) sobre su servicio social</h1>
<p>
Te invitamos a compartir tu experiencia respecto del programa de servicio social en el que
participaste, a efecto de mejorar la oferta de programas disponibles para los alumnos que
desean liberar este requisito. Te recordamos que tus respuestas son confidenciales.
Los datos están sujetos al aviso de privacidad integral que se puede consultar en el sitio
web: <a
href="https://www.acatlan.unam.mx/normatividad"
className="column text-decoration-none text-morado"
target="_blank"> www.acatlan.unam.mx/normatividad </a>
</p>
</div>
<FullCuestionario />
</div>
);
+122 -27
View File
@@ -1,27 +1,107 @@
"use client"
import { axiosInstance } from "@/api/config";
import BarraProgreso from "@/components/alumno/barra-progreso";
import CompletarDatosPersonales from "@/components/alumno/completar-datos-personales";
import NavCues from "@/components/alumno/cuestionario/nav-cues";
import InformacinoServicio from "@/components/alumno/informacion-servicio";
import MensajeAlumno from "@/components/alumno/mensajes-alumno";
import PreTermino from "@/components/alumno/pre-termino";
import { useEffect, useState } from "react";
interface InfoAlumnoExtendido extends InfoAlumno {
Usuario: { usuario: string, nombre: string},
}
interface Usuario {
usuario: string,
nombre: string,
}
interface InfoAlumno{
idServicio: number,
creditos: string,
correo: string,
telefono: string,
direccion: string,
fechaInicio: string,
fechaFin: string,
fechaLiberacion: string,
informeGlobal: string, // Falta ajustar el tipo de datos
programaInterno: string,
profesor: string,
//createdAt: Date,
idCuestionarioAlumno: number,
idCuestionarioAlumno2: number,
Carrera: Carrera,
Status: Status,
Programa: Programa,
}
interface Carrera {
idCarrera: number,
carrera: string,
}
interface Status {
idStatus: number,
status: string,
}
interface Programa {
idPrograma: number,
institucion: string,
dependencia: string,
programa: string,
clavePrograma: string,
}
export default function Home() {
const [data, setData] = useState<InfoAlumnoExtendido>();
const handleInfo = async () => {
const idUsuario = localStorage.getItem('idUsuario');
const usuario = localStorage.getItem('usuario');
const nombre = localStorage.getItem('nombre');
const tokenAlumno = localStorage.getItem('token')
console.log('entro para hacer el fetch')
console.log('Este es el id del usuario', idUsuario)
try {
const inf = await axiosInstance.get(`/servicio/alumno?idUsuario=${idUsuario}`)
const Usuario = {
usuario, nombre,
}
console.log("Esta es la inforamcion que trae el back", inf);
const combinado: InfoAlumnoExtendido = { ...inf.data, Usuario };
console.log('Esta es la info combinada', combinado)
setData(combinado);
console.log("Este es la infromacion combinada", data);
} catch (error) {
console.log("Error al hacer la peticion ", error)
}
}
useEffect(() => {
handleInfo();
}, []);
return (
<div>
<BarraProgreso idStatus={5}/>
<CompletarDatosPersonales
idServicio={123}
alumno={{ token: { headers: { Authorization: "Bearer ..." } }, tokenArchivo: { headers: { Authorization: "Bearer ..." } } }}
imprimirMensaje={(msg) => console.log(msg)}
imprimirWarning={(msg, callback) => { if (confirm(msg)) callback(); }}
imprimirError={(err) => console.error(err)}
obtenerServicio={() => console.log("obtener servicio")}
updateIsLoading={(loading) => console.log("loading", loading)}
/>
{ data?.Status.idStatus && (
<BarraProgreso idStatus={data?.Status.idStatus}/>
)}
<InformacinoServicio
servicio={{
<div className="my-5">
<MensajeAlumno Status={{ idStatus: 2 }} />
</div>
{/* servicio={{
Programa: {
institucion: "UNAM",
dependencia: "Académicos",
@@ -35,25 +115,40 @@ export default function Home() {
fechaInicio: new Date().toISOString(),
fechaFin: new Date().toISOString(),
createdAt: new Date().toISOString(),
}}
/>
}} */}
{ data && (
<InformacinoServicio
servicio={data}
/>
)}
<MensajeAlumno Status={{ idStatus: 2 }} />
{ data?.Status.idStatus === 2 && (
<CompletarDatosPersonales
idServicio={123}
alumno={{ token: { headers: { Authorization: "Bearer ..." } }, tokenArchivo: { headers: { Authorization: "Bearer ..." } } }}
imprimirMensaje={(msg) => console.log(msg)}
imprimirWarning={(msg, callback) => { if (confirm(msg)) callback(); }}
imprimirError={(err) => console.error(err)}
obtenerServicio={() => console.log("obtener servicio")}
updateIsLoading={(loading) => console.log("loading", loading)}
/>
)}
<PreTermino
alumno={{ tokenArchivo: "token123" }}
servicio={{ idServicio: 123, informeGlobal: undefined }}
imprimirMensaje={(msg) => console.log(msg)}
imprimirWarning={(msg, callback) => {
if (confirm(msg)) callback();
}}
imprimirError={(err) => console.error(err)}
obtenerServicio={() => console.log("obtener servicio")}
updateIsLoading={(loading) => console.log("loading", loading)}
/>
{ data?.Status.idStatus !== undefined && data?.Status.idStatus >= 4 && (
<PreTermino
alumno={{ tokenArchivo: "token123" }}
servicio={data}
imprimirMensaje={(msg) => console.log(msg)}
imprimirWarning={(msg, callback) => {
if (confirm(msg)) callback();
}}
imprimirError={(err) => console.error(err)}
obtenerServicio={() => console.log("obtener servicio")}
updateIsLoading={(loading) => console.log("loading", loading)}
/>
)}
</div>
);
}
+2 -2
View File
@@ -25,10 +25,10 @@ export default function Nuevo() {
}
return (
<div>
<div className="container">
<BotonRegresar />
<h2>Agregar un Servicio Social</h2>
<h2 className="fw-bold">Agregar un Servicio Social</h2>
<CasoEspecialForm
imprimirError={imprimirError}
+2 -2
View File
@@ -49,8 +49,8 @@ export default function Page() {
return (
<section className="container px-2 pb-6">
<div className="pb-5 pt-6 mt-5 mb-4 border-b border-gray-200">
<button onClick={() => router.push('/casoEspecial/nuevo')}>Nuevo Caso Especial</button>
<div className="pb-4 pt-6 mt-5 mb-4 border-b border-gray-200">
<button className="rounded-2" onClick={() => router.push('/casoEspecial/nuevo')}>Nuevo Caso Especial</button>
</div>
{responsable.idTipoUsuario !== undefined && responsable.token ? (
+9
View File
@@ -3,6 +3,15 @@ import Header from "@/components/layout/header";
import "./globals.css";
import Footer from "@/components/layout/footer";
import "@/sass/bootstrap.scss"
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'IRIS',
description: 'Este es un servicio para hacer el servicio social de la FES Acatlan',
icons: {
icon: '/favicon.ico'
}
}
export default function RootLayout({
children,
+22 -6
View File
@@ -6,13 +6,28 @@ import React from "react";
export default function Home() {
const router = useRouter();
const [error, setError] = React.useState('');
const [loadingData, setLoadingData] = React.useState({
usuario: '',
password: '',
});
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setLoadingData((prevData) => ({ ...prevData, [name]: value}));
if (error) setError('');
}
const handleOnSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const object = Object.fromEntries(formData);
try {
const res = await axiosInstance.post('/usuario/login', object);
const res = await axiosInstance.post('/auth/login', {
usuario: loadingData.usuario,
password: loadingData.password,
});
// Extraer datos del backend
const token = res?.data?.token ?? '';
@@ -31,6 +46,7 @@ export default function Home() {
localStorage.setItem('nombre', String(nombre));
localStorage.setItem('idTipoUsuario', String(idTipoUsuario));
// Validar y redirigir según el idTipoUsuario
if (token && idUsuario && idTipoUsuario) {
switch (idTipoUsuario) {
@@ -48,16 +64,16 @@ export default function Home() {
break;
default:
console.warn(`Tipo de usuario desconocido: ${idTipoUsuario}`);
localStorage.clear();
//localStorage.clear();
break;
}
} else {
localStorage.clear();
//localStorage.clear();
console.error('Error: datos de usuario incompletos');
}
} catch (error) {
console.error('Error en el inicio de sesión:', error);
localStorage.clear();
//localStorage.clear();
}
};
@@ -68,12 +84,12 @@ export default function Home() {
<div className="mb-3">
<label htmlFor="usuario" className="form-label">Usuario</label>
<input type="text" name="usuario" id="usuario" className="form-control" required />
<input type="text" name="usuario" id="usuario" className="form-control" onChange={handleChange} required />
</div>
<div className="mb-4">
<label htmlFor="password" className="form-label">Contraseña</label>
<input type="password" name="password" id="password" className="form-control" required />
<input type="password" name="password" id="password" className="form-control" onChange={handleChange} required />
</div>
<div className="d-grid">
+1 -1
View File
@@ -110,7 +110,7 @@ export default function Page() {
</p>
<p>
<a href="https://www.acatlan.unam.mx/normatividad" target="_blank" rel="noreferrer"> www.acatlan.unam.mx/normatividad</a>
<a href="https://www.acatlan.unam.mx/normatividad" target="_blank" rel="noreferrer" className="text-decoration-none text-morado"> www.acatlan.unam.mx/normatividad</a>
</p>
</div>
+1 -1
View File
@@ -81,7 +81,7 @@ export default function Page() {
</p>
</div>
<h2 className="title">Añadir Servicio Social</h2>
<h2 className="title fw-bold mt-4 mb-4">Añadir Servicio Social</h2>
<NuevoServicio
responsable={responsable}
+10 -7
View File
@@ -53,17 +53,20 @@ export default function Page() {
};
useEffect(() => {
const r: Responsable = {
idUsuario: Number(localStorage.getItem('idUsuario')) || undefined,
idTipoUsuario: Number(localStorage.getItem('idTipoUsuario')) || undefined,
//tipoUsuario: localStorage.getItem('tipoUsuario') || undefined,
token: localStorage.getItem('token') || undefined,
};
const r: Responsable = {
idUsuario: Number(localStorage.getItem('idUsuario')) || undefined,
idTipoUsuario: Number(localStorage.getItem('idTipoUsuario')) || undefined,
//tipoUsuario: localStorage.getItem('tipoUsuario') || undefined,
token: localStorage.getItem('token') || undefined,
};
setResponsable(r);
console.log('Responsable:', r);
console.log('id Usuario en componente padrre', r.idUsuario);
//ontenerCatalogoStatus();
console.log("Esta es la infromacino del useState en responsable", responsable)
if (r.idTipoUsuario === 1) router.push('/administrador');
if (r.idTipoUsuario === 3) router.push('/alumno');
if (r.idTipoUsuario === 4) router.push('/casoEspecial');
@@ -85,7 +88,7 @@ export default function Page() {
</div>
<div className="pb-3">
<button className="button is-info" onClick={() => router.push('/responsable/nuevo')}>Agregar alumno</button>
<button className="button is-info rounded-2" onClick={() => router.push('/responsable/nuevo')}>Agregar alumno</button>
</div>
{tabla}
+18 -5
View File
@@ -145,13 +145,25 @@ export default function Archivo({
axiosInstance.put(`/servicio/rechazar_informe`, data);
return (
<div className="mb-4">
<div className="container mb-4">
<div className="flex items-center">
<h6 className="pr-4 text-lg">Ver {title}</h6>
<div className="pr-4">
<h5 className="pr-4 text-lg">
Ver {title}
<a
className="btn btn-link btn-light"
className="btn btn-link btn-light text-decoration-none ms-3 text-morado"
target="_blank"
rel="noopener noreferrer"
href={`https://drive.google.com/file/d/${archivo()}/view?usp=sharing`}
style={{ background: '#eae4f8'}}
>
Ver
</a>
</h5>
{/*
<div className="pr-4">
<a
className="btn btn-link btn-light text-decoration-none"
target="_blank"
rel="noopener noreferrer"
href={`https://drive.google.com/file/d/${archivo()}/view?usp=sharing`}
@@ -159,6 +171,7 @@ export default function Archivo({
Ver
</a>
</div>
*/}
{((datos.Status?.idStatus === 1 && title === "carta de aceptación") ||
(datos.Status?.idStatus === 5 &&
@@ -81,7 +81,7 @@ export default function CancelarServicio({
const res = await axiosInstance.put(`/servicio/cancelar`, data);
localStorage.removeItem("idServicio");
imprimirMensaje(res.data.message);
router.push("/admin");
router.push("/administrador");
} catch (err: unknown) {
if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
else if (err instanceof Error) imprimirError(err.message);
@@ -92,49 +92,49 @@ export default function CancelarServicio({
};
return (
<div className="mt-5 space-y-4">
{/* Botón de Cancelar */}
<button
disabled={datos.Status?.idStatus === 6 || datos.Status?.idStatus === 10}
onClick={updateCancelar}
className={`px-4 py-2 rounded text-white ${
datos.Status?.idStatus === 6 || datos.Status?.idStatus === 10
? "bg-gray-400 cursor-not-allowed"
: "bg-red-600 hover:bg-red-700"
}`}
>
Cancelar
</button>
{/* Área de mensaje */}
{cancelar && (
<div className="space-y-2">
<label className="block font-medium">Razón de la cancelación:</label>
<textarea
maxLength={500}
value={mensajeCancelar}
onChange={(e) => setMensajeCancelar(e.target.value)}
className="border rounded p-2 w-full"
/>
<div className="container mt-5 space-y-4">
{/* Botón de Cancelar */}
<button
disabled={!mensajeCancelar}
onClick={() =>
imprimirWarning(
"¿Seguro(a) que quiere cancelar este servicio?",
cancelarServicio
)
}
className={`px-4 py-2 rounded text-white ${
!mensajeCancelar
disabled={datos.Status?.idStatus === 6 || datos.Status?.idStatus === 10}
onClick={updateCancelar}
className={`px-4 py-2 bg-danger rounded text-white${
datos.Status?.idStatus === 6 || datos.Status?.idStatus === 10
? "bg-gray-400 cursor-not-allowed"
: "bg-blue-600 hover:bg-blue-700"
: "bg-red-600 hover:bg-red-700"
}`}
>
Cancelar servicio
Cancelar
</button>
</div>
)}
{/* Área de mensaje */}
{cancelar && (
<div className="space-y-2 mt-3">
<label className="block font-medium mb-2">Razón de la cancelación:</label>
<textarea
maxLength={500}
value={mensajeCancelar}
onChange={(e) => setMensajeCancelar(e.target.value)}
className="form-control border rounded p-2 w-full"
/>
<button
disabled={!mensajeCancelar}
onClick={() =>
imprimirWarning(
"¿Seguro(a) que quiere cancelar este servicio?",
cancelarServicio
)
}
className={`bg-morado mt-3 mb-4 px-4 py-2 rounded text-white ${
!mensajeCancelar
? "bg-gray-400 cursor-not-allowed"
: "bg-blue-600 hover:bg-blue-700"
}`}
>
Cancelar servicio
</button>
</div>
)}
</div>
);
}
+19 -5
View File
@@ -5,15 +5,25 @@ import { useRouter } from "next/navigation";
import React, { useState } from "react";
import { Button, Form } from "react-bootstrap";
import { FaUpload } from "react-icons/fa";
import { ImDownload } from "react-icons/im";
export default function CargaMasiva({datos}: {datos: CargaMasivaProps}) {
const router = useRouter();
const [csv, setCsv] = useState<File | null>(null)
const url = process.env.NEXT_PUBLIC_API_URL
const link = `${url}/plantilla.csv`
//const link = `${url}/plantilla.csv`
const handleDowload = () => {
console.log("Esta entrando a la funcion");
const link = document.createElement("a");
link.href = "/plantilla/plantilla.csv";
link.download = "plantilla.csv";
link.click();
}
//const [link] = useState(`${url}/plantilla.csv`)
//console.log("Esta es la url para descargar la plantilla", link);
const validarExt = (file: File | null) => {
if (!file) return
const extPermitidas = /(.csv)$/i
@@ -38,9 +48,13 @@ export default function CargaMasiva({datos}: {datos: CargaMasivaProps}) {
//updateIsLoading(true)
try {
console.log("Este es el archivo csv", formData)
const res = await axiosInstance.post("/programa/carga_masiva", formData,{
headers: {
Authorization: `Bearer ${datos.admin.tokenArchivo}`,
'Content-Type': 'multipart/form-data',
},
})
console.log('Respuesta de carga masiva:', res.data)
@@ -86,16 +100,16 @@ export default function CargaMasiva({datos}: {datos: CargaMasivaProps}) {
disabled={!csv}
onClick={enviarCargaMasiva}>
Enviar archivo
</Button>
</Button>
<Button
href={link}
<Button
onClick={handleDowload}
target="_blank"
rel="noopener noreferrer"
className="bg-morado border-morado"
>
Descargar plantilla
</Button>
</Button>
</div>
</div>
);
@@ -119,7 +119,7 @@ export default function ConfirmarServicio({
};
return (
<div className="space-y-4">
<div className="container space-y-4">
{datos.Status?.idStatus === 5 && datos.Programa?.acatlan && (
<div className="flex items-center space-x-2">
<input
+43 -16
View File
@@ -1,5 +1,6 @@
"use client"
import { axiosInstance } from "@/api/config";
import { error } from "console";
import { useState } from "react";
import { Button, Col, FormGroup, FormLabel, FormSelect, InputGroup } from "react-bootstrap";
@@ -10,26 +11,50 @@ interface Props {
}
export default function Cuestionario({ years, admin, updateIsLoading }: Props) {
const [selectedCuestionario, setSelectedCuestionario] = useState("");
const [selectedCuestionario, setSelectedCuestionario] = useState({});
const [version, setVersion] = useState("");
const [selectedYear, setSelectedYear] = useState("");
const downloadExcel = async () => {
try {
//updateIsLoading(true);
const res = await axiosInstance.get(`/${selectedCuestionario}`, {
params: { year: selectedYear, version },
//const res = await axiosInstance.get(`/cuestionario_alumno?year=${selectedCuestionario}&version=${version}`, {
const res = await axiosInstance.get(`/cuestionario-alumno2`, {
params: { anio: selectedYear, version },
responseType: "blob",
});
console.log("Esrta es la respuesta", res)
console.log("Esta es la infromacino de la respuesta", res.data)
//saveAs(res.data, `${selectedYear}_${selectedCuestionario}_${version}.csv`);
// Crear blob manualmente
const blob = new Blob([res.data], { type: "text/csv" });
// Crear URL temporal para descargar
const url = window.URL.createObjectURL(blob);
// Crear link "virtual"
const link = document.createElement("a");
link.href = url;
link.download = `${selectedYear}_${selectedCuestionario}_${version}.csv`;
// Disparar descarga
document.body.appendChild(link);
link.click();
// limpiar URL temporal
link.remove();
window.URL.revokeObjectURL(url);
// reset
setSelectedYear("");
setSelectedCuestionario("");
setVersion("");
//updateIsLoading(false);
} catch (err: unknown) {
console.error("Error en descargar el formulario", err)
//updateIsLoading(false);
// optional: handle error, e.g. console.error(err)
}
@@ -42,9 +67,10 @@ export default function Cuestionario({ years, admin, updateIsLoading }: Props) {
<div>
<Col>
<FormGroup>
<FormLabel>Cuestionario:</FormLabel>
<FormLabel className="fw-semibold">Cuestionario:</FormLabel>
<InputGroup>
<FormSelect>
<FormSelect onChange={(e) => setSelectedCuestionario(e.target.value)}>
<option value="">Seleccione un cuestionario:</option>
<option value="cuestionario_alumno">Cuestionario de Alumnos</option>
<option value="cuestionario_programa">Cuestionario de Programas</option>
</FormSelect>
@@ -54,9 +80,10 @@ export default function Cuestionario({ years, admin, updateIsLoading }: Props) {
<Col>
<FormGroup>
<FormLabel>Version:</FormLabel>
<FormLabel className="fw-semibold">Version:</FormLabel>
<InputGroup>
<FormSelect>
<FormSelect value={version} onChange={(e) => setVersion(e.target.value)}>
<option value="">Seleccione una version:</option>
<option value="v1">V1</option>
<option value="v2">V2</option>
</FormSelect>
@@ -66,15 +93,15 @@ export default function Cuestionario({ years, admin, updateIsLoading }: Props) {
<Col>
<FormGroup>
<FormLabel>Año:</FormLabel>
<FormLabel className="fw-semibold">Año:</FormLabel>
<InputGroup>
<FormSelect value={selectedYear} onChange={(e) => setSelectedYear(e.target.value)}>
<option value="">Seleccione un año:</option>
{years.map((y, i) => (
<option key={i} value={y}>
{y}
</option>
))}
<option value="">Seleccione un año:</option>
{years.map((y, i) => (
<option key={i} value={y}>
{y}
</option>
))}
</FormSelect>
</InputGroup>
</FormGroup>
@@ -82,10 +109,10 @@ export default function Cuestionario({ years, admin, updateIsLoading }: Props) {
<div className="d-flex gap-2 mt-4 mb-3">
<Button
disabled={!selectedYear || !selectedCuestionario || !version}
//disabled={!selectedYear || !selectedCuestionario || !version}
onClick={downloadExcel}
>
Enviar archivo
Descragar Excel
</Button>
</div>
</div>
@@ -26,6 +26,11 @@ interface Props {
updateIsLoading: (value: boolean) => void;
}
function convertirFecha(fecha: string | Date) {
return new Date(fecha).toISOString().split("T")[0];
}
export default function EditarResponsable({
//admin,
responsable,
@@ -54,19 +59,29 @@ export default function EditarResponsable({
// Actualizar información del responsable
const actualizar = async () => {
const data: Record<string, unknown> = { idUsuario: responsable.idUsuario };
const idResponsable = localStorage.getItem("idResponsable");
if (!idResponsable) return
const data: Record<string, unknown> = { idUsuario: responsable.idUsuario };
if (nuevo.correo) data.correo = nuevo.correo;
if (nuevo.nombre) data.nombre = nuevo.nombre;
// Hacemos el parseo de la fecha
//data.fechaNacimiento = convertirFecha(data.fechaNacimiento);
try {
updateIsLoading(true);
const res = await axiosInstance.put(`/usuario/responsable/update`, data);
const res = await axiosInstance.patch(`/usuario/responsable/${idResponsable}`, data);
imprimirMensaje(res.data.message);
router.push("/administrador/responsables/responsable");
} catch (err: unknown) {
let msg: unknown = err;
if (isAxiosError(err) && err.response?.data) {
msg = err.response.data;
console.error("ERROR DEL SERVER:", err.response.data);
msg = JSON.stringify(err.response.data, null, 2);
} else if (err instanceof Error) {
msg = err.message;
}
@@ -80,9 +95,13 @@ export default function EditarResponsable({
const password = async () => {
const data = { idUsuario: responsable.idUsuario };
const idResponsable = localStorage.getItem("idResponsable");
if (!idResponsable) return
try {
updateIsLoading(true);
const res = await axiosInstance.put(`/usuario/new_password_responsable`, data);
const res = await axiosInstance.post(`/usuario/new-password-responsable/${idResponsable}`);
imprimirMensaje(res.data.message);
router.push("/administrador/responsables/responsable");
} catch (err: unknown) {
@@ -100,62 +119,64 @@ export default function EditarResponsable({
return (
<div className="space-y-4 mt-6">
<h3 className="text-2xl font-semibold mb-4">Editar información del responsable</h3>
<div className="sspace-y-4 mt-6">
<h2 className="text-2xl mb-4 fw-semibold">Editar información del responsable</h2>
{/* Nombre */}
<div>
<label className="block mb-1 font-medium">Nombre</label>
<input
type="text"
placeholder={responsable.nombre}
value={nuevo.nombre || ""}
onChange={(e) => setNuevo({ ...nuevo, nombre: e.target.value })}
className="border rounded p-2 w-full"
/>
</div>
{/* Correo */}
<div>
<label className="block mb-1 font-medium">Correo electrónico</label>
<input
type="email"
placeholder={responsable.usuario}
value={nuevo.correo || ""}
onChange={(e) => setNuevo({ ...nuevo, correo: e.target.value })}
className="border rounded p-2 w-full"
/>
</div>
{/* Nombre */}
<div className="mb-3">
<label className="form-label fw-semibold block mb-1 font-medium">Nombre</label>
<input
type="text"
placeholder={responsable.nombre}
value={nuevo.nombre || ""}
onChange={(e) => setNuevo({ ...nuevo, nombre: e.target.value })}
className="form-control border rounded p-2 w-full"
/>
</div>
{/* Botones */}
<div className="pt-5 flex gap-4">
<button
disabled={mostrarBoton()}
onClick={() =>
imprimirWarning(
"¿Seguro(a) que quiere actualizar la información de este usuario?",
actualizar
)
}
className={`px-4 py-2 rounded text-white ${
mostrarBoton() ? "bg-gray-400 cursor-not-allowed" : "bg-blue-600 hover:bg-blue-700"
}`}
>
Guardar Cambios
</button>
{/* Correo */}
<div>
<label className="form-label block mb-1 font-medium">Correo electrónico</label>
<input
type="email"
placeholder={responsable.usuario}
value={nuevo.correo || ""}
onChange={(e) => setNuevo({ ...nuevo, correo: e.target.value })}
className="form-control border rounded p-2 w-full"
/>
</div>
<button
onClick={() =>
imprimirWarning(
"¿Seguro(a) que quiere cambiar la contraseña para este usuario?",
password
)
}
className="px-4 py-2 rounded bg-blue-500 hover:bg-blue-600 text-white"
>
Cambiar contraseña
</button>
</div>
{/* Botones */}
<div className="pt-5 flex gap-4">
<button
disabled={mostrarBoton()}
onClick={() =>
imprimirWarning(
"¿Seguro(a) que quiere actualizar la información de este usuario?",
actualizar
)
}
className={`mb-4 px-4 py-2 rounded text-white ${
mostrarBoton() ? "bg-gray-400 cursor-not-allowed" : "bg-blue-600 hover:bg-blue-700"
}`}
>
Guardar Cambios
</button>
<button
onClick={() =>
imprimirWarning(
"¿Seguro(a) que quiere cambiar la contraseña para este usuario?",
password
)
}
className="ms-3 px-4 py-2 rounded bg-morado hover:bg-blue-600 text-white"
>
Cambiar contraseña
</button>
</div>
</div>
);
}
+260 -139
View File
@@ -8,9 +8,12 @@ import validator from "validator";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import { useRouter } from "next/navigation";
import { Col, FormGroup, FormLabel, InputGroup } from "react-bootstrap";
import { FaRegCalendarAlt, FaUpload } from "react-icons/fa";
import { TbFlagSearch } from "react-icons/tb";
interface Servicio {
Status: { idStatus?: number };
status: { idStatus?: number };
correo?: string;
direccion?: string;
telefono?: string;
@@ -42,8 +45,11 @@ export default function EditarServicio({
imprimirWarning,
updateIsLoading,
}: Props) {
const [selectedInicio, setSelectedInicio] = useState<Date | null>(null);
const [selectFechaFin, setSelectedFechaFin] = useState<Date | null>(null);
const [servicioid, setServicioid] = useState<number>();
const [servicio, setServicio] = useState<Servicio>({ Status: {} });
const [servicio, setServicio] = useState<Servicio>({ status: {} });
const [correo, setCorreo] = useState("");
const [telefono, setTelefono] = useState("");
const [direccion, setDireccion] = useState("");
@@ -60,6 +66,14 @@ export default function EditarServicio({
const fecha = (date?: Date) =>
date ? moment(date).format("DD/MM/YYYY") : "";
const validarFechas = () => {
const fechaInicio = moment(selectedInicio);
const fechaFin = moment(selectFechaFin);
if (!fechaInicio.isValid() || !fechaFin.isValid()) return true;
return false
}
// Validación de archivos
const sizeFileValido = (file: File) => {
if (file.size >= 20000000) {
@@ -80,14 +94,17 @@ export default function EditarServicio({
try {
updateIsLoading(true);
console.log("Obteniendo registro para servicioid al hacer el get:", servicioid);
const res = await axiosInstance.get(`/servicio/admin?idServicio=${servicioid}`);
const res = await axiosInstance.get(`/servicio/admin/${servicioid}`);
console.log("Respuesta del servicio obtenido:", res.data);
const data = res.data;
setServicio(data);
console.log("Esta es la info de la respuesta", res.data)
console.log("Esta es la info de la respuesta con doble data", res.data.data)
// Redirección si el estado no es válido
if (data.Status.idStatus === 6 || data.Status.idStatus === 10) {
router.push("/admin/servicio");
if (data.status.idStatus === 6 || data.status.idStatus === 10) {
router.push("/administrador/servicio");
}
setFechaInicio(new Date(data.fechaInicio));
@@ -120,9 +137,11 @@ export default function EditarServicio({
if (direccion) data.direccion = direccion;
if (correo) data.correo = correo;
if (telefono) data.telefono = telefono;
if (fechaInicio) data.fechaInicio = fechaInicio;
if (fechaFin) data.fechaFin = fechaFin;
if (fechaNacimiento) data.fechaNacimiento = fechaNacimiento;
// Transformamos las fechas para que no muestre error en el back
if (selectedInicio && moment(selectedInicio).isValid()) data.fechaInicio = moment(selectedInicio).format("YYYY-MM-DD");
if (selectFechaFin && moment(selectFechaFin).isValid()) data.fechaFin = moment(selectFechaFin).format("YYYY-MM-DD");
if (fechaNacimiento && moment(fechaNacimiento).isValid()) data.fechaNacimiento = moment(fechaNacimiento).format("YYYY-MM-DD");
formData.append("data", JSON.stringify(data));
@@ -146,13 +165,20 @@ export default function EditarServicio({
const password = async () => {
const data = { servicioid };
console.log("Id del servicio para nueva password", data);
console.log("Id servicio entrando a la info", data.servicioid)
//const idServicio ={ idServicio: servicioid }
try {
console.log("Si entro par mandar la solicitud")
updateIsLoading(true);
const res = await axiosInstance.put(`/usuario/new_password_alumno`, data);
const res = await axiosInstance.post(`/usuario/new-password-alumno/${data.servicioid}`);
imprimirMensaje(res.data.message);
updateIsLoading(false);
router.push("/admin");
router.push("/administrador");
} catch (err: unknown) {
console.log("No esta mandando la solicitud")
updateIsLoading(false);
if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
else if (err instanceof Error) imprimirError(err.message);
@@ -190,6 +216,9 @@ export default function EditarServicio({
} else {
setActualizarFechaFin(true);
}
console.log("Esta es la info de servicio", servicio);
}, [fechaInicio]);
// Validar tamaños de archivos
@@ -211,7 +240,7 @@ export default function EditarServicio({
useEffect(() => {
const id = Number(localStorage.getItem("idServicio"));
console.log("ID Servicio para editar:", id);
if (!id) router.push("/admin");
if (!id) router.push("/administrador");
else {
setServicioid(id);
console.log("idServicio seteado:", id);
@@ -223,143 +252,235 @@ export default function EditarServicio({
return (
<div className="space-y-4 mt-6">
<h3 className="text-2xl font-semibold mb-4">
Editar información del alumno
</h3>
<h2 className="fw-bold mb-4">
Editar información del alumno
</h2>
{/* Correo */}
<div>
<label className="block font-medium mb-1">
Correo electrónico del alumno
</label>
<input
type="email"
placeholder={servicio.correo || "Correo"}
value={correo}
onChange={(e) => setCorreo(e.target.value)}
className="border rounded p-2 w-full"
/>
</div>
{/* Fecha inicio */}
<div>
<label className="block font-medium mb-1">Fecha de inicio</label>
<DatePicker
selected={fechaFin}
onChange={(date: Date | null) => {
if (date) setFechaFin(date);
}}
minDate={fechaInicio}
className="border rounded p-2 w-full"
/>
</div>
{/* Fecha fin */}
<div>
<label className="block font-medium mb-1">Fecha de fin</label>
<DatePicker
selected={fechaInicio}
onChange={(date: Date | null) => {
if (date) setFechaInicio(date);
}}
minDate={new Date("2020-01-01")}
className="border rounded p-2 w-full"
/>
</div>
{/* Dirección */}
{servicio.direccion && (
<div>
<label className="block font-medium mb-1">Dirección</label>
<input
type="text"
placeholder={servicio.direccion}
value={direccion}
onChange={(e) => setDireccion(e.target.value)}
className="border rounded p-2 w-full"
/>
{/* Correo */}
<div className="mb-3">
<label className="form-label fw-semibold block font-medium mb-1">
Correo electrónico del alumno
</label>
<input
type="email"
placeholder={servicio.correo || "Correo"}
value={correo}
onChange={(e) => setCorreo(e.target.value)}
className="form-control border rounded p-2 w-full"
/>
</div>
)}
{/* Teléfono */}
{servicio.telefono && (
<div>
<label className="block font-medium mb-1">Teléfono</label>
<input
type="tel"
maxLength={10}
placeholder={servicio.telefono}
value={telefono}
onChange={(e) => setTelefono(e.target.value)}
className="border rounded p-2 w-full"
/>
{/* Fecha inicio */}
<Col>
<FormGroup>
<FormLabel>Fecha de inicio</FormLabel>
<InputGroup>
<InputGroup.Text>
<FaRegCalendarAlt />
</InputGroup.Text>
<DatePicker
selected={selectedInicio}
onChange={(date: Date | null ) => {
if (date) setSelectedInicio(date);
}}
placeholderText="Selecciona una fecha de inicio"
minDate={fechaInicio}
dateFormat={'dd-MM-yyyy'}
className="form-control"
wrapperClassName="flex-grow-1"
calendarClassName="mi-calendario"
/>
</InputGroup>
</FormGroup>
</Col>
<Col>
<FormGroup>
<FormLabel>Fecha de fin</FormLabel>
<InputGroup>
<InputGroup.Text>
<FaRegCalendarAlt />
</InputGroup.Text>
<DatePicker
selected={selectFechaFin}
onChange={(date: Date | null) => {
if (date) setSelectedFechaFin(date);
}}
placeholderText="Selecciona una fecha de fin"
dateFormat={'dd-MM-yyyy'}
className="form-control"
wrapperClassName="flex-grow-1"
calendarClassName="mi-calendario"
/>
</InputGroup>
</FormGroup>
</Col>
{/*
Fecha inicio
<div className="mb-3">
<label className="form-label fw-semibold block font-medium mb-1">Fecha de inicio</label>
<DatePicker
selected={fechaFin}
onChange={(date: Date | null) => {
if (date) setFechaFin(date);
}}
minDate={fechaInicio}
className="border rounded p-2 w-full"
/>
</div>
)}
{/* Fecha nacimiento */}
{servicio.fechaNacimiento && (
<div>
<label className="block font-medium mb-1">
Fecha de nacimiento
</label>
<DatePicker
selected={fechaFin}
onChange={(date: Date | null) => {
if (date) setFechaFin(date);
}}
minDate={fechaInicio}
className="border rounded p-2 w-full"
/>
fecha fin
<div className="mb-3">
<label className="form-labeñ fw-semibold block font-medium mb-1">Fecha de fin</label>
<DatePicker
selected={fechaInicio}
onChange={(date: Date | null) => {
if (date) setFechaInicio(date);
}}
minDate={new Date("2020-01-01")}
className="border rounded p-2 w-full"
/>
</div>
)}
*/}
{/* Subir archivos */}
<div className="space-y-2">
<label className="block font-medium mb-1">Carta de aceptación</label>
<input
type="file"
accept="application/pdf"
onChange={(e) =>
setCartaAceptacion(e.target.files ? e.target.files[0] : null)
}
className="border p-2 rounded w-full"
/>
</div>
{/* Dirección */}
{servicio.direccion && (
<div className="mb-3">
<label className="form-label fw-semibold block font-medium mb-1">Dirección</label>
<input
type="text"
placeholder={servicio.direccion}
value={direccion}
onChange={(e) => setDireccion(e.target.value)}
className="form-control border rounded p-2 w-full"
/>
</div>
)}
{/* Botones */}
<div className="mt-6 flex gap-4">
<button
disabled={mostrar()}
onClick={() =>
imprimirWarning(
"¿Seguro(a) que quiere actualizar estos datos?",
actualizar
)
}
className={`px-4 py-2 rounded text-white ${
mostrar()
? "bg-gray-400 cursor-not-allowed"
: "bg-blue-600 hover:bg-blue-700"
}`}
>
Actualizar Datos
</button>
{/* Teléfono */}
{servicio.telefono && (
<div className="mb-3">
<label className="form-label fw-semibold block font-medium mb-1">Teléfono</label>
<input
type="tel"
maxLength={10}
placeholder={servicio.telefono}
value={telefono}
onChange={(e) => setTelefono(e.target.value)}
className="form-control border rounded p-2 w-full"
/>
</div>
)}
<button
disabled={
servicio.Status.idStatus === 1 || servicio.Status.idStatus === 7
}
onClick={() =>
imprimirWarning(
"¿Seguro(a) que quieres cambiar/reenviar la contraseña de este alumno?",
password
)
}
className="px-4 py-2 rounded bg-blue-500 hover:bg-blue-600 text-white"
>
Cambiar/Reenviar contraseña
</button>
</div>
{/*
{servicio.fechaNacimiento && (
<Col>
<FormGroup>
<FormLabel>Fecha de nacimiento</FormLabel>
<InputGroup>
<InputGroup.Text>
</InputGroup.Text>
</InputGroup>
</FormGroup>
</Col>
)}
{servicio.fechaNacimiento && (
<div className="mb-3">
<label className="form-label fw-semibold block font-medium mb-1">
Fecha de nacimiento
</label>
<DatePicker
selected={fechaFin}
onChange={(date: Date | null) => {
if (date) setFechaNacimiento(date);
}}
minDate={fechaInicio}
className="border rounded p-2 w-full"
/>
</div>
)}
*/}
<FormGroup className="mb-4">
<FormLabel>Carta de aceptaciòn</FormLabel>
<div
className="border p-4 text-center rounded"
style={{ cursor: "pointer" }}
onClick={() => document.getElementById("pdfInput")?.click()}
>
<FaUpload size={40} className="mb-2"/>
<p className="mb-1">
{cartaAceptacion?.name || 'Arrastra aqui tu archivo o da click aqui para buscar'}
</p>
<p className="is-size-6">Tamaño màximo 20MB</p>
<p className="is-size-7">Si al momento de elegir un archivo este no se selecciona, haga click en cancelar en la ventana emergente e intente de nuevo.</p>
</div>
<input
id="pdfInput"
type="file"
accept=".pdf"
style={{ display: 'none'}}
onChange={(e) => {
setCartaAceptacion(e.target.files ? e.target.files[0] : null)
}}
/>
</FormGroup>
{/* Subir archivos */}
{/*
<div className="space-y-2">
<label className="block font-medium mb-1">Carta de aceptación</label>
<input
type="file"
accept="application/pdf"
onChange={(e) =>
setCartaAceptacion(e.target.files ? e.target.files[0] : null)
}
className="border p-2 rounded w-full"
/>
</div>
*/}
{/* Botones */}
<div className="mt-6 flex gap-4 mb-5">
<button
disabled={mostrar()}
onClick={() =>
imprimirWarning(
"¿Seguro(a) que quiere actualizar estos datos?",
actualizar
)
}
className={`me-2 px-4 py-2 rounded text-white ${
mostrar()
? "bg-gray-400 cursor-not-allowed"
: "bg-blue-600 hover:bg-blue-700"
}`}
>
Actualizar Datos
</button>
<button
disabled={
servicio.status.idStatus === 1 || servicio.status.idStatus === 7
}
onClick={() =>
imprimirWarning(
"¿Seguro(a) que quieres cambiar/reenviar la contraseña de este alumno?",
password
)
}
className="px-4 py-2 rounded bg-blue-500 hover:bg-blue-600 text-white"
>
Cambiar/Reenviar contraseña
</button>
</div>
</div>
);
}
@@ -33,6 +33,25 @@ export default function GustavoBazPrada({
}
);
// Crear blob manualmente
const blob = new Blob([res.data], { type: "text/csv" });
// Crear URL temporal para descargar
const url = window.URL.createObjectURL(blob);
// Crear link "virtual"
const link = document.createElement("a");
link.href = url;
link.download = `${selectedYear}_gustavo_baz_prada.csv`;
// Disparar descarga
document.body.appendChild(link);
link.click();
// limpiar URL temporal
link.remove();
window.URL.revokeObjectURL(url);
//fileDownload(res.data, `${selectedYear}_gustavo_baz_prada.csv`);
setSelectedYear("");
@@ -51,20 +70,20 @@ export default function GustavoBazPrada({
<Col>
<FormGroup>
<FormLabel>Selecciona un año:</FormLabel>
<InputGroup>
<FormSelect
value={selectedYear}
onChange={(e) => setSelectedYear(e.target.value)}
>
<option value="">Seleccione un año:</option>
{(years || []).map((y, i) => (
<option key={i} value={y}>
{y}
</option>
))}
</FormSelect>
</InputGroup>
<FormLabel>Selecciona un año:</FormLabel>
<InputGroup>
<FormSelect
value={selectedYear}
onChange={(e) => setSelectedYear(e.target.value)}
>
<option value="">Seleccione un año:</option>
{(years || []).map((y, i) => (
<option key={i} value={y}>
{y}
</option>
))}
</FormSelect>
</InputGroup>
</FormGroup>
</Col>
@@ -43,10 +43,17 @@ export default function InformacionResponsable({ admin, imprimirError, updateIsL
const obtenerResponsable = async () => {
try {
updateIsLoading(true);
const res = await axiosInstance.get(`/usuario/responsable?idUsuario=${idResponsable}`, {
console.log("Este es el id del responsable", idResponsable)
const res = await axiosInstance.get(`/usuario/responsable/${idResponsable}`, {
headers: { Authorization: admin.token },
});
setResponsable(res.data);
console.log("Esta es la info de la res", res.data)
console.log("Esta es la info con doble data", res.data.data)
obtenerProgramas();
} catch (err: unknown) {
if (isAxiosError(err)) imprimirError(String(err.response?.data) || err.message || 'Error al obtener responsable');
@@ -60,21 +67,26 @@ export default function InformacionResponsable({ admin, imprimirError, updateIsL
// Funcion para obtener programas
const obtenerProgramas = async () => {
try {
const res = await axiosInstance.get(`/programa/programas_admin?idUsuario=${idResponsable}`, {
headers: { Authorization: admin.token },
});
setProgramas(res.data);
const res = await axiosInstance.get(`/programa/programas_admin/${idResponsable}`,);
console.log("Esta es la info de la res de programas", res.data)
console.log("Esta es la info con doble data de programas", res.data.data)
setProgramas(res.data.data);
} 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');
if (isAxiosError(err)) {
console.error("ERROR COMPLETO:", err.response?.data);
imprimirError(JSON.stringify(err.response?.data, null, 2));
} else if (err instanceof Error) {
imprimirError(err.message);
} else imprimirError('Error al obtener programas');
}
};
// Cargar al montar
useEffect(() => {
const id = Number(localStorage.getItem('idResponsable'));
if (!id) {
router.push('/administrador/responsables');
} else {
@@ -21,9 +21,9 @@ interface Status {
}
interface Alumno {
Usuario?: Usuario;
Carrera?: Carrera;
Status?: Status;
usuario?: Usuario;
carrera?: Carrera;
status?: Status;
creditos?: number;
correo?: string;
fechaNacimiento?: string;
@@ -56,11 +56,100 @@ export default function InformacionCasoEspecial({ alumno }: Props) {
return (
<div className="mt-4">
{/* Título */}
<h3 className="text-primary fw-bold mb-3">{alumno.Status?.status}</h3>
<h2 className="fw-bold mb-3">{alumno.status?.status}</h2>
<h4 className="mb-4">Datos personales</h4>
<div className="mb-3">
<label className="form-label fw-semibold">Número de Cuenta: </label>
<p className="form-control">{alumno.usuario?.usuario || ''}</p>
</div>
<div className="fw-semibold mb-3">
<label className="form-label">Nombre:</label>
<p className="form-control">{alumno.usuario?.nombre || ''}</p>
</div>
<div className="fw-semibold mb-3">
<label className="form-label">Carrera:</label>
<p className="form-control">{alumno.carrera?.carrera || ''}</p>
</div>
<div className="fw-semibold mb-3">
<label className="form-label">Créditos:</label>
<p className="form-control">{alumno.creditos || ''}</p>
</div>
<div className="fw-semibold mb-3">
<label className="form-label">Correo:</label>
<p className="form-control">{alumno.correo || ''}</p>
</div>
<div className="fw-semibold mb-3">
<label className="form-label">Fecha de Nacimiento:</label>
<p className="form-control">{fecha(alumno.fechaNacimiento)}</p>
</div>
<div className="fw-semibold mb-3">
<label className="form-label">Direcciòn:</label>
<p className="form-control">{alumno.direccion}</p>
</div>
<div className="fw-semibold mb-3">
<label className="form-label">Telèfono:</label>
<p className="form-control">{alumno.telefono}</p>
</div>
{alumno.motivo && (
<div className="fw-semibold mb-3">
<label className="form-label">Motivo:</label>
<p className="form-control">{
alumno.motivo === "1"
? "Tercera edad"
: alumno.motivo === "2"
? "Capacidades diferentes"
: ""
}</p>
</div>
)}
{alumno.institucion && (
<div className="fw-semibold mb-3">
<label className="form-label">Instituciòn:</label>
<p className="form-control">{alumno.institucion}</p>
</div>
)}
{alumno.dependencia && (
<div className="fw-semibold mb-3">
<label className="form-label">Dependencia:</label>
<p className="form-control">{alumno.dependencia}</p>
</div>
)}
<div className="fw-semibold mb-3">
<label className="form-label">Fecha Inicio:</label>
<p className="form-control">{fecha(alumno.fechaInicio)}</p>
</div>
<div className="fw-semibold mb-3">
<label className="form-label">Fecha Fin:</label>
<p className="form-control">{fecha(alumno.fechaFin)}</p>
</div>
<div className="fw-semibold mb-5">
<label className="form-label">Fecha Registro:</label>
<p className="form-control">{fecha(alumno.createdAt)}</p>
</div>
{/* Campos */}
{/*
// Informacino de antes
<Form.Group as={Row} className="mb-2">
<Form.Label column sm={3}>Número de Cuenta:</Form.Label>
<Col sm={9}>
@@ -117,7 +206,7 @@ export default function InformacionCasoEspecial({ alumno }: Props) {
</Col>
</Form.Group>
{alumno.motivo && (
{alumno.motivo && (
<Form.Group as={Row} className="mb-2">
<Form.Label column sm={3}>Motivo:</Form.Label>
<Col sm={9}>
@@ -174,8 +263,9 @@ export default function InformacionCasoEspecial({ alumno }: Props) {
<Form.Control plaintext readOnly value={fecha(alumno.createdAt)} />
</Col>
</Form.Group>
*/}
{(alumno.Status?.idStatus === 11 || alumno.Status?.idStatus === 12) && (
{(alumno.status?.idStatus === 11 || alumno.status?.idStatus === 12) && (
<div className="text-end mt-4">
<Button
variant="info"
@@ -29,15 +29,15 @@ interface Programa {
programa?: string;
clavePrograma?: string;
acatlan?: boolean;
Usuario?: Usuario;
usuario?: Usuario;
}
interface Datos {
idServicio?: number;
Programa?: Programa;
Carrera?: Carrera;
Usuario?: Usuario;
Status?: Status;
programa?: Programa;
carrera?: Carrera;
usuario?: Usuario;
status?: Status;
creditos?: string;
correo?: string;
createdAt?: string;
@@ -132,36 +132,36 @@ export default function InformacionServicio({ admin, imprimirError, updateIsLoad
return (
<div className="container mv-5">
<div className="mb-5">
<h3 className="fw-bold mb-4">Datos del programa</h3>
<h3 className="mt-3 mb-2">Datos del programa</h3>
<div className="mb-3">
<label className="form-label fw-semibold">Institucion:</label>
<p className="form-control">{datos.Programa?.institucion || '-'}</p>
<p className="form-control">{datos.programa?.institucion || '-'}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Dependencias:</label>
<p className="form-control">{datos.Programa?.dependencia || '-'}</p>
<p className="form-control">{datos.programa?.dependencia || '-'}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Programa:</label>
<p className="form-control">{datos.Programa?.programa}</p>
<p className="form-control">{datos.programa?.programa}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Clave de programa:</label>
<p className="form-control">{datos.Programa?.clavePrograma}</p>
<p className="form-control">{datos.programa?.clavePrograma}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Responsable:</label>
<p className="form-control">{datos.Programa?.Usuario?.nombre}</p>
<p className="form-control">{datos.programa?.usuario?.nombre}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Correo:</label>
<p className="form-control">{datos.Programa?.Usuario?.usuario}</p>
<p className="form-control">{datos.programa?.usuario?.usuario}</p>
</div>
</div>
@@ -170,74 +170,88 @@ export default function InformacionServicio({ admin, imprimirError, updateIsLoad
<div className="mb-3">
<label className="form-label fw-semibold">Numero de cuenta:</label>
<p className="form-control">{datos.Usuario?.usuario || '-'}</p>
<p className="form-control">{datos.usuario?.usuario || '-'}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Nombre:</label>
<p className="form-control">{datos.Usuario?.nombre || '-'}</p>
<p className="form-control">{datos.usuario?.nombre || '-'}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Fecha de nacimiento:
<p className="form-control">{datos.fechaNacimiento}</p>
</label>
</div>
{datos.fechaNacimiento && (
<div className="mb-3">
<label className="form-label fw-semibold">Fecha de nacimiento:</label>
<p className="form-control">{formatDate(datos.fechaNacimiento)}</p>
</div>
)}
<div className="mb-3">
<label className="form-label fw-semibold">Carrera:</label>
<p className="form-control">{datos.Carrera?.carrera || '-'}</p>
<p className="form-control">{datos.carrera?.carrera || '-'}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Creditos:</label>
<p className="form-control">{datos.creditos || '-'}</p>
<p className="form-control">{datos.creditos?.replace(/^0+/, '') + '%' || '-'}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Telèfono:</label>
<p className="form-control">{datos.telefono}</p>
</div>
{datos.telefono && (
<div className="mb-3">
<label className="form-label fw-semibold">Telèfono:</label>
<p className="form-control">{datos.telefono}</p>
</div>
)}
{datos.direccion && (
<div className="mb-3">
<label className="form-label fw-semibold">Direcciòn:</label>
<p className="form-control">{datos.direccion}</p>
</div>
)}
<div className="mb-3">
<label className="form-label fw-semibold">Direcciòn:</label>
<p className="form-control">{datos.direccion}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Email:</label>
<p className="form-control">{datos.correo || '-'}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Programa Interno:</label>
<p className="form-control">{datos.programaInterno}</p>
</div>
{datos.programaInterno && (
<div className="mb-3">
<label className="form-label fw-semibold">Programa Interno:</label>
<p className="form-control">{datos.programaInterno}</p>
</div>
)}
{datos.profesor && (
<div className="mb-3">
<label className="form-label fw-semibold">Profesor:</label>
<p className="form-control">{datos.profesor}</p>
</div>
)}
<div className="mb-3">
<label className="form-label fw-semibold">Profesor:</label>
<p className="form-control">{datos.profesor}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Fecha de registro:</label>
<p className="form-control">{datos.createdAt || '-'}</p>
<p className="form-control">{formatDate(datos.createdAt) || '-'}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">fecha de inicio:</label>
<p className="form-control">{datos.fechaInicio || '-'}</p>
<p className="form-control">{formatDate(datos.fechaInicio)|| '-'}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Fecha de termino:</label>
<p className="form-control">{datos.fechaFin || '-'}</p>
<p className="form-control">{formatDate(datos.fechaFin) || '-'}</p>
</div>
<div className="mb-3">
<label className="form-label fw-semibold">Fecha de liberaciòn:</label>
<p className="form-control">{datos.fechaLiberacion}</p>
</div>
{datos.fechaLiberacion && (
<div className="mb-3">
<label className="form-label fw-semibold">Fecha de liberaciòn:</label>
<p className="form-control">{formatDate(datos.fechaLiberacion)}</p>
</div>
)}
</div>
<button className="btn btn-primary"
@@ -247,4 +261,23 @@ export default function InformacionServicio({ admin, imprimirError, updateIsLoad
</button>
</div>
);
}
// Para dar formato a la fecha
function formatDate(value?: string | null): string {
if (!value) return "";
// Si ya viene como fecha ISO, forzamos a hora local sin modificar el día
const d = new Date(value.includes("T") ? value : `${value}T00:00:00`);
if (isNaN(d.getTime())) {
console.warn("⚠️ Fecha inválida:", value);
return "";
}
const day = String(d.getDate()).padStart(2, "0");
const month = String(d.getMonth() + 1).padStart(2, "0");
const year = d.getFullYear();
return `${day}/${month}/${year}`;
}
@@ -38,17 +38,21 @@ export default function ReasignacionProgramas({
// Función principal: reasignar programas
const reasignarProgramas = async () => {
const data = {
idUsuario: responsable.idUsuario,
correoOtroResponsable,
//idUsuario: responsable.idUsuario,
correo: correoOtroResponsable,
};
console.log("Esta es la data que se pasa en el update de responsable", data)
console.log("Esta es la info del correo entrando en el data", data.correo)
try {
updateIsLoading(true);
const res = await axiosInstance.put(`/programa/reasignar_programas`, data);
const res = await axiosInstance.put(`/programa/reasignar_programas/${responsable.idUsuario}`, data);
updateIsLoading(false);
imprimirMensaje(res.data.message);
router.push("/admin/responsables/responsable");
router.push("/administrador/responsables");
} catch (err: unknown) {
console.log("Esta entrando al catch no sale la peticion")
updateIsLoading(false);
if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
else if (err instanceof Error) imprimirError(err.message);
@@ -58,7 +62,7 @@ export default function ReasignacionProgramas({
return (
<div className="mt-6">
<h3 className="text-2xl font-semibold mb-3">Reasignación de programas</h3>
<h3 className="fw-semibold text-2xl font-semibold mb-3">Reasignación de programas</h3>
<div className="text-base mb-4">
<p>
@@ -69,21 +73,21 @@ export default function ReasignacionProgramas({
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-1">
<label className="form-label fw-semibold block text-sm font-medium text-gray-700 mb-2">
Usuario/Correo electrónico
</label>
<input
type="email"
placeholder="Usuario"
value={correoOtroResponsable}
onChange={(e) => setCorreoOtroResponsable(e.target.value)}
className="border border-gray-300 rounded-lg p-2 w-full"
type="email"
placeholder="Usuario"
value={correoOtroResponsable}
onChange={(e) => setCorreoOtroResponsable(e.target.value)}
className="form-control border border-gray-300 rounded-lg p-2 w-full"
/>
</div>
<div className="pt-5">
<div className="pt-3">
<button
className={`px-4 py-2 rounded-md text-white ${
className={`px-4 py-2 rounded-1 text-white ${
mostrarBoton()
? "bg-gray-400 cursor-not-allowed"
: "bg-blue-600 hover:bg-blue-700"
+29 -5
View File
@@ -32,17 +32,38 @@ export default function Reporte({ admin }: Props) {
try {
//updateIsLoading(true);
console.log("Fecha inicio seleccionada:", selectedInicio);
console.log("Fecha fin seleccionada:", selectedFin);
//console.log("Fechas parseadas", selectedInicio ? moment(selectedInicio).format("YYYY") : null, selectedFin ? moment(selectedFin).format("YYYY") : null);
const res = await axiosInstance.get("/servicio/reporte", {
params: {
inicio: moment(selectedInicio).format("YYYY-MM-DD"),
fin: moment(selectedFin).format("YYYY-MM-DD"),
},
headers: {
Authorization: `Bearer ${admin.token}`,
inicio: moment(selectedInicio).format("YYYY-MM-DD"), // Mandamos solo el año, quitamos el mes y día
fin: moment(selectedFin).format("YYYY-MM-DD"), // Mandamos solo el año, quitamos el mes y día
},
responseType: "blob",
});
// Creamos el blob manualmente
const blob = new Blob([res.data], {type: 'text/csv'})
// Creamos la url temporal para la descarga
const url = window.URL.createObjectURL(blob)
// Creamos el link
const link = document.createElement("a")
link.href = url;
link.download = `Reporte.csv`
// Disparar descarga
document.body.appendChild(link)
link.click()
// Limpiamos la url
link.remove()
window.URL.revokeObjectURL(url)
//saveAs(res.data, "reporte.csv");
// reset
@@ -50,9 +71,12 @@ export default function Reporte({ admin }: Props) {
setSelectedFin(null);
//updateIsLoading(false);
} catch (err: unknown) {
console.log("Error al descargar el reporte", err)
//updateIsLoading(false);
// optional: handle error
}
};
return (
@@ -8,6 +8,7 @@ import { Button, Col, Form, FormGroup, FormLabel, FormSelect, InputGroup, Row, S
import ServicioSocialTabla from "../servicio-social-tabla";
import { ServicioSocialResponse } from "@/types/responses";
import { FaInfoCircle, FaSchool, FaUser } from "react-icons/fa";
import { useRouter } from "next/navigation";
interface Admin {
idTipoUsuario?: number;
@@ -45,6 +46,9 @@ interface CasosEspecialesResponse {
}
export default function TablaCasosEspeciales({ admin, imprimirError }: Props) {
// Para el redirecionamiento
const router = useRouter();
const [isLoading, setIsLoading] = useState(false);
const [page, setPage] = useState(1);
const [total, setTotal] = useState(0);
@@ -88,11 +92,12 @@ export default function TablaCasosEspeciales({ admin, imprimirError }: Props) {
try {
const config = admin?.token ? { headers: { Authorization: `Bearer ${admin.token}` } } : undefined;
console.debug('Obtener servicios - localStorage token:', typeof window !== 'undefined' ? localStorage.getItem('token') : undefined, 'admin.token:', admin?.token);
const res = await axiosInstance.get(`/caso_especial/servicios_especiales?pagina=${pagina}${query}`, config);
const res = await axiosInstance.get(`/caso-especial/servicios_especiales?pagina=${pagina}${query}`);
console.debug('Respuesta casos especiales:', res.data);
setData(res.data.serviciosEspeciales || []);
setData(res.data.data.serviciosEspeciales ?? []);
setTotal(res.data.count);
console.log('Respuesta casos especiales:', res.data);
console.log("Respuesta Caso especial con doble data", res.data.data)
} catch (err: unknown) {
if (imprimirError) {
if (isAxiosError(err)) {
@@ -130,9 +135,12 @@ export default function TablaCasosEspeciales({ admin, imprimirError }: Props) {
useEffect(() => {
console.log("Admin recibido:", admin);
obtenerCatalogoStatus();
// Asegurar que se ejecute la petición si el usuario tiene permisos
if (admin && Number(admin.idTipoUsuario) === 1) {
obtenerCatalogoStatus();
console.log("entro para traer la informacion de los usuarios")
} else if (!admin) {
console.warn("Admin no definido, no se cargaron los casos especiales.");
}
@@ -244,15 +252,27 @@ export default function TablaCasosEspeciales({ admin, imprimirError }: Props) {
{/* Tabla
<ServicioSocialTabla />
onPageChange={onPageChange}
columnasResponsable={admin?.idTipoUsuario === 1}
*/}
<ServicioSocialTabla
data={data}
total={total}
columnaFechaRegistro={true}
columnasResponsable={false}
idTipoUsuario={admin?.idTipoUsuario}
columnasResponsable={admin?.idTipoUsuario === 1}
onPageChange={onPageChange}
columnaFechaInicio={false}
columnaFechaFin={false}
onRowAction={(row, path) => {
try {
router.push(`/responsable/${path}`)
} catch (error) {
console.error('Error al manejar accion de fila', error)
}
}}
/>
</section>
@@ -68,6 +68,7 @@ export default function TablaResponsables() {
className="form-control border-0 rounded-4"
value={correo}
onChange={(e) => setCorreo(e.target.value)}
onKeyDown={(e) => {if (e.key === 'Enter') fetchData(correo)}}
/>
</div>
</Col>
@@ -80,6 +81,7 @@ export default function TablaResponsables() {
className="form-control border-0 rounded-4"
value={nombre}
onChange={(e) => setNombre(e.target.value)}
onKeyDown={(e) => { if (e.key === 'Enter') fetchData(nombre)}}
/>
</div>
</Col>
@@ -38,6 +38,8 @@ export default function TablaServicioSocial({ admin, imprimirError }: Props) {
if (admin?.idTipoUsuario === 1) {
obtenerCatalogoStatus();
}
console.log("Esta es la info que tiene al guardar en la state", data)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [admin?.idTipoUsuario]);
@@ -70,10 +72,14 @@ export default function TablaServicioSocial({ admin, imprimirError }: Props) {
// asegurar que enviamos Authorization si existe en admin, y loggear token para debug
const config = admin?.token ? { headers: { Authorization: `Bearer ${admin.token}` } } : undefined;
console.debug('Obtener servicios - localStorage token:', typeof window !== 'undefined' ? localStorage.getItem('token') : undefined, 'admin.token:', admin?.token);
const res = await axiosInstance.get(`/servicio/servicios_admin?pagina=${paginaActual}${query}`, config);
const res = await axiosInstance.get(`/servicio/admin?pagina=${paginaActual}${query}`);
console.debug('Respuesta servicios_admin:', res.data);
setData(res.data.serviciosAdmin || []);
//setData(res.data)
//setData(res.data.serviciosAdmin);
setTotal(res.data.count ?? 0);
console.log("Esta es la info", res.data)
} catch (err: unknown) {
// manejar error
console.error('Error obtenerServicios', err);
@@ -98,7 +104,6 @@ export default function TablaServicioSocial({ admin, imprimirError }: Props) {
}
};
return (
<section>
<div className="columns">
@@ -157,6 +162,7 @@ export default function TablaServicioSocial({ admin, imprimirError }: Props) {
value={search.idStatus}
onChange={(e) => setSearch(Prev => ({ ...Prev, idStatus: e.target.value }))}
className="rounded-4"
onKeyDown={(e) => { if (e.key === 'Enter') obtenerServicios()}}
>
<option value="">Status</option>
{status.slice(0, 10).map((s) => (
@@ -14,10 +14,10 @@ export default function TituloStatus({ status }: Props) {
console.log('idStatus en TituloStatus:', idStatus);
return (
<div className="mb-5">
{idStatus === 1 && <h3 className="title">Confirmar el pre-registro del alumno</h3>}
{idStatus === 4 && <h3 className="title">Término</h3>}
{idStatus === 5 && <h3 className="title">Validar el término del alumno</h3>}
<div className="mb-4">
{idStatus === 1 && <h2 className="fw-bold mt-4">Confirmar el pre-registro del alumno</h2>}
{idStatus === 4 && <h2 className="fw-bold mt-4">Término</h2>}
{idStatus === 5 && <h2 className="fw-bold mt-4">Validar el término del alumno</h2>}
</div>
);
}
+55 -55
View File
@@ -1,73 +1,73 @@
"use client";
import React from "react";
import { FaUserPlus, FaUserCheck, FaUser, FaUsers, FaUserClock, FaUserTie } from "react-icons/fa";
interface Props {
idStatus: number;
}
interface Step {
label: string;
icon: string; // Puedes usar iconos de heroicons o font-awesome
visible: boolean;
type?: "default" | "danger";
}
export default function BarraProgreso({ idStatus }: Props) {
const steps: Step[] = [
{ label: "Pre Registro", icon: "account-plus", visible: idStatus < 6 },
{ label: "Pre Registro Validado", icon: "account-clock", visible: idStatus < 6 },
{ label: "Registro", icon: "account", visible: idStatus < 6 },
{ label: "Pre Termino", icon: "account-details", visible: idStatus < 6 },
{ label: "Termino", icon: "account-clock", visible: idStatus < 6 },
{ label: "Liberacion", icon: "account-check", visible: idStatus < 6 },
{ label: "Carta Aceptación Rechazada", icon: "file", visible: idStatus === 6, type: "danger" },
{ label: "Carta Termino Rechazada", icon: "file", visible: idStatus === 7, type: "danger" },
{ label: "Informe Global Rechazado", icon: "file", visible: idStatus === 8, type: "danger" },
{ label: "Cancelado", icon: "account-cancel", visible: idStatus === 9, type: "danger" },
const steps = [
{ label: "Pre Registro", icon: <FaUserPlus />, id: 1 },
{ label: "Pre Registro Validado", icon: <FaUserCheck />, id: 2 },
{ label: "Registro", icon: <FaUser />, id: 3 },
{ label: "Pre Termino", icon: <FaUsers />, id: 4 },
{ label: "Termino", icon: <FaUserClock />, id: 5 },
{ label: "Liberacion", icon: <FaUserTie />, id: 6 },
];
return (
<div className="b-steps-container mt-6 mb-5">
<div className="b-steps">
{steps.filter(s => s.visible).map((step, idx) => (
<div key={idx} className={`step-item ${step.type === 'danger' ? 'is-danger' : 'is-info'}`} aria-hidden>
<div className="step-marker">
{/* Placeholder icon: use font-awesome or heroicons in the app */}
<span className={`icon ${step.type === 'danger' ? 'icon-danger' : 'icon-info'}`} aria-hidden>
<i className={`fa fa-${step.icon}`} />
</span>
</div>
<div className="step-details">
<div className="step-title">{step.label}</div>
</div>
</div>
))}
</div>
<div className="container mt-5">
<div className="d-flex justify-content-center align-items-center position-relative">
{steps.map((step, index) => {
const isActive = idStatus >= step.id;
const isCurrent = idStatus === step.id;
<style jsx>{`
.b-steps { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: stretch; }
.step-item { display: flex; align-items: center; padding: 0.6rem 0.9rem; border-radius: 6px; background: #e6f2ff; color: #0b66b2; min-width: 220px; }
.step-item.is-info { background: #ecf8ff; color: #0b66b2; }
.step-item.is-danger { background: #ffecec; color: #a10b0b; }
.step-marker { display:flex; align-items:center; justify-content:center; width:40px; height:40px; border-radius:50%; margin-right:0.75rem; background: rgba(255,255,255,0.6); }
.step-item.is-info .step-marker { background: #dff4ff; }
.step-item.is-danger .step-marker { background: #ffdede; }
.icon { font-size: 1.1rem; }
.step-title { font-weight: 600; font-size: 0.95rem; }
return (
<div key={index} className="text-center position-relative flex-fill">
{/* Línea de conexión */}
{index > 0 && (
<div
className={`position-absolute top-50 start-0 translate-middle-y w-100 border-top ${
isActive ? "border-primary" : "border-secondary opacity-25"
}`}
style={{ zIndex: 0 }}
></div>
)}
/* Mimic the Buefy rule to hide ::before/::after on danger steps */
.b-steps .step-item.is-danger::before,
.b-steps .step-item.is-danger::after {
display: none !important;
content: none !important;
}
{/* Círculo del paso */}
<div
className={`rounded-circle d-flex justify-content-center align-items-center mx-auto mb-2 border ${
isActive
? "bg-primary text-white border-primary"
: isCurrent
? "border-primary text-primary bg-white"
: "bg-light text-secondary border-secondary opacity-75"
}`}
style={{
width: "48px",
height: "48px",
position: "relative",
zIndex: 1,
}}
>
{step.icon}
</div>
@media (max-width: 768px) {
.step-item { min-width: 140px; padding: 0.45rem 0.6rem; }
.step-title { font-size: 0.85rem; }
}
`}</style>
{/* Título */}
<div
className={`fw-semibold ${
isActive || isCurrent ? "text-dark" : "text-secondary"
}`}
style={{ fontSize: "0.95rem" }}
>
{step.label}
</div>
</div>
);
})}
</div>
</div>
);
}
@@ -7,6 +7,8 @@ import { axiosInstance } from '@/api/config';
import { isAxiosError } from 'axios';
import type { AxiosResponse } from 'axios';
import moment from "moment";
import { Col, FormGroup, FormLabel, InputGroup } from "react-bootstrap";
import { FaRegCalendarAlt } from "react-icons/fa";
interface Alumno {
token: { headers: Record<string, string> };
@@ -74,64 +76,89 @@ export default function CompletarDatosPersonales({
};
return (
<div className="space-y-4">
<h3 className="text-xl font-semibold">Formulario Pre-registro</h3>
<div className="container space-y-4">
<h2 className="text-xl fw-semibold">Formulario Pre-registro</h2>
{/* Fecha de nacimiento */}
<div>
<label className="block mb-1 font-medium">Fecha de nacimiento</label>
<Col>
<FormGroup>
<FormLabel className="form-label fw-semibold">Fecha de nacimiento:</FormLabel>
<InputGroup>
<InputGroup.Text>
<FaRegCalendarAlt />
</InputGroup.Text>
<DatePicker
selected={nacimiento}
onChange={(date: Date | null) => {
if (date) setNacimiento(date);
}}
maxDate={maxDate}
className="border border-gray-300 rounded px-3 py-2 form-control"
placeholderText="Fecha de nacimiento"
wrapperClassName="flex-grow-1"
calendarClassName="mi-calendario"
/>
</InputGroup>
</FormGroup>
</Col>
{/*
<div className="mb-3">
<label className="block mb-1 fw-semibold">Fecha de nacimiento</label>
<DatePicker
selected={nacimiento}
onChange={(date: Date | null) => {
if (date) setNacimiento(date);
}}
maxDate={maxDate}
className="border border-gray-300 rounded px-3 py-2 w-full"
className="border border-gray-300 rounded px-3 py-2 form-control"
placeholderText="Fecha de nacimiento"
/>
wrapperClassName="flex-grow-1"
calendarClassName="mi-calendario"
/>
</div>
*/}
{/* Teléfono */}
<div>
<label className="block mb-1 font-medium">Teléfono</label>
<div className="mb-3">
<label className="block mb-1 form-label fw-semibold mb-2">Teléfono</label>
<input
type="tel"
placeholder="Teléfono"
maxLength={10}
value={telefono}
onChange={(e) => setTelefono(e.target.value)}
className="border border-gray-300 rounded px-3 py-2 w-full"
type="tel"
placeholder="Teléfono"
maxLength={10}
value={telefono}
onChange={(e) => setTelefono(e.target.value)}
className="border border-gray-300 rounded px-3 py-2 form-control"
/>
</div>
{/* Dirección */}
<div>
<label className="block mb-1 font-medium">Dirección</label>
<div className="mb-3">
<label className="block mb-1 form-label fw-semibold mb-2">Dirección</label>
<input
type="text"
placeholder="Dirección"
maxLength={200}
value={direccion}
onChange={(e) => setDireccion(e.target.value)}
className="border border-gray-300 rounded px-3 py-2 w-full"
type="text"
placeholder="Dirección"
maxLength={200}
value={direccion}
onChange={(e) => setDireccion(e.target.value)}
className="border border-gray-300 rounded px-3 py-2 form-control"
/>
</div>
{/* Botón enviar */}
<div className="text-center mt-4">
<button
disabled={!telefono || !direccion}
onClick={() =>
imprimirWarning(
"¿Estas seguro(a) que tus datos son correctos?",
terminarPreRegistro
)
}
className={`px-4 py-2 rounded text-white ${
!telefono || !direccion
? "bg-gray-400 cursor-not-allowed"
: "bg-green-600 hover:bg-green-700"
}`}
disabled={!telefono || !direccion}
onClick={() =>
imprimirWarning(
"¿Estas seguro(a) que tus datos son correctos?",
terminarPreRegistro
)
}
className={`px-4 py-2 rounded text-white mb-5 ${
!telefono || !direccion
? "bg-gray-400 cursor-not-allowed"
: "bg-green-600 hover:bg-green-700"
}`}
>
Enviar
</button>
@@ -300,7 +300,7 @@ export default function FullCuestionario() {
<div>
{p.opciones?.map((op) => (
<div key={op} className="SINO">
<label>
<label className="mt-2">
<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>
@@ -309,7 +309,7 @@ export default function FullCuestionario() {
)}
{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í" />
<input id={p.id} className="form-control bg-transparent" 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>
@@ -327,18 +327,18 @@ export default function FullCuestionario() {
<table className="table table-bordered text-center">
<thead>
<tr>
<th></th>
<th className="bg-transparent"></th>
{t.renglones[0].opciones.map((op) => (
<th key={op}>{op}</th>
<th className="bg-transparent" key={op}>{op}</th>
))}
</tr>
</thead>
<tbody>
{t.renglones.map((r) => (
<tr key={r.idRenglon}>
<td>{r.textoRenglon}</td>
<td className="bg-transparent">{r.textoRenglon}</td>
{r.opciones.map((op) => (
<td key={op}>
<td className="bg-transparent" 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>
))}
@@ -351,12 +351,10 @@ export default function FullCuestionario() {
);
})}
<div className="my-6 mb-6 has-text-centered">
<div>
<button className="button is-success is-medium" onClick={submitForm} disabled={!isFormComplete}>
<div className="my-6 mb-6 text-center mb-5">
<button className="btn btn-success is-medium" onClick={submitForm} disabled={!isFormComplete}>
{isLoading ? 'Enviando...' : 'Enviar'}
</button>
</div>
</div>
</div>
+93 -93
View File
@@ -50,116 +50,116 @@ export default function InformacinoServicio({ servicio }: Props) {
};
return (
<div>
{/* Datos del programa */}
<div className="mb-5">
<h4 className="is-size-4 pb-2">Datos del programa</h4>
<div className="container">
{/* Datos del programa */}
<div className="mb-5">
<h4 className="is-size-4 pb-2">Datos del programa</h4>
<div className="mb-2">
<label>Institución:</label>
<p className="input">{servicio.Programa.institucion}</p>
<div className="mb-2">
<label className="form-label fw-semibold">Institución:</label>
<p className="form-control">{servicio.Programa.institucion}</p>
</div>
<div className="mb-2">
<label className="form-label fw-semibold">Dependencia:</label>
<p className="form-control">{servicio.Programa.dependencia}</p>
</div>
<div className="mb-2">
<label className="form-label fw-semibold">Programa:</label>
<p className="form-control">{servicio.Programa.programa}</p>
</div>
<div className="mb-2">
<label className="form-label fw-semibold">Clave de programa:</label>
<p className="form-control">{servicio.Programa.clavePrograma}</p>
</div>
</div>
<div className="mb-2">
<label>Dependencia:</label>
<p className="input">{servicio.Programa.dependencia}</p>
</div>
{/* Datos personales */}
<div className="mb-5">
<h4 className="is-size-4 pb-2">Datos personales</h4>
<div className="mb-2">
<label>Programa:</label>
<p className="input">{servicio.Programa.programa}</p>
</div>
<div className="mb-2">
<label className="form-label fw-semibold">Número de cuenta:</label>
<p className="form-control">{servicio.Usuario.usuario}</p>
</div>
<div className="mb-2">
<label>Clave de programa:</label>
<p className="input">{servicio.Programa.clavePrograma}</p>
</div>
</div>
<div className="mb-2">
<label className="form-label fw-semibold">Nombre:</label>
<p className="form-control">{servicio.Usuario.nombre}</p>
</div>
{/* Datos personales */}
<div className="mb-5">
<h4 className="is-size-4 pb-2">Datos personales</h4>
<div className="mb-2">
<label className="form-label fw-semibold">Carrera:</label>
<p className="form-control">{servicio.Carrera.carrera}</p>
</div>
<div className="mb-2">
<label>Número de cuenta:</label>
<p className="input">{servicio.Usuario.usuario}</p>
</div>
<div className="mb-2">
<label className="form-label fw-semibold">Créditos:</label>
<p className="form-control">
{servicio.creditos ? parseInt(servicio.creditos) : ""}
{servicio.creditos && "%"}
</p>
</div>
<div className="mb-2">
<label>Nombre:</label>
<p className="input">{servicio.Usuario.nombre}</p>
</div>
{servicio.telefono && (
<div className="mb-2">
<label className="form-label">Teléfono:</label>
<p className="form-control">{servicio.telefono}</p>
</div>
)}
<div className="mb-2">
<label>Carrera:</label>
<p className="input">{servicio.Carrera.carrera}</p>
</div>
{servicio.direccion && (
<div className="mb-2">
<label className="form-label fw-semibold">Dirección:</label>
<p className="form-control">{servicio.direccion}</p>
</div>
)}
<div className="mb-2">
<label>Créditos:</label>
<p className="input">
{servicio.creditos ? parseInt(servicio.creditos) : ""}
{servicio.creditos && "%"}
</p>
</div>
<div className="mb-2">
<label className="form-label fw-semibold">Email:</label>
<p className="form-control">{servicio.correo}</p>
</div>
{servicio.telefono && (
<div className="mb-2">
<label>Teléfono:</label>
<p className="input">{servicio.telefono}</p>
</div>
)}
{servicio.programaInterno && (
<div className="mb-2">
<label className="form-label fw-semibold">Programa Interno:</label>
<p className="form-control">{servicio.programaInterno}</p>
</div>
)}
{servicio.direccion && (
<div className="mb-2">
<label>Dirección:</label>
<p className="input">{servicio.direccion}</p>
</div>
)}
{servicio.profesor && (
<div className="mb-2">
<label className="form-label fw-semibold">Profesor:</label>
<p className="form-control">{servicio.profesor}</p>
</div>
)}
<div className="mb-2">
<label>Email:</label>
<p className="input">{servicio.correo}</p>
</div>
{servicio.createdAt && (
<div className="mb-2">
<label className="form-label fw-semibold">Fecha de registro:</label>
<p className="form-control">{fecha(servicio.createdAt)}</p>
</div>
)}
{servicio.programaInterno && (
<div className="mb-2">
<label>Programa Interno:</label>
<p className="input">{servicio.programaInterno}</p>
</div>
)}
<div className="mb-2">
<label className="form-label fw-semibold">Fecha de inicio:</label>
<p className="form-control">{fecha(servicio.fechaInicio)}</p>
</div>
{servicio.profesor && (
<div className="mb-2">
<label>Profesor:</label>
<p className="input">{servicio.profesor}</p>
</div>
)}
<div className="mb-2">
<label className="form-label fw-semibold">Fecha de término:</label>
<p className="form-control">{fecha(servicio.fechaFin)}</p>
</div>
{servicio.createdAt && (
<div className="mb-2">
<label>Fecha de registro:</label>
<p className="input">{fecha(servicio.createdAt)}</p>
{servicio.fechaLiberacion && (
<div className="mb-2">
<label className="form-label fw-semibold">Fecha de liberación:</label>
<p className="form-control">{fecha(servicio.fechaLiberacion)}</p>
</div>
)}
</div>
)}
<div className="mb-2">
<label>Fecha de inicio:</label>
<p className="input">{fecha(servicio.fechaInicio)}</p>
</div>
<div className="mb-2">
<label>Fecha de término:</label>
<p className="input">{fecha(servicio.fechaFin)}</p>
</div>
{servicio.fechaLiberacion && (
<div className="mb-2">
<label>Fecha de liberación:</label>
<p className="input">{fecha(servicio.fechaLiberacion)}</p>
</div>
)}
</div>
</div>
);
}
+2 -2
View File
@@ -10,8 +10,8 @@ interface Props {
export default function MensajeAlumno({ Status }: Props) {
return (
<div className="mb-6">
<h4 className="block is-size-4">Estimado alumno(a):</h4>
<div className="container mb-6">
<h4 className="block is-size-4 mb-4">Estimado alumno(a):</h4>
<p className="has-text-justified is-size-6">
{Status.idStatus === 2 && (
+110 -64
View File
@@ -3,6 +3,8 @@
import { useState, useEffect } from "react";
import { axiosInstance } from "@/api/config";
import { isAxiosError } from 'axios';
import { Button, FormGroup, FormLabel } from "react-bootstrap";
import { FaUpload } from "react-icons/fa";
interface Alumno {
tokenArchivo: string;
@@ -53,95 +55,139 @@ export default function PreTermino({
formData.append("informeGlobal", file);
try {
updateIsLoading(true);
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);
updateIsLoading(true);
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 (isAxiosError(err)) {
imprimirError((err.response?.data) || err.message);
} else {
imprimirError(err);
}
if (isAxiosError(err)) {
imprimirError((err.response?.data) || err.message);
} else {
imprimirError(err);
}
} finally {
updateIsLoading(false);
updateIsLoading(false);
}
};
return (
<div>
<h3 className="label">
<div className="container">
<h6 className="label fw-semibold">
Cuestionario de evaluación del programa de servicio social.
</h3>
</h6>
{!servicio.idCuestionarioAlumno && !servicio.idCuestionarioAlumno2 ? (
<div className="mb-6">
<a
href="/alumno/cuestionario"
className="button is-info is-light"
>
<span className="icon">
<i className="fas fa-book-open"></i>
</span>
<span>Cuestionario</span>
</a>
<div className="mb-5">
<a
href="/alumno/cuestionario"
className="btn btn-outline-primary is-info is-light"
>
<span className="icon">
<i className="fas fa-book-open"></i>
</span>
<span>Cuestionario</span>
</a>
</div>
) : (
<div className="mb-6">
<p className="block is-size-6">
Cuestionario contestado{" "}
<span className="icon has-text-success">
<i className="fas fa-check-bold"></i>
</span>
</p>
<p className="block is-size-6">
Cuestionario contestado{" "}
<span className="icon has-text-success">
<i className="fas fa-check-bold"></i>
</span>
</p>
</div>
)}
<h3 className="label">
<h6 className="label fw-semibold">
Informe global de actividades{" "}
{!servicio.informeGlobal && (
<span>(en formato .PDF. No se aceptan fotos)</span>
)}
.
</h3>
</h6>
{/*
Codigo anterior para el envio del archivo
<div>
<div className="field">
<input
type="file"
accept="application/pdf"
onChange={(e) => {
if (e.target.files && e.target.files[0]) {
setFile(e.target.files[0]);
}
}}
/>
<p className="is-size-6">Tamaño máximo 20MB</p>
</div>
<div className="field has-text-centered my-5">
<button
className="button is-success"
disabled={!file}
onClick={() =>
imprimirWarning(
"¿Estas seguro(a) de querer subir este informe global?",
enviarInformeGlobal
)
}
>
Enviar
</button>
</div>
</div>
*/}
{!servicio.informeGlobal ? (
<div>
<div className="field">
<input
type="file"
accept="application/pdf"
onChange={(e) => {
if (e.target.files && e.target.files[0]) {
setFile(e.target.files[0]);
}
}}
/>
<p className="is-size-6">Tamaño máximo 20MB</p>
</div>
<div className="ph-5">
<FormGroup>
<div className="border p-4 text-center rounded"
style={{ cursor: 'pointer'}}
onClick={() => document.getElementById("fileInput")?.click()}
>
<FaUpload size={40} className="mb-2"/>
<p className="mb-1">
{file?.name || 'Arrastra aquì tu archivo o da click aquì para buscar'}
</p>
<p className="is-size-6">Tamaño maximo 20MB</p>
<p className="is-size-7">Sia al momento de elegir un archivo este no se selecciona, haga click en cancelar en la ventana emergente e intente de nuevo.</p>
</div>
<div className="field has-text-centered my-5">
<button
className="button is-success"
disabled={!file}
onClick={() =>
imprimirWarning(
"¿Estas seguro(a) de querer subir este informe global?",
enviarInformeGlobal
)
}
>
Enviar
</button>
</div>
<input
id="fileInput"
type="file"
accept="application/pdf"
onChange={(e) => {
if (e.target.files && e.target.files[0]) {
setFile(e.target.files[0]);
}
}}
hidden
/>
</FormGroup>
<div className="d-flex gap-2 justify-content-center mb-5">
<Button
className=""
disabled={!file}
onClick={() =>
imprimirWarning(
"¿Estas seguro(a) de querer subir este informe global?",
enviarInformeGlobal
)
}
>Enviar</Button>
</div>
</div>
) : (
<p className="block is-size-6">
Informe Global enviado.{" "}
<span className="icon has-text-success">
<i className="fas fa-check-bold"></i>
</span>
<p className="block is-size-6 mb-5">
Informe Global enviado.{" "}
<span className="icon has-text-success">
<i className="fas fa-check-bold"></i>
</span>
</p>
)}
</div>
+271 -245
View File
@@ -55,6 +55,19 @@ export default function CasoEspecialForm({
const [minDate, setMinDate] = useState<Date>(new Date('2020-01-02'));
const [minDate2, setMinDate2] = useState<Date>(new Date());
// Para mostrar las fechas
const handleFechaInicioChange = (date: Date | null) => {
setFechaInicio(date || new Date());
}
const handleFechaFinChange = (date: Date | null) => {
setFechaFin(date || new Date());
}
const handleFechaNacimientoChange = (date: Date | null) => {
setFechaNacimiento(date || new Date())
}
// Función para resetear campos
const resetear = (): void => {
setDependencia('');
@@ -213,276 +226,289 @@ export default function CasoEspecialForm({
// Render
return (
<div className="container mt-4">
<div className="mb-3">
<label className="form-label">Número de Cuenta</label>
<div className="input-group">
<input
type="text"
className="form-control"
placeholder="Número de Cuenta"
maxLength={9}
value={numeroCuenta}
onChange={(e) => setNumeroCuenta(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && buscarAlumno()}
/>
<button className="btn btn-info text-white" onClick={buscarAlumno}>
Buscar
</button>
</div>
</div>
<div className="mb-3">
<label className="form-label">Nombre</label>
<p className="form-control">{alumno.nombre || ''}</p>
</div>
<div className="mb-3">
<label className="form-label">Carrera</label>
<p className="form-control">{alumno.carrera || ''}</p>
</div>
<div className="mb-3">
<label className="form-label">Créditos</label>
<p className="form-control">
{alumno.creditos ? parseInt(alumno.creditos) : ''}{' '}
{alumno.creditos ? '%' : ''}
</p>
</div>
<div className="mb-3">
<label className="form-label">Dirección</label>
<input
type="text"
className="form-control"
maxLength={200}
value={direccion}
onChange={(e) => setDireccion(e.target.value)}
/>
</div>
<div className="mb-3">
<label className="form-label">Teléfono</label>
<input
type="tel"
className="form-control"
maxLength={10}
value={telefono}
onChange={(e) => setTelefono(e.target.value)}
/>
</div>
<div className="mb-3">
<label className="form-label">Correo electrónico</label>
<input
type="email"
className="form-control"
value={correo}
onChange={(e) => setCorreo(e.target.value)}
/>
</div>
<Col>
<FormGroup>
<FormLabel>Fecha de inicio</FormLabel>
<InputGroup>
<InputGroup.Text>
<FaRegCalendarAlt />
</InputGroup.Text>
<DatePicker
selected={fechaInicio}
minDate={minDate}
dateFormat="dd-MM-yyyy"
className="form-control"
wrapperClassName="flex-grow-1"
calendarClassName="mi-calendario"
/>
</InputGroup>
</FormGroup>
</Col>
<Col>
<FormGroup>
<FormLabel>Fecha de fin</FormLabel>
<InputGroup>
<InputGroup.Text>
<FaRegCalendarAlt />
</InputGroup.Text>
<DatePicker
selected={fechaFin}
value={fechaFin.toISOString().substring(0,10)}
minDate={minDate2}
dateFormat="dd-MM-yyyy"
className="form-control"
wrapperClassName="flex-grow-1"
calendarClassName="mi-calendario"
/>
</InputGroup>
</FormGroup>
</Col>
<Col>
<FormGroup>
<FormLabel>Fecha de nacimiento</FormLabel>
<InputGroup>
<InputGroup.Text>
<FaRegCalendarAlt />
</InputGroup.Text>
<DatePicker
selected={fechaNacimiento}
maxDate={new Date()}
dateFormat="dd-MM-yyyy"
className="form-control"
wrapperClassName="flex-grow-1"
calendarClassName="mi-calendario"
/>
</InputGroup>
</FormGroup>
</Col>
<div className="mb-3">
<label className="form-label">Fecha de inicio</label>
<input
type="date"
className="form-control"
value={fechaInicio.toISOString().substring(0, 10)}
onChange={(e) => setFechaInicio(new Date(e.target.value))}
min={minDate.toISOString().substring(0, 10)}
/>
</div>
{fechaInicio && (
<div className="mt-4">
<div className="mb-3">
<label className="form-label">Fecha de fin</label>
<input
type="date"
className="form-control"
value={fechaFin.toISOString().substring(0, 10)}
onChange={(e) => setFechaFin(new Date(e.target.value))}
min={minDate2.toISOString().substring(0, 10)}
/>
<label className="form-label">Número de Cuenta</label>
<div className="input-group">
<input
type="text"
className="form-control"
placeholder="Número de Cuenta"
maxLength={9}
value={numeroCuenta}
onChange={(e) => setNumeroCuenta(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && buscarAlumno()}
/>
<button className="text-white rounded-1" onClick={buscarAlumno}>
Buscar
</button>
</div>
</div>
)}
<div className="mb-3">
<label className="form-label">Fecha de nacimiento</label>
<input
type="date"
className="form-control"
max={new Date().toISOString().substring(0, 10)}
value={fechaNacimiento.toISOString().substring(0, 10)}
onChange={(e) => setFechaNacimiento(new Date(e.target.value))}
/>
</div>
{alumno.nombre && (
<div className="mb-3">
<label className="form-label">Nombre</label>
<p className="form-control">{alumno.nombre || ''}</p>
</div>
)}
<div className="mb-3">
<label className="form-label">Artículo</label>
<select
className="form-select"
value={idStatus}
onChange={(e) => setIdStatus(e.target.value)}
>
<option value="">Selecciona una opción</option>
<option value="11">Artículo 52</option>
<option value="12">Artículo 91</option>
</select>
</div>
{alumno.carrera && (
<div className="mb-3">
<label className="form-label">Carrera</label>
<p className="form-control">{alumno.carrera || ''}</p>
</div>
)}
{alumno.creditos && (
<div className="mb-3">
<label className="form-label">Créditos</label>
<p className="form-control">
{alumno.creditos ? parseInt(alumno.creditos) : ''}{' '}
{alumno.creditos ? '%' : ''}
</p>
</div>
)}
{idStatus === '11' && (
<div className="mb-3">
<label className="form-label">Motivo</label>
<select
className="form-select"
value={motivo}
onChange={(e) => setMotivo(e.target.value)}
>
<option value="">Selecciona una opción</option>
<option value="1">Tercera edad</option>
<option value="2">Capacidades diferentes</option>
</select>
</div>
)}
{idStatus === '12' && (
<>
<div className="mb-3">
<label className="form-label">Institución</label>
<label className="form-label">Dirección</label>
<input
type="text"
className="form-control"
maxLength={250}
value={institucion}
onChange={(e) => setInstitucion(e.target.value)}
maxLength={200}
value={direccion}
onChange={(e) => setDireccion(e.target.value)}
/>
</div>
<div className="mb-3">
<label className="form-label">Dependencia</label>
<label className="form-label">Teléfono</label>
<input
type="text"
type="tel"
className="form-control"
maxLength={250}
value={dependencia}
onChange={(e) => setDependencia(e.target.value)}
maxLength={10}
value={telefono}
onChange={(e) => setTelefono(e.target.value)}
/>
</div>
</>
)}
<FormGroup className='mb-3'>
<FormLabel>Archivo (.zip, .rar)</FormLabel>
<div
className='border p-4 text-center rounded'
style={{ cursor: 'pointer' }}
onClick={() => document.getElementById('fileInput')?.click()}
>
<FaUpload size={40} className='mb-2'/>
<p className='mb-1'>
{file?.name || 'Arrastra aquí tu archivo o da click aquí para buscar'}
</p>
<p className='is-size-6'>Tmaño máximo 20MB</p>
<p className='is-size-6'>Si al momento de elegir un archivo este no se selecciona, haga click en cancelar en la ventana emergente e intente de nuevo.</p>
<div className="mb-3">
<label className="form-label">Correo electrónico</label>
<input
type="email"
className="form-control"
value={correo}
onChange={(e) => setCorreo(e.target.value)}
/>
</div>
<input
id='fileInput'
type="file"
style={{ display: 'none'}}
onChange={e => setFile(e.target.files ? e.target.files[0] : null)}
/>
</FormGroup>
<Col>
<FormGroup>
<FormLabel>Fecha de inicio</FormLabel>
<InputGroup>
<InputGroup.Text>
<FaRegCalendarAlt />
</InputGroup.Text>
<DatePicker
selected={fechaInicio}
onChange={handleFechaInicioChange}
minDate={minDate}
dateFormat="dd-MM-yyyy"
className="form-control"
wrapperClassName="flex-grow-1"
calendarClassName="mi-calendario"
/>
</InputGroup>
</FormGroup>
</Col>
{fechaInicio && (
<Col>
<FormGroup>
<FormLabel>Fecha de fin</FormLabel>
<InputGroup>
<InputGroup.Text>
<FaRegCalendarAlt />
</InputGroup.Text>
<DatePicker
selected={fechaFin}
onChange={handleFechaFinChange}
value={fechaFin.toISOString().substring(0,10)}
minDate={minDate2}
dateFormat="dd-MM-yyyy"
className="form-control"
wrapperClassName="flex-grow-1"
calendarClassName="mi-calendario"
/>
</InputGroup>
</FormGroup>
</Col>
)}
<Col>
<FormGroup>
<FormLabel>Fecha de nacimiento</FormLabel>
<InputGroup>
<InputGroup.Text>
<FaRegCalendarAlt />
</InputGroup.Text>
<DatePicker
selected={fechaNacimiento}
maxDate={new Date()}
onChange={handleFechaNacimientoChange}
dateFormat="dd-MM-yyyy"
className="form-control"
wrapperClassName="flex-grow-1"
calendarClassName="mi-calendario"
/>
</InputGroup>
</FormGroup>
</Col>
{/*
<div className="mb-3">
<label className="form-label">Archivo (.zip, .rar)</label>
<input
type="file"
accept=".zip,.rar"
className="form-control"
onChange={(e) => setFile(e.target.files ? e.target.files[0] : null)}
/>
<div className="form-text">Tamaño máximo 20MB</div>
</div>
<label className="form-label">Fecha de inicio</label>
<input
type="date"
className="form-control"
value={fechaInicio.toISOString().substring(0, 10)}
onChange={(e) => setFechaInicio(new Date(e.target.value))}
min={minDate.toISOString().substring(0, 10)}
/>
</div>
{fechaInicio && (
<div className="mb-3">
<label className="form-label">Fecha de fin</label>
<input
type="date"
className="form-control"
value={fechaFin.toISOString().substring(0, 10)}
onChange={(e) => setFechaFin(new Date(e.target.value))}
min={minDate2.toISOString().substring(0, 10)}
/>
</div>
)}
<div className="mb-3">
<label className="form-label">Fecha de nacimiento</label>
<input
type="date"
className="form-control"
max={new Date().toISOString().substring(0, 10)}
value={fechaNacimiento.toISOString().substring(0, 10)}
onChange={(e) => setFechaNacimiento(new Date(e.target.value))}
/>
</div>
*/}
<div className="text-center mt-4 mb-3">
<button
className="btn btn-success"
disabled={mostrarBoton()}
onClick={() =>
imprimirWarning(
'¿Estás seguro(a) de querer crear un nuevo caso especial?',
enviar
)
}
>
Enviar
</button>
</div>
<div className="mb-3">
<label className="form-label">Artículo</label>
<select
className="form-select"
value={idStatus}
onChange={(e) => setIdStatus(e.target.value)}
>
<option value="">Selecciona una opción</option>
<option value="11">Artículo 52</option>
<option value="12">Artículo 91</option>
</select>
</div>
<BotonRegresar />
{idStatus === '11' && (
<div className="mb-3">
<label className="form-label">Motivo</label>
<select
className="form-select"
value={motivo}
onChange={(e) => setMotivo(e.target.value)}
>
<option value="">Selecciona una opción</option>
<option value="1">Tercera edad</option>
<option value="2">Capacidades diferentes</option>
</select>
</div>
)}
{idStatus === '12' && (
<>
<div className="mb-3">
<label className="form-label">Institución</label>
<input
type="text"
className="form-control"
maxLength={250}
value={institucion}
onChange={(e) => setInstitucion(e.target.value)}
/>
</div>
<div className="mb-3">
<label className="form-label">Dependencia</label>
<input
type="text"
className="form-control"
maxLength={250}
value={dependencia}
onChange={(e) => setDependencia(e.target.value)}
/>
</div>
</>
)}
<FormGroup className='mb-3'>
<FormLabel>Archivo (.zip, .rar)</FormLabel>
<div
className='border p-4 text-center rounded'
style={{ cursor: 'pointer' }}
onClick={() => document.getElementById('fileInput')?.click()}
>
<FaUpload size={40} className='mb-2'/>
<p className='mb-1'>
{file?.name || 'Arrastra aquí tu archivo o da click aquí para buscar'}
</p>
<p className='is-size-6'>Tmaño máximo 20MB</p>
<p className='is-size-6'>Si al momento de elegir un archivo este no se selecciona, haga click en cancelar en la ventana emergente e intente de nuevo.</p>
</div>
<input
id='fileInput'
type="file"
style={{ display: 'none'}}
onChange={e => setFile(e.target.files ? e.target.files[0] : null)}
/>
</FormGroup>
{/*
<div className="mb-3">
<label className="form-label">Archivo (.zip, .rar)</label>
<input
type="file"
accept=".zip,.rar"
className="form-control"
onChange={(e) => setFile(e.target.files ? e.target.files[0] : null)}
/>
<div className="form-text">Tamaño máximo 20MB</div>
</div>
*/}
<div className="text-center mt-4 mb-3">
<button
className="btn btn-success"
disabled={mostrarBoton()}
onClick={() =>
imprimirWarning(
'¿Estás seguro(a) de querer crear un nuevo caso especial?',
enviar
)
}
>
Enviar
</button>
</div>
<BotonRegresar />
</div>
);
}
@@ -20,7 +20,7 @@ interface ServicioEspecial {
idServicio: number;
nombre: string;
numeroCuenta: string;
status: string;
Status: string;
// agrega más campos según lo que devuelva tu API
}
@@ -71,13 +71,9 @@ export default function LiberarCasoEspecial({ responsable, imprimirError }: Prop
if (search.nombre) query += `&nombre=${search.nombre}`;
if (search.numeroCuenta) query += `&numeroCuenta=${search.numeroCuenta}`;
const res = await axiosInstance.get(`/caso_especial/servicios_especiales?pagina=${page}${query}`, {
headers: {
Authorization: `Bearer ${responsable.token}`,
},
});
const res = await axiosInstance.get(`/caso-especial/servicios_especiales?pagina=${page}${query}`);
setData(res.data.serviciosEspeciales);
setData(res.data.data.serviciosEspeciales);
setTotal(res.data.count);
} catch (err: unknown) {
let msg = 'Error al obtener los casos especiales';
@@ -120,14 +116,14 @@ export default function LiberarCasoEspecial({ responsable, imprimirError }: Prop
return (
<div className="mb-6 container mt-4">
<h3 className="h4 mb-4">Casos Especiales</h3>
<h2 className="mb-4 fw-bold">Casos Especiales</h2>
<section className="container-fluid my-3">
<section className="my-3">
<Form onSubmit={(e) => { e.preventDefault(); obtenerCasosEspeciales(); }}>
<Row className="g-3">
<Col md={3}>
<FormGroup>
<FormLabel>Número de Cuenta</FormLabel>
<FormLabel className="fw-semibold">Número de Cuenta</FormLabel>
<InputGroup>
<InputGroup.Text className="rounded-4">
<FaSchool />
@@ -147,7 +143,7 @@ export default function LiberarCasoEspecial({ responsable, imprimirError }: Prop
<Col md={3}>
<FormGroup>
<FormLabel>Nombre</FormLabel>
<FormLabel className="fw-semibold">Nombre</FormLabel>
<InputGroup>
<InputGroup.Text className="rounded-4">
<FaUser />
@@ -166,7 +162,7 @@ export default function LiberarCasoEspecial({ responsable, imprimirError }: Prop
<Col md={3}>
<FormGroup>
<FormLabel>Status</FormLabel>
<FormLabel className="fw-semibold">Status</FormLabel>
<InputGroup>
<InputGroup.Text className="rounded-4">
<FaInfoCircle />
@@ -291,12 +291,12 @@ export default function CuestionarioResponsbale2({
const p = item as Pregunta;
return (
<div key={p.id} className="mb-6 mt-6">
<label htmlFor={p.id} className="form-label">{p.numeroPregunta}. {p.texto}</label>
<label htmlFor={p.id} className="form-label mb-3">{p.numeroPregunta}. {p.texto}</label>
{p.tipo === 'seleccionUnica' && p.opciones && (
<div>
<div className="mb-2">
{p.opciones.map((op) => (
<div key={op} className="SINO">
<label>
<label className="mb-3">
<input type="radio" name={p.id} checked={respuestas[p.id] === op} onChange={() => setSingle(p.id, op)} /> {op}
</label>
</div>
@@ -316,7 +316,7 @@ export default function CuestionarioResponsbale2({
)}
{p.tipo === 'texto' && (
<div>
<textarea id={p.id} maxLength={p.limite} placeholder="Escribe tu respuesta aquí" value={String(respuestas[p.id] ?? '')} onChange={(e) => setSingle(p.id, e.target.value)} className="form-control" />
<textarea id={p.id} maxLength={p.limite} placeholder="Escribe tu respuesta aquí" value={String(respuestas[p.id] ?? '')} onChange={(e) => setSingle(p.id, e.target.value)} className="form-control mb-3 bg-transparent" />
</div>
)}
</div>
@@ -326,22 +326,22 @@ export default function CuestionarioResponsbale2({
return (
<div key={t.idTabla} className="mb-6 table-responsive">
{(index === 0 || t.numeroPregunta !== (sortedItems[index - 1] as Tabla).numeroPregunta) && (
<h3 className="mb-3">{t.numeroPregunta}. {t.preguntaTabla}</h3>
<h5 className="mb-3 mt-4">{t.numeroPregunta}. {t.preguntaTabla}</h5>
)}
{t.subPreguntaTabla && <h5 className="mb-3">{t.subPreguntaTabla}</h5>}
<table className="table table-bordered text-center">
<thead>
<tr>
<th></th>
{(t.renglones[0].opciones || []).map((op) => <th key={op}>{op}</th>)}
<th className="bg-transparent"></th>
{(t.renglones[0].opciones || []).map((op) => <th key={op} className="bg-transparent">{op}</th>)}
</tr>
</thead>
<tbody>
{t.renglones.map((r) => (
<tr key={r.idRenglon}>
<td>{r.textoRenglon}</td>
<td className="bg-transparent">{r.textoRenglon}</td>
{(r.opciones || []).map((op) => (
<td key={op}>
<td key={op} className="bg-transparent">
<input type="radio" name={`tabla-${t.idTabla}-renglon-${r.idRenglon}`} value={op} checked={((respuestas[String(t.idTabla)] as Record<number, string | null>) || {})[r.idRenglon] === op} onChange={() => setTableAnswer(t.idTabla, r.idRenglon, op)} />
</td>
))}
+68 -41
View File
@@ -60,6 +60,14 @@ export default function NuevoServicio({
const [minDate2, setMinDate2] = useState<Date>(new Date());
const [programa, setPrograma] = useState<Programa>({});
const handleFechaInicioChange = (date: Date | null) => {
setFechaInicio(date || new Date());
}
const handleFechaFinChange = (date: Date | null) => {
setFechaFin(date || new Date());
}
const resetar = () => {
setCorreo("");
setProfesor("");
@@ -86,9 +94,10 @@ export default function NuevoServicio({
updateIsLoading(true);
try {
const headers = responsable?.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
const res = await axiosInstance.get<Alumno>(`/usuario/escolares?numeroCuenta=${encodeURIComponent(numeroCuenta)}`, { headers });
const res = await axiosInstance.post<Alumno>(`/usuario/escolares/${numeroCuenta}`, { headers });
resetar();
setAlumno(res.data);
obtenerProgramas();
updateIsLoading(false);
} catch (err: unknown) {
setNumeroCuenta("");
@@ -141,7 +150,7 @@ export default function NuevoServicio({
const obtenerProgramas = async () => {
try {
const headers = responsable?.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
const res = await axiosInstance.get<Programa[]>(`/programa/programas_responsable?idUsuario=${responsable.idUsuario}`, { headers });
const res = await axiosInstance.get<Programa[]>(`/programa/programas_responsable/${responsable.idUsuario}`, { headers });
setProgramas(res.data);
} catch (err: unknown) {
const axiosErr = err as AxiosError;
@@ -174,7 +183,7 @@ export default function NuevoServicio({
md.setDate(md.getDate() - 16);
setMinDate(md);
updateFechas();
obtenerProgramas();
//obtenerProgramas();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@@ -187,7 +196,7 @@ export default function NuevoServicio({
return (
<div>
<div className="mb-4">
<label className="form-label">Número de Cuenta</label>
<label className="form-label fw-bolder">Número de Cuenta</label>
<div className="d-flex gap-2">
<InputGroup.Text>
<FaSchool />
@@ -205,23 +214,29 @@ export default function NuevoServicio({
</div>
</div>
<div className="mb-3">
<label className="form-label">Nombre</label>
<p className="form-control">{alumno.nombre}</p>
</div>
{alumno.nombre && (
<div className="mb-3">
<label className="form-label fw-bolder">Nombre</label>
<p className="form-control">{alumno.nombre}</p>
</div>
)}
{alumno.carrera && (
<div className="mb-3">
<label className="form-label fw-bolder">Carrera</label>
<p className="form-control">{alumno.carrera ? String(alumno.carrera) : ''}</p>
</div>
)}
{alumno.creditos && (
<div className="mb-3">
<label className="form-label fw-bolder">Créditos</label>
<p className="form-control">{alumno.creditos ? parseInt(String(alumno.creditos)) : ''}{alumno.creditos ? '%' : ''}</p>
</div>
)}
<div className="mb-3">
<label className="form-label">Carrera</label>
<p className="form-control">{alumno.carrera ? String(alumno.carrera) : ''}</p>
</div>
<div className="mb-3">
<label className="form-label">Créditos</label>
<p className="form-control">{alumno.creditos ? parseInt(String(alumno.creditos)) : ''}{alumno.creditos ? '%' : ''}</p>
</div>
<div className="mb-3">
<label className="form-label">Seleccione programa</label>
<label className="form-label fw-bolder">Seleccione programa</label>
<select className="form-select" value={JSON.stringify(programa) } onChange={(e) => { try { setPrograma(JSON.parse(e.target.value)); } catch { setPrograma({}); } }}>
<option value={JSON.stringify({})} disabled>Seleccionar</option>
{programas.map((p, i) => (
@@ -230,30 +245,36 @@ export default function NuevoServicio({
</select>
</div>
<div className="mb-3">
<label className="form-label">Institución</label>
<p className="form-control">{programa.institucion}</p>
</div>
{programa.institucion && (
<div className="mb-3">
<label className="form-label fw-bolder">Institución</label>
<p className="form-control">{programa.institucion}</p>
</div>
)}
<div className="mb-3">
<label className="form-label">Dependencia</label>
<p className="form-control">{programa.dependencia}</p>
</div>
{programa.dependencia && (
<div className="mb-3">
<label className="form-label fw-bolder">Dependencia</label>
<p className="form-control">{programa.dependencia}</p>
</div>
)}
<div className="mb-3">
<label className="form-label">Clave del programa</label>
<p className="form-control">{programa.clavePrograma}</p>
</div>
{programa.clavePrograma && (
<div className="mb-3">
<label className="form-label fw-bolder">Clave del programa</label>
<p className="form-control">{programa.clavePrograma}</p>
</div>
)}
{programa.acatlan && (
<>
<div className="mb-3">
<label className="form-label">Programa interno</label>
<label className="form-label fw-bolder">Programa interno</label>
<input className="form-control" placeholder="Programa interno" value={programaInterno} onChange={(e) => setProgramaInterno(e.target.value)} />
</div>
<div className="mb-3">
<label className="form-label">Profesor/Responsable de Programa</label>
<label className="form-label fw-bolder">Profesor/Responsable de Programa</label>
<input className="form-control" placeholder="Profesor/Responsable de Programa" value={profesor} onChange={(e) => setProfesor(e.target.value)} />
</div>
</>
@@ -309,7 +330,7 @@ export default function NuevoServicio({
<Col>
<FormGroup>
<FormLabel>Fecha de inicio</FormLabel>
<FormLabel className="fw-bolder">Fecha de inicio</FormLabel>
<InputGroup>
<InputGroup.Text>
<FaRegCalendarAlt />
@@ -317,6 +338,7 @@ export default function NuevoServicio({
<DatePicker
selected={fechaInicio}
onChange={handleFechaInicioChange}
minDate={minDate}
dateFormat="dd-MM-yyyy"
className="form-control"
@@ -329,7 +351,7 @@ export default function NuevoServicio({
<Col>
<FormGroup>
<FormLabel>Fecha de fin</FormLabel>
<FormLabel className="fw-bolder">Fecha de fin</FormLabel>
<InputGroup>
<InputGroup.Text>
<FaRegCalendarAlt />
@@ -337,6 +359,7 @@ export default function NuevoServicio({
<DatePicker
selected={fechaFin}
onChange={handleFechaFinChange}
value={fechaFin.toISOString().substring(0,10)}
minDate={minDate2}
dateFormat="dd-MM-yyyy"
@@ -348,7 +371,8 @@ export default function NuevoServicio({
</FormGroup>
</Col>
<div className="mb-3">
{/*
<div className="mb-3">
<label className="form-label">Fecha de inicio</label>
<input type="date" className="form-control" value={fechaInicio.toISOString().substring(0,10)} min={minDate.toISOString().substring(0,10)} onChange={(e) => setFechaInicio(new Date(e.target.value))} />
</div>
@@ -359,14 +383,15 @@ export default function NuevoServicio({
<input type="date" className="form-control" value={fechaFin.toISOString().substring(0,10)} min={minDate2.toISOString().substring(0,10)} onChange={(e) => setFechaFin(new Date(e.target.value))} />
</div>
)}
*/}
<div className="mb-3">
<label className="form-label">Correo electrónico del Alumno</label>
<label className="form-label fw-bolder">Correo electrónico del Alumno</label>
<input type="email" className="form-control" placeholder="Email" value={correo} onChange={(e) => setCorreo(e.target.value)} />
</div>
<FormGroup className="mb-3">
<FormLabel>Carta de aceptación (en formato .PDF. No se aceptan fotos).</FormLabel>
<FormLabel className="fw-bolder">Carta de aceptación (en formato .PDF. No se aceptan fotos).</FormLabel>
<div className="border p-4 text-center rounded" style={{ cursor: "pointer" }} onClick={() => document.getElementById("fileInput")?.click()}>
<FaUpload size={40} className="mb-2"/>
<p className="mb-1">
@@ -384,7 +409,8 @@ export default function NuevoServicio({
/>
</FormGroup>
<div className="mb-3">
{/*
<div className="mb-3">
<label className="form-label">Carta de aceptación (en formato .PDF. No se aceptan fotos).</label>
<input type="file" accept="application/pdf" className="form-control" onChange={(e) => onFileChange(e.target.files?.[0])} />
<div className="mt-2 text-muted">
@@ -393,9 +419,10 @@ export default function NuevoServicio({
<p>Si al momento de elegir un archivo este no se selecciona, haga click en cancelar en la ventana emergente e intente de nuevo.</p>
</div>
</div>
*/}
<div className="has-text-centered mt-4">
<button disabled={mostrarBoton()} onClick={() => imprimirWarning('¿Esta seguro(a) de querer Pre-Registrar a este alumno?', preRegistrar)}>
<div className="text-center mt-4 mb-3">
<button className="btn btn-success" disabled={mostrarBoton()} onClick={() => imprimirWarning('¿Esta seguro(a) de querer Pre-Registrar a este alumno?', preRegistrar)}>
Enviar archivo
</button>
</div>
@@ -49,14 +49,21 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
if (search.nombre) query += `&nombre=${encodeURIComponent(search.nombre)}`;
if (search.numeroCuenta) query += `&numeroCuenta=${encodeURIComponent(search.numeroCuenta)}`;
const idUsuario = localStorage.getItem("idUsuario")
try {
console.log('Informacion en el componente hijo del responsable:', responsable);
console.log('Id del usuario responsable:', responsable.idUsuario);
const idUsuario = localStorage.getItem('idUsuario') ?? '';
const idUsuario1 = localStorage.getItem('idUsuario') ?? '';
console.log('idUsuario usado en la consulta componente hijo:', idUsuario);
console.log("Este es la optencion del id del usuario desde el local", idUsuario1)
//const headers = responsable?.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
const res = await axiosInstance.get<{ serviciosResponsable: ServicioSocialResponse[]; count: number }>(`/servicio/servicios_responsable?idUsuario=${idUsuario}&pagina=${pagina}${query}`);
//const res = await axiosInstance.get<{ serviciosResponsable: ServicioSocialResponse[]; count: number }>(`/servicio/servicios_responsable?idUsuario=${idUsuario}&pagina=${pagina}${query}`);
const res = await axiosInstance.get(`/servicio/servicios_responsable?idUsuario=${idUsuario1}&pagina=${pagina}${query}`);
//const res = await axiosInstance.get(`/servicio/servicios_responsable?idUsuario=${idUsuario1}&pagina=${pagina}${query}`);
setData(res.data.serviciosResponsable);
setTotal(res.data.count);
setIsLoading(false);
+25 -14
View File
@@ -46,25 +46,25 @@ export default function ServicioSocialTabla({
// 🔹 Cargar datos del padre si existen
useEffect(() => {
if (data && data.length > 0) {
setInfo(data);
setInfo(data);
}
}, [data]);
// 🔹 Paginación simple
function handlePrev() {
if (currentPage > 1) {
const np = currentPage - 1;
setCurrentPage(np);
onPageChange?.(np);
const np = currentPage - 1;
setCurrentPage(np);
onPageChange?.(np);
}
}
function handleNext() {
const lastPage = Math.max(1, Math.ceil(total / 10));
if (currentPage < lastPage) {
const np = currentPage + 1;
setCurrentPage(np);
onPageChange?.(np);
const np = currentPage + 1;
setCurrentPage(np);
onPageChange?.(np);
}
}
@@ -77,11 +77,19 @@ export default function ServicioSocialTabla({
localStorage.setItem("idServicio", String(row.idServicio));
}
// esta mal esta logica
if ("idCasoEspecial" in row && row.idCasoEspecial) {
localStorage.setItem("idCasoEspecial", String(row.idCasoEspecial));
}
router.push("/administrador/servicio");
if ( row.idServicio ) {
router.push("/administrador/servicio");
} else if ("idCasoEspecial" in row && row.idCasoEspecial) {
router.push('/administrador/casos_especiales/caso_especial')
}
// Hacer validacion para saber que id fue y redireccionar
//router.push("/administrador/servicio");
//router.push('/administrador/casos_especiales/caso_especial')
} else if (
row.idServicio ||
@@ -175,15 +183,18 @@ const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEsp
//}
>
{columnaFechaRegistro && <td>{formatDate(item.createdAt)}</td>}
<td>{item.Usuario?.usuario}</td>
<td>{item.Usuario?.nombre}</td>
<td>{item.Carrera?.carrera}</td>
<td>{item.usuario?.usuario}</td>
<td>{item.usuario?.nombre}</td>
<td>{item.carrera?.carrera}</td>
{columnaFechaInicio && (
<td>{formatDate(item.fechaInicio)}</td>
)}
{columnaFechaFin && <td>{formatDate(item.fechaFin)}</td>}
<td>
{columnasResponsable && item.Status?.idStatus === 7 ? (
{columnasResponsable && item.status?.idStatus === 7 ? (
<button
className="btn btn-sm btn-danger"
onClick={() =>
@@ -195,10 +206,10 @@ const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEsp
) : (
<span
className={`badge bg-${statusClass(
item.Status?.idStatus
item.status?.idStatus
)}`}
>
{item.Status?.status}
{item.status?.status}
</span>
)}
</td>
+3 -3
View File
@@ -8,9 +8,9 @@ export interface ServicioSocialResponse {
fechaFin?: string | null;
fechaInicio?: string | null;
fecha_registro?: string | null;
Usuario?: Usuario;
Carrera?: Carrera;
Status?: Status;
usuario?: Usuario;
carrera?: Carrera;
status?: Status;
cartaTermino?: boolean;
idCuestionarioPrograma?: number | null;
idCuestionarioPrograma2?: number | null;