1 Commits

5 changed files with 648 additions and 564 deletions
+45 -43
View File
@@ -1,59 +1,61 @@
import axios from 'axios';
import axios from "axios";
// Crea una instancia base de Axios
export const axiosInstance = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000/api', // poner la url
headers: {
'Content-Type': 'application/json',
},
timeout: 10000, // tiempo máximo de espera (10 segundos)
baseURL: process.env.NEXT_PUBLIC_API_URL || "http://localhost:3411", // poner la url
headers: {
"Content-Type": "application/json",
},
timeout: 10000, // tiempo máximo de espera (10 segundos)
});
// Interceptor para agregar el token automáticamente
axiosInstance.interceptors.request.use(
(config) => {
if (typeof window !== 'undefined') {
const token = localStorage.getItem('token');
if (token) {
// Múltiples formatos según lo que espere el backend
config.headers.Authorization = `Bearer ${token}`;
//Quitar estas lienas
config.headers['token'] = token;
config.headers['x-access-token'] = token;
config.headers['token-v2'] = token;
}
(config) => {
if (typeof window !== "undefined") {
const token = localStorage.getItem("token");
if (token) {
// Múltiples formatos según lo que espere el backend
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
//Quitar estas lienas
config.headers["token"] = token;
config.headers["x-access-token"] = token;
config.headers["token-v2"] = token;
}
}
return config;
},
(error) => Promise.reject(error)
);
// Interceptor para manejar respuestas y errores globales
axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
if (error.response) {
// Token inválido o sesión expirada
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
}
(response) => response,
(error) => {
if (error.response) {
// Token inválido o sesión expirada
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
}
}
// Errores del servidor
console.error('Error en la respuesta del servidor:', error.response.data);
} else if (error.request) {
// No hubo respuesta del servidor
console.error('No se recibió respuesta del servidor.');
} else {
// Error en la configuración de la petición
console.error('Error en la configuración de la solicitud:', error.message);
}
return Promise.reject(error);
// Errores del servidor
console.error("Error en la respuesta del servidor:", error.response.data);
} else if (error.request) {
// No hubo respuesta del servidor
console.error("No se recibió respuesta del servidor.");
} else {
// Error en la configuración de la petición
console.error(
"Error en la configuración de la solicitud:",
error.message
);
}
return Promise.reject(error);
}
);
+93 -69
View File
@@ -1,85 +1,109 @@
'use client'
"use client";
import { axiosInstance } from "@/api/config";
import { useRouter } from "next/navigation";
import React from "react";
export default function Home() {
const router = useRouter();
const router = useRouter();
const handleOnSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const object = Object.fromEntries(formData);
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);
try {
const res = await axiosInstance.post("/auth/login", object);
// Extraer datos del backend
const token = res?.data?.token ?? '';
const usuarioObj = res?.data?.Usuario ?? res?.data ?? {};
const idUsuario = usuarioObj.idUsuario ?? '';
const usuario = usuarioObj.usuario ?? '';
const nombre = usuarioObj.nombre ?? '';
const idTipoUsuario = Number(usuarioObj.TipoUsuario?.idTipoUsuario ?? 0);
//const idTipoUsuario = Number((usuarioObj as any).TipoUsuario?.idTipoUsuario ?? 0);
// Extraer datos del backend
const token = res?.data?.token ?? "";
const usuarioObj = res?.data?.Usuario ?? res?.data ?? {};
const idUsuario = usuarioObj.idUsuario ?? "";
const usuario = usuarioObj.usuario ?? "";
const nombre = usuarioObj.nombre ?? "";
const idTipoUsuario = Number(usuarioObj.TipoUsuario?.idTipoUsuario ?? 0);
//const idTipoUsuario = Number((usuarioObj as any).TipoUsuario?.idTipoUsuario ?? 0);
// Guardar en localStorage
localStorage.setItem("token", String(token));
localStorage.setItem("idUsuario", String(idUsuario));
localStorage.setItem("usuario", String(usuario));
localStorage.setItem("nombre", String(nombre));
localStorage.setItem("idTipoUsuario", String(idTipoUsuario));
// Guardar en localStorage
localStorage.setItem('token', String(token));
localStorage.setItem('idUsuario', String(idUsuario));
localStorage.setItem('usuario', String(usuario));
localStorage.setItem('nombre', String(nombre));
localStorage.setItem('idTipoUsuario', String(idTipoUsuario));
// Validar y redirigir según el idTipoUsuario
if (token && idUsuario && idTipoUsuario) {
switch (idTipoUsuario) {
case 1:
router.push('/administrador');
break;
case 2:
router.push('/responsable');
break;
case 3:
router.push('/alumno');
break;
case 4:
router.push('/casoEspecial');
break;
default:
console.warn(`Tipo de usuario desconocido: ${idTipoUsuario}`);
localStorage.clear();
break;
}
} else {
localStorage.clear();
console.error('Error: datos de usuario incompletos');
}
} catch (error) {
console.error('Error en el inicio de sesión:', error);
// Validar y redirigir según el idTipoUsuario
if (token && idUsuario && idTipoUsuario) {
switch (idTipoUsuario) {
case 1:
router.push("/administrador");
break;
case 2:
router.push("/responsable");
break;
case 3:
router.push("/alumno");
break;
case 4:
router.push("/casoEspecial");
break;
default:
console.warn(`Tipo de usuario desconocido: ${idTipoUsuario}`);
localStorage.clear();
break;
}
};
} else {
localStorage.clear();
console.error("Error: datos de usuario incompletos");
}
} catch (error) {
console.error("Error en el inicio de sesión:", error);
localStorage.clear();
}
};
return (
<div className="d-flex justify-content-center align-items-center bg-light" style={{ minHeight: 'calc(100vh - 200px)' }}>
<form className="p-4 shadow rounded bg-white w-100" style={{ maxWidth: '400px' }} onSubmit={handleOnSubmit}>
<h2 className="text-center mb-4 fw-bold">IRIS</h2>
return (
<div
className="d-flex justify-content-center align-items-center bg-light"
style={{ minHeight: "calc(100vh - 200px)" }}
>
<form
className="p-4 shadow rounded bg-white w-100"
style={{ maxWidth: "400px" }}
onSubmit={handleOnSubmit}
>
<h2 className="text-center mb-4 fw-bold">IRIS</h2>
<div className="mb-3">
<label htmlFor="usuario" className="form-label">Usuario</label>
<input type="text" name="usuario" id="usuario" className="form-control" 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 />
</div>
<div className="d-grid">
<button type="submit" className="btn btn-primary btn-lg">Iniciar Sesión</button>
</div>
</form>
<div className="mb-3">
<label htmlFor="usuario" className="form-label">
Usuario
</label>
<input
type="text"
name="usuario"
id="usuario"
className="form-control"
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
/>
</div>
<div className="d-grid">
<button type="submit" className="btn btn-primary btn-lg">
Iniciar Sesión
</button>
</div>
</form>
</div>
);
}
@@ -1,8 +1,18 @@
"use client";
import React, { useEffect, useRef, useState } from "react";
import { useRouter } from 'next/navigation';
import { Form, FormGroup, FormLabel, FormControl, FormSelect, Button, InputGroup, Row, Col } from "react-bootstrap";
import { useRouter } from "next/navigation";
import {
Form,
FormGroup,
FormLabel,
FormControl,
FormSelect,
Button,
InputGroup,
Row,
Col,
} from "react-bootstrap";
import { FaUser, FaSchool, FaInfoCircle } from "react-icons/fa";
import ServicioSocialTabla from "../servicio-social-tabla";
import { axiosInstance } from "@/api/config";
@@ -11,197 +21,240 @@ import { Prev } from "react-bootstrap/esm/PageItem";
import { AxiosError } from "axios";
interface Admin {
idTipoUsuario: number;
token?: string;
idTipoUsuario: number;
token?: string;
}
interface Props {
admin: Admin;
imprimirError: (mensaje: string) => void;
admin: Admin;
imprimirError: (mensaje: string) => void;
}
type StatusItem = { idStatus: number; status: string };
export default function TablaServicioSocial({ admin, imprimirError }: Props) {
const router = useRouter();
const [isLoading, setIsLoading] = useState(false);
const [page, setPage] = useState(1);
const [total, setTotal] = useState(0);
const [data, setData] = useState<ServicioSocialResponse[]>([]);
const [status, setStatus] = useState<StatusItem[]>([]);
const router = useRouter();
const [isLoading, setIsLoading] = useState(false);
const [page, setPage] = useState(1);
const [total, setTotal] = useState(0);
const [data, setData] = useState<ServicioSocialResponse[]>([]);
const [status, setStatus] = useState<StatusItem[]>([]);
const [search, setSearch] = useState({ numeroCuenta: '', nombre: '', idStatus: '' });
const searchAnterior = useRef({ numeroCuenta: '', nombre: '', idStatus: '' });
const [search, setSearch] = useState({
numeroCuenta: "",
nombre: "",
idStatus: "",
});
const searchAnterior = useRef({ numeroCuenta: "", nombre: "", idStatus: "" });
useEffect(() => {
if (admin?.idTipoUsuario === 1) {
obtenerCatalogoStatus();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [admin?.idTipoUsuario]);
useEffect(() => {
if (admin?.idTipoUsuario === 1) {
obtenerCatalogoStatus();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [admin?.idTipoUsuario]);
function onPageChange(newPage: number) {
setPage(newPage);
obtenerServicios(newPage);
function onPageChange(newPage: number) {
setPage(newPage);
obtenerServicios(newPage);
}
async function obtenerServicios(pagina?: number) {
const paginaActual = pagina ?? page;
let query = "";
setIsLoading(true);
if (
search.numeroCuenta !== searchAnterior.current.numeroCuenta ||
search.nombre !== searchAnterior.current.nombre ||
search.idStatus !== searchAnterior.current.idStatus
) {
// resetear a primera página si cambió la búsqueda
setPage(1);
searchAnterior.current = { ...search };
}
async function obtenerServicios(pagina?: number) {
const paginaActual = pagina ?? page;
let query = '';
if (search.idStatus)
query += `&idStatus=${encodeURIComponent(search.idStatus)}`;
if (search.nombre) query += `&nombre=${encodeURIComponent(search.nombre)}`;
if (search.numeroCuenta)
query += `&numeroCuenta=${encodeURIComponent(search.numeroCuenta)}`;
setIsLoading(true);
if (
search.numeroCuenta !== searchAnterior.current.numeroCuenta ||
search.nombre !== searchAnterior.current.nombre ||
search.idStatus !== searchAnterior.current.idStatus
) {
// resetear a primera página si cambió la búsqueda
setPage(1);
searchAnterior.current = { ...search };
}
if (search.idStatus) query += `&idStatus=${encodeURIComponent(search.idStatus)}`;
if (search.nombre) query += `&nombre=${encodeURIComponent(search.nombre)}`;
if (search.numeroCuenta) query += `&numeroCuenta=${encodeURIComponent(search.numeroCuenta)}`;
try {
// 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);
console.debug('Respuesta servicios_admin:', res.data);
setData(res.data.serviciosAdmin || []);
setTotal(res.data.count ?? 0);
} catch (err: unknown) {
// manejar error
console.error('Error obtenerServicios', err);
//const mensaje = (err as any)?.response?.data ?? String(err); Falta imprimir error
//imprimirError(mensaje);
} finally {
setIsLoading(false);
}
try {
// 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/admin?pagina=${paginaActual}${query}`,
config
);
console.debug("Respuesta servicios_admin:", res.data);
setData(res.data.serviciosAdmin || []);
setTotal(res.data.count ?? 0);
} catch (err: unknown) {
// manejar error
console.error("Error obtenerServicios", err);
//const mensaje = (err as any)?.response?.data ?? String(err); Falta imprimir error
//imprimirError(mensaje);
} finally {
setIsLoading(false);
}
}
const obtenerCatalogoStatus = async () => {
try {
//const headers = responsable?.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
const res = await axiosInstance.get<StatusItem[]>('/status');
setStatus(res.data);
console.log(res.data);
//console.log('Status obtenidos', status);
obtenerServicios();
} catch (err: unknown) {
const axiosErr = err as AxiosError;
console.log('Error al obtener catálogo de status:', err);
}
};
const obtenerCatalogoStatus = async () => {
try {
//const headers = responsable?.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
const res = await axiosInstance.get<StatusItem[]>("/status");
setStatus(res.data);
console.log(res.data);
//console.log('Status obtenidos', status);
obtenerServicios();
} catch (err: unknown) {
const axiosErr = err as AxiosError;
console.log("Error al obtener catálogo de status:", err);
}
};
return (
<section>
<div className="columns">
<h2 className="title">Servicios Sociales</h2>
return (
<section>
<div className="columns">
<h2 className="title">Servicios Sociales</h2>
<section className="container-fluid my-4">
<Form
onSubmit={(e) => {
e.preventDefault();
obtenerServicios(1);
}}
>
<Row className="g-3">
<Col md={3}>
<FormGroup>
<FormLabel>Número de Cuenta</FormLabel>
<InputGroup>
<InputGroup.Text className="rounded-4">
<FaSchool />
</InputGroup.Text>
<FormControl
type="text"
placeholder="No.Cuenta"
maxLength={9}
value={search.numeroCuenta}
onChange={(e) =>
setSearch((prev) => ({
...prev,
numeroCuenta: e.target.value,
}))
}
onKeyDown={(e) => {
if (e.key === "Enter") obtenerServicios(1);
}}
className="rounded-4"
/>
</InputGroup>
</FormGroup>
</Col>
<section className="container-fluid my-4">
<Form onSubmit={(e) => { e.preventDefault(); obtenerServicios(1); }}>
<Row className="g-3">
<Col md={3}>
<FormGroup>
<FormLabel>Número de Cuenta</FormLabel>
<InputGroup>
<InputGroup.Text className="rounded-4">
<FaSchool />
</InputGroup.Text>
<FormControl
type="text"
placeholder="No.Cuenta"
maxLength={9}
value={search.numeroCuenta}
onChange={(e) => setSearch(prev => ({ ...prev, numeroCuenta: e.target.value }))}
onKeyDown={(e) => { if (e.key === 'Enter') obtenerServicios(1); }}
className="rounded-4"
/>
</InputGroup>
</FormGroup>
</Col>
<Col md={3}>
<FormGroup>
<FormLabel>Nombre</FormLabel>
<InputGroup>
<InputGroup.Text className="rounded-4">
<FaUser />
</InputGroup.Text>
<FormControl
type="text"
placeholder="Nombre"
value={search.nombre}
onChange={(e) =>
setSearch((prev) => ({
...prev,
nombre: e.target.value,
}))
}
onKeyDown={(e) => {
if (e.key === "Enter") obtenerServicios(1);
}}
className="rounded-4"
/>
</InputGroup>
</FormGroup>
</Col>
<Col md={3}>
<FormGroup>
<FormLabel>Nombre</FormLabel>
<InputGroup>
<InputGroup.Text className="rounded-4">
<FaUser />
</InputGroup.Text>
<FormControl
type="text"
placeholder="Nombre"
value={search.nombre}
onChange={(e) => setSearch(prev => ({ ...prev, nombre: e.target.value }))}
onKeyDown={(e) => { if (e.key === 'Enter') obtenerServicios(1); }}
className="rounded-4"
/>
</InputGroup>
</FormGroup>
</Col>
<Col md={3}>
<FormGroup>
<FormLabel>Status</FormLabel>
<InputGroup>
<InputGroup.Text className="rounded-4">
<FaInfoCircle />
</InputGroup.Text>
<FormSelect
value={search.idStatus}
onChange={(e) =>
setSearch((Prev) => ({
...Prev,
idStatus: e.target.value,
}))
}
className="rounded-4"
>
<option value="">Status</option>
{status.slice(0, 10).map((s) => (
<option key={s.idStatus} value={s.idStatus}>
{s.status}
</option>
))}
</FormSelect>
</InputGroup>
</FormGroup>
</Col>
<Col md={3}>
<FormGroup>
<FormLabel>Status</FormLabel>
<InputGroup>
<InputGroup.Text className="rounded-4">
<FaInfoCircle />
</InputGroup.Text>
<FormSelect
value={search.idStatus}
onChange={(e) => setSearch(Prev => ({ ...Prev, idStatus: e.target.value }))}
className="rounded-4"
>
<option value="">Status</option>
{status.slice(0, 10).map((s) => (
<option key={s.idStatus} value={s.idStatus}>{s.status}</option>
))}
</FormSelect>
</InputGroup>
</FormGroup>
</Col>
<Col md={3} className="d-flex align-items-end">
<Button type="submit" className="w-100 rounded-5" disabled={isLoading}>
{isLoading ? 'Buscando...' : 'Buscar'}
</Button>
</Col>
</Row>
</Form>
</section>
</div>
<ServicioSocialTabla
data={data}
total={total}
columnaFechaFin={true}
columnaFechaInicio={true}
onPageChange={onPageChange}
idTipoUsuario={admin?.idTipoUsuario}
columnasResponsable={admin?.idTipoUsuario === 1}
columnaFechaRegistro={true}
columnaCuestionario={false}
columnaCartaTermino={false}
columnaCuestionarioCompleto={false}
onRowAction={(row, path) => {
try {
// Falta corregir este parte de codigo para poder subirlo
//if ((row as any)?.idServicio) localStorage.setItem('idServicio', String((row as any).idServicio));
router.push(`/responsable/${path}`);
} catch (e) {
console.error('Error al manejar acción de fila', e);
}
}}
/>
<Col md={3} className="d-flex align-items-end">
<Button
type="submit"
className="w-100 rounded-5"
disabled={isLoading}
>
{isLoading ? "Buscando..." : "Buscar"}
</Button>
</Col>
</Row>
</Form>
</section>
)
</div>
<ServicioSocialTabla
data={data}
total={total}
columnaFechaFin={true}
columnaFechaInicio={true}
onPageChange={onPageChange}
idTipoUsuario={admin?.idTipoUsuario}
columnasResponsable={admin?.idTipoUsuario === 1}
columnaFechaRegistro={true}
columnaCuestionario={false}
columnaCartaTermino={false}
columnaCuestionarioCompleto={false}
onRowAction={(row, path) => {
try {
// Falta corregir este parte de codigo para poder subirlo
//if ((row as any)?.idServicio) localStorage.setItem('idServicio', String((row as any).idServicio));
router.push(`/responsable/${path}`);
} catch (e) {
console.error("Error al manejar acción de fila", e);
}
}}
/>
</section>
);
}
+248 -243
View File
@@ -2,104 +2,107 @@
import { useEffect, useState } from "react";
import { axiosInstance } from "@/api/config";
import { ServicioSocialConCasoEspecial, ServicioSocialResponse } from "@/types/responses";
import {
ServicioSocialConCasoEspecial,
ServicioSocialResponse,
} from "@/types/responses";
import { useRouter } from "next/navigation";
interface Props {
data?: ServicioSocialResponse[];
total?: number;
onPageChange?: (newPage: number) => void;
columnaFechaInicio?: boolean;
columnaFechaFin?: boolean;
idTipoUsuario?: number; // 1=admin, 2=responsable, 3=alumno, 4=caso especial
columnasResponsable?: boolean;
onRowAction?: (row: ServicioSocialResponse, path: string) => void;
columnaCuestionario?: boolean;
columnaCartaTermino?: boolean;
columnaCuestionarioCompleto?: boolean;
columnaFechaRegistro?: boolean;
data?: ServicioSocialResponse[];
total?: number;
onPageChange?: (newPage: number) => void;
columnaFechaInicio?: boolean;
columnaFechaFin?: boolean;
idTipoUsuario?: number; // 1=admin, 2=responsable, 3=alumno, 4=caso especial
columnasResponsable?: boolean;
onRowAction?: (row: ServicioSocialResponse, path: string) => void;
columnaCuestionario?: boolean;
columnaCartaTermino?: boolean;
columnaCuestionarioCompleto?: boolean;
columnaFechaRegistro?: boolean;
}
export default function ServicioSocialTabla({
data,
total = 0,
onPageChange,
idTipoUsuario,
columnasResponsable = false,
columnaFechaInicio = false,
columnaFechaFin = false,
columnaCuestionario = false,
columnaCartaTermino = false,
columnaCuestionarioCompleto = false,
columnaFechaRegistro = false,
onRowAction,
data,
total = 0,
onPageChange,
idTipoUsuario,
columnasResponsable = false,
columnaFechaInicio = false,
columnaFechaFin = false,
columnaCuestionario = false,
columnaCartaTermino = false,
columnaCuestionarioCompleto = false,
columnaFechaRegistro = false,
onRowAction,
}: Props) {
const [info, setInfo] = useState<ServicioSocialResponse[]>(data || []);
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [info, setInfo] = useState<ServicioSocialResponse[]>(data || []);
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const router = useRouter();
const router = useRouter();
//const columnaFechaInicio = true;
//const columnaFechaFin = true;
//const columnaFechaInicio = true;
//const columnaFechaFin = true;
// 🔹 Cargar datos del padre si existen
useEffect(() => {
if (data && data.length > 0) {
setInfo(data);
}
}, [data]);
// 🔹 Paginación simple
function handlePrev() {
if (currentPage > 1) {
const np = currentPage - 1;
setCurrentPage(np);
onPageChange?.(np);
}
// 🔹 Cargar datos del padre si existen
useEffect(() => {
if (data && data.length > 0) {
setInfo(data);
}
}, [data]);
function handleNext() {
const lastPage = Math.max(1, Math.ceil(total / 10));
if (currentPage < lastPage) {
const np = currentPage + 1;
setCurrentPage(np);
onPageChange?.(np);
}
// 🔹 Paginación simple
function handlePrev() {
if (currentPage > 1) {
const np = currentPage - 1;
setCurrentPage(np);
onPageChange?.(np);
}
}
const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEspecial) => {
if (!row) return;
if (idTipoUsuario === 1) {
if (row.idServicio) {
localStorage.setItem("idServicio", String(row.idServicio));
}
// esta mal esta logica
if ("idCasoEspecial" in row && row.idCasoEspecial) {
localStorage.setItem("idCasoEspecial", String(row.idCasoEspecial));
}
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 ||
("idCasoEspecial" in row && row.idCasoEspecial)
) {
console.log("Limpiando selección (no admin)");
}
function handleNext() {
const lastPage = Math.max(1, Math.ceil(total / 10));
if (currentPage < lastPage) {
const np = currentPage + 1;
setCurrentPage(np);
onPageChange?.(np);
}
}
/*
const servicioSelected = (
row: ServicioSocialResponse | ServicioSocialConCasoEspecial
) => {
if (!row) return;
if (idTipoUsuario === 1) {
if (row.idServicio) {
localStorage.setItem("idServicio", String(row.idServicio));
}
// esta mal esta logica
if ("idCasoEspecial" in row && row.idCasoEspecial) {
localStorage.setItem("idCasoEspecial", String(row.idCasoEspecial));
}
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 ||
("idCasoEspecial" in row && row.idCasoEspecial)
) {
console.log("Limpiando selección (no admin)");
}
};
/*
const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEspecial) => {
if (!row) return;
@@ -146,177 +149,179 @@ const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEsp
*/
return (
<section>
{loading ? (
<div>Cargando...</div>
) : (
<>
<div className="table-responsive">
<table className="table table-striped">
<thead>
<tr>
{columnaFechaRegistro && <th>Fecha Registro</th>}
<th>Número de Cuenta</th>
<th>Nombre</th>
<th>Carrera</th>
{columnaFechaInicio && <th>Fecha Inicio</th>}
{columnaFechaFin && <th>Fecha Fin</th>}
<th>Status</th>
{columnaCuestionarioCompleto && <th>Cuestionario Completo</th>}
{columnaCartaTermino && <th>Carta Termino</th>}
{columnaCuestionario && <th>Cuestionario</th>}
</tr>
</thead>
<tbody>
{info.map((item, index) => (
<tr
key={index}
style={{
cursor: idTipoUsuario === 1 ? "pointer" : "default",
}}
onClick={() => (
idTipoUsuario === 1 ? servicioSelected(item) : undefined
)}
//onClick={() => Falta corregir
//idTipoUsuario === 1 ? servicioSelected(item) : undefined
//}
>
{columnaFechaRegistro && <td>{formatDate(item.createdAt)}</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 ? (
<button
className="btn btn-sm btn-danger"
onClick={() =>
onRowAction?.(item, "carta_aceptacion")
}
>
Carta Aceptación Rechazada
</button>
) : (
<span
className={`badge bg-${statusClass(
item.Status?.idStatus
)}`}
>
{item.Status?.status}
</span>
)}
</td>
{columnaCartaTermino && (
<td>{item.cartaTermino ? (
<span className="badge bg-success">Completado</span>
) : (
<span className="badge bg-danger">No Completado</span>
)}</td>
)}
{columnaCuestionarioCompleto && (
<td>{item.cuestionarioCompletado ? (
<span className="badge bg-success">Completado</span>
) : (
<span className="badge bg-danger">No Completado</span>
)}</td>
)}
{columnaCuestionario && (
<td>
{item.cuestionarioCompletado ? (
<span className="badge bg-success">Completado</span>
) : (
<span className="badge bg-danger">No Completado</span>
)}
</td>
)}
</tr>
))}
{info.length === 0 && (
<tr>
<td colSpan={7} className="text-center">
No hay registros
</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="d-flex justify-content-between align-items-center mt-2">
<div>Total: {total}</div>
<div>
<button
className="btn btn-sm btn-outline-primary me-2"
onClick={handlePrev}
disabled={currentPage <= 1}
>
Anterior
</button>
<span>Página {currentPage}</span>
<button
className="btn btn-sm btn-outline-primary ms-2"
onClick={handleNext}
disabled={
currentPage >= Math.max(1, Math.ceil(total / 10))
return (
<section>
{loading ? (
<div>Cargando...</div>
) : (
<>
<div className="table-responsive">
<table className="table table-striped">
<thead>
<tr>
{columnaFechaRegistro && <th>Fecha Registro</th>}
<th>Número de Cuenta</th>
<th>Nombre</th>
<th>Carrera</th>
{columnaFechaInicio && <th>Fecha Inicio</th>}
{columnaFechaFin && <th>Fecha Fin</th>}
<th>Status</th>
{columnaCuestionarioCompleto && (
<th>Cuestionario Completo</th>
)}
{columnaCartaTermino && <th>Carta Termino</th>}
{columnaCuestionario && <th>Cuestionario</th>}
</tr>
</thead>
<tbody>
{info.map((item, index) => (
<tr
key={index}
style={{
cursor: idTipoUsuario === 1 ? "pointer" : "default",
}}
onClick={() =>
idTipoUsuario === 1 ? servicioSelected(item) : undefined
}
>
Siguiente
</button>
</div>
//onClick={() => Falta corregir
//idTipoUsuario === 1 ? servicioSelected(item) : undefined
//}
>
{columnaFechaRegistro && (
<td>{formatDate(item.createdAt)}</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 ? (
<button
className="btn btn-sm btn-danger"
onClick={() =>
onRowAction?.(item, "carta_aceptacion")
}
>
Carta Aceptación Rechazada
</button>
) : (
<span
className={`badge bg-${statusClass(
item.status?.idStatus
)}`}
>
{item.status?.status}
</span>
)}
</td>
{columnaCartaTermino && (
<td>
{item.cartaTermino ? (
<span className="badge bg-success">Completado</span>
) : (
<span className="badge bg-danger">No Completado</span>
)}
</td>
)}
{columnaCuestionarioCompleto && (
<td>
{item.cuestionarioCompletado ? (
<span className="badge bg-success">Completado</span>
) : (
<span className="badge bg-danger">No Completado</span>
)}
</td>
)}
{columnaCuestionario && (
<td>
{item.cuestionarioCompletado ? (
<span className="badge bg-success">Completado</span>
) : (
<span className="badge bg-danger">No Completado</span>
)}
</td>
)}
</tr>
))}
{info.length === 0 && (
<tr>
<td colSpan={7} className="text-center">
No hay registros
</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="d-flex justify-content-between align-items-center mt-2">
<div>Total: {total}</div>
<div>
<button
className="btn btn-sm btn-outline-primary me-2"
onClick={handlePrev}
disabled={currentPage <= 1}
>
Anterior
</button>
<span>Página {currentPage}</span>
<button
className="btn btn-sm btn-outline-primary ms-2"
onClick={handleNext}
disabled={currentPage >= Math.max(1, Math.ceil(total / 10))}
>
Siguiente
</button>
</div>
</>
)}
</section>
);
</div>
</>
)}
</section>
);
}
function formatDate(value?: string | null): string {
if (!value) return "";
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`);
// 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 "";
}
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();
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}`;
return `${day}/${month}/${year}`;
}
function statusClass(id?: number) {
switch (id) {
case 1:
return "dark";
case 2:
return "info";
case 3:
return "warning";
case 4:
return "primary";
case 5:
case 6:
return "success";
case 7:
case 8:
case 9:
case 10:
return "danger";
default:
return "secondary";
}
switch (id) {
case 1:
return "dark";
case 2:
return "info";
case 3:
return "warning";
case 4:
return "primary";
case 5:
case 6:
return "success";
case 7:
case 8:
case 9:
case 10:
return "danger";
default:
return "secondary";
}
}
+36 -36
View File
@@ -1,60 +1,60 @@
import { AxiosRequestConfig } from "axios";
export interface ServicioSocialResponse {
idServicio?: number;
id?: number;
createdAt?: string;
fecha_creacion?: string | null;
fechaFin?: string | null;
fechaInicio?: string | null;
fecha_registro?: string | null;
Usuario?: Usuario;
Carrera?: Carrera;
Status?: Status;
cartaTermino?: boolean;
idCuestionarioPrograma?: number | null;
idCuestionarioPrograma2?: number | null;
cuestionarioCompletado?: boolean;
idServicio?: number;
id?: number;
createdAt?: string;
fecha_creacion?: string | null;
fechaFin?: string | null;
fechaInicio?: string | null;
fecha_registro?: string | null;
usuario?: Usuario;
carrera?: Carrera;
status?: Status;
cartaTermino?: boolean;
idCuestionarioPrograma?: number | null;
idCuestionarioPrograma2?: number | null;
cuestionarioCompletado?: boolean;
}
export interface Usuario {
idUsuario?: number;
usuario: string | number;
nombre: string;
idservicio?: number;
idUsuario?: number;
usuario: string | number;
nombre: string;
idservicio?: number;
}
export interface OtraTabla {
title: string;
admin: Record<string, unknown>;
alumno: Record<string, unknown>;
imprimirError?: (...args: unknown[]) => void;
imprimirMensaje?: (...args: unknown[]) => void;
imprimirWairning?: (...args: unknown[]) => void;
updateIsLoading?: (...args: unknown[]) => void;
title: string;
admin: Record<string, unknown>;
alumno: Record<string, unknown>;
imprimirError?: (...args: unknown[]) => void;
imprimirMensaje?: (...args: unknown[]) => void;
imprimirWairning?: (...args: unknown[]) => void;
updateIsLoading?: (...args: unknown[]) => void;
}
export interface Carrera {
idCarrera?: number;
carrera: string;
idCarrera?: number;
carrera: string;
}
export interface Status {
idStatus: number;
status: string;
idStatus: number;
status: string;
}
export interface CargaMasivaProps {
admin: { tokenArchivo: string };
admin: { tokenArchivo: string };
}
export interface Responsables {
idUsuario: number;
usuario: string;
nombre: string;
activo: boolean;
idUsuario: number;
usuario: string;
nombre: string;
activo: boolean;
}
interface ServicioSocialConCasoEspecial extends ServicioSocialResponse {
idCasoEspecial?: number;
}
idCasoEspecial?: number;
}