Se modifico la logia en el envio de archivos falta corregir el endpoint de servicio/update
This commit is contained in:
Generated
+783
-373
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -13,14 +13,14 @@
|
||||
"bootstrap": "^5.3.8",
|
||||
"file-saver": "^2.0.5",
|
||||
"moment": "^2.30.1",
|
||||
"next": "15.5.3",
|
||||
"next": "^16.0.8",
|
||||
"react": "19.1.0",
|
||||
"react-bootstrap": "^2.10.10",
|
||||
"react-datepicker": "^8.7.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-hot-toast": "^2.6.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"sass": "^1.92.1",
|
||||
"sass": "^1.95.0",
|
||||
"sweetalert2": "^11.26.2",
|
||||
"sweetalert2-react-content": "^5.1.0",
|
||||
"validator": "^13.15.15"
|
||||
|
||||
+3
-3
@@ -19,9 +19,9 @@ axiosInstance.interceptors.request.use(
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
|
||||
//Quitar estas lienas
|
||||
config.headers['token'] = token;
|
||||
config.headers['x-access-token'] = token;
|
||||
config.headers['token-v2'] = token;
|
||||
// config.headers['token'] = token;
|
||||
// config.headers['x-access-token'] = token;
|
||||
// config.headers['token-v2'] = token;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ interface InfoAlumno{
|
||||
//createdAt: Date,
|
||||
idCuestionarioAlumno: number,
|
||||
idCuestionarioAlumno2: number,
|
||||
Carrera: Carrera,
|
||||
Status: Status,
|
||||
Programa: Programa,
|
||||
carrera: Carrera,
|
||||
status: Status,
|
||||
programa: Programa,
|
||||
}
|
||||
|
||||
interface Carrera {
|
||||
@@ -93,8 +93,8 @@ export default function Home() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
{ data?.Status.idStatus && (
|
||||
<BarraProgreso idStatus={data?.Status.idStatus}/>
|
||||
{ data?.status.idStatus && (
|
||||
<BarraProgreso idStatus={data?.status.idStatus}/>
|
||||
)}
|
||||
|
||||
<div className="my-5">
|
||||
@@ -123,7 +123,7 @@ export default function Home() {
|
||||
/>
|
||||
)}
|
||||
|
||||
{ data?.Status.idStatus === 2 && (
|
||||
{ data?.status.idStatus === 2 && (
|
||||
<CompletarDatosPersonales
|
||||
idServicio={123}
|
||||
alumno={{ token: { headers: { Authorization: "Bearer ..." } }, tokenArchivo: { headers: { Authorization: "Bearer ..." } } }}
|
||||
@@ -135,7 +135,7 @@ export default function Home() {
|
||||
/>
|
||||
)}
|
||||
|
||||
{ data?.Status.idStatus !== undefined && data?.Status.idStatus >= 4 && (
|
||||
{ data?.status.idStatus !== undefined && data?.status.idStatus >= 4 && (
|
||||
<PreTermino
|
||||
alumno={{ tokenArchivo: "token123" }}
|
||||
servicio={data}
|
||||
|
||||
+13
-4
@@ -1,3 +1,4 @@
|
||||
@import "react-datepicker/dist/react-datepicker.css";
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
@@ -10,9 +11,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
@import "react-datepicker/dist/react-datepicker.css";
|
||||
|
||||
|
||||
html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
@@ -20,7 +18,7 @@ body {
|
||||
}
|
||||
|
||||
body {
|
||||
color: var(--foreground);
|
||||
/* Do not override text color globally so Bootstrap utilities and components keep their intended colors */
|
||||
background: var(--background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
@@ -60,6 +58,17 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure fw-bold utility is available and wins if other rules override it */
|
||||
.fw-bold,
|
||||
h1.fw-bold, h2.fw-bold, h3.fw-bold, h4.fw-bold, h5.fw-bold, h6.fw-bold {
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
/* Ensure form labels are easily readable and bold like before */
|
||||
.form-label {
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
|
||||
@@ -3,6 +3,7 @@ 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 = {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { axiosInstance } from "@/api/config";
|
||||
import type { AxiosError } from 'axios';
|
||||
|
||||
type Responsable = { idUsuario?: number; idTipoUsuario?: number; tipoUsuario?: string | null; token?: string; tokenArchivo?: string };
|
||||
type Alumno = { nombre?: string; usuario?: string };
|
||||
type Alumno = { nombre?: string; idUsuario?: number };
|
||||
|
||||
export default function Page() {
|
||||
const router = useRouter();
|
||||
@@ -16,6 +16,8 @@ export default function Page() {
|
||||
const [idServicio, setIdServicio] = useState<number | null>(null);
|
||||
const [alumno, setAlumno] = useState<Alumno>({});
|
||||
const [responsable, setResponsable] = useState<Responsable>({});
|
||||
// Para verificar que se guardo el idServicio
|
||||
const [isReady, setIsReady] = useState(false);
|
||||
|
||||
const updateIsLoading = (v: boolean) => setIsLoading(v);
|
||||
|
||||
@@ -54,9 +56,17 @@ export default function Page() {
|
||||
const tipoUsuario = localStorage.getItem('tipoUsuario');
|
||||
const token = localStorage.getItem('token') || undefined;
|
||||
const tokenArchivo = localStorage.getItem('token') || undefined;
|
||||
setResponsable({ idUsuario: Number.isNaN(idUsuario) ? undefined : idUsuario, idTipoUsuario: Number.isNaN(idTipoUsuario) ? undefined : idTipoUsuario, tipoUsuario, token: token ?? undefined, tokenArchivo: tokenArchivo ?? undefined });
|
||||
setResponsable({
|
||||
idUsuario: Number.isNaN(idUsuario) ? undefined : idUsuario,
|
||||
idTipoUsuario: Number.isNaN(idTipoUsuario) ? undefined : idTipoUsuario,
|
||||
tipoUsuario,
|
||||
token: token ?? undefined,
|
||||
tokenArchivo: tokenArchivo ?? undefined
|
||||
});
|
||||
const s = Number(localStorage.getItem('idServicio'));
|
||||
setIdServicio(Number.isNaN(s) ? null : s);
|
||||
|
||||
setIsReady(true);
|
||||
};
|
||||
|
||||
const obtenerRegistro = async () => {
|
||||
@@ -64,8 +74,12 @@ export default function Page() {
|
||||
updateIsLoading(true);
|
||||
try {
|
||||
const headers = responsable.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
|
||||
const res = await axiosInstance.get<{ Usuario?: Alumno; Status?: { idStatus?: number } }>(`/servicio/admin?idServicio=${idServicio}`, { headers });
|
||||
setAlumno(res.data.Usuario ?? {});
|
||||
const res = await axiosInstance.get<{ usuario?: Alumno; Status?: { idStatus?: number } }>(`/servicio/admin/${idServicio}`);
|
||||
|
||||
console.log('Respuesta al obtener el servicio:', res.data);
|
||||
console.log("Info Usuario: ", res.data.usuario)
|
||||
console.log("Nombre del alumno: ", res.data.usuario?.nombre);
|
||||
setAlumno(res.data.usuario ?? {});
|
||||
updateIsLoading(false);
|
||||
const s = res.data.Status?.idStatus ?? 0;
|
||||
// Se comennto para hacer pruebas
|
||||
@@ -82,20 +96,28 @@ export default function Page() {
|
||||
useEffect(() => { getLocalhostInfo(); }, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isReady) return; // Para esperar a que cargue la info del localStorage
|
||||
|
||||
if (responsable.idTipoUsuario === 1) router.push('/admin');
|
||||
if (responsable.idTipoUsuario === 3) router.push('/alumno');
|
||||
if (responsable.idTipoUsuario === 4) router.push('/casoEspecial');
|
||||
if (idServicio !== null) {
|
||||
console.log("ID Servicio no es nulo, se obtiene el registro.", idServicio);
|
||||
obtenerRegistro();
|
||||
} else (
|
||||
router.push('/responsable')
|
||||
)
|
||||
// Se comento para hacer pruebas
|
||||
//if (idServicio === null) router.push('/responsable');
|
||||
else if (idServicio !== null) obtenerRegistro();
|
||||
// else if (idServicio !== null) obtenerRegistro();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [responsable, idServicio]);
|
||||
}, [isReady, responsable, idServicio]);
|
||||
|
||||
return (
|
||||
<section className="container px-2 pb-6">
|
||||
<BotonRegresar />
|
||||
|
||||
<h3 className="title">{alumno.nombre} {alumno.usuario}</h3>
|
||||
<h3 className="title">{alumno.nombre}</h3>
|
||||
|
||||
{idServicio !== null && (
|
||||
<UploadArchivo
|
||||
|
||||
@@ -19,6 +19,10 @@ export default function Page() {
|
||||
const [idServicio, setIdServicio] = useState<number | null>(null);
|
||||
const [alumno, setAlumno] = useState<Record<string, unknown> | null>(null);
|
||||
const [responsable, setResponsable] = useState<Responsable>({});
|
||||
// Para esperar a que cargue la info del localStorage
|
||||
const [isReady, setIsReady] = useState(false);
|
||||
|
||||
|
||||
|
||||
const updateIsLoading = (v: boolean) => setIsLoading(v);
|
||||
|
||||
@@ -59,9 +63,16 @@ export default function Page() {
|
||||
const idTipoUsuario = Number(localStorage.getItem('idTipoUsuario'));
|
||||
const tipoUsuario = localStorage.getItem('tipoUsuario');
|
||||
const token = localStorage.getItem('token') || undefined;
|
||||
setResponsable({ idUsuario: Number.isNaN(idUsuario) ? undefined : idUsuario, idTipoUsuario: Number.isNaN(idTipoUsuario) ? undefined : idTipoUsuario, tipoUsuario, token: token ?? undefined });
|
||||
setResponsable({
|
||||
idUsuario: Number.isNaN(idUsuario) ? undefined : idUsuario,
|
||||
idTipoUsuario: Number.isNaN(idTipoUsuario) ? undefined : idTipoUsuario,
|
||||
tipoUsuario,
|
||||
token: token ?? undefined
|
||||
});
|
||||
const s = Number(localStorage.getItem('idServicio'));
|
||||
setIdServicio(Number.isNaN(s) ? null : s);
|
||||
|
||||
setIsReady(true);
|
||||
};
|
||||
|
||||
const obtenerRegistro = async () => {
|
||||
@@ -69,7 +80,7 @@ export default function Page() {
|
||||
updateIsLoading(true);
|
||||
try {
|
||||
const headers = responsable.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
|
||||
const res = await axiosInstance.get<{ Usuario?: Record<string, unknown>; idCuestionarioPrograma?: number }>(`/servicio/admin?idServicio=${idServicio}`, { headers });
|
||||
const res = await axiosInstance.get<{ Usuario?: Record<string, unknown>; idCuestionarioPrograma?: number }>(`/servicio/admin/${idServicio}`,);
|
||||
setAlumno(res.data.Usuario ?? null);
|
||||
updateIsLoading(false);
|
||||
if (res.data.idCuestionarioPrograma) router.push('/responsable');
|
||||
@@ -90,14 +101,20 @@ export default function Page() {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Hacemos la validacion para asegurarnos de que cargo la info del local
|
||||
if (!isReady) return; // Para esperar a que cargue la info del localStorage
|
||||
|
||||
// Redireccionamientos segun tipo de usuario
|
||||
if (responsable.idTipoUsuario === 1) router.push('/administrador');
|
||||
if (responsable.idTipoUsuario === 3) router.push('/alumno');
|
||||
if (responsable.idTipoUsuario === 4) router.push('/casoEspecial');
|
||||
// Para verificar el servicio
|
||||
//if (idServicio === null) router.push('/responsable'); // Esta mal la logica
|
||||
else if (idServicio !== null) obtenerRegistro();
|
||||
if (idServicio !== null) {
|
||||
obtenerRegistro();
|
||||
} else router.push('/responsable');
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [responsable, idServicio]);
|
||||
}, [isReady, responsable, idServicio]);
|
||||
|
||||
return (
|
||||
<section className="container my-5 px-3">
|
||||
|
||||
@@ -59,7 +59,7 @@ export default function Page() {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (responsable.idTipoUsuario === 1) router.push('/admin');
|
||||
if (responsable.idTipoUsuario === 1) router.push('/administrador');
|
||||
if (responsable.idTipoUsuario === 3) router.push('/alumno');
|
||||
if (responsable.idTipoUsuario === 4) router.push('/casoEspecial');
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
||||
@@ -25,7 +25,7 @@ interface Datos {
|
||||
//Programa?: Programa
|
||||
//Carrera?: Carrera;
|
||||
//Usuario?: Usuario;
|
||||
Status?: Status;
|
||||
status?: Status;
|
||||
creditos?: string;
|
||||
correo?: string;
|
||||
fechaRegistro?: string;
|
||||
@@ -97,6 +97,11 @@ export default function Archivo({
|
||||
};
|
||||
|
||||
const rechazarArchivo = () => {
|
||||
// Depuramos para ver errores
|
||||
console.log("Title", title)
|
||||
console.log("status", datos.status?.idStatus)
|
||||
console.log("idServicio", datos.idServicio)
|
||||
|
||||
switch (title) {
|
||||
case "carta de aceptación":
|
||||
rechazarFunc(rechazarCartaAceptacion);
|
||||
@@ -118,6 +123,8 @@ export default function Archivo({
|
||||
mensaje: mensajeRechazo,
|
||||
};
|
||||
|
||||
console.log("Datos para rechazar:", data);
|
||||
|
||||
try {
|
||||
updateIsLoading(true);
|
||||
const res = await funcRechazar(data);
|
||||
@@ -146,19 +153,47 @@ export default function Archivo({
|
||||
|
||||
return (
|
||||
<div className="container mb-4">
|
||||
<div className="flex items-center">
|
||||
<h5 className="pr-4 text-lg">
|
||||
Ver {title}
|
||||
<a
|
||||
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'}}
|
||||
<div className="d-flex align-items-center">
|
||||
|
||||
{/* Texto */}
|
||||
<h5 className="mb-0">
|
||||
Ver {title}
|
||||
</h5>
|
||||
|
||||
<div className="d-flex align-items-center gap-2">
|
||||
|
||||
<a
|
||||
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>
|
||||
|
||||
<button
|
||||
className="btn btn-danger"
|
||||
onClick={updateRechazar}
|
||||
>
|
||||
Ver
|
||||
</a>
|
||||
</h5>
|
||||
Rechazar
|
||||
</button>
|
||||
|
||||
{((datos.status?.idStatus === 1 && title === "carta de aceptación") ||
|
||||
(datos.status?.idStatus === 5 &&
|
||||
(title === "carta de termino" || title === "informe global"))) && (
|
||||
<button
|
||||
className="btn btn-danger"
|
||||
onClick={updateRechazar}
|
||||
>
|
||||
Rechazar
|
||||
</button>
|
||||
)}
|
||||
|
||||
</div>
|
||||
|
||||
{/* Solo de moemento para la parte visual falta corregir esto */}
|
||||
|
||||
|
||||
{/*
|
||||
<div className="pr-4">
|
||||
@@ -173,8 +208,8 @@ export default function Archivo({
|
||||
</div>
|
||||
*/}
|
||||
|
||||
{((datos.Status?.idStatus === 1 && title === "carta de aceptación") ||
|
||||
(datos.Status?.idStatus === 5 &&
|
||||
{/* {((datos.status?.idStatus === 1 && title === "carta de aceptación") ||
|
||||
(datos.status?.idStatus === 5 &&
|
||||
(title === "carta de termino" || title === "informe global"))) && (
|
||||
<button
|
||||
className="btn btn-danger"
|
||||
@@ -183,6 +218,11 @@ export default function Archivo({
|
||||
Rechazar
|
||||
</button>
|
||||
)}
|
||||
</div> */}
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{rechazar && (
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { axiosInstance } from "@/api/config";
|
||||
import { isAxiosError } from 'axios';
|
||||
import axios, { isAxiosError } from 'axios';
|
||||
import moment from "moment";
|
||||
import validator from "validator";
|
||||
import DatePicker from "react-datepicker";
|
||||
@@ -31,7 +31,7 @@ interface AdminToken {
|
||||
tokenArchivo?: { headers: Record<string, string> };
|
||||
}; */}
|
||||
interface Props {
|
||||
admin: string;
|
||||
admin: AdminToken;
|
||||
imprimirError: (err: unknown) => void;
|
||||
imprimirMensaje: (msg: string) => void;
|
||||
imprimirWarning: (msg: string, onConfirm: () => void) => void;
|
||||
@@ -146,13 +146,41 @@ export default function EditarServicio({
|
||||
formData.append("data", JSON.stringify(data));
|
||||
|
||||
console.log("Datos a actualizar:", formData);
|
||||
for (const [key, value] of formData.entries()) {
|
||||
console.log("FormData:", key, value);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
updateIsLoading(true);
|
||||
const res = await axiosInstance.put(`/servicio/update`, formData); //, admin.tokenArchivo
|
||||
|
||||
// Agregue esta parte para verificar que funcione
|
||||
if (cartaAceptacion) {
|
||||
console.log("Carta Aceptación:", {
|
||||
name: cartaAceptacion.name,
|
||||
size: cartaAceptacion.size,
|
||||
type: cartaAceptacion.type,
|
||||
});
|
||||
}
|
||||
|
||||
if (cartaTermino) {
|
||||
console.log("Carta Término:", cartaTermino.name);
|
||||
}
|
||||
|
||||
if (informeGlobal) {
|
||||
console.log("Informe Global:", informeGlobal.name);
|
||||
}
|
||||
|
||||
const token = localStorage.getItem("token") || "";
|
||||
|
||||
const res = await axios.put(`http://localhost:3392/servicio/update`, formData, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
}); //, admin.tokenArchivo
|
||||
imprimirMensaje(res.data.message);
|
||||
updateIsLoading(false);
|
||||
router.push("/administrador/servicio");
|
||||
router.replace("/administrador/servicio");
|
||||
} catch (err: unknown) {
|
||||
updateIsLoading(false);
|
||||
if (isAxiosError(err)) imprimirError(err.response?.data ?? err.message);
|
||||
@@ -176,7 +204,7 @@ export default function EditarServicio({
|
||||
const res = await axiosInstance.post(`/usuario/new-password-alumno/${data.servicioid}`);
|
||||
imprimirMensaje(res.data.message);
|
||||
updateIsLoading(false);
|
||||
router.push("/administrador");
|
||||
router.replace("/administrador");
|
||||
} catch (err: unknown) {
|
||||
console.log("No esta mandando la solicitud")
|
||||
updateIsLoading(false);
|
||||
@@ -423,7 +451,7 @@ export default function EditarServicio({
|
||||
<input
|
||||
id="pdfInput"
|
||||
type="file"
|
||||
accept=".pdf"
|
||||
accept="application/pdf"
|
||||
style={{ display: 'none'}}
|
||||
onChange={(e) => {
|
||||
setCartaAceptacion(e.target.files ? e.target.files[0] : null)
|
||||
|
||||
@@ -302,7 +302,7 @@ function formatDate(value?: string | null): string {
|
||||
const d = new Date(value.includes("T") ? value : `${value}T00:00:00`);
|
||||
|
||||
if (isNaN(d.getTime())) {
|
||||
console.warn("⚠️ Fecha inválida:", value);
|
||||
// console.warn("⚠️ Fecha inválida:", value);
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
@@ -159,6 +159,7 @@ export default function TablaServicioSocial({ admin, imprimirError }: Props) {
|
||||
<FaInfoCircle />
|
||||
</InputGroup.Text>
|
||||
<FormSelect
|
||||
suppressHydrationWarning
|
||||
value={search.idStatus}
|
||||
onChange={(e) => setSearch(Prev => ({ ...Prev, idStatus: e.target.value }))}
|
||||
className="rounded-4"
|
||||
|
||||
@@ -19,9 +19,9 @@ interface Carrera {
|
||||
}
|
||||
|
||||
export interface Servicio {
|
||||
Programa: Programa;
|
||||
Usuario: Usuario;
|
||||
Carrera: Carrera;
|
||||
programa: Programa;
|
||||
//usuario: Usuario;
|
||||
carrera: Carrera;
|
||||
creditos?: string;
|
||||
telefono?: string;
|
||||
direccion?: string;
|
||||
@@ -57,22 +57,22 @@ export default function InformacinoServicio({ servicio }: Props) {
|
||||
|
||||
<div className="mb-2">
|
||||
<label className="form-label fw-semibold">Institución:</label>
|
||||
<p className="form-control">{servicio.Programa.institucion}</p>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<p className="form-control">{servicio.programa.clavePrograma}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -80,19 +80,20 @@ export default function InformacinoServicio({ servicio }: Props) {
|
||||
<div className="mb-5">
|
||||
<h4 className="is-size-4 pb-2">Datos personales</h4>
|
||||
|
||||
{/*
|
||||
<div className="mb-2">
|
||||
<label className="form-label fw-semibold">Número de cuenta:</label>
|
||||
<p className="form-control">{servicio.Usuario.usuario}</p>
|
||||
<p className="form-control">{servicio.usuario.usuario}</p>
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
<label className="form-label fw-semibold">Nombre:</label>
|
||||
<p className="form-control">{servicio.Usuario.nombre}</p>
|
||||
<p className="form-control">{servicio.usuario.nombre}</p>
|
||||
</div>
|
||||
|
||||
*/}
|
||||
<div className="mb-2">
|
||||
<label className="form-label fw-semibold">Carrera:</label>
|
||||
<p className="form-control">{servicio.Carrera.carrera}</p>
|
||||
<p className="form-control">{servicio.carrera.carrera}</p>
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
|
||||
@@ -7,8 +7,8 @@ const BotonRegresar: React.FC = () => {
|
||||
const router = useRouter();
|
||||
|
||||
const handleGoBack = () => {
|
||||
//window.history.back();
|
||||
router.back();
|
||||
window.history.back();
|
||||
//router.back();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ export default function CasoEspecialForm({
|
||||
const buscarAlumno = async (): Promise<void> => {
|
||||
try {
|
||||
updateIsLoading(true);
|
||||
const res = await axiosInstance.get(`/usuario/escolares?numeroCuenta=${numeroCuenta}`);
|
||||
const res = await axiosInstance.post(`/usuario/escolares/${numeroCuenta}`);
|
||||
resetear();
|
||||
setAlumno(res.data);
|
||||
} catch (err: unknown) {
|
||||
@@ -137,17 +137,17 @@ export default function CasoEspecialForm({
|
||||
if (!file) return;
|
||||
|
||||
const data = {
|
||||
idUsuario: alumno.idUsuario,
|
||||
idCarrera: alumno.idCarrera,
|
||||
idStatus,
|
||||
numeroCuenta,
|
||||
creditos: alumno.creditos,
|
||||
correo,
|
||||
fechaInicio: moment(fechaInicio),
|
||||
fechaFin: moment(fechaFin),
|
||||
fechaNacimiento: moment(fechaNacimiento),
|
||||
direccion,
|
||||
telefono,
|
||||
idUsuario: Number(alumno.idUsuario),
|
||||
idCarrera: Number(alumno.idCarrera),
|
||||
idStatus: Number(idStatus),
|
||||
numeroCuenta: numeroCuenta.toString(),
|
||||
creditos: alumno.creditos?.toString() || '',
|
||||
correo: correo.trim(),
|
||||
fechaInicio: fechaInicio.toISOString(),
|
||||
fechaFin: fechaFin.toISOString(),
|
||||
fechaNacimiento: fechaNacimiento.toISOString(),
|
||||
direccion: direccion.trim(),
|
||||
telefono: telefono.toString(),
|
||||
institucion,
|
||||
dependencia,
|
||||
motivo,
|
||||
@@ -159,7 +159,7 @@ export default function CasoEspecialForm({
|
||||
|
||||
try {
|
||||
updateIsLoading(true);
|
||||
const res = await axiosInstance.post(`/caso_especial/nuevo`, formData);
|
||||
const res = await axiosInstance.post(`/caso-especial`, formData);
|
||||
resetear();
|
||||
setNumeroCuenta('');
|
||||
imprimirMensaje(res.data.message);
|
||||
@@ -475,6 +475,7 @@ export default function CasoEspecialForm({
|
||||
<input
|
||||
id='fileInput'
|
||||
type="file"
|
||||
accept='.zip, .rar'
|
||||
style={{ display: 'none'}}
|
||||
onChange={e => setFile(e.target.files ? e.target.files[0] : null)}
|
||||
/>
|
||||
|
||||
@@ -204,6 +204,7 @@ export default function CuestionarioResponsbale2({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const t of formulario.tablas) {
|
||||
for (const r of t.renglones) {
|
||||
const tablaResp = respuestas[String(t.idTabla)] as Record<number, string | null> | undefined;
|
||||
@@ -235,12 +236,32 @@ export default function CuestionarioResponsbale2({
|
||||
const valor = respuestasTabla[idR as unknown as number];
|
||||
let clave = `p${numPregunta}_${idR}`;
|
||||
if (subLetra) clave = `p${numPregunta}_${subLetra}_${idR}`;
|
||||
resultado[clave] = valor ?? '';
|
||||
// antes resultado[clave] = valor ?? '';
|
||||
// Modifique esta linea
|
||||
if (valor !== null && valor !== '') {
|
||||
resultado[clave] = valor;
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
const preguntaDef = formulario.preguntas.find((p) => p.id === key);
|
||||
if (!preguntaDef) continue;
|
||||
resultado[`p${preguntaDef.numeroPregunta}`] = resps[key] as string;
|
||||
|
||||
// VALIDAR CONDICIONAL (p6)
|
||||
if (preguntaDef.condicional) {
|
||||
const cond = preguntaDef.condicional;
|
||||
if (resps[cond.preguntaId] !== cond.valor) {
|
||||
continue; // ⛔ NO mandar esta pregunta
|
||||
}
|
||||
}
|
||||
|
||||
const valor = resps[key];
|
||||
|
||||
if (valor !== null && String(valor).trim() !== '') {
|
||||
resultado[`p${preguntaDef.numeroPregunta}`] = valor as string;
|
||||
}
|
||||
|
||||
//resultado[`p${preguntaDef.numeroPregunta}`] = resps[key] as string;
|
||||
}
|
||||
}
|
||||
return resultado;
|
||||
@@ -251,9 +272,12 @@ export default function CuestionarioResponsbale2({
|
||||
updateIsLoading(true);
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const data = { ...formatearRespuestas(respuestas), idServicio: localStorage.getItem('idServicio') };
|
||||
const data = { ...formatearRespuestas(respuestas), idServicio: Number(localStorage.getItem('idServicio')) };
|
||||
|
||||
console.log('Datos a enviar:', data);
|
||||
|
||||
const headers = responsable?.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
|
||||
await axiosInstance.post('/cuestionario_programa', data, { headers });
|
||||
await axiosInstance.post('/cuestionario-programa2', data, { headers });
|
||||
imprimirMensaje('Se enviaron los datos correctamente');
|
||||
try { localStorage.removeItem('idCuestionarioAlumno'); } catch (_) {}
|
||||
if (typeof window !== 'undefined') window.location.href = '/alumno';
|
||||
|
||||
@@ -94,7 +94,8 @@ export default function NuevoServicio({
|
||||
updateIsLoading(true);
|
||||
try {
|
||||
const headers = responsable?.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
|
||||
const res = await axiosInstance.post<Alumno>(`/usuario/escolares/${numeroCuenta}`, { headers });
|
||||
// Enviar headers como tercer parámetro (config), no como body
|
||||
const res = await axiosInstance.post<Alumno>(`/usuario/escolares/${numeroCuenta}`, undefined, { headers });
|
||||
resetar();
|
||||
setAlumno(res.data);
|
||||
obtenerProgramas();
|
||||
@@ -128,12 +129,26 @@ export default function NuevoServicio({
|
||||
} as const;
|
||||
|
||||
formData.append("alumno", JSON.stringify(data));
|
||||
if (file) formData.append("cartaAceptacion", file, file.name);
|
||||
if (!file) {
|
||||
imprimirError({ message: 'No hay archivo seleccionado' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Para verificar que se envie el archivo
|
||||
console.log("Archivo a enviar:", file);
|
||||
//if (file)
|
||||
formData.append("cartaAceptacion", file, file.name);
|
||||
|
||||
updateIsLoading(true);
|
||||
try {
|
||||
const headers = responsable?.tokenArchivo ? { Authorization: `Bearer ${responsable.tokenArchivo}`, 'Content-Type': 'multipart/form-data' } : { 'Content-Type': 'multipart/form-data' };
|
||||
const res = await axiosInstance.post("/servicio/nuevo", formData, { headers });
|
||||
const headers = responsable?.tokenArchivo ? { Authorization: `Bearer ${responsable.tokenArchivo}` }: {};
|
||||
const res = await axiosInstance.post("/servicio/nuevo", formData, {
|
||||
headers: {
|
||||
...(responsable?.tokenArchivo && {
|
||||
Authorization: `Bearer ${responsable.tokenArchivo}`,
|
||||
}),
|
||||
},
|
||||
});
|
||||
setNumeroCuenta("");
|
||||
resetar();
|
||||
updateIsLoading(false);
|
||||
@@ -150,8 +165,24 @@ 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/${responsable.idUsuario}`, { headers });
|
||||
setProgramas(res.data);
|
||||
const res = await axiosInstance.get(`/programa/programas_responsable/${responsable.idUsuario}`, { headers });
|
||||
|
||||
// Normalizar la respuesta: soportar varias formas comunes:
|
||||
// - res.data = Array
|
||||
// - res.data = { data: Array }
|
||||
// - res.data = { programas: Array }
|
||||
const payload = res?.data ?? res;
|
||||
console.log("Esta es la info que traen los programas", payload);
|
||||
if (Array.isArray(payload)) {
|
||||
setProgramas(payload as Programa[]);
|
||||
} else if (payload && Array.isArray((payload as any).data)) {
|
||||
setProgramas((payload as any).data as Programa[]);
|
||||
} else if (payload && Array.isArray((payload as any).programas)) {
|
||||
setProgramas((payload as any).programas as Programa[]);
|
||||
} else {
|
||||
console.warn('Respuesta inesperada al obtener programas, se usará lista vacía', payload);
|
||||
setProgramas([]);
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
const axiosErr = err as AxiosError;
|
||||
if (axiosErr?.response?.data) imprimirError(axiosErr.response.data as object);
|
||||
@@ -188,6 +219,14 @@ export default function NuevoServicio({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// Fetch programas when responsable id is available
|
||||
useEffect(() => {
|
||||
if (responsable?.idUsuario) {
|
||||
obtenerProgramas();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [responsable?.idUsuario]);
|
||||
|
||||
useEffect(() => {
|
||||
updateFechas();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@@ -205,12 +244,12 @@ export default function NuevoServicio({
|
||||
type="text"
|
||||
placeholder="Número de Cuenta"
|
||||
maxLength={9}
|
||||
value={numeroCuenta}
|
||||
value={numeroCuenta ?? ''}
|
||||
onChange={(e) => setNumeroCuenta(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && buscarAlumno()}
|
||||
className="form-control"
|
||||
/>
|
||||
<button className="" onClick={() => buscarAlumno()}>Buscar</button>
|
||||
<button type="button" className="" onClick={() => buscarAlumno()}>Buscar</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -239,7 +278,10 @@ export default function NuevoServicio({
|
||||
<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) => (
|
||||
{(!Array.isArray(programas) || programas.length === 0) && (
|
||||
<option value={JSON.stringify({})} disabled>No hay programas disponibles</option>
|
||||
)}
|
||||
{Array.isArray(programas) && programas.length > 0 && programas.map((p, i) => (
|
||||
<option key={i} value={JSON.stringify(p)}>{p.programa}</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { axiosInstance } from "@/api/config";
|
||||
import type { AxiosError } from "axios";
|
||||
@@ -23,8 +21,9 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
|
||||
const [total, setTotal] = useState(0);
|
||||
const [data, setData] = useState<ServicioSocialResponse[]>([]);
|
||||
const [status, setStatus] = useState<StatusItem[]>([]);
|
||||
const [search, setSearch] = useState<{ numeroCuenta?: string; nombre?: string; idStatus?: string }>({ idStatus: '' });
|
||||
const [search, setSearch] = useState<{ numeroCuenta?: string; nombre?: string; idStatus?: string }>({ numeroCuenta: '', nombre: '', idStatus: '' });
|
||||
const [searchAnterior, setSearchAnterior] = useState<{ numeroCuenta?: string; nombre?: string; idStatus?: string }>({});
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
const onPageChange = (p: number) => {
|
||||
setPage(p);
|
||||
@@ -94,6 +93,8 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
|
||||
|
||||
useEffect(() => {
|
||||
obtenerCatalogoStatus();
|
||||
// mark as mounted to avoid rendering dynamic options during SSR hydration
|
||||
setMounted(true);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
@@ -140,7 +141,7 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
|
||||
</InputGroup>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
{/* llega hasta el 10 */}
|
||||
{/* llega hasta el 10 */}
|
||||
<Col md={3}>
|
||||
<FormGroup>
|
||||
<FormLabel>Status</FormLabel>
|
||||
@@ -149,12 +150,14 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
|
||||
<FaInfoCircle />
|
||||
</InputGroup.Text>
|
||||
<FormSelect
|
||||
suppressHydrationWarning
|
||||
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, 9).map((s) => (
|
||||
{mounted && status.slice(0, 9).map((s) => (
|
||||
<option key={s.idStatus} value={s.idStatus}>
|
||||
{s.status}
|
||||
</option>
|
||||
@@ -165,10 +168,11 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
|
||||
</Col>
|
||||
|
||||
<Col md={3} className="d-flex align-items-end">
|
||||
<Button
|
||||
type="button"
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-100 rounded-5"
|
||||
disabled={isLoading}>{isLoading ? 'Buscando...' : 'Buscar'}
|
||||
disabled={isLoading}>
|
||||
{isLoading ? 'Buscando...' : 'Buscar'}
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { axiosInstance } from "@/api/config";
|
||||
import type { AxiosError } from "axios";
|
||||
import { Form } from "react-bootstrap";
|
||||
import { FaUpload } from "react-icons/fa";
|
||||
|
||||
type Responsable = { tokenArchivo?: string };
|
||||
|
||||
@@ -38,20 +40,27 @@ export default function UploadArchivo({
|
||||
formData.append('data', JSON.stringify(data));
|
||||
formData.append(variableName, file, file.name);
|
||||
|
||||
console.log("Esta es la info que se mandara al backend:", formData);
|
||||
|
||||
updateIsLoading(true);
|
||||
try {
|
||||
const headers = responsable?.tokenArchivo ? { Authorization: `Bearer ${responsable.tokenArchivo}`, 'Content-Type': 'multipart/form-data' } : { 'Content-Type': 'multipart/form-data' };
|
||||
const res = await axiosInstance.put(`/servicio/${path}`, formData, { headers });
|
||||
try { localStorage.removeItem('idServicio'); } catch (error) {}
|
||||
updateIsLoading(false);
|
||||
imprimirMensaje(res.data?.message || 'Archivo subido');
|
||||
if (typeof window !== 'undefined') window.location.href = '/responsable';
|
||||
const res = await axiosInstance.put(`/servicio/${path}`, formData, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${responsable.tokenArchivo}`,
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
try { localStorage.removeItem('idServicio'); }
|
||||
catch (error) {}
|
||||
updateIsLoading(false);
|
||||
imprimirMensaje(res.data?.message || 'Archivo subido');
|
||||
if (typeof window !== 'undefined') window.location.href = '/responsable';
|
||||
} catch (err: unknown) {
|
||||
updateIsLoading(false);
|
||||
const axiosErr = err as AxiosError;
|
||||
if (axiosErr?.response?.data) imprimirError(axiosErr.response.data as object);
|
||||
else if (err instanceof Error) imprimirError(err.message);
|
||||
else imprimirError({ message: 'Error desconocido' });
|
||||
updateIsLoading(false);
|
||||
const axiosErr = err as AxiosError;
|
||||
if (axiosErr?.response?.data) imprimirError(axiosErr.response.data as object);
|
||||
else if (err instanceof Error) imprimirError(err.message);
|
||||
else imprimirError({ message: 'Error desconocido' });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -65,13 +74,46 @@ export default function UploadArchivo({
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-3">
|
||||
{/* <div className="mb-3">
|
||||
<label className="form-label">Carta de {tipoCarta} (en formato .pdf, no se aceptan fotos).</label>
|
||||
<input type="file" accept="application/pdf" className="form-control" onChange={(e) => setFile(e.target.files?.[0] ?? null)} />
|
||||
<div className="mt-2 text-center">
|
||||
<p className="h5">{file?.name || 'Arrastra aquí tu archivo o da click aquí para buscarlo.'}</p>
|
||||
<p className="small">Tamaño máximo 20MB</p>
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
|
||||
|
||||
{/*
|
||||
Falta corregir y arreglar
|
||||
*/}
|
||||
<div className="ph-5">
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>
|
||||
Carta de {tipoCarta} (en formato .pdf, no se aceptan fotos).
|
||||
</Form.Label>
|
||||
|
||||
<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 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>
|
||||
<input
|
||||
type="file"
|
||||
accept="application/pdf"
|
||||
id="fileInput"
|
||||
className="d-none"
|
||||
onChange={(e) => setFile(e.target.files?.[0] ?? null)} />
|
||||
</div>
|
||||
</Form.Group>
|
||||
</div>
|
||||
|
||||
<div className="text-center my-4">
|
||||
@@ -79,6 +121,7 @@ export default function UploadArchivo({
|
||||
Enviar
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,30 @@ export default function ServicioSocialTabla({
|
||||
}
|
||||
}
|
||||
|
||||
const servicioSelectedResponsable = (row: ServicioSocialResponse | ServicioSocialConCasoEspecial) => {
|
||||
if (!row) return;
|
||||
|
||||
if (idTipoUsuario === 2) {
|
||||
console.log("Responsable seleccionó un servicio social:", row);
|
||||
if (row.idServicio) {
|
||||
localStorage.setItem("idServicio", String(row.idServicio));
|
||||
}
|
||||
router.push("/responsable/cuestionario");
|
||||
}
|
||||
}
|
||||
|
||||
const servicioSelectedResponsableCartaTermino = (row: ServicioSocialResponse | ServicioSocialConCasoEspecial) => {
|
||||
if (!row) return;
|
||||
|
||||
if (idTipoUsuario === 2) {
|
||||
console.log("Responsable seleccionó un servicio social para carta de termino:", row);
|
||||
if (row.idServicio) {
|
||||
localStorage.setItem("idServicio", String(row.idServicio));
|
||||
}
|
||||
router.push("/responsable/carta_termino");
|
||||
}
|
||||
}
|
||||
|
||||
const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEspecial) => {
|
||||
if (!row) return;
|
||||
|
||||
@@ -156,16 +180,16 @@ const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEsp
|
||||
<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>}
|
||||
{columnaFechaRegistro && <th className="text-center align-middle">Fecha Registro</th>}
|
||||
<th className="text-center align-middle">Número de Cuenta</th>
|
||||
<th className="text-center align-middle">Nombre</th>
|
||||
<th className="text-center align-middle">Carrera</th>
|
||||
{columnaFechaInicio && <th className="text-center align-middle">Fecha Inicio</th>}
|
||||
{columnaFechaFin && <th className="text-center align-middle">Fecha Fin</th>}
|
||||
<th className="text-center align-middle">Status</th>
|
||||
{columnaCuestionarioCompleto && <th className="text-center align-middle">Cuestionario Completo</th>}
|
||||
{columnaCartaTermino && <th className="text-center align-middle">Carta Termino</th>}
|
||||
{columnaCuestionario && <th className="text-center align-middle">Cuestionario</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -182,21 +206,24 @@ const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEsp
|
||||
//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>
|
||||
|
||||
{columnaFechaRegistro && <td className="text-center align-middle">{formatDate(item.createdAt)}</td>}
|
||||
<td className="text-center align-middle">{item.usuario?.usuario}</td>
|
||||
<td className="text-center align-middle">{item.usuario?.nombre}</td>
|
||||
<td className="text-center align-middle">{item.carrera?.carrera}</td>
|
||||
|
||||
{/*
|
||||
Poner si quieres hacer condicional para no mostrar infromacion
|
||||
? formatDate(item.fechaInicio) : "-" */}
|
||||
{columnaFechaInicio && (
|
||||
<td>{formatDate(item.fechaInicio)}</td>
|
||||
<td className="text-center align-middle">{formatDate(item.fechaInicio)}</td>
|
||||
)}
|
||||
|
||||
{columnaFechaFin && <td>{formatDate(item.fechaFin)}</td>}
|
||||
|
||||
<td>
|
||||
<td className="text-center align-middle">
|
||||
{columnasResponsable && item.status?.idStatus === 7 ? (
|
||||
<button
|
||||
className="btn btn-sm btn-danger"
|
||||
className="badge bg-danger border-0"
|
||||
onClick={() =>
|
||||
onRowAction?.(item, "carta_aceptacion")
|
||||
}
|
||||
@@ -214,15 +241,22 @@ const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEsp
|
||||
)}
|
||||
</td>
|
||||
{columnaCartaTermino && (
|
||||
<td>{item.cartaTermino ? (
|
||||
<span className="badge bg-success">Completado</span>
|
||||
<td className="text-center align-middle"
|
||||
style={{ cursor: idTipoUsuario === 2 ? 'pointer' : 'default'}}
|
||||
onClick={() => (
|
||||
idTipoUsuario === 2 ? servicioSelectedResponsableCartaTermino(item) : undefined
|
||||
)}
|
||||
>
|
||||
{item.cartaTermino ? (
|
||||
<span className="badge">✅</span>
|
||||
) : (
|
||||
<span className="badge bg-danger">No Completado</span>
|
||||
)}</td>
|
||||
)}
|
||||
|
||||
{columnaCuestionarioCompleto && (
|
||||
<td>{item.cuestionarioCompletado ? (
|
||||
<td className="text-center align-middle"
|
||||
>{item.cuestionarioCompletado ? (
|
||||
<span className="badge bg-success">Completado</span>
|
||||
) : (
|
||||
<span className="badge bg-danger">No Completado</span>
|
||||
@@ -231,9 +265,14 @@ const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEsp
|
||||
|
||||
|
||||
{columnaCuestionario && (
|
||||
<td>
|
||||
<td className="text-center align-middle"
|
||||
style={{ cursor: idTipoUsuario === 2 ? 'pointer' : 'default'}}
|
||||
onClick={() => (
|
||||
idTipoUsuario === 2 ? servicioSelectedResponsable(item) : undefined
|
||||
)}
|
||||
>
|
||||
{item.cuestionarioCompletado ? (
|
||||
<span className="badge bg-success">Completado</span>
|
||||
<span className="badge">✅</span>
|
||||
) : (
|
||||
<span className="badge bg-danger">No Completado</span>
|
||||
)}
|
||||
@@ -280,6 +319,7 @@ const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEsp
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function formatDate(value?: string | null): string {
|
||||
if (!value) return "";
|
||||
|
||||
@@ -287,7 +327,7 @@ function formatDate(value?: string | null): string {
|
||||
const d = new Date(value.includes("T") ? value : `${value}T00:00:00`);
|
||||
|
||||
if (isNaN(d.getTime())) {
|
||||
console.warn("⚠️ Fecha inválida:", value);
|
||||
// console.warn("⚠️ Fecha inválida:", value);
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
// Funciones (SIEMPRE primero)
|
||||
@import "bootstrap/scss/functions";
|
||||
|
||||
// VARIABLES PERSONALIZADAS
|
||||
$primary: #5a2d82;
|
||||
$secondary: #198754;
|
||||
$border-radius: 1.5rem;
|
||||
|
||||
// Variables base (SIN maps ni dark)
|
||||
@import "bootstrap/scss/variables";
|
||||
|
||||
// Mixins
|
||||
@import "bootstrap/scss/mixins";
|
||||
|
||||
// Core CSS
|
||||
@import "bootstrap/scss/root";
|
||||
@import "bootstrap/scss/reboot";
|
||||
@import "bootstrap/scss/type";
|
||||
|
||||
// 6️Componentes que se usan
|
||||
@import "bootstrap/scss/buttons";
|
||||
@import "bootstrap/scss/forms";
|
||||
@import "bootstrap/scss/grid";
|
||||
@import "bootstrap/scss/utilities";
|
||||
|
||||
@import "bootstrap/scss/utilities/api";
|
||||
|
||||
Vendored
+35
-14
@@ -1,4 +1,4 @@
|
||||
@import 'bootstrap/scss/functions';
|
||||
@import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
|
||||
$azul: #003d79;
|
||||
$dorado: #bd8c01;
|
||||
@@ -19,8 +19,7 @@ $font-family-sans-serif: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI'
|
||||
'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
||||
'Segoe UI Symbol';
|
||||
|
||||
@import 'bootstrap/scss/variables';
|
||||
@import 'bootstrap/scss/variables-dark';
|
||||
|
||||
|
||||
$custom-colors: (
|
||||
'azul': $azul,
|
||||
@@ -65,7 +64,7 @@ $custom-colors: (
|
||||
}
|
||||
|
||||
|
||||
$theme-colors: map-merge($theme-colors, $custom-colors);
|
||||
$theme-colors: if(variable-exists("theme-colors"), map-merge($theme-colors, $custom-colors), $custom-colors);
|
||||
|
||||
.form-registro {
|
||||
.form-floating {
|
||||
@@ -93,9 +92,6 @@ $theme-colors: map-merge($theme-colors, $custom-colors);
|
||||
}
|
||||
}
|
||||
|
||||
@import 'bootstrap/scss/maps';
|
||||
@import 'bootstrap/scss/mixins';
|
||||
@import 'bootstrap/scss/bootstrap';
|
||||
|
||||
|
||||
.aviso {
|
||||
@@ -137,7 +133,7 @@ $theme-colors: map-merge($theme-colors, $custom-colors);
|
||||
height: 2px;
|
||||
background-color: $azul;
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
@media (min-width: 768px) {
|
||||
left: 10rem;
|
||||
}
|
||||
}
|
||||
@@ -208,12 +204,12 @@ $theme-colors: map-merge($theme-colors, $custom-colors);
|
||||
}
|
||||
|
||||
.full-center {
|
||||
//flex-grow-1 d-flex flex-column justify-content-center align-items-center
|
||||
@extend .flex-grow-1;
|
||||
@extend .d-flex;
|
||||
@extend .flex-column;
|
||||
@extend .justify-content-center;
|
||||
@extend .align-items-center;
|
||||
/* Equivalent of Bootstrap utility classes without using @extend */
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.minNavbar {
|
||||
@@ -268,3 +264,28 @@ $theme-colors: map-merge($theme-colors, $custom-colors);
|
||||
.imageFlip:hover {
|
||||
transform: rotateY(360deg);
|
||||
}
|
||||
|
||||
/* Utility classes for custom colors (restore bg-<name> / text-<name> used in JSX)
|
||||
These are minimal helpers so we don't need to import Bootstrap SCSS utilities. */
|
||||
.bg-azul { background-color: #003d79 !important; }
|
||||
.text-azul { color: #003d79 !important; }
|
||||
.bg-dorado { background-color: #bd8c01 !important; }
|
||||
.text-dorado { color: #bd8c01 !important; }
|
||||
.bg-morado { background-color: #714dd2 !important; }
|
||||
.text-morado { color: #714dd2 !important; }
|
||||
.bg-verde { background-color: #48c78e !important; }
|
||||
.text-verde { color: #48c78e !important; }
|
||||
.bg-red-guapa { background-color: #9e1d15 !important; }
|
||||
.text-red-guapa { color: #9e1d15 !important; }
|
||||
.bg-blue-guapa { background-color: #3d6cb4 !important; }
|
||||
.text-blue-guapa { color: #3d6cb4 !important; }
|
||||
.bg-yellow-guapa { background-color: #eca728 !important; }
|
||||
.text-yellow-guapa { color: #eca728 !important; }
|
||||
|
||||
/* Restore common Bootstrap text utilities if overridden */
|
||||
.text-white { color: #fff !important; }
|
||||
.text-dark { color: #000 !important; }
|
||||
.text-muted { color: #6c757d !important; }
|
||||
.text-body { color: var(--bs-body-color, #212529) !important; }
|
||||
.fw-bold { font-weight: 700 !important; }
|
||||
|
||||
|
||||
+19
-5
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
@@ -11,7 +15,7 @@
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
@@ -19,9 +23,19 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
".next/dev/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user