Compare commits
95 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 51aa3121bc | |||
| 4b7516f9ec | |||
| ef43cf238c | |||
| 5fbdf59fb2 | |||
| 3f1412a911 | |||
| c1eead5a3e | |||
| 4fdf6429ec | |||
| cb7beef846 | |||
| 2146daf642 | |||
| 1ad4163319 | |||
| 870d47326a | |||
| 64d8509363 | |||
| b77726cd36 | |||
| 20fa308877 | |||
| 40f0f38f61 | |||
| e2e8793420 | |||
| 4b49987cf5 | |||
| 828e56f36f | |||
| 578b3f4c52 | |||
| dcb2544bd9 | |||
| e0cb71ee45 | |||
| a3a9f03025 | |||
| 4647014dcd | |||
| c50f3ea9f3 | |||
| fbcde608ed | |||
| c291c66fef | |||
| 08ac1f064b | |||
| 72f27183c4 | |||
| 9efbe3851c | |||
| cb5889143e | |||
| dfb9a0d1d7 | |||
| 600741652c | |||
| 7bfac7afb1 | |||
| 2861751e6a | |||
| 7c256e4c2f | |||
| 38d6cca656 | |||
| 7877d2f8dd | |||
| 1c869bd092 | |||
| 595fdddd52 | |||
| 97f251aa69 | |||
| 0147cbf34c | |||
| 863783307e | |||
| d8276b3c07 | |||
| ea4fa4a8b6 | |||
| fcfa2d2c3b | |||
| 513e8dab8d | |||
| 25eaba5b9c | |||
| 5bd61a39ad | |||
| 28d2ba31aa | |||
| f913419122 | |||
| f25856a068 | |||
| d21ea10b0a | |||
| 8e6d1c6e80 | |||
| ea5b94f48b | |||
| 44f9486f45 | |||
| 51d647c751 | |||
| de7d09bad5 | |||
| a9ccaf120e | |||
| cfe05cb966 | |||
| cc47077705 | |||
| de3dfe06ca | |||
| ef42e30dfa | |||
| d297d7474e | |||
| 39e47e9262 | |||
| 70143c0fc5 | |||
| 50aacba98e | |||
| b8a279d2b3 | |||
| dc431e0df1 | |||
| 57c314a085 | |||
| 3f9978a43e | |||
| 922a3bd8de | |||
| 7633905fd2 | |||
| 0342f94f5a | |||
| 7446782446 | |||
| da2cad15b9 | |||
| c71738333f | |||
| 4765105d90 | |||
| 4dc5256071 | |||
| d3ba08a3cf | |||
| bd7b34c59c | |||
| feee742080 | |||
| 801e1b4205 | |||
| 3e28503718 | |||
| 3de2f08ed2 | |||
| bbb0b0f795 | |||
| 6ff9641761 | |||
| 99adfdebb5 | |||
| ac1fd05638 | |||
| 8b27cbd425 | |||
| 82b5b1fc50 | |||
| e27b1fb643 | |||
| da73df3e7d | |||
| 5a0fe4edde | |||
| b1bafec1be | |||
| 1cc2637b25 |
@@ -0,0 +1,85 @@
|
|||||||
|
name: Despliegue Automatizado Universal
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
get-context:
|
||||||
|
runs-on: host
|
||||||
|
outputs:
|
||||||
|
node_version: ${{ steps.setup.outputs.version }}
|
||||||
|
target_app: ${{ steps.setup.outputs.app }}
|
||||||
|
steps:
|
||||||
|
- name: Resolver Aplicación desde apps.conf
|
||||||
|
id: setup
|
||||||
|
run: |
|
||||||
|
# 1. Obtener el nombre del repositorio actual en Gitea (ej: front-Censo)
|
||||||
|
REPO_NAME="${{ github.event.repository.name }}"
|
||||||
|
|
||||||
|
# 2. Determinar si buscamos un entorno -dev (develop) o producción (master)
|
||||||
|
if [ "${{ github.ref_name }}" = "develop" ]; then
|
||||||
|
SUFFIX="-dev"
|
||||||
|
else
|
||||||
|
SUFFIX=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Buscando qué sección de apps.conf tiene REPO=$REPO_NAME y termina en '$SUFFIX'..."
|
||||||
|
|
||||||
|
# 3. Buscar en /etc/apps.conf el bloque que contenga REPO=nombre_del_repo
|
||||||
|
TARGET_APP=$(awk -v repo="REPO=$REPO_NAME" -v suf="$SUFFIX" '
|
||||||
|
/^\[/ { gsub(/[\[\]]/, "", $0); current_box=$0; next }
|
||||||
|
$0 == repo {
|
||||||
|
if ((suf == "-dev" && current_box ~ /-dev$/) || (suf == "" && current_box !~ /-dev$/)) {
|
||||||
|
print current_box;
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' /etc/apps.conf)
|
||||||
|
|
||||||
|
if [ -z "$TARGET_APP" ]; then
|
||||||
|
echo "ERROR: No se encontró ninguna sección en /etc/apps.conf para el repositorio $REPO_NAME con el sufijo correcto."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. Leer la versión de Node del bloque encontrado
|
||||||
|
VERSION=$(awk -v app="$TARGET_APP" '
|
||||||
|
$0=="["app"]" { found=1; next }
|
||||||
|
/^\[/ && found { exit }
|
||||||
|
found && /^NODE=/ { split($0, a, "="); print a[2]; exit }
|
||||||
|
' /etc/apps.conf)
|
||||||
|
|
||||||
|
MAJOR_VERSION=$(echo "$VERSION" | tr -d '[:space:]' | grep -oE '[0-9]+' | head -n1)
|
||||||
|
|
||||||
|
echo "-> ID de Aplicación encontrado: $TARGET_APP"
|
||||||
|
echo "-> Versión Mayor de Node resuelta: $MAJOR_VERSION"
|
||||||
|
|
||||||
|
echo "app=${TARGET_APP}" >> $GITHUB_OUTPUT
|
||||||
|
echo "version=${MAJOR_VERSION}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
build:
|
||||||
|
needs: get-context
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Configurar Node.js dinámicamente
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ needs.get-context.outputs.node_version }}
|
||||||
|
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run build
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
needs: [get-context, build]
|
||||||
|
runs-on: host
|
||||||
|
steps:
|
||||||
|
- name: Ejecutar Despliegue en Servidor Físico
|
||||||
|
run: |
|
||||||
|
TARGET_APP="${{ needs.get-context.outputs.target_app }}"
|
||||||
|
BRANCH_NAME="${{ github.ref_name }}"
|
||||||
|
|
||||||
|
sudo -u deploy /home/deploy/scripts/deploy-front.sh "$TARGET_APP" "$BRANCH_NAME"
|
||||||
@@ -19,6 +19,10 @@ const eslintConfig = [
|
|||||||
"build/**",
|
"build/**",
|
||||||
"next-env.d.ts",
|
"next-env.d.ts",
|
||||||
],
|
],
|
||||||
|
rules: {
|
||||||
|
// permit using `any` in the codebase, otherwise Next's defaults treat it as an error
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
Generated
+925
-503
File diff suppressed because it is too large
Load Diff
+5
-3
@@ -11,17 +11,19 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.12.2",
|
"axios": "^1.12.2",
|
||||||
"bootstrap": "^5.3.8",
|
"bootstrap": "^5.3.8",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"next": "15.5.3",
|
"next": "^16.0.7",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-bootstrap": "^2.10.10",
|
"react-bootstrap": "^2.10.10",
|
||||||
"react-datepicker": "^8.7.0",
|
"react-datepicker": "^8.7.0",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"react-hot-toast": "^2.6.0",
|
"react-hot-toast": "^2.6.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"sass": "^1.92.1",
|
"react-toastify": "^11.0.5",
|
||||||
"sweetalert2": "^11.26.2",
|
"sass": "^1.95.0",
|
||||||
|
"sweetalert2": "^11.26.17",
|
||||||
"sweetalert2-react-content": "^5.1.0",
|
"sweetalert2-react-content": "^5.1.0",
|
||||||
"validator": "^13.15.15"
|
"validator": "^13.15.15"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
|
||||||
|
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#000000" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800px" height="800px" viewBox="0 0 519.578 519.578" xml:space="preserve">
|
||||||
|
|
||||||
|
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M21 10L12 5L3 10L6 11.6667M21 10L18 11.6667M21 10V10C21.6129 10.3064 22 10.9328 22 11.618V16.9998M6 11.6667L12 15L18 11.6667M6 11.6667V17.6667L12 21L18 17.6667L18 11.6667" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 491 B |
@@ -0,0 +1 @@
|
|||||||
|
correo,nombre,institucion,dependencia,programa,clave
|
||||||
|
+23
-5
@@ -2,11 +2,11 @@ import axios from 'axios';
|
|||||||
|
|
||||||
// Crea una instancia base de Axios
|
// Crea una instancia base de Axios
|
||||||
export const axiosInstance = axios.create({
|
export const axiosInstance = axios.create({
|
||||||
baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000/api', // poner la url
|
baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000', // poner la url
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
timeout: 10000, // tiempo máximo de espera (10 segundos)
|
timeout: 20000, // tiempo máximo de espera (20 segundos)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Interceptor para agregar el token automáticamente
|
// Interceptor para agregar el token automáticamente
|
||||||
@@ -19,9 +19,9 @@ axiosInstance.interceptors.request.use(
|
|||||||
config.headers.Authorization = `Bearer ${token}`;
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
|
|
||||||
//Quitar estas lienas
|
//Quitar estas lienas
|
||||||
config.headers['token'] = token;
|
// config.headers['token'] = token;
|
||||||
config.headers['x-access-token'] = token;
|
// config.headers['x-access-token'] = token;
|
||||||
config.headers['token-v2'] = token;
|
// config.headers['token-v2'] = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,23 @@ axiosInstance.interceptors.request.use(
|
|||||||
},
|
},
|
||||||
(error) => Promise.reject(error)
|
(error) => Promise.reject(error)
|
||||||
);
|
);
|
||||||
|
// (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;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
// return config;
|
||||||
|
// },
|
||||||
|
// (error) => Promise.reject(error)
|
||||||
|
|
||||||
// Interceptor para manejar respuestas y errores globales
|
// Interceptor para manejar respuestas y errores globales
|
||||||
axiosInstance.interceptors.response.use(
|
axiosInstance.interceptors.response.use(
|
||||||
@@ -38,6 +55,7 @@ axiosInstance.interceptors.response.use(
|
|||||||
// Token inválido o sesión expirada
|
// Token inválido o sesión expirada
|
||||||
if (error.response.status === 401) {
|
if (error.response.status === 401) {
|
||||||
console.warn('Sesión expirada o token inválido.');
|
console.warn('Sesión expirada o token inválido.');
|
||||||
|
console.log('Expiro el token')
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
window.location.href = '/'; // redirige automáticamente
|
window.location.href = '/'; // redirige automáticamente
|
||||||
|
|||||||
+144
@@ -0,0 +1,144 @@
|
|||||||
|
'use client'
|
||||||
|
import EditarAlumno from "@/components/administrador/editar-caso-especial";
|
||||||
|
import BotonRegresar from "@/components/boton-regresar";
|
||||||
|
import { getUserCasoEspecial } from "@/services/userCasoE.services";
|
||||||
|
import { AxiosError, isAxiosError } from "axios";
|
||||||
|
import { useParams, useRouter } from "next/navigation";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
|
interface Admin {
|
||||||
|
idTipoUsuario: number;
|
||||||
|
tipoUsuario?: string;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
idCasoEspecial: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function EditarCasoEspecial() {
|
||||||
|
const [idCasoEspecial, setIdCasoEspecial] = useState<number | null>(null);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [casoEspecial, setCasoEspecial] = useState<Admin>({
|
||||||
|
idTipoUsuario: 0,
|
||||||
|
tipoUsuario: "",
|
||||||
|
token: ""
|
||||||
|
});
|
||||||
|
const [datos, setDatos] = useState({}); // es de casoEspecial
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const params = useParams();
|
||||||
|
const idCasoEspe = Number(params.idCasoEspecial);
|
||||||
|
|
||||||
|
// fetch local storage and user data when component mounts
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchUser = async () => {
|
||||||
|
await getLocalInfo();
|
||||||
|
|
||||||
|
if (!idCasoEspecial) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setIsLoading(true);
|
||||||
|
const data = await getUserCasoEspecial(idCasoEspecial);
|
||||||
|
|
||||||
|
setDatos(data);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
const axiosErr = error as AxiosError<{ message: string }>;
|
||||||
|
const mensaje = axiosErr?.response?.data?.message || 'No se pudo obtener la infromacion del caso especial.';
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error',
|
||||||
|
icon: 'error',
|
||||||
|
text: mensaje,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchUser();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (isNaN(idCasoEspe)) {
|
||||||
|
return <p>Servicio inválido</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getLocalInfo = () => {
|
||||||
|
const storedAdmin: Admin = {
|
||||||
|
idTipoUsuario: Number(localStorage.getItem('idTipoUsuario')),
|
||||||
|
tipoUsuario: localStorage.getItem('tipoUsuario') || undefined,
|
||||||
|
token: localStorage.getItem('token') || '',
|
||||||
|
}
|
||||||
|
|
||||||
|
setCasoEspecial(storedAdmin);
|
||||||
|
|
||||||
|
const storageIdCaso = Number(localStorage.getItem('idCasoEspecial'));
|
||||||
|
setIdCasoEspecial(storageIdCaso);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const imprimirError = (err: unknown = {}, title = '¡Hubo un error!', onConfirm = () => {}) => {
|
||||||
|
let message = 'Ocurrió un error';
|
||||||
|
if (typeof err === 'string') message = err;
|
||||||
|
else if (err instanceof Error) message = err.message;
|
||||||
|
else if (isAxiosError(err) && err.response?.data?.message) message = String(err.response.data.message);
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title,
|
||||||
|
text: message,
|
||||||
|
icon: 'error',
|
||||||
|
confirmButtonText: 'Entendido',
|
||||||
|
}).then(() => onConfirm());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const anyErr = err as { err?: string };
|
||||||
|
if (anyErr.err === 'token error') {
|
||||||
|
localStorage.clear();
|
||||||
|
router.replace('/');
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const imprimirMensaje = (message: string, title = '¡Felicidades!', onConfirm = () => {}) => {
|
||||||
|
Swal.fire({
|
||||||
|
title,
|
||||||
|
text: message,
|
||||||
|
icon: 'success',
|
||||||
|
confirmButtonText: 'Ok',
|
||||||
|
}).then(() => onConfirm());
|
||||||
|
};
|
||||||
|
|
||||||
|
const imprimirWarning = (
|
||||||
|
message: string,
|
||||||
|
onConfirm = () => {},
|
||||||
|
title = '¡Espera un minuto!',
|
||||||
|
onCancel = () => {}
|
||||||
|
) => {
|
||||||
|
Swal.fire({
|
||||||
|
title,
|
||||||
|
text: message,
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: 'Confirmar',
|
||||||
|
cancelButtonText: 'Cancelar',
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) onConfirm();
|
||||||
|
else onCancel();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateIsLoading = (value: boolean) => setIsLoading(value);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="container px-2 pb-5">
|
||||||
|
<BotonRegresar />
|
||||||
|
<EditarAlumno
|
||||||
|
idCasoEspecial={idCasoEspe}
|
||||||
|
admin={casoEspecial}
|
||||||
|
viejo={datos}
|
||||||
|
updateIsLoading={updateIsLoading}
|
||||||
|
imprimirError={imprimirError}
|
||||||
|
imprimirMensaje={imprimirMensaje}
|
||||||
|
imprimirWarning={imprimirWarning}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -3,13 +3,14 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { axiosInstance } from '@/api/config';
|
import { axiosInstance } from '@/api/config';
|
||||||
import { isAxiosError } from 'axios';
|
import axios, { AxiosError, isAxiosError } from 'axios';
|
||||||
import BotonRegresar from '@/components/boton-regresar';
|
import BotonRegresar from '@/components/boton-regresar';
|
||||||
import InformacionCasoEspecial from '@/components/administrador/informacion-caso-especial';
|
import InformacionCasoEspecial from '@/components/administrador/informacion-caso-especial';
|
||||||
import LiberarCasoEspecial from '@/components/administrador/liberar-caso-especial';
|
import LiberarCasoEspecial from '@/components/administrador/liberar-caso-especial';
|
||||||
|
|
||||||
import Swal from 'sweetalert2';
|
import Swal from 'sweetalert2';
|
||||||
import withReactContent from 'sweetalert2-react-content';
|
import withReactContent from 'sweetalert2-react-content';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -27,9 +28,10 @@ interface Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Alumno {
|
interface Alumno {
|
||||||
Usuario?: object;
|
idCasoEspecial: number;
|
||||||
Carrera?: object;
|
usuario?: object;
|
||||||
Status?: Status;
|
carrera?: object;
|
||||||
|
status?: Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CasoEspecialPage() {
|
export default function CasoEspecialPage() {
|
||||||
@@ -38,7 +40,7 @@ export default function CasoEspecialPage() {
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [idCasoEspecial, setIdCasoEspecial] = useState<number | null>(null);
|
const [idCasoEspecial, setIdCasoEspecial] = useState<number | null>(null);
|
||||||
const [admin, setAdmin] = useState<Admin>({});
|
const [admin, setAdmin] = useState<Admin>({});
|
||||||
const [alumno, setAlumno] = useState<Alumno>({ Usuario: {}, Carrera: {}, Status: {} });
|
const [alumno, setAlumno] = useState<Alumno>({ idCasoEspecial: 0, usuario: {}, carrera: {}, status: {} });
|
||||||
|
|
||||||
// Funciones de dialogo
|
// Funciones de dialogo
|
||||||
const imprimirError = (err: unknown = {}, title = '¡Hubo un error!', onConfirm = () => {}) => {
|
const imprimirError = (err: unknown = {}, title = '¡Hubo un error!', onConfirm = () => {}) => {
|
||||||
@@ -58,7 +60,7 @@ export default function CasoEspecialPage() {
|
|||||||
const anyErr = err as { err?: string };
|
const anyErr = err as { err?: string };
|
||||||
if (anyErr.err === 'token error') {
|
if (anyErr.err === 'token error') {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
router.push('/');
|
router.replace('/');
|
||||||
}
|
}
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
};
|
};
|
||||||
@@ -78,7 +80,7 @@ export default function CasoEspecialPage() {
|
|||||||
title = '¡Espera un minuto!',
|
title = '¡Espera un minuto!',
|
||||||
onCancel = () => {}
|
onCancel = () => {}
|
||||||
) => {
|
) => {
|
||||||
MySwal.fire({
|
Swal.fire({
|
||||||
title,
|
title,
|
||||||
text: message,
|
text: message,
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
@@ -111,14 +113,27 @@ export default function CasoEspecialPage() {
|
|||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await axiosInstance.get(`/caso_especial?idCasoEspecial=${idCasoEspecial}`, { headers: { token: admin.token } });
|
// throw new Error('Error simulado del servidor'); Para simular error del servidor
|
||||||
setAlumno(res.data);
|
// await new Promise(resolve => setTimeout(resolve, 3000)); // Simulamos que el back tarda en enviar la infromacion 3 seg
|
||||||
|
const res = await axiosInstance.get(`/caso-especial/caso_especial/${idCasoEspecial}`);
|
||||||
|
setAlumno(res.data.data);
|
||||||
|
|
||||||
|
console.log("Respuesta del servidor", res.data)
|
||||||
|
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
|
const axiosErr = err as AxiosError<any>;
|
||||||
else if (err instanceof Error) imprimirError(err.message);
|
const mensaje = axiosErr?.response?.data?.message || 'No se cargo la infromacion, por favor intentelo mas tarde.'
|
||||||
else imprimirError();
|
Swal.fire({
|
||||||
|
icon: 'error',
|
||||||
|
title: 'Error',
|
||||||
|
text: mensaje,
|
||||||
|
})
|
||||||
|
router.replace('/administrador/casos_especiales');
|
||||||
|
// if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
|
||||||
|
// else if (err instanceof Error) imprimirError(err.message);
|
||||||
|
// else imprimirError();
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -129,9 +144,9 @@ export default function CasoEspecialPage() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (admin.idTipoUsuario) {
|
if (admin.idTipoUsuario) {
|
||||||
if (admin.idTipoUsuario === 2) router.push('/responsable');
|
if (admin.idTipoUsuario === 2) router.replace('/responsable');
|
||||||
if (admin.idTipoUsuario === 3) router.push('/alumno');
|
if (admin.idTipoUsuario === 3) router.replace('/alumno');
|
||||||
if (admin.idTipoUsuario === 4) router.push('/casoEspecial');
|
if (admin.idTipoUsuario === 4) router.replace('/casoEspecial');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idCasoEspecial) {
|
if (idCasoEspecial) {
|
||||||
@@ -148,7 +163,7 @@ export default function CasoEspecialPage() {
|
|||||||
|
|
||||||
<InformacionCasoEspecial alumno={alumno} />
|
<InformacionCasoEspecial alumno={alumno} />
|
||||||
|
|
||||||
{(alumno.Status?.idStatus === 11 || alumno.Status?.idStatus === 12) && (
|
{(alumno.status?.idStatus === 11 || alumno.status?.idStatus === 12) && (
|
||||||
<LiberarCasoEspecial
|
<LiberarCasoEspecial
|
||||||
idCasoEspecial={idCasoEspecial!}
|
idCasoEspecial={idCasoEspecial!}
|
||||||
admin={{ token: admin.token! }}
|
admin={{ token: admin.token! }}
|
||||||
@@ -160,7 +175,7 @@ export default function CasoEspecialPage() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-30 z-50">
|
<div className="fixed inset-0 flex items-center justify-center bg-transparent bg-opacity-30 z-50">
|
||||||
<div className="loader">Cargando...</div>
|
<div className="loader">Cargando...</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
"use client"
|
'use client'
|
||||||
import Footer from "@/components/layout/footer";
|
import Footer from "@/components/layout/footer";
|
||||||
import Header from "@/components/layout/header";
|
import Header from "@/components/layout/header";
|
||||||
import Logout from "@/components/layout/logout";
|
import Logout from "@/components/layout/logout";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import "@/sass/bootstrap.scss"
|
import "@/sass/bootstrap.scss"
|
||||||
|
|
||||||
console.log("Header", Header);
|
|
||||||
console.log("Footer", Footer);
|
|
||||||
|
|
||||||
export default function AdministradorLayout({
|
export default function AdministradorLayout({
|
||||||
children}: {
|
children}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Logout />
|
<Logout />
|
||||||
<main className="bg-light">{children}</main>
|
<main className="bg-light">{children}</main>
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ export default function Administrador() {
|
|||||||
const token = localStorage.getItem('token') ?? undefined;
|
const token = localStorage.getItem('token') ?? undefined;
|
||||||
if (!idTipoUsuario) return; // no logueado
|
if (!idTipoUsuario) return; // no logueado
|
||||||
setAdmin({ idTipoUsuario, token });
|
setAdmin({ idTipoUsuario, token });
|
||||||
|
|
||||||
|
console.log('Datos del administrador', admin)
|
||||||
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function imprimirError(mensaje: string) {
|
function imprimirError(mensaje: string) {
|
||||||
|
|||||||
@@ -2,13 +2,14 @@
|
|||||||
import Cuestionario from "@/components/administrador/cuestionario";
|
import Cuestionario from "@/components/administrador/cuestionario";
|
||||||
import GustavoBazPrada from "@/components/administrador/gustavo-baz-prada";
|
import GustavoBazPrada from "@/components/administrador/gustavo-baz-prada";
|
||||||
import Reporte from "@/components/administrador/reporte";
|
import Reporte from "@/components/administrador/reporte";
|
||||||
|
import ReporteCasoEspecial from "@/components/administrador/reporte-caso-especial";
|
||||||
import BotonRegresar from "@/components/boton-regresar";
|
import BotonRegresar from "@/components/boton-regresar";
|
||||||
import { type } from "node:os";
|
import { type } from "node:os";
|
||||||
import { useEffect } from "react";
|
import { useEffect, useState, useMemo } from "react";
|
||||||
|
|
||||||
export default function Registro() {
|
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 [admin, setAdmin] = useState({ token: "" });
|
||||||
|
|
||||||
const obtenerYears = () => {
|
const obtenerYears = () => {
|
||||||
const years1 = [];
|
const years1 = [];
|
||||||
@@ -20,11 +21,15 @@ export default function Registro() {
|
|||||||
return years1
|
return years1
|
||||||
}
|
}
|
||||||
|
|
||||||
const years = obtenerYears()
|
const years = useMemo(() => obtenerYears(), [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setAdmin({ token: localStorage.getItem("token") || "" });
|
||||||
console.log("Estos son los datos de years", years)
|
console.log("Estos son los datos de years", years)
|
||||||
console.log("Este es el tipo de datos de years", typeof(years))
|
console.log("Este es el tipo de datos de years", typeof(years))
|
||||||
|
|
||||||
|
console.log("Estos son los datos de admin", admin)
|
||||||
|
console.log("Este es el tipo de datos de admin", typeof(admin))
|
||||||
}, [years]);
|
}, [years]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -42,6 +47,8 @@ export default function Registro() {
|
|||||||
<GustavoBazPrada
|
<GustavoBazPrada
|
||||||
years={years}
|
years={years}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ReporteCasoEspecial />
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ export default function Editar() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true)
|
updateIsLoading(true)
|
||||||
const res = await axiosInstance.get(`usuario/responsable?idUsuario=${idUsuario}`)
|
const res = await axiosInstance.get(`usuario/responsable/${idUsuario}`)
|
||||||
//imprimirMensaje(res.data.message)
|
//imprimirMensaje(res.data.message)
|
||||||
setData(res.data)
|
setData(res.data)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default function Servicio() {
|
|||||||
alert(`Error: ${mensaje}`);
|
alert(`Error: ${mensaje}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ⚠️ NUEVA función para advertencias (confirmaciones)
|
// NUEVA función para advertencias (confirmaciones)
|
||||||
const imprimirWarning = (mensaje: string, onConfirm: () => void) => {
|
const imprimirWarning = (mensaje: string, onConfirm: () => void) => {
|
||||||
if (window.confirm(mensaje)) {
|
if (window.confirm(mensaje)) {
|
||||||
onConfirm();
|
onConfirm();
|
||||||
@@ -48,9 +48,8 @@ export default function Servicio() {
|
|||||||
return (
|
return (
|
||||||
<section className="container">
|
<section className="container">
|
||||||
<BotonRegresar />
|
<BotonRegresar />
|
||||||
{/* <EditarServicio admin={}/> */}
|
|
||||||
<EditarServicio
|
<EditarServicio
|
||||||
admin={admin.token || ''}
|
admin={{ token: admin.token || '' }}
|
||||||
imprimirError={imprimirError}
|
imprimirError={imprimirError}
|
||||||
imprimirMensaje={imprimirMensajeError}
|
imprimirMensaje={imprimirMensajeError}
|
||||||
imprimirWarning={imprimirWarning}
|
imprimirWarning={imprimirWarning}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import Archivo from '@/components/administrador/archivo';
|
|||||||
import TituloStatus from '@/components/administrador/titulo-status';
|
import TituloStatus from '@/components/administrador/titulo-status';
|
||||||
import InformacionServicio from '@/components/administrador/informacion-servicio';
|
import InformacionServicio from '@/components/administrador/informacion-servicio';
|
||||||
import { Status } from '@/types/responses';
|
import { Status } from '@/types/responses';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
import Swal from 'sweetalert2';
|
||||||
|
import { Spinner } from 'react-bootstrap';
|
||||||
|
|
||||||
|
|
||||||
// Tipos estrictos basados en tus datos
|
// Tipos estrictos basados en tus datos
|
||||||
@@ -78,10 +81,10 @@ Programa: { Usuario: {} },
|
|||||||
|
|
||||||
//Interface
|
//Interface
|
||||||
interface Datos {
|
interface Datos {
|
||||||
Programa?: Programa;
|
programa?: Programa;
|
||||||
Carrera?: Carrera;
|
carrera?: Carrera;
|
||||||
Usuario?: Usuario;
|
usuario?: Usuario;
|
||||||
Status?: Status;
|
status?: Status;
|
||||||
creditos?: string;
|
creditos?: string;
|
||||||
correo?: string;
|
correo?: string;
|
||||||
fechaRegistro?: string;
|
fechaRegistro?: string;
|
||||||
@@ -98,10 +101,10 @@ interface Datos {
|
|||||||
cartaTermino?: string;
|
cartaTermino?: string;
|
||||||
informeGlobal?: string;
|
informeGlobal?: string;
|
||||||
|
|
||||||
idCuestionarioPrograma?: number;
|
cuestionarioPrograma?: {idCuestionarioPrograma: number};
|
||||||
idCuestionarioPrograma2?: number;
|
cuestionarioPrograma2?: {idCuestionarioPrograma2: number};
|
||||||
idCuestionarioAlumno?: number;
|
cuestionarioAlumno?: {idCuestionarioAlumno: number};
|
||||||
idCuestionarioAlumno2?: number;
|
cuestionarioAlumno2?: {idCuestionarioAlumno2: number};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Servicio() {
|
export default function Servicio() {
|
||||||
@@ -130,22 +133,44 @@ export default function Servicio() {
|
|||||||
setAdmin({ token });
|
setAdmin({ token });
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const confirmar = (message: string, onConfirm: () => void) => {
|
||||||
|
Swal.fire({
|
||||||
|
title: message,
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: 'confirmar',
|
||||||
|
cancelButtonText: 'cancelar',
|
||||||
|
confirmButtonColor: "#0d6efd",
|
||||||
|
cancelButtonColor: "#dc3545",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
onConfirm();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Función para imprimir errores
|
// Función para imprimir errores
|
||||||
const imprimirError = (error: unknown) => {
|
const imprimirError = (error: unknown) => {
|
||||||
alert(`❌ Error: ${JSON.stringify(error)}`);
|
|
||||||
|
Swal.fire('Error', JSON.stringify(error), 'error')
|
||||||
|
// alert(`❌ Error: ${JSON.stringify(error)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const imprimirMensaje = (message: string) => {
|
const imprimirMensaje = (message: string) => {
|
||||||
alert(`✅ ${message}`);
|
Swal.fire('Exito', message, 'success')
|
||||||
|
// alert(`✅ ${message}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const imprimirWarning = (message: string, onConfirm: () => void) => {
|
const imprimirWarning = (message: string, onConfirm: () => void) => {
|
||||||
if (confirm(`⚠️ ${message}\n¿Deseas continuar?`)) {
|
confirmar(message, onConfirm)
|
||||||
onConfirm();
|
// if (confirm(`
|
||||||
}
|
// ${Swal.fire('Aviso', message, 'warning')}
|
||||||
|
// `)) {
|
||||||
|
// onConfirm();
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Función para actualizar el estado de carga
|
// Función para acualizar el estado de carga
|
||||||
const updateIsLoading = (value: boolean) => {
|
const updateIsLoading = (value: boolean) => {
|
||||||
setIsLoading(value);
|
setIsLoading(value);
|
||||||
};
|
};
|
||||||
@@ -168,42 +193,71 @@ export default function Servicio() {
|
|||||||
const tipoUsuario = localStorage.getItem('tipoUsuario') ?? '';
|
const tipoUsuario = localStorage.getItem('tipoUsuario') ?? '';
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
|
|
||||||
|
const idServicioLS = Number(localStorage.getItem('idServicio'));
|
||||||
|
setIdServicio(idServicioLS);
|
||||||
|
|
||||||
if (!idUsuario || !idTipoUsuario || !token) return null;
|
if (!idUsuario || !idTipoUsuario || !token) return null;
|
||||||
|
|
||||||
const adminInfo: AdminInfo = {
|
return {
|
||||||
idUsuario,
|
idUsuario,
|
||||||
idTipoUsuario,
|
idTipoUsuario,
|
||||||
tipoUsuario,
|
tipoUsuario,
|
||||||
token: {
|
token: {
|
||||||
headers: {
|
headers: {
|
||||||
token,
|
token,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
|
};
|
||||||
|
|
||||||
//setAdmin(adminInfo);
|
// const adminInfo: AdminInfo = {
|
||||||
const idServisio = setIdServicio(Number(localStorage.getItem('idServicio')));
|
// idUsuario,
|
||||||
console.log('ID Servicio obtenido:', idServisio);
|
// idTipoUsuario,
|
||||||
return adminInfo;
|
// tipoUsuario,
|
||||||
|
// token: {
|
||||||
|
// headers: {
|
||||||
|
// token,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
|
// //setAdmin(adminInfo);
|
||||||
|
// const idServisio = setIdServicio(Number(localStorage.getItem('idServicio')));
|
||||||
|
// console.log('ID Servicio obtenido:', idServisio);
|
||||||
|
// return adminInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
const obtenerRegistro = async (adminInfo: AdminInfo, idServicioVal: number) => {
|
const obtenerRegistro = async (adminInfo: AdminInfo, idServicioVal: number) => {
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res = await axiosInstance.get(`/servicio/admin?idServicio=${idServicioVal}`); //, adminInfo.token
|
|
||||||
|
// await new Promise(resolve => setTimeout(resolve, 3000));
|
||||||
|
// throw new Error('Api caida')
|
||||||
|
const res = await axiosInstance.get(`/servicio/admin/${idServicioVal}`); //, adminInfo.token
|
||||||
console.log('Respuesta del servicio:', res.data);
|
console.log('Respuesta del servicio:', res.data);
|
||||||
setDatos(res.data);
|
setDatos(res.data);
|
||||||
console.log('Programa obtenido:', datos.Status);
|
console.log('Programa obtenido:', datos.status);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
//imprimirError(error.response?.data || { message: 'Error al obtener el registro' });
|
//imprimirError(error.response?.data || { message: 'Error al obtener el registro' });
|
||||||
|
Swal.fire('Aviso', 'Error al cargar los datos. Intente nuevamente más tarde.', 'error')
|
||||||
console.log('Error al obtener el registro:', error);
|
console.log('Error al obtener el registro:', error);
|
||||||
|
router.replace('/administrador')
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const tieneCuestionarioPrograma =
|
||||||
|
datos.cuestionarioPrograma?.idCuestionarioPrograma != null ||
|
||||||
|
datos.cuestionarioPrograma2?.idCuestionarioPrograma2 != null;
|
||||||
|
|
||||||
|
const tieneCuestionarioAlumno =
|
||||||
|
datos.cuestionarioAlumno?.idCuestionarioAlumno != null ||
|
||||||
|
datos.cuestionarioAlumno2?.idCuestionarioAlumno2 != null;
|
||||||
|
|
||||||
// === Ciclo de vida (similar a created() en Vue) ===
|
// === Ciclo de vida (similar a created() en Vue) ===
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
|
console.log("Datos que le llegan al useEffect de servicio page:", datos);
|
||||||
const adminInfo = getLocalhostInfo();
|
const adminInfo = getLocalhostInfo();
|
||||||
|
|
||||||
if (!adminInfo) {
|
if (!adminInfo) {
|
||||||
@@ -239,16 +293,29 @@ export default function Servicio() {
|
|||||||
<section className="container px-2 pb-6">
|
<section className="container px-2 pb-6">
|
||||||
<BotonRegresar />
|
<BotonRegresar />
|
||||||
|
|
||||||
<h3 className="container fw-bold title">{datos.Status?.status}</h3>
|
<h3 className="container fw-bold title">{datos.status?.status}</h3>
|
||||||
|
|
||||||
<InformacionServicio
|
|
||||||
datos={datos}
|
|
||||||
admin={admin}
|
|
||||||
imprimirError={imprimirError}
|
|
||||||
updateIsLoading={updateIsLoading}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TituloStatus status={datos.Status}/>
|
{isLoading ? (
|
||||||
|
<Spinner />
|
||||||
|
) : datos ? (
|
||||||
|
<InformacionServicio
|
||||||
|
datos={datos}
|
||||||
|
admin={admin}
|
||||||
|
imprimirError={imprimirError}
|
||||||
|
updateIsLoading={updateIsLoading}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{/* {!isLoading && datos && (
|
||||||
|
<InformacionServicio
|
||||||
|
datos={datos}
|
||||||
|
admin={admin}
|
||||||
|
imprimirError={imprimirError}
|
||||||
|
updateIsLoading={updateIsLoading}
|
||||||
|
/>
|
||||||
|
)} */}
|
||||||
|
|
||||||
|
<TituloStatus status={datos.status}/>
|
||||||
|
|
||||||
{/* Para mostrar si tiene la carta y poder ver los diferentes archivos */}
|
{/* Para mostrar si tiene la carta y poder ver los diferentes archivos */}
|
||||||
{datos.cartaAceptacion && (
|
{datos.cartaAceptacion && (
|
||||||
@@ -287,31 +354,48 @@ export default function Servicio() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className='container'>
|
<div className="container">
|
||||||
{datos.idCuestionarioPrograma || datos.idCuestionarioPrograma2 ? (
|
{tieneCuestionarioPrograma && (
|
||||||
|
<p className="my-4">
|
||||||
|
<strong>Cuenta con cuestionario de programa resuelto.</strong>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tieneCuestionarioAlumno && (
|
||||||
|
<p className="my-4">
|
||||||
|
<strong>Cuenta con cuestionario de alumno resuelto.</strong>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* <div className='container'>
|
||||||
|
{datos.cuestionarioPrograma2?.idCuestionarioPrograma2 != null || datos.cuestionarioPrograma?.idCuestionarioPrograma != null ? (
|
||||||
<p className="my-4">
|
<p className="my-4">
|
||||||
<strong>Cuenta con cuestionario de programa resuelto.</strong>
|
<strong>Cuenta con cuestionario de programa resuelto.</strong>
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{datos.idCuestionarioAlumno || datos.idCuestionarioAlumno2 ? (
|
{datos.cuestionarioAlumno2?.idCuestionarioAlumno2 != null || datos.cuestionarioAlumno?.idCuestionarioAlumno != null ?(
|
||||||
<p className="my-4">
|
<p className="my-4">
|
||||||
<strong>Cuenta con cuestionario de alumno resuelto.</strong>
|
<strong>Cuenta con cuestionario de alumno resuelto.</strong>
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
<ConfirmarServicio
|
{idServicio && datos.status && (
|
||||||
idServicio={idServicio ?? 0}
|
<ConfirmarServicio
|
||||||
admin={admin}
|
idServicio={idServicio ?? 0}
|
||||||
datos={datos}
|
admin={admin}
|
||||||
imprimirMensaje={imprimirMensaje}
|
datos={datos}
|
||||||
imprimirWarning={imprimirWarning}
|
imprimirMensaje={imprimirMensaje}
|
||||||
imprimirError={imprimirError}
|
imprimirWarning={imprimirWarning}
|
||||||
updateIsLoading={updateIsLoading}
|
imprimirError={imprimirError}
|
||||||
/>
|
updateIsLoading={updateIsLoading}
|
||||||
|
/>
|
||||||
<CancelarServicio
|
)}
|
||||||
|
|
||||||
|
{datos.status?.idStatus != 5 && datos.status?.idStatus != 6 && (
|
||||||
|
<CancelarServicio
|
||||||
idServicio={idServicio ?? 0}
|
idServicio={idServicio ?? 0}
|
||||||
admin={admin}
|
admin={admin}
|
||||||
datos={datos}
|
datos={datos}
|
||||||
@@ -320,6 +404,8 @@ export default function Servicio() {
|
|||||||
imprimirError={imprimirError}
|
imprimirError={imprimirError}
|
||||||
updateIsLoading={updateIsLoading}
|
updateIsLoading={updateIsLoading}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/*
|
{/*
|
||||||
|
|||||||
+13
-1
@@ -5,8 +5,20 @@ import FormularioCuestionario from '@/components/alumno/cuestionario2/full-cuest
|
|||||||
import BotonRegresar from '@/components/boton-regresar';
|
import BotonRegresar from '@/components/boton-regresar';
|
||||||
import FullCuestionarioNewBad2 from '@/components/alumno/cuestionario2/full-cuestionario-newbad2';
|
import FullCuestionarioNewBad2 from '@/components/alumno/cuestionario2/full-cuestionario-newbad2';
|
||||||
import FullCuestionario from '@/components/alumno/cuestionario2/full-cuestionario';
|
import FullCuestionario from '@/components/alumno/cuestionario2/full-cuestionario';
|
||||||
|
import { useParams } from 'next/navigation';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
idServicio: number;
|
||||||
|
}
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
|
const params = useParams();
|
||||||
|
const idServicio = Number(params.idServicio);
|
||||||
|
|
||||||
|
if (isNaN(idServicio)) {
|
||||||
|
return <p>Servicio inválido</p>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='container bg-light'>
|
<div className='container bg-light'>
|
||||||
<div className='mt-4'>
|
<div className='mt-4'>
|
||||||
@@ -28,7 +40,7 @@ web: <a
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FullCuestionario />
|
<FullCuestionario idServicio={idServicio}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
+21
-10
@@ -32,9 +32,9 @@ interface InfoAlumno{
|
|||||||
//createdAt: Date,
|
//createdAt: Date,
|
||||||
idCuestionarioAlumno: number,
|
idCuestionarioAlumno: number,
|
||||||
idCuestionarioAlumno2: number,
|
idCuestionarioAlumno2: number,
|
||||||
Carrera: Carrera,
|
carrera: Carrera,
|
||||||
Status: Status,
|
status: Status,
|
||||||
Programa: Programa,
|
programa: Programa,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Carrera {
|
interface Carrera {
|
||||||
@@ -57,6 +57,7 @@ interface Programa {
|
|||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const [data, setData] = useState<InfoAlumnoExtendido>();
|
const [data, setData] = useState<InfoAlumnoExtendido>();
|
||||||
|
// const [servicio, setServicio] = useState<InfoAlumno>();
|
||||||
|
|
||||||
const handleInfo = async () => {
|
const handleInfo = async () => {
|
||||||
const idUsuario = localStorage.getItem('idUsuario');
|
const idUsuario = localStorage.getItem('idUsuario');
|
||||||
@@ -80,7 +81,13 @@ export default function Home() {
|
|||||||
const combinado: InfoAlumnoExtendido = { ...inf.data, Usuario };
|
const combinado: InfoAlumnoExtendido = { ...inf.data, Usuario };
|
||||||
console.log('Esta es la info combinada', combinado)
|
console.log('Esta es la info combinada', combinado)
|
||||||
|
|
||||||
|
// setServicio(inf.data.servicio);
|
||||||
|
// console.log("Este es el servicio", servicio);
|
||||||
|
|
||||||
setData(combinado);
|
setData(combinado);
|
||||||
|
|
||||||
|
console.log("Este es el status del alumno", data?.status.idStatus)
|
||||||
|
|
||||||
console.log("Este es la infromacion combinada", data);
|
console.log("Este es la infromacion combinada", data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error al hacer la peticion ", error)
|
console.log("Error al hacer la peticion ", error)
|
||||||
@@ -88,17 +95,21 @@ export default function Home() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (data) {
|
||||||
|
console.log("Este es el data en el useEffect", data);
|
||||||
|
console.log("Este es el status en el useEffect", data.status.idStatus);
|
||||||
|
}
|
||||||
handleInfo();
|
handleInfo();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{ data?.Status.idStatus && (
|
{ data?.status.idStatus && (
|
||||||
<BarraProgreso idStatus={data?.Status.idStatus}/>
|
<BarraProgreso idStatus={data?.status.idStatus}/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="my-5">
|
<div className="my-5">
|
||||||
<MensajeAlumno Status={{ idStatus: 2 }} />
|
<MensajeAlumno status={{ idStatus: data?.status.idStatus ?? 6 }} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* servicio={{
|
{/* servicio={{
|
||||||
@@ -123,9 +134,9 @@ export default function Home() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{ data?.Status.idStatus === 2 && (
|
{ data?.status.idStatus === 2 && (
|
||||||
<CompletarDatosPersonales
|
<CompletarDatosPersonales
|
||||||
idServicio={123}
|
idServicio={data.idServicio}
|
||||||
alumno={{ token: { headers: { Authorization: "Bearer ..." } }, tokenArchivo: { headers: { Authorization: "Bearer ..." } } }}
|
alumno={{ token: { headers: { Authorization: "Bearer ..." } }, tokenArchivo: { headers: { Authorization: "Bearer ..." } } }}
|
||||||
imprimirMensaje={(msg) => console.log(msg)}
|
imprimirMensaje={(msg) => console.log(msg)}
|
||||||
imprimirWarning={(msg, callback) => { if (confirm(msg)) callback(); }}
|
imprimirWarning={(msg, callback) => { if (confirm(msg)) callback(); }}
|
||||||
@@ -135,9 +146,9 @@ export default function Home() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{ data?.Status.idStatus !== undefined && data?.Status.idStatus >= 4 && (
|
{ data?.status.idStatus !== undefined && data?.status.idStatus >= 4 && data?.status.idStatus !== 8 && (
|
||||||
<PreTermino
|
<PreTermino
|
||||||
alumno={{ tokenArchivo: "token123" }}
|
alumno={{tokenAlumno: localStorage.getItem('token') || ""}}
|
||||||
servicio={data}
|
servicio={data}
|
||||||
imprimirMensaje={(msg) => console.log(msg)}
|
imprimirMensaje={(msg) => console.log(msg)}
|
||||||
imprimirWarning={(msg, callback) => {
|
imprimirWarning={(msg, callback) => {
|
||||||
|
|||||||
@@ -2,9 +2,13 @@
|
|||||||
import BotonRegresar from "@/components/boton-regresar";
|
import BotonRegresar from "@/components/boton-regresar";
|
||||||
import CasoEspecialForm from "@/components/casoEspecial/caso-especial-form";
|
import CasoEspecialForm from "@/components/casoEspecial/caso-especial-form";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
export default function Nuevo() {
|
export default function Nuevo() {
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
// const token = localStorage.getItem('token');
|
||||||
|
|
||||||
|
// console.log("Este es el token en nuevo caso especial:", token);
|
||||||
|
|
||||||
const imprimirError = (error: unknown) => {
|
const imprimirError = (error: unknown) => {
|
||||||
alert(`Error: ${JSON.stringify(error)}`)
|
alert(`Error: ${JSON.stringify(error)}`)
|
||||||
@@ -14,10 +18,24 @@ export default function Nuevo() {
|
|||||||
alert(`${message}`);
|
alert(`${message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const imprimirWarning = (message: string, onConfirm: () => void) => {
|
const imprimirWarning = (message: string, onConfirm: () => void, title: string) => {
|
||||||
if (confirm(`${message}\n¿Desea continuar?`)) {
|
Swal.fire({
|
||||||
onConfirm();
|
title,
|
||||||
}
|
text: message,
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: 'confirmar',
|
||||||
|
cancelButtonText: 'cancelar',
|
||||||
|
confirmButtonColor: "#0d6efd",
|
||||||
|
cancelButtonColor: "#dc3545",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
onConfirm();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// if (confirm(`${message}\n¿Desea continuar?`)) {
|
||||||
|
// onConfirm();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateIsLoading = (value: boolean) => {
|
const updateIsLoading = (value: boolean) => {
|
||||||
|
|||||||
+115
-4
@@ -1,3 +1,4 @@
|
|||||||
|
@import "react-datepicker/dist/react-datepicker.css";
|
||||||
:root {
|
:root {
|
||||||
--background: #ffffff;
|
--background: #ffffff;
|
||||||
--foreground: #171717;
|
--foreground: #171717;
|
||||||
@@ -10,9 +11,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@import "react-datepicker/dist/react-datepicker.css";
|
|
||||||
|
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
max-width: 100vw;
|
max-width: 100vw;
|
||||||
@@ -20,7 +18,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
color: var(--foreground);
|
/* Do not override text color globally so Bootstrap utilities and components keep their intended colors */
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-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 {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -138,3 +147,105 @@ table {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Para los estilos en la vista de login */
|
||||||
|
.password-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
border: 1px solid #ced4da;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-wrapper:focus-within {
|
||||||
|
border-color: #0d6efd; /* Bootstrap primary */
|
||||||
|
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-input {
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
width: 100%;
|
||||||
|
background: transparent;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Estilos para los calendarios de las fechas */
|
||||||
|
/* CONTENEDOR GENERAL */
|
||||||
|
.mi-calendario {
|
||||||
|
font-family: inherit;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #0d6efd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HEADER (mes / año) */
|
||||||
|
.mi-calendario .react-datepicker__header {
|
||||||
|
background-color: #838383;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TEXTO DEL HEADER */
|
||||||
|
.mi-calendario .react-datepicker__current-month,
|
||||||
|
.mi-calendario .react-datepicker__day-name {
|
||||||
|
color: #ffffff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SELECTS DE MES Y AÑO */
|
||||||
|
.mi-calendario .react-datepicker__month-select,
|
||||||
|
.mi-calendario .react-datepicker__year-select {
|
||||||
|
background-color: transparent;
|
||||||
|
color: #ffffff;
|
||||||
|
border: 1px solid #ffffff;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 2px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OPCIONES DEL SELECT */
|
||||||
|
.mi-calendario .react-datepicker__month-select option,
|
||||||
|
.mi-calendario .react-datepicker__year-select option {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DÍAS */
|
||||||
|
.mi-calendario .react-datepicker__day {
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DÍA SELECCIONADO */
|
||||||
|
.mi-calendario .react-datepicker__day--selected,
|
||||||
|
.mi-calendario .react-datepicker__day--keyboard-selected {
|
||||||
|
background-color: #0d6efd;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HOVER DE DÍAS */
|
||||||
|
.mi-calendario .react-datepicker__day:hover {
|
||||||
|
background-color: #cfe2ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DÍAS DESHABILITADOS */
|
||||||
|
.mi-calendario .react-datepicker__day--disabled {
|
||||||
|
color: #adb5bd;
|
||||||
|
}
|
||||||
|
.mi-calendario .react-datepicker__year-select::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mi-calendario .react-datepicker__year-select::-webkit-scrollbar-track {
|
||||||
|
background: #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mi-calendario .react-datepicker__year-select::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #0d6efd;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 2px solid #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mi-calendario .react-datepicker__year-select::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: #0b5ed7;
|
||||||
|
}
|
||||||
|
|||||||
+2
-1
@@ -17,13 +17,14 @@ export default function RootLayout({
|
|||||||
children,
|
children,
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body className="d-flex flex-column min-vh-100">
|
<body className="d-flex flex-column min-vh-100">
|
||||||
<Header />
|
<Header />
|
||||||
<main className="flex-grow-1 bg-light">
|
<main className="flex-grow-1 bg-light">
|
||||||
{children}
|
{children}
|
||||||
|
{/* <ToastContainer position="top-right" autoClose={3000} /> */}
|
||||||
</main>
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+55
-11
@@ -1,18 +1,36 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { axiosInstance } from "@/api/config";
|
import { axiosInstance } from "@/api/config";
|
||||||
|
import Image from "next/image";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
const router = useRouter();
|
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>) => {
|
const handleOnSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const formData = new FormData(e.currentTarget);
|
// const formData = new FormData(e.currentTarget);
|
||||||
const object = Object.fromEntries(formData);
|
// const object = Object.fromEntries(formData);
|
||||||
|
|
||||||
try {
|
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
|
// Extraer datos del backend
|
||||||
const token = res?.data?.token ?? '';
|
const token = res?.data?.token ?? '';
|
||||||
@@ -31,6 +49,7 @@ export default function Home() {
|
|||||||
localStorage.setItem('nombre', String(nombre));
|
localStorage.setItem('nombre', String(nombre));
|
||||||
localStorage.setItem('idTipoUsuario', String(idTipoUsuario));
|
localStorage.setItem('idTipoUsuario', String(idTipoUsuario));
|
||||||
|
|
||||||
|
|
||||||
// Validar y redirigir según el idTipoUsuario
|
// Validar y redirigir según el idTipoUsuario
|
||||||
if (token && idUsuario && idTipoUsuario) {
|
if (token && idUsuario && idTipoUsuario) {
|
||||||
switch (idTipoUsuario) {
|
switch (idTipoUsuario) {
|
||||||
@@ -48,19 +67,26 @@ export default function Home() {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`Tipo de usuario desconocido: ${idTipoUsuario}`);
|
console.warn(`Tipo de usuario desconocido: ${idTipoUsuario}`);
|
||||||
localStorage.clear();
|
//localStorage.clear();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
localStorage.clear();
|
//localStorage.clear();
|
||||||
console.error('Error: datos de usuario incompletos');
|
console.error('Error: datos de usuario incompletos');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
Swal.fire("Error", "Por favor verifique que el usuario o la contraseña sean correctos.", "error");
|
||||||
|
// toast.error("Usuario o contraseña estan mal")
|
||||||
|
//alert("Usuario o password mal")
|
||||||
console.error('Error en el inicio de sesión:', error);
|
console.error('Error en el inicio de sesión:', error);
|
||||||
localStorage.clear();
|
//localStorage.clear();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const togglePassword = () => {
|
||||||
|
setShowPassword(prev => !prev)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="d-flex justify-content-center align-items-center bg-light" style={{ minHeight: 'calc(100vh - 200px)' }}>
|
<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}>
|
<form className="p-4 shadow rounded bg-white w-100" style={{ maxWidth: '400px' }} onSubmit={handleOnSubmit}>
|
||||||
@@ -68,12 +94,30 @@ export default function Home() {
|
|||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label htmlFor="usuario" className="form-label">Usuario</label>
|
<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>
|
||||||
|
|
||||||
<div className="mb-4">
|
<label htmlFor="password" className="form-label">Contraseña</label>
|
||||||
<label htmlFor="password" className="form-label">Contraseña</label>
|
|
||||||
<input type="password" name="password" id="password" className="form-control" required />
|
<div className="password-wrapper d-flex align-items-center mb-4 p-0">
|
||||||
|
<input id="password" type={showPassword ? "text" : "password"} className="password-input " name="password" onChange={handleChange} required />
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={togglePassword}
|
||||||
|
className="btn btn-light p-1 bg-transparent border-0"
|
||||||
|
aria-label="Mostrar u ocultar contraseña"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={
|
||||||
|
showPassword
|
||||||
|
? "/image/eyeopen.svg"
|
||||||
|
: "/image/eyeclose.svg"
|
||||||
|
}
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
alt="Mostrar u ocultar contraseña"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="d-grid">
|
<div className="d-grid">
|
||||||
|
|||||||
@@ -98,15 +98,15 @@ export default function Page() {
|
|||||||
|
|
||||||
{idServicio !== null && (
|
{idServicio !== null && (
|
||||||
<UploadArchivo
|
<UploadArchivo
|
||||||
path="carta_aceptacion"
|
path="carta_aceptacion"
|
||||||
tipoCarta="aceptación"
|
tipoCarta="aceptación"
|
||||||
variableName="cartaAceptacion"
|
variableName="cartaAceptacion"
|
||||||
idServicio={idServicio}
|
idServicio={idServicio}
|
||||||
responsable={{ tokenArchivo: responsable.tokenArchivo }}
|
responsable={{ tokenArchivo: responsable.tokenArchivo }}
|
||||||
imprimirMensaje={imprimirMensaje}
|
imprimirMensaje={imprimirMensaje}
|
||||||
imprimirWarning={imprimirWarning}
|
imprimirWarning={imprimirWarning}
|
||||||
imprimirError={imprimirError}
|
imprimirError={imprimirError}
|
||||||
updateIsLoading={updateIsLoading}
|
updateIsLoading={updateIsLoading}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { axiosInstance } from "@/api/config";
|
|||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
|
|
||||||
type Responsable = { idUsuario?: number; idTipoUsuario?: number; tipoUsuario?: string | null; token?: string; tokenArchivo?: string };
|
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() {
|
export default function Page() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -16,6 +16,8 @@ export default function Page() {
|
|||||||
const [idServicio, setIdServicio] = useState<number | null>(null);
|
const [idServicio, setIdServicio] = useState<number | null>(null);
|
||||||
const [alumno, setAlumno] = useState<Alumno>({});
|
const [alumno, setAlumno] = useState<Alumno>({});
|
||||||
const [responsable, setResponsable] = useState<Responsable>({});
|
const [responsable, setResponsable] = useState<Responsable>({});
|
||||||
|
// Para verificar que se guardo el idServicio
|
||||||
|
const [isReady, setIsReady] = useState(false);
|
||||||
|
|
||||||
const updateIsLoading = (v: boolean) => setIsLoading(v);
|
const updateIsLoading = (v: boolean) => setIsLoading(v);
|
||||||
|
|
||||||
@@ -54,9 +56,17 @@ export default function Page() {
|
|||||||
const tipoUsuario = localStorage.getItem('tipoUsuario');
|
const tipoUsuario = localStorage.getItem('tipoUsuario');
|
||||||
const token = localStorage.getItem('token') || undefined;
|
const token = localStorage.getItem('token') || undefined;
|
||||||
const tokenArchivo = 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'));
|
const s = Number(localStorage.getItem('idServicio'));
|
||||||
setIdServicio(Number.isNaN(s) ? null : s);
|
setIdServicio(Number.isNaN(s) ? null : s);
|
||||||
|
|
||||||
|
setIsReady(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const obtenerRegistro = async () => {
|
const obtenerRegistro = async () => {
|
||||||
@@ -64,8 +74,12 @@ export default function Page() {
|
|||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const headers = responsable.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
|
const headers = responsable.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
|
||||||
const res = await axiosInstance.get<{ Usuario?: Alumno; Status?: { idStatus?: number } }>(`/servicio/admin?idServicio=${idServicio}`, { headers });
|
const res = await axiosInstance.get<{ usuario?: Alumno; Status?: { idStatus?: number } }>(`/servicio/admin/${idServicio}`);
|
||||||
setAlumno(res.data.Usuario ?? {});
|
|
||||||
|
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);
|
updateIsLoading(false);
|
||||||
const s = res.data.Status?.idStatus ?? 0;
|
const s = res.data.Status?.idStatus ?? 0;
|
||||||
// Se comennto para hacer pruebas
|
// Se comennto para hacer pruebas
|
||||||
@@ -82,20 +96,28 @@ export default function Page() {
|
|||||||
useEffect(() => { getLocalhostInfo(); }, []);
|
useEffect(() => { getLocalhostInfo(); }, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (responsable.idTipoUsuario === 1) router.push('/admin');
|
if (!isReady) return; // Para esperar a que cargue la info del localStorage
|
||||||
if (responsable.idTipoUsuario === 3) router.push('/alumno');
|
|
||||||
if (responsable.idTipoUsuario === 4) router.push('/casoEspecial');
|
if (responsable.idTipoUsuario === 1) router.replace('/admin');
|
||||||
|
if (responsable.idTipoUsuario === 3) router.replace('/alumno');
|
||||||
|
if (responsable.idTipoUsuario === 4) router.replace('/casoEspecial');
|
||||||
|
if (idServicio !== null) {
|
||||||
|
console.log("ID Servicio no es nulo, se obtiene el registro.", idServicio);
|
||||||
|
obtenerRegistro();
|
||||||
|
} else (
|
||||||
|
router.replace('/responsable')
|
||||||
|
)
|
||||||
// Se comento para hacer pruebas
|
// Se comento para hacer pruebas
|
||||||
//if (idServicio === null) router.push('/responsable');
|
//if (idServicio === null) router.push('/responsable');
|
||||||
else if (idServicio !== null) obtenerRegistro();
|
// else if (idServicio !== null) obtenerRegistro();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [responsable, idServicio]);
|
}, [isReady, responsable, idServicio]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="container px-2 pb-6">
|
<section className="container px-2 pb-6">
|
||||||
<BotonRegresar />
|
<BotonRegresar />
|
||||||
|
|
||||||
<h3 className="title">{alumno.nombre} {alumno.usuario}</h3>
|
<h3 className="title">{alumno.nombre}</h3>
|
||||||
|
|
||||||
{idServicio !== null && (
|
{idServicio !== null && (
|
||||||
<UploadArchivo
|
<UploadArchivo
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ export default function Page() {
|
|||||||
const [idServicio, setIdServicio] = useState<number | null>(null);
|
const [idServicio, setIdServicio] = useState<number | null>(null);
|
||||||
const [alumno, setAlumno] = useState<Record<string, unknown> | null>(null);
|
const [alumno, setAlumno] = useState<Record<string, unknown> | null>(null);
|
||||||
const [responsable, setResponsable] = useState<Responsable>({});
|
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);
|
const updateIsLoading = (v: boolean) => setIsLoading(v);
|
||||||
|
|
||||||
@@ -37,7 +41,7 @@ export default function Page() {
|
|||||||
const anyErr = err as { err?: unknown };
|
const anyErr = err as { err?: unknown };
|
||||||
if (anyErr.err === 'token error') {
|
if (anyErr.err === 'token error') {
|
||||||
try { localStorage.clear(); } catch (_) {}
|
try { localStorage.clear(); } catch (_) {}
|
||||||
router.push('/');
|
router.replace('/');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -59,17 +63,24 @@ export default function Page() {
|
|||||||
const idTipoUsuario = Number(localStorage.getItem('idTipoUsuario'));
|
const idTipoUsuario = Number(localStorage.getItem('idTipoUsuario'));
|
||||||
const tipoUsuario = localStorage.getItem('tipoUsuario');
|
const tipoUsuario = localStorage.getItem('tipoUsuario');
|
||||||
const token = localStorage.getItem('token') || undefined;
|
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'));
|
const s = Number(localStorage.getItem('idServicio'));
|
||||||
setIdServicio(Number.isNaN(s) ? null : s);
|
setIdServicio(Number.isNaN(s) ? null : s);
|
||||||
|
|
||||||
|
setIsReady(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const obtenerRegistro = async () => {
|
const obtenerRegistro = async () => {
|
||||||
if (!idServicio) return;
|
if (!idServicio) return;
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const headers = responsable.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
|
//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);
|
setAlumno(res.data.Usuario ?? null);
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
if (res.data.idCuestionarioPrograma) router.push('/responsable');
|
if (res.data.idCuestionarioPrograma) router.push('/responsable');
|
||||||
@@ -90,14 +101,20 @@ export default function Page() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
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 === 1) router.push('/administrador');
|
||||||
if (responsable.idTipoUsuario === 3) router.push('/alumno');
|
if (responsable.idTipoUsuario === 3) router.push('/alumno');
|
||||||
if (responsable.idTipoUsuario === 4) router.push('/casoEspecial');
|
if (responsable.idTipoUsuario === 4) router.push('/casoEspecial');
|
||||||
// Para verificar el servicio
|
// Para verificar el servicio
|
||||||
//if (idServicio === null) router.push('/responsable'); // Esta mal la logica
|
//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
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [responsable, idServicio]);
|
}, [isReady, responsable, idServicio]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="container my-5 px-3">
|
<section className="container my-5 px-3">
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default function Page() {
|
|||||||
const anyErr = err as { err?: unknown };
|
const anyErr = err as { err?: unknown };
|
||||||
if (anyErr.err === 'token error') {
|
if (anyErr.err === 'token error') {
|
||||||
try { localStorage.clear(); } catch (_) {}
|
try { localStorage.clear(); } catch (_) {}
|
||||||
router.push('/');
|
router.replace('/');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -59,7 +59,7 @@ export default function Page() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
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 === 3) router.push('/alumno');
|
||||||
if (responsable.idTipoUsuario === 4) router.push('/casoEspecial');
|
if (responsable.idTipoUsuario === 4) router.push('/casoEspecial');
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
|||||||
@@ -53,17 +53,20 @@ export default function Page() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const r: Responsable = {
|
const r: Responsable = {
|
||||||
idUsuario: Number(localStorage.getItem('idUsuario')) || undefined,
|
idUsuario: Number(localStorage.getItem('idUsuario')) || undefined,
|
||||||
idTipoUsuario: Number(localStorage.getItem('idTipoUsuario')) || undefined,
|
idTipoUsuario: Number(localStorage.getItem('idTipoUsuario')) || undefined,
|
||||||
//tipoUsuario: localStorage.getItem('tipoUsuario') || undefined,
|
//tipoUsuario: localStorage.getItem('tipoUsuario') || undefined,
|
||||||
token: localStorage.getItem('token') || undefined,
|
token: localStorage.getItem('token') || undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
setResponsable(r);
|
setResponsable(r);
|
||||||
console.log('Responsable:', r);
|
console.log('Responsable:', r);
|
||||||
console.log('id Usuario en componente padrre', r.idUsuario);
|
console.log('id Usuario en componente padrre', r.idUsuario);
|
||||||
//ontenerCatalogoStatus();
|
//ontenerCatalogoStatus();
|
||||||
|
|
||||||
|
console.log("Esta es la infromacino del useState en responsable", responsable)
|
||||||
|
|
||||||
if (r.idTipoUsuario === 1) router.push('/administrador');
|
if (r.idTipoUsuario === 1) router.push('/administrador');
|
||||||
if (r.idTipoUsuario === 3) router.push('/alumno');
|
if (r.idTipoUsuario === 3) router.push('/alumno');
|
||||||
if (r.idTipoUsuario === 4) router.push('/casoEspecial');
|
if (r.idTipoUsuario === 4) router.push('/casoEspecial');
|
||||||
@@ -75,8 +78,8 @@ export default function Page() {
|
|||||||
), [responsable]);
|
), [responsable]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="container px-2 pb-6">
|
<section className="container px-2 pb-6 mb-2">
|
||||||
<div className="pt-6 pb-4">
|
<div className="pb-3">
|
||||||
<p className="is-size-4 block mt-5 h4 mb-4">Estimado(a) responsable del programa de servicio social:</p>
|
<p className="is-size-4 block mt-5 h4 mb-4">Estimado(a) responsable del programa de servicio social:</p>
|
||||||
|
|
||||||
<p className="block">
|
<p className="block">
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import { useState } from "react";
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { axiosInstance } from '@/api/config';
|
import { axiosInstance } from '@/api/config';
|
||||||
import { isAxiosError } from 'axios';
|
import { isAxiosError } from 'axios';
|
||||||
import type { AxiosResponse } from 'axios';
|
import type { AxiosError, AxiosResponse } from 'axios';
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
interface Status {
|
interface Status {
|
||||||
idStatus: number;
|
idStatus: number;
|
||||||
@@ -25,7 +26,7 @@ interface Datos {
|
|||||||
//Programa?: Programa
|
//Programa?: Programa
|
||||||
//Carrera?: Carrera;
|
//Carrera?: Carrera;
|
||||||
//Usuario?: Usuario;
|
//Usuario?: Usuario;
|
||||||
Status?: Status;
|
status?: Status;
|
||||||
creditos?: string;
|
creditos?: string;
|
||||||
correo?: string;
|
correo?: string;
|
||||||
fechaRegistro?: string;
|
fechaRegistro?: string;
|
||||||
@@ -57,7 +58,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ApiResponse {
|
interface ApiResponse {
|
||||||
data: { message: string };
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RechazarData {
|
interface RechazarData {
|
||||||
@@ -97,6 +98,11 @@ export default function Archivo({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const rechazarArchivo = () => {
|
const rechazarArchivo = () => {
|
||||||
|
// Depuramos para ver errores
|
||||||
|
console.log("Title", title)
|
||||||
|
console.log("status", datos.status?.idStatus)
|
||||||
|
console.log("idServicio", datos.idServicio)
|
||||||
|
|
||||||
switch (title) {
|
switch (title) {
|
||||||
case "carta de aceptación":
|
case "carta de aceptación":
|
||||||
rechazarFunc(rechazarCartaAceptacion);
|
rechazarFunc(rechazarCartaAceptacion);
|
||||||
@@ -118,18 +124,36 @@ export default function Archivo({
|
|||||||
mensaje: mensajeRechazo,
|
mensaje: mensajeRechazo,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log("Datos para rechazar:", data);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res = await funcRechazar(data);
|
const res = await funcRechazar(data);
|
||||||
localStorage.removeItem("idServicio");
|
localStorage.removeItem("idServicio");
|
||||||
imprimirMensaje(res.data.data.message);
|
|
||||||
router.push("/administrador");
|
console.log("Respuesta al rechazar:", res.data);
|
||||||
|
|
||||||
|
const mensaje = res.data?.message || "Documento rechazado exitosamente";
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Exito',
|
||||||
|
text: mensaje,
|
||||||
|
icon: 'success',
|
||||||
|
})
|
||||||
|
// imprimirMensaje(mensaje);
|
||||||
|
router.replace("/administrador");
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
if (isAxiosError(err)) {
|
const axiosErr = err as AxiosError<any>;
|
||||||
imprimirError(err.response?.data || err.message);
|
const mensaje = axiosErr?.response?.data?.message || 'No se pudo rechazar el documento'
|
||||||
} else {
|
Swal.fire({
|
||||||
imprimirError(err);
|
title: 'Error',
|
||||||
}
|
text: mensaje,
|
||||||
|
icon: 'error',
|
||||||
|
})
|
||||||
|
// if (isAxiosError(err)) {
|
||||||
|
// imprimirError(err.response?.data || err.message);
|
||||||
|
// } else {
|
||||||
|
// imprimirError(err);
|
||||||
|
// }
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -146,19 +170,40 @@ export default function Archivo({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container mb-4">
|
<div className="container mb-4">
|
||||||
<div className="flex items-center">
|
<div className="d-flex align-items-center">
|
||||||
<h5 className="pr-4 text-lg">
|
|
||||||
Ver {title}
|
{/* Texto */}
|
||||||
<a
|
<h5 className="mb-0">
|
||||||
className="btn btn-link btn-light text-decoration-none ms-3 text-morado"
|
Ver {title}
|
||||||
target="_blank"
|
</h5>
|
||||||
rel="noopener noreferrer"
|
|
||||||
href={`https://drive.google.com/file/d/${archivo()}/view?usp=sharing`}
|
<div className="d-flex align-items-center gap-2">
|
||||||
style={{ background: '#eae4f8'}}
|
|
||||||
>
|
<a
|
||||||
Ver
|
className="btn btn-link btn-light text-decoration-none ms-3 text-morado"
|
||||||
</a>
|
target="_blank"
|
||||||
</h5>
|
rel="noopener noreferrer"
|
||||||
|
href={`https://drive.google.com/file/d/${archivo()}/view?usp=sharing`}
|
||||||
|
style={{ background: '#eae4f8'}}
|
||||||
|
>
|
||||||
|
Ver
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{((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">
|
<div className="pr-4">
|
||||||
@@ -173,8 +218,8 @@ export default function Archivo({
|
|||||||
</div>
|
</div>
|
||||||
*/}
|
*/}
|
||||||
|
|
||||||
{((datos.Status?.idStatus === 1 && title === "carta de aceptación") ||
|
{/* {((datos.status?.idStatus === 1 && title === "carta de aceptación") ||
|
||||||
(datos.Status?.idStatus === 5 &&
|
(datos.status?.idStatus === 5 &&
|
||||||
(title === "carta de termino" || title === "informe global"))) && (
|
(title === "carta de termino" || title === "informe global"))) && (
|
||||||
<button
|
<button
|
||||||
className="btn btn-danger"
|
className="btn btn-danger"
|
||||||
@@ -183,11 +228,16 @@ export default function Archivo({
|
|||||||
Rechazar
|
Rechazar
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
</div> */}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{rechazar && (
|
{rechazar && (
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<label>Razón del rechazo:</label>
|
<label>Razón del rechazo (No olvide indicar el documento rechazado):</label>
|
||||||
<textarea
|
<textarea
|
||||||
maxLength={500}
|
maxLength={500}
|
||||||
value={mensajeRechazo}
|
value={mensajeRechazo}
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { axiosInstance } from '@/api/config';
|
import { axiosInstance } from '@/api/config';
|
||||||
import { isAxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
interface Status {
|
interface Status {
|
||||||
idStatus: number;
|
idStatus: number;
|
||||||
@@ -80,12 +81,22 @@ export default function CancelarServicio({
|
|||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res = await axiosInstance.put(`/servicio/cancelar`, data);
|
const res = await axiosInstance.put(`/servicio/cancelar`, data);
|
||||||
localStorage.removeItem("idServicio");
|
localStorage.removeItem("idServicio");
|
||||||
imprimirMensaje(res.data.message);
|
|
||||||
router.push("/admin");
|
Swal.fire('Exito', res.data.message, 'success')
|
||||||
|
// imprimirMensaje(res.data.message);
|
||||||
|
router.push("/administrador");
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
|
const axiosErr = err as AxiosError<any>;
|
||||||
else if (err instanceof Error) imprimirError(err.message);
|
const mensaje = axiosErr?.response?.data?.message || 'No se pudo cancelar el servicio, intentelo mas tarde.';
|
||||||
else imprimirError(err);
|
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'error',
|
||||||
|
title: 'Error',
|
||||||
|
text: mensaje,
|
||||||
|
})
|
||||||
|
// if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
|
||||||
|
// else if (err instanceof Error) imprimirError(err.message);
|
||||||
|
// else imprimirError(err);
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,30 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { axiosInstance } from "@/api/config";
|
import { axiosInstance } from "@/api/config";
|
||||||
import { CargaMasivaProps } from "@/types/responses";
|
import { CargaMasivaProps } from "@/types/responses";
|
||||||
|
import { AxiosError } from "axios";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Button, Form } from "react-bootstrap";
|
import { Button, Form } from "react-bootstrap";
|
||||||
import { FaUpload } from "react-icons/fa";
|
import { FaUpload } from "react-icons/fa6";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
export default function CargaMasiva({datos}: {datos: CargaMasivaProps}) {
|
export default function CargaMasiva({datos}: {datos: CargaMasivaProps}) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [csv, setCsv] = useState<File | null>(null)
|
const [csv, setCsv] = useState<File | null>(null)
|
||||||
|
|
||||||
const url = process.env.NEXT_PUBLIC_API_URL
|
//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`)
|
//const [link] = useState(`${url}/plantilla.csv`)
|
||||||
|
|
||||||
|
//console.log("Esta es la url para descargar la plantilla", link);
|
||||||
|
|
||||||
const validarExt = (file: File | null) => {
|
const validarExt = (file: File | null) => {
|
||||||
if (!file) return
|
if (!file) return
|
||||||
const extPermitidas = /(.csv)$/i
|
const extPermitidas = /(.csv)$/i
|
||||||
@@ -38,18 +49,40 @@ export default function CargaMasiva({datos}: {datos: CargaMasivaProps}) {
|
|||||||
//updateIsLoading(true)
|
//updateIsLoading(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await axiosInstance.post("/programa/carga_masiva", formData,{
|
|
||||||
|
console.log("Este es el archivo csv", formData)
|
||||||
|
|
||||||
|
// Cambioamos a variable de entorno
|
||||||
|
const res = await axiosInstance.post(`${process.env.NEXT_PUBLIC_API_URL}/programa/carga_masiva`, formData,{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${datos.admin.tokenArchivo}`,
|
Authorization: `Bearer ${datos.admin.tokenArchivo}`,
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
console.log('Respuesta de carga masiva:', res.data)
|
console.log('Respuesta de carga masiva:', res.data)
|
||||||
//updateIsLoading(false)
|
//updateIsLoading(false)
|
||||||
//ImprimirMensaje(res.data.message)
|
//ImprimirMensaje(res.data.message)
|
||||||
router.push("/administrador/responsables")
|
const message = res?.data?.message || 'Se completo la carga masiva con exito.';
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Archivo enviado',
|
||||||
|
text: message, //'El archivo se subió correctamente'
|
||||||
|
icon: 'success',
|
||||||
|
});
|
||||||
|
setCsv(null);
|
||||||
|
//alert("Se subio la carga masiva correctamente.");
|
||||||
|
//router.push("/administrador/responsables")
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
//updateIsLoading(false)
|
//updateIsLoading(false)
|
||||||
//imprimirError(error.response.data || error)
|
//imprimirError(error.response.data || error)
|
||||||
|
|
||||||
|
const axiosErr = error as AxiosError<any>;
|
||||||
|
const mensaje = axiosErr?.response?.data?.message || 'Error en la carga masiva.'
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error al enviar el archivo',
|
||||||
|
text: mensaje,
|
||||||
|
icon: 'error',
|
||||||
|
})
|
||||||
|
setCsv(null)
|
||||||
console.log('Error en carga masiva:', error)
|
console.log('Error en carga masiva:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,16 +119,17 @@ export default function CargaMasiva({datos}: {datos: CargaMasivaProps}) {
|
|||||||
disabled={!csv}
|
disabled={!csv}
|
||||||
onClick={enviarCargaMasiva}>
|
onClick={enviarCargaMasiva}>
|
||||||
Enviar archivo
|
Enviar archivo
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
href={link}
|
type="button"
|
||||||
target="_blank"
|
onClick={handleDowload}
|
||||||
rel="noopener noreferrer"
|
// target="_blank"
|
||||||
|
// rel="noopener noreferrer"
|
||||||
className="bg-morado border-morado"
|
className="bg-morado border-morado"
|
||||||
>
|
>
|
||||||
Descargar plantilla
|
Descargar plantilla
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { isAxiosError } from 'axios';
|
import { isAxiosError } from 'axios';
|
||||||
import { axiosInstance } from '@/api/config';
|
import { axiosInstance } from '@/api/config';
|
||||||
import type { AxiosResponse } from 'axios';
|
import { AxiosError, AxiosResponse } from 'axios';
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { Carrera, Usuario } from "@/types/responses";
|
import { Carrera, Usuario } from "@/types/responses";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
interface Status {
|
interface Status {
|
||||||
idStatus: number;
|
idStatus: number;
|
||||||
@@ -11,6 +12,8 @@ interface Status {
|
|||||||
|
|
||||||
interface Programa {
|
interface Programa {
|
||||||
acatlan?: boolean;
|
acatlan?: boolean;
|
||||||
|
clavePrograma?: string;
|
||||||
|
programa?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Alumno {
|
interface Alumno {
|
||||||
@@ -24,10 +27,10 @@ interface Admin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Datos {
|
interface Datos {
|
||||||
Programa?: Programa;
|
programa?: Programa;
|
||||||
//Carrera?: Carrera;
|
//Carrera?: Carrera;
|
||||||
//Usuario?: Usuario;
|
//Usuario?: Usuario;
|
||||||
Status?: Status;
|
status?: Status;
|
||||||
creditos?: string;
|
creditos?: string;
|
||||||
correo?: string;
|
correo?: string;
|
||||||
fechaRegistro?: string;
|
fechaRegistro?: string;
|
||||||
@@ -83,9 +86,11 @@ export default function ConfirmarServicio({
|
|||||||
const [vistoBuenoAcatlan, setVistoBuenoAcatlan] = useState(false);
|
const [vistoBuenoAcatlan, setVistoBuenoAcatlan] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
console.log("Datos resividos de datod", datos)
|
||||||
|
|
||||||
const confirmarServicio = () => {
|
const confirmarServicio = () => {
|
||||||
if (datos.Status?.idStatus === 1) confirmar(confirmarPreRegistro);
|
if (datos.status?.idStatus === 1) confirmar(confirmarPreRegistro);
|
||||||
else if (datos.Status?.idStatus === 5) confirmar(confirmarLiberacion);
|
else if (datos.status?.idStatus === 5) confirmar(confirmarLiberacion);
|
||||||
};
|
};
|
||||||
|
|
||||||
const confirmar = async (
|
const confirmar = async (
|
||||||
@@ -97,20 +102,33 @@ export default function ConfirmarServicio({
|
|||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res = await funcConfirmar(data);
|
const res = await funcConfirmar(data);
|
||||||
// ✅ TS sabe que res.data.message existe
|
// ✅ TS sabe que res.data.message existe
|
||||||
imprimirMensaje(res.data.message);
|
Swal.fire({
|
||||||
router.push("/admin");
|
icon: 'success',
|
||||||
|
title: 'Exito',
|
||||||
|
text: res.data.message,
|
||||||
|
});
|
||||||
|
// imprimirMensaje(res.data.message);
|
||||||
|
router.replace("/administrador");
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
if (isAxiosError(err)) {
|
const axiosErr = err as AxiosError<any>;
|
||||||
imprimirError(err.response?.data || err.message);
|
const mensaje = axiosErr?.response?.data?.message || 'No se pudo confirmar el servicio, por favor intentelo mas tarde.';
|
||||||
} else {
|
|
||||||
imprimirError(err);
|
Swal.fire({
|
||||||
}
|
icon: 'error',
|
||||||
|
title: 'Error',
|
||||||
|
text: mensaje,
|
||||||
|
});
|
||||||
|
// if (isAxiosError(err)) {
|
||||||
|
// imprimirError(err.response?.data || err.message);
|
||||||
|
// } else {
|
||||||
|
// imprimirError(err);
|
||||||
|
// }
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const confirmarPreRegistro = (data: ConfirmarData) =>
|
const confirmarPreRegistro = (data: ConfirmarData) =>
|
||||||
axiosInstance.put<ApiResponse>(`/servicio/registro`, data);
|
axiosInstance.put<ApiResponse>(`/servicio/registro`, data);
|
||||||
|
|
||||||
const confirmarLiberacion = (data: ConfirmarData) => {
|
const confirmarLiberacion = (data: ConfirmarData) => {
|
||||||
@@ -118,9 +136,29 @@ export default function ConfirmarServicio({
|
|||||||
return axiosInstance.put<ApiResponse>(`/servicio/liberacion`, data);
|
return axiosInstance.put<ApiResponse>(`/servicio/liberacion`, data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Validar las claves permitidas en un arreglo
|
||||||
|
const clavesPermitidas = process.env.NEXT_PUBLIC_CP?.split(',').map(c => c.trim()) || [];
|
||||||
|
|
||||||
|
const confirma = () => {
|
||||||
|
Swal.fire({
|
||||||
|
title: "¿Seguro(a) que quieres confirmar este servicio?",
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: 'confirmar',
|
||||||
|
cancelButtonText: 'cancelar',
|
||||||
|
confirmButtonColor: "#0d6efd",
|
||||||
|
cancelButtonColor: "#dc3545",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
confirmarServicio();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container space-y-4">
|
// datos.Programa?.acatlan && datos.programa?.programa === clavesPermitidas &&
|
||||||
{datos.Status?.idStatus === 5 && datos.Programa?.acatlan && (
|
<div className="container space-y-4">
|
||||||
|
{datos.status?.idStatus === 5 && clavesPermitidas.includes(datos?.programa?.clavePrograma || '') && (
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -129,28 +167,23 @@ export default function ConfirmarServicio({
|
|||||||
onChange={(e) => setVistoBuenoAcatlan(e.target.checked)}
|
onChange={(e) => setVistoBuenoAcatlan(e.target.checked)}
|
||||||
className="form-checkbox h-5 w-5 text-blue-600"
|
className="form-checkbox h-5 w-5 text-blue-600"
|
||||||
/>
|
/>
|
||||||
<label htmlFor="vistoBuenoAcatlan" className="text-gray-700">
|
<label htmlFor="vistoBuenoAcatlan" className="text-gray-700 mb-4 me-2 ms-2">
|
||||||
Visto bueno Acatlán
|
Visto bueno Acatlán
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(datos.Status?.idStatus === 1 || datos.Status?.idStatus === 5) && (
|
{(datos.status?.idStatus === 1 || datos.status?.idStatus === 5) && (
|
||||||
<button
|
<button
|
||||||
disabled={
|
disabled={
|
||||||
datos.Status?.idStatus === 5 &&
|
datos.status?.idStatus === 5 &&
|
||||||
datos.Programa?.acatlan &&
|
datos.programa?.acatlan &&
|
||||||
!vistoBuenoAcatlan
|
!vistoBuenoAcatlan
|
||||||
}
|
}
|
||||||
onClick={() =>
|
onClick={confirma}
|
||||||
imprimirWarning(
|
|
||||||
"¿Seguro(a) que quieres confirmar este servicio?",
|
|
||||||
confirmarServicio
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className={`px-4 py-2 rounded text-white ${
|
className={`px-4 py-2 rounded text-white ${
|
||||||
datos.Status?.idStatus === 5 &&
|
datos.status?.idStatus === 5 &&
|
||||||
datos.Programa?.acatlan &&
|
datos.programa?.acatlan &&
|
||||||
!vistoBuenoAcatlan
|
!vistoBuenoAcatlan
|
||||||
? "bg-gray-400 cursor-not-allowed"
|
? "bg-gray-400 cursor-not-allowed"
|
||||||
: "bg-green-600 hover:bg-green-700"
|
: "bg-green-600 hover:bg-green-700"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { axiosInstance } from "@/api/config";
|
|||||||
import { error } from "console";
|
import { error } from "console";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Button, Col, FormGroup, FormLabel, FormSelect, InputGroup } from "react-bootstrap";
|
import { Button, Col, FormGroup, FormLabel, FormSelect, InputGroup } from "react-bootstrap";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
years: number[];
|
years: number[];
|
||||||
@@ -19,8 +20,33 @@ export default function Cuestionario({ years, admin, updateIsLoading }: Props) {
|
|||||||
try {
|
try {
|
||||||
//updateIsLoading(true);
|
//updateIsLoading(true);
|
||||||
//const res = await axiosInstance.get(`/cuestionario_alumno?year=${selectedCuestionario}&version=${version}`, {
|
//const res = await axiosInstance.get(`/cuestionario_alumno?year=${selectedCuestionario}&version=${version}`, {
|
||||||
const res = await axiosInstance.get(`/cuestionario_alumno`, {
|
|
||||||
params: { year: selectedYear, version },
|
// Hacer la validacion de que tipo de cuestionario quiere
|
||||||
|
// if(selectedCuestionario === "cuestionario_alumno") {
|
||||||
|
// var res = await axiosInstance.get(`/cuestionario-alumno2`, {
|
||||||
|
// params: { anio: selectedYear, version },
|
||||||
|
// responseType: "blob",
|
||||||
|
// });
|
||||||
|
// } else if(selectedCuestionario === "cuestionario_programa") {
|
||||||
|
// var res = await axiosInstance.get(`/cuestionario-programa2`, {
|
||||||
|
// params: { anio: selectedYear, version },
|
||||||
|
// responseType: "blob",
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// Swal.fire({
|
||||||
|
// title: 'Error',
|
||||||
|
// text: 'Seleccione un cuestionario válido.',
|
||||||
|
// icon: 'error',
|
||||||
|
// })
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// antes
|
||||||
|
|
||||||
|
console.log("Estos son los datos que se van a enviar para descargar el cuestionario", { selectedCuestionario, version, selectedYear })
|
||||||
|
|
||||||
|
const res = await axiosInstance.get(`/${selectedCuestionario}`, {
|
||||||
|
params: { anio: selectedYear, version },
|
||||||
responseType: "blob",
|
responseType: "blob",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -48,12 +74,25 @@ export default function Cuestionario({ years, admin, updateIsLoading }: Props) {
|
|||||||
link.remove();
|
link.remove();
|
||||||
window.URL.revokeObjectURL(url);
|
window.URL.revokeObjectURL(url);
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Éxito',
|
||||||
|
text: 'Se descargo el cuestionario exitosamente.',
|
||||||
|
icon: 'success',
|
||||||
|
})
|
||||||
|
|
||||||
// reset
|
// reset
|
||||||
setSelectedYear("");
|
setSelectedYear("");
|
||||||
setSelectedCuestionario("");
|
setSelectedCuestionario("");
|
||||||
setVersion("");
|
setVersion("");
|
||||||
//updateIsLoading(false);
|
//updateIsLoading(false);
|
||||||
} catch (err: unknown) {
|
} catch (err) {
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error',
|
||||||
|
text: 'Error al descargar el cuestionario.',
|
||||||
|
icon: 'error',
|
||||||
|
})
|
||||||
|
|
||||||
console.error("Error en descargar el formulario", err)
|
console.error("Error en descargar el formulario", err)
|
||||||
//updateIsLoading(false);
|
//updateIsLoading(false);
|
||||||
// optional: handle error, e.g. console.error(err)
|
// optional: handle error, e.g. console.error(err)
|
||||||
@@ -71,8 +110,8 @@ export default function Cuestionario({ years, admin, updateIsLoading }: Props) {
|
|||||||
<InputGroup>
|
<InputGroup>
|
||||||
<FormSelect onChange={(e) => setSelectedCuestionario(e.target.value)}>
|
<FormSelect onChange={(e) => setSelectedCuestionario(e.target.value)}>
|
||||||
<option value="">Seleccione un cuestionario:</option>
|
<option value="">Seleccione un cuestionario:</option>
|
||||||
<option value="cuestionario_alumno">Cuestionario de Alumnos</option>
|
<option value="cuestionario-alumno2">Cuestionario de Alumnos</option>
|
||||||
<option value="cuestionario_programa">Cuestionario de Programas</option>
|
<option value="cuestionario-programa2">Cuestionario de Programas</option>
|
||||||
</FormSelect>
|
</FormSelect>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ import validator from "validator";
|
|||||||
import DatePicker from "react-datepicker";
|
import DatePicker from "react-datepicker";
|
||||||
import "react-datepicker/dist/react-datepicker.css";
|
import "react-datepicker/dist/react-datepicker.css";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
import { registerLocale } from "react-datepicker";
|
||||||
|
import { es } from "date-fns/locale/es";
|
||||||
|
import { Col, FormGroup, FormLabel, InputGroup } from "react-bootstrap";
|
||||||
|
import { FaRegCalendar } from "react-icons/fa6";
|
||||||
|
|
||||||
|
registerLocale("es", es);
|
||||||
|
|
||||||
interface Viejo {
|
interface Viejo {
|
||||||
correo?: string;
|
correo?: string;
|
||||||
@@ -22,7 +28,9 @@ interface Viejo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Admin {
|
interface Admin {
|
||||||
token: { headers: Record<string, string> };
|
idTipoUsuario: number;
|
||||||
|
tipoUsuario?: string;
|
||||||
|
token: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -84,7 +92,12 @@ export default function EditarAlumno({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const actualizar = async () => {
|
const actualizar = async () => {
|
||||||
const data: Record<string, unknown> = { idCasoEspecial };
|
const data: Record<string, unknown> = { idCasoEspecial };
|
||||||
|
|
||||||
|
if (!data.idCasoEspecial) {
|
||||||
|
console.log('No tiene el id')
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (nuevo.direccion) data.direccion = nuevo.direccion;
|
if (nuevo.direccion) data.direccion = nuevo.direccion;
|
||||||
if (nuevo.correo) data.correo = nuevo.correo;
|
if (nuevo.correo) data.correo = nuevo.correo;
|
||||||
@@ -92,16 +105,18 @@ export default function EditarAlumno({
|
|||||||
if (nuevo.motivo) data.motivo = nuevo.motivo;
|
if (nuevo.motivo) data.motivo = nuevo.motivo;
|
||||||
if (nuevo.dependencia) data.dependencia = nuevo.dependencia;
|
if (nuevo.dependencia) data.dependencia = nuevo.dependencia;
|
||||||
if (nuevo.institucion) data.institucion = nuevo.institucion;
|
if (nuevo.institucion) data.institucion = nuevo.institucion;
|
||||||
if (nuevo.fechaInicio) data.fechaInicio = moment(nuevo.fechaInicio).toDate();
|
if (nuevo.fechaInicio) data.fechaInicio = formatDate(nuevo.fechaInicio);
|
||||||
if (nuevo.fechaFin) data.fechaFin = moment(nuevo.fechaFin).toDate();
|
if (nuevo.fechaFin) data.fechaFin = formatDate(nuevo.fechaFin);
|
||||||
if (nuevo.fechaNacimiento)
|
if (nuevo.fechaNacimiento)
|
||||||
data.fechaNacimiento = moment(nuevo.fechaNacimiento).toDate();
|
data.fechaNacimiento = formatDate(nuevo.fechaNacimiento);
|
||||||
|
|
||||||
|
console.log('Esta es la info', data);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res = await axiosInstance.put(`/caso_especial/update`, data, admin.token);
|
const res = await axiosInstance.put(`/caso-especial/update/${idCasoEspecial}`, data);
|
||||||
imprimirMensaje(res.data.message);
|
imprimirMensaje(res.data.message);
|
||||||
router.push("/admin/casos_especiales/caso_especial");
|
router.push("/administrador/casos_especiales");
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
let msg: unknown = err;
|
let msg: unknown = err;
|
||||||
if (isAxiosError(err) && err.response?.data) {
|
if (isAxiosError(err) && err.response?.data) {
|
||||||
@@ -110,65 +125,139 @@ export default function EditarAlumno({
|
|||||||
msg = err.message;
|
msg = err.message;
|
||||||
}
|
}
|
||||||
imprimirError(msg);
|
imprimirError(msg);
|
||||||
|
router.replace('/adminsitrador/casos_especiales')
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const formatDate = (date: Date) => {
|
||||||
|
return date.toISOString().split("T")[0];
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4 mt-6">
|
<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 */}
|
{/* Correo */}
|
||||||
<div>
|
<div className="mb-3">
|
||||||
<label className="block mb-1 font-medium">Correo electrónico</label>
|
<label className="form-label fw-semibold block mb-1 font-medium">Correo electrónico</label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
placeholder={viejo.correo}
|
placeholder={viejo.correo}
|
||||||
value={nuevo.correo || ""}
|
value={nuevo.correo || ""}
|
||||||
onChange={(e) => setNuevo({ ...nuevo, correo: e.target.value })}
|
onChange={(e) => setNuevo({ ...nuevo, correo: e.target.value })}
|
||||||
className="border rounded p-2 w-full"
|
className="form-control border rounded p-2 w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Teléfono */}
|
{/* Teléfono */}
|
||||||
<div>
|
<div className="mb-3">
|
||||||
<label className="block mb-1 font-medium">Teléfono</label>
|
<label className="form-label fw-semibold block mb-1 font-medium">Teléfono</label>
|
||||||
<input
|
<input
|
||||||
type="tel"
|
type="tel"
|
||||||
maxLength={10}
|
maxLength={10}
|
||||||
placeholder={viejo.telefono}
|
placeholder={viejo.telefono}
|
||||||
value={nuevo.telefono || ""}
|
value={nuevo.telefono || ""}
|
||||||
onChange={(e) => setNuevo({ ...nuevo, telefono: e.target.value })}
|
onChange={(e) => setNuevo({ ...nuevo, telefono: e.target.value })}
|
||||||
className="border rounded p-2 w-full"
|
className="form-control border rounded p-2 w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Dirección */}
|
{/* Dirección */}
|
||||||
<div>
|
<div className="mb-3">
|
||||||
<label className="block mb-1 font-medium">Dirección</label>
|
<label className="form-label fw-semibold block mb-1 font-medium">Dirección</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={viejo.direccion}
|
placeholder={viejo.direccion}
|
||||||
value={nuevo.direccion || ""}
|
value={nuevo.direccion || ""}
|
||||||
onChange={(e) => setNuevo({ ...nuevo, direccion: e.target.value })}
|
onChange={(e) => setNuevo({ ...nuevo, direccion: e.target.value })}
|
||||||
className="border rounded p-2 w-full"
|
className="form-control border rounded p-2 w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Col>
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>
|
||||||
|
Fecha de inicio
|
||||||
|
</FormLabel>
|
||||||
|
<InputGroup>
|
||||||
|
<InputGroup.Text>
|
||||||
|
<FaRegCalendar />
|
||||||
|
</InputGroup.Text>
|
||||||
|
<DatePicker
|
||||||
|
selected={nuevo.fechaInicio}
|
||||||
|
onChange={(date) => setNuevo({ ...nuevo, fechaInicio: date || undefined })}
|
||||||
|
minDate={minDate1}
|
||||||
|
placeholderText={fecha(viejo.fechaInicio)}
|
||||||
|
className="form-control"
|
||||||
|
wrapperClassName="flex-grow-1"
|
||||||
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={60}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale="es"
|
||||||
|
/>
|
||||||
|
</InputGroup>
|
||||||
|
</FormGroup>
|
||||||
|
</Col>
|
||||||
|
|
||||||
{/* Fecha inicio */}
|
{/* Fecha inicio */}
|
||||||
<div>
|
{/* <div>
|
||||||
<label className="block mb-1 font-medium">Fecha de inicio</label>
|
<label className="form-label fw-semibold block mb-1 font-medium">Fecha de inicio</label>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
selected={nuevo.fechaInicio}
|
selected={nuevo.fechaInicio}
|
||||||
onChange={(date) => setNuevo({ ...nuevo, fechaInicio: date || undefined })}
|
onChange={(date) => setNuevo({ ...nuevo, fechaInicio: date || undefined })}
|
||||||
minDate={minDate1}
|
minDate={minDate1}
|
||||||
placeholderText={fecha(viejo.fechaInicio)}
|
placeholderText={fecha(viejo.fechaInicio)}
|
||||||
className="border rounded p-2 w-full"
|
className="form-control"
|
||||||
/>
|
wrapperClassName="flex-grow-1"
|
||||||
</div>
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
{/* Fecha fin */}
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={60}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale="es"
|
||||||
|
/>
|
||||||
|
</div> */}
|
||||||
|
|
||||||
|
<Col>
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>Fecha de fin</FormLabel>
|
||||||
|
<InputGroup>
|
||||||
|
<InputGroup.Text>
|
||||||
|
<FaRegCalendar />
|
||||||
|
</InputGroup.Text>
|
||||||
|
<DatePicker
|
||||||
|
selected={nuevo.fechaFin}
|
||||||
|
onChange={(date) => setNuevo({ ...nuevo, fechaFin: date || undefined })}
|
||||||
|
minDate={minDate2}
|
||||||
|
placeholderText={fecha(viejo.fechaFin)}
|
||||||
|
dateFormat={'dd-MM-yyyy'}
|
||||||
|
className="form-control"
|
||||||
|
wrapperClassName="flex-grow-1"
|
||||||
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={60}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale='es'
|
||||||
|
/>
|
||||||
|
</InputGroup>
|
||||||
|
</FormGroup>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
{/* Fecha fin
|
||||||
{nuevo.fechaInicio && (
|
{nuevo.fechaInicio && (
|
||||||
<div>
|
<div>
|
||||||
<label className="block mb-1 font-medium">Fecha de fin</label>
|
<label className="block mb-1 font-medium">Fecha de fin</label>
|
||||||
@@ -178,29 +267,61 @@ export default function EditarAlumno({
|
|||||||
minDate={minDate2}
|
minDate={minDate2}
|
||||||
placeholderText={fecha(viejo.fechaFin)}
|
placeholderText={fecha(viejo.fechaFin)}
|
||||||
className="border rounded p-2 w-full"
|
className="border rounded p-2 w-full"
|
||||||
|
|
||||||
|
locale='es'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)} */}
|
||||||
|
|
||||||
|
<Col>
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>Fecha de nacimiento</FormLabel>
|
||||||
|
<InputGroup>
|
||||||
|
<InputGroup.Text>
|
||||||
|
<FaRegCalendar />
|
||||||
|
</InputGroup.Text>
|
||||||
|
<DatePicker
|
||||||
|
selected={nuevo.fechaNacimiento}
|
||||||
|
onChange={(date) => setNuevo({ ...nuevo, fechaNacimiento: date || undefined })}
|
||||||
|
placeholderText={fecha(viejo.fechaNacimiento)}
|
||||||
|
dateFormat={'dd-MM-yyyy'}
|
||||||
|
className="form-control"
|
||||||
|
wrapperClassName="flex-grow-1"
|
||||||
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={60}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale='es'
|
||||||
|
/>
|
||||||
|
</InputGroup>
|
||||||
|
</FormGroup>
|
||||||
|
</Col>
|
||||||
|
|
||||||
{/* Fecha nacimiento */}
|
{/* Fecha nacimiento */}
|
||||||
<div>
|
{/* <div>
|
||||||
<label className="block mb-1 font-medium">Fecha de nacimiento</label>
|
<label className="block mb-1 font-medium">Fecha de nacimiento</label>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
selected={nuevo.fechaNacimiento}
|
selected={nuevo.fechaNacimiento}
|
||||||
onChange={(date) => setNuevo({ ...nuevo, fechaNacimiento: date || undefined })}
|
onChange={(date) => setNuevo({ ...nuevo, fechaNacimiento: date || undefined })}
|
||||||
placeholderText={fecha(viejo.fechaNacimiento)}
|
placeholderText={fecha(viejo.fechaNacimiento)}
|
||||||
className="border rounded p-2 w-full"
|
className="form-control border rounded p-2 w-full"
|
||||||
|
|
||||||
|
locale='es'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
{/* Motivo */}
|
{/* Motivo */}
|
||||||
{viejo.motivo && (
|
{viejo.motivo && (
|
||||||
<div>
|
<div className="mb-3">
|
||||||
<label className="block mb-1 font-medium">Motivo</label>
|
<label className="form-label fw-semibold block mb-1 font-medium">Motivo</label>
|
||||||
<select
|
<select
|
||||||
value={nuevo.motivo || ""}
|
value={nuevo.motivo || ""}
|
||||||
onChange={(e) => setNuevo({ ...nuevo, motivo: e.target.value })}
|
onChange={(e) => setNuevo({ ...nuevo, motivo: e.target.value })}
|
||||||
className="border rounded p-2 w-full my-2"
|
className="form-control border rounded p-2 w-full my-2"
|
||||||
>
|
>
|
||||||
<option value="">Seleccione...</option>
|
<option value="">Seleccione...</option>
|
||||||
<option value="1">Tercera edad</option>
|
<option value="1">Tercera edad</option>
|
||||||
@@ -211,28 +332,28 @@ export default function EditarAlumno({
|
|||||||
|
|
||||||
{/* Dependencia */}
|
{/* Dependencia */}
|
||||||
{viejo.dependencia && (
|
{viejo.dependencia && (
|
||||||
<div>
|
<div className="mb-3">
|
||||||
<label className="block mb-1 font-medium">Dependencia</label>
|
<label className="form-label fw-semibold block mb-1 font-medium">Dependencia</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={viejo.dependencia}
|
placeholder={viejo.dependencia}
|
||||||
value={nuevo.dependencia || ""}
|
value={nuevo.dependencia || ""}
|
||||||
onChange={(e) => setNuevo({ ...nuevo, dependencia: e.target.value })}
|
onChange={(e) => setNuevo({ ...nuevo, dependencia: e.target.value })}
|
||||||
className="border rounded p-2 w-full"
|
className="form-control border rounded p-2 w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Institución */}
|
{/* Institución */}
|
||||||
{viejo.institucion && (
|
{viejo.institucion && (
|
||||||
<div>
|
<div className="mb-3">
|
||||||
<label className="block mb-1 font-medium">Institución</label>
|
<label className="form-label fw-semibold block mb-1 font-medium">Institución</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={viejo.institucion}
|
placeholder={viejo.institucion}
|
||||||
value={nuevo.institucion || ""}
|
value={nuevo.institucion || ""}
|
||||||
onChange={(e) => setNuevo({ ...nuevo, institucion: e.target.value })}
|
onChange={(e) => setNuevo({ ...nuevo, institucion: e.target.value })}
|
||||||
className="border rounded p-2 w-full"
|
className="form-control border rounded p-2 w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { axiosInstance } from "@/api/config";
|
|||||||
import { isAxiosError } from "axios";
|
import { isAxiosError } from "axios";
|
||||||
import validator from "validator";
|
import validator from "validator";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
interface Responsable {
|
interface Responsable {
|
||||||
idUsuario?: number;
|
idUsuario?: number;
|
||||||
@@ -26,6 +27,11 @@ interface Props {
|
|||||||
updateIsLoading: (value: boolean) => void;
|
updateIsLoading: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function convertirFecha(fecha: string | Date) {
|
||||||
|
return new Date(fecha).toISOString().split("T")[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export default function EditarResponsable({
|
export default function EditarResponsable({
|
||||||
//admin,
|
//admin,
|
||||||
responsable,
|
responsable,
|
||||||
@@ -52,25 +58,81 @@ export default function EditarResponsable({
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Funcion para confirmar actualizacion
|
||||||
|
const confirmarActualizacion = () => {
|
||||||
|
Swal.fire({
|
||||||
|
title: '¿Seguro(a) que quiere actualizar la información de este usuario?',
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Sí, actualizar",
|
||||||
|
cancelButtonText: "Cancelar",
|
||||||
|
confirmButtonColor: "#0d6efd",
|
||||||
|
cancelButtonColor: "#dc3545",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
actualizar(); // 👈 aquí ejecutas la función
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmarCambioPassword = () => {
|
||||||
|
Swal.fire({
|
||||||
|
title: '¿Seguro(a) que quiere cambiar la contraseña para este usuario?',
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Sí, actualizar",
|
||||||
|
cancelButtonText: "Cancelar",
|
||||||
|
confirmButtonColor: "#0d6efd",
|
||||||
|
cancelButtonColor: "#dc3545",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
password(); // 👈 aquí ejecutas la función
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Actualizar información del responsable
|
// Actualizar información del responsable
|
||||||
const actualizar = async () => {
|
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.correo) data.correo = nuevo.correo;
|
||||||
if (nuevo.nombre) data.nombre = nuevo.nombre;
|
if (nuevo.nombre) data.nombre = nuevo.nombre;
|
||||||
|
|
||||||
|
// Hacemos el parseo de la fecha
|
||||||
|
//data.fechaNacimiento = convertirFecha(data.fechaNacimiento);
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
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) {
|
Swal.fire({
|
||||||
let msg: unknown = err;
|
title: 'Éxito',
|
||||||
if (isAxiosError(err) && err.response?.data) {
|
text: 'Se actualizaron los datos correctamente',
|
||||||
msg = err.response.data;
|
icon: 'success',
|
||||||
} else if (err instanceof Error) {
|
})
|
||||||
msg = err.message;
|
|
||||||
}
|
//imprimirMensaje(res.data.message);
|
||||||
imprimirError(msg);
|
router.replace("/administrador/responsables/responsable");
|
||||||
|
} catch (err) {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error',
|
||||||
|
text: 'Error al actualizar los datos',
|
||||||
|
icon: 'error',
|
||||||
|
})
|
||||||
|
// let msg: unknown = err;
|
||||||
|
// if (isAxiosError(err) && 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;
|
||||||
|
// }
|
||||||
|
// imprimirError(msg);
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -80,21 +142,39 @@ export default function EditarResponsable({
|
|||||||
const password = async () => {
|
const password = async () => {
|
||||||
const data = { idUsuario: responsable.idUsuario };
|
const data = { idUsuario: responsable.idUsuario };
|
||||||
|
|
||||||
|
const idResponsable = localStorage.getItem("idResponsable");
|
||||||
|
|
||||||
|
if (!idResponsable) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
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");
|
Swal.fire({
|
||||||
} catch (err: unknown) {
|
title: 'Éxito',
|
||||||
let msg: unknown = err;
|
text: 'Se envio la nueva contraseña al responsable',
|
||||||
if (isAxiosError(err) && err.response?.data) {
|
icon: 'success',
|
||||||
msg = err.response.data;
|
})
|
||||||
} else if (err instanceof Error) {
|
|
||||||
msg = err.message;
|
//imprimirMensaje(res.data.message);
|
||||||
}
|
router.replace("/administrador/responsables/responsable");
|
||||||
imprimirError(msg);
|
} catch (err) {
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error',
|
||||||
|
text: 'Error al actualizar la contraseña del responsable',
|
||||||
|
icon: 'error',
|
||||||
|
})
|
||||||
|
|
||||||
|
// let msg: unknown = err;
|
||||||
|
// if (isAxiosError(err) && err.response?.data) {
|
||||||
|
// msg = err.response.data;
|
||||||
|
// } else if (err instanceof Error) {
|
||||||
|
// msg = err.message;
|
||||||
|
// }
|
||||||
|
// imprimirError(msg);
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -133,12 +213,7 @@ export default function EditarResponsable({
|
|||||||
<div className="pt-5 flex gap-4">
|
<div className="pt-5 flex gap-4">
|
||||||
<button
|
<button
|
||||||
disabled={mostrarBoton()}
|
disabled={mostrarBoton()}
|
||||||
onClick={() =>
|
onClick={confirmarActualizacion}
|
||||||
imprimirWarning(
|
|
||||||
"¿Seguro(a) que quiere actualizar la información de este usuario?",
|
|
||||||
actualizar
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className={`mb-4 px-4 py-2 rounded text-white ${
|
className={`mb-4 px-4 py-2 rounded text-white ${
|
||||||
mostrarBoton() ? "bg-gray-400 cursor-not-allowed" : "bg-blue-600 hover:bg-blue-700"
|
mostrarBoton() ? "bg-gray-400 cursor-not-allowed" : "bg-blue-600 hover:bg-blue-700"
|
||||||
}`}
|
}`}
|
||||||
@@ -147,12 +222,7 @@ export default function EditarResponsable({
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={confirmarCambioPassword}
|
||||||
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"
|
className="ms-3 px-4 py-2 rounded bg-morado hover:bg-blue-600 text-white"
|
||||||
>
|
>
|
||||||
Cambiar contraseña
|
Cambiar contraseña
|
||||||
|
|||||||
@@ -2,17 +2,22 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { axiosInstance } from "@/api/config";
|
import { axiosInstance } from "@/api/config";
|
||||||
import { isAxiosError } from 'axios';
|
import axios, { isAxiosError } from 'axios';
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import validator from "validator";
|
import validator from "validator";
|
||||||
import DatePicker from "react-datepicker";
|
import DatePicker from "react-datepicker";
|
||||||
import "react-datepicker/dist/react-datepicker.css";
|
import "react-datepicker/dist/react-datepicker.css";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { Col, FormGroup, FormLabel, InputGroup } from "react-bootstrap";
|
import { Col, FormGroup, FormLabel, InputGroup } from "react-bootstrap";
|
||||||
import { FaRegCalendarAlt, FaUpload } from "react-icons/fa";
|
import { FaRegCalendar, FaUpload } from "react-icons/fa6";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
import { registerLocale } from "react-datepicker";
|
||||||
|
import { es } from "date-fns/locale/es";
|
||||||
|
|
||||||
|
registerLocale("es", es);
|
||||||
|
|
||||||
interface Servicio {
|
interface Servicio {
|
||||||
Status: { idStatus?: number };
|
status: { idStatus?: number };
|
||||||
correo?: string;
|
correo?: string;
|
||||||
direccion?: string;
|
direccion?: string;
|
||||||
telefono?: string;
|
telefono?: string;
|
||||||
@@ -30,7 +35,7 @@ interface AdminToken {
|
|||||||
tokenArchivo?: { headers: Record<string, string> };
|
tokenArchivo?: { headers: Record<string, string> };
|
||||||
}; */}
|
}; */}
|
||||||
interface Props {
|
interface Props {
|
||||||
admin: string;
|
admin: AdminToken;
|
||||||
imprimirError: (err: unknown) => void;
|
imprimirError: (err: unknown) => void;
|
||||||
imprimirMensaje: (msg: string) => void;
|
imprimirMensaje: (msg: string) => void;
|
||||||
imprimirWarning: (msg: string, onConfirm: () => void) => void;
|
imprimirWarning: (msg: string, onConfirm: () => void) => void;
|
||||||
@@ -44,8 +49,11 @@ export default function EditarServicio({
|
|||||||
imprimirWarning,
|
imprimirWarning,
|
||||||
updateIsLoading,
|
updateIsLoading,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const [selectedInicio, setSelectedInicio] = useState<Date | null>(null);
|
||||||
|
const [selectFechaFin, setSelectedFechaFin] = useState<Date | null>(null);
|
||||||
|
|
||||||
const [servicioid, setServicioid] = useState<number>();
|
const [servicioid, setServicioid] = useState<number>();
|
||||||
const [servicio, setServicio] = useState<Servicio>({ Status: {} });
|
const [servicio, setServicio] = useState<Servicio>({ status: {} });
|
||||||
const [correo, setCorreo] = useState("");
|
const [correo, setCorreo] = useState("");
|
||||||
const [telefono, setTelefono] = useState("");
|
const [telefono, setTelefono] = useState("");
|
||||||
const [direccion, setDireccion] = useState("");
|
const [direccion, setDireccion] = useState("");
|
||||||
@@ -62,6 +70,14 @@ export default function EditarServicio({
|
|||||||
const fecha = (date?: Date) =>
|
const fecha = (date?: Date) =>
|
||||||
date ? moment(date).format("DD/MM/YYYY") : "";
|
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
|
// Validación de archivos
|
||||||
const sizeFileValido = (file: File) => {
|
const sizeFileValido = (file: File) => {
|
||||||
if (file.size >= 20000000) {
|
if (file.size >= 20000000) {
|
||||||
@@ -82,13 +98,16 @@ export default function EditarServicio({
|
|||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
console.log("Obteniendo registro para servicioid al hacer el get:", servicioid);
|
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);
|
console.log("Respuesta del servicio obtenido:", res.data);
|
||||||
const data = res.data;
|
const data = res.data;
|
||||||
setServicio(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
|
// Redirección si el estado no es válido
|
||||||
if (data.Status.idStatus === 6 || data.Status.idStatus === 10) {
|
if (data.status.idStatus === 6 || data.status.idStatus === 10) {
|
||||||
router.push("/administrador/servicio");
|
router.push("/administrador/servicio");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,25 +141,61 @@ export default function EditarServicio({
|
|||||||
if (direccion) data.direccion = direccion;
|
if (direccion) data.direccion = direccion;
|
||||||
if (correo) data.correo = correo;
|
if (correo) data.correo = correo;
|
||||||
if (telefono) data.telefono = telefono;
|
if (telefono) data.telefono = telefono;
|
||||||
if (fechaInicio) data.fechaInicio = fechaInicio;
|
|
||||||
if (fechaFin) data.fechaFin = fechaFin;
|
// Transformamos las fechas para que no muestre error en el back
|
||||||
if (fechaNacimiento) data.fechaNacimiento = fechaNacimiento;
|
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));
|
formData.append("data", JSON.stringify(data));
|
||||||
|
|
||||||
console.log("Datos a actualizar:", formData);
|
console.log("Datos a actualizar:", formData);
|
||||||
|
for (const [key, value] of formData.entries()) {
|
||||||
|
console.log("FormData:", key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res = await axiosInstance.put(`/servicio/update`, formData); //, admin.tokenArchivo
|
|
||||||
imprimirMensaje(res.data.message);
|
// 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") || "";
|
||||||
|
|
||||||
|
// Falta corregir este endpoint utilizar la variable del .env
|
||||||
|
const res = await axios.put(`${process.env.NEXT_PUBLIC_API_URL}/servicio/update`, formData, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
}); //, admin.tokenArchivo
|
||||||
|
|
||||||
|
Swal.fire('Exito', 'Se actualizaron los datos correctamente.', 'success')
|
||||||
|
|
||||||
|
// imprimirMensaje(res.data.message);
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
router.push("/administrador/servicio");
|
router.replace("/administrador/servicio");
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
|
Swal.fire('Error', 'No se pudieron actualizar los datos', 'error')
|
||||||
|
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
if (isAxiosError(err)) imprimirError(err.response?.data ?? err.message);
|
// if (isAxiosError(err)) imprimirError(err.response?.data ?? err.message);
|
||||||
else if (err instanceof Error) imprimirError(err.message);
|
// else if (err instanceof Error) imprimirError(err.message);
|
||||||
else imprimirError(err);
|
// else imprimirError(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -151,19 +206,25 @@ export default function EditarServicio({
|
|||||||
console.log("Id del servicio para nueva password", data);
|
console.log("Id del servicio para nueva password", data);
|
||||||
console.log("Id servicio entrando a la info", data.servicioid)
|
console.log("Id servicio entrando a la info", data.servicioid)
|
||||||
|
|
||||||
|
//const idServicio ={ idServicio: servicioid }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("Si entro par mandar la solicitud")
|
console.log("Si entro par mandar la solicitud")
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res = await axiosInstance.put(`/usuario/new_password_alumno`, { idServicio: servicioid });
|
const res = await axiosInstance.post(`/usuario/new-password-alumno/${data.servicioid}`);
|
||||||
imprimirMensaje(res.data.message);
|
// imprimirMensaje(res.data.message);
|
||||||
|
|
||||||
|
Swal.fire('Exito', 'Se actualizo la contraseña', 'success')
|
||||||
|
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
router.push("/administrador");
|
router.replace("/administrador");
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
|
Swal.fire('Error', 'No se pudo mandar la nueva contraseña', 'error')
|
||||||
console.log("No esta mandando la solicitud")
|
console.log("No esta mandando la solicitud")
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
|
// if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
|
||||||
else if (err instanceof Error) imprimirError(err.message);
|
// else if (err instanceof Error) imprimirError(err.message);
|
||||||
else imprimirError(err);
|
// else imprimirError(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -197,8 +258,44 @@ export default function EditarServicio({
|
|||||||
} else {
|
} else {
|
||||||
setActualizarFechaFin(true);
|
setActualizarFechaFin(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
console.log("Esta es la info de servicio", servicio);
|
||||||
}, [fechaInicio]);
|
}, [fechaInicio]);
|
||||||
|
|
||||||
|
const confirmarActualizarDatos = () => {
|
||||||
|
Swal.fire({
|
||||||
|
title: '¿Seguro(a) que quiere actualizar estos datos?',
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: 'Confirmar',
|
||||||
|
cancelButtonText: 'Cancelar',
|
||||||
|
confirmButtonColor: "#0d6efd",
|
||||||
|
cancelButtonColor: "#dc3545",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
actualizar()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmarEnvioPassword = () => {
|
||||||
|
Swal.fire({
|
||||||
|
title: '¿Seguro(a) que quieres cambiar/reenviar la contraseña de este alumno?',
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: 'Confirmar',
|
||||||
|
cancelButtonText: 'Cancelar',
|
||||||
|
confirmButtonColor: "#0d6efd",
|
||||||
|
cancelButtonColor: "#dc3545",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
password();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Validar tamaños de archivos
|
// Validar tamaños de archivos
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cartaAceptacion && !sizeFileValido(cartaAceptacion))
|
if (cartaAceptacion && !sizeFileValido(cartaAceptacion))
|
||||||
@@ -218,7 +315,7 @@ export default function EditarServicio({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const id = Number(localStorage.getItem("idServicio"));
|
const id = Number(localStorage.getItem("idServicio"));
|
||||||
console.log("ID Servicio para editar:", id);
|
console.log("ID Servicio para editar:", id);
|
||||||
if (!id) router.push("/administrador");
|
if (!id) router.replace("/administrador");
|
||||||
else {
|
else {
|
||||||
setServicioid(id);
|
setServicioid(id);
|
||||||
console.log("idServicio seteado:", id);
|
console.log("idServicio seteado:", id);
|
||||||
@@ -254,18 +351,27 @@ export default function EditarServicio({
|
|||||||
<FormLabel>Fecha de inicio</FormLabel>
|
<FormLabel>Fecha de inicio</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text>
|
<InputGroup.Text>
|
||||||
<FaRegCalendarAlt />
|
<FaRegCalendar />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
|
selected={selectedInicio}
|
||||||
onChange={(date: Date | null ) => {
|
onChange={(date: Date | null ) => {
|
||||||
if (date) setFechaInicio(date);
|
if (date) setSelectedInicio(date);
|
||||||
}}
|
}}
|
||||||
placeholderText="Selecciona una fecha de inicio"
|
placeholderText="Selecciona una fecha de inicio"
|
||||||
minDate={fechaInicio}
|
// minDate={fechaInicio} Quitamos la restricción de fecha mínima
|
||||||
dateFormat={'dd-MM-yyyy'}
|
dateFormat={'dd-MM-yyyy'}
|
||||||
className="form-control"
|
className="form-control"
|
||||||
wrapperClassName="flex-grow-1"
|
wrapperClassName="flex-grow-1"
|
||||||
calendarClassName="mi-calendario"
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={60}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale='es'
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@@ -276,22 +382,32 @@ export default function EditarServicio({
|
|||||||
<FormLabel>Fecha de fin</FormLabel>
|
<FormLabel>Fecha de fin</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text>
|
<InputGroup.Text>
|
||||||
<FaRegCalendarAlt />
|
<FaRegCalendar />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
|
selected={selectFechaFin}
|
||||||
onChange={(date: Date | null) => {
|
onChange={(date: Date | null) => {
|
||||||
if (date) setFechaFin(date);
|
if (date) setSelectedFechaFin(date);
|
||||||
}}
|
}}
|
||||||
placeholderText="Selecciona una fecha de fin"
|
placeholderText="Selecciona una fecha de fin"
|
||||||
dateFormat={'dd-MM-yyyy'}
|
dateFormat={'dd-MM-yyyy'}
|
||||||
className="form-control"
|
className="form-control"
|
||||||
wrapperClassName="flex-grow-1"
|
wrapperClassName="flex-grow-1"
|
||||||
calendarClassName="mi-calendario"
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={60}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale='es'
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
|
{/*
|
||||||
|
Fecha inicio
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold block font-medium mb-1">Fecha de inicio</label>
|
<label className="form-label fw-semibold block font-medium mb-1">Fecha de inicio</label>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
@@ -304,7 +420,7 @@ export default function EditarServicio({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Fecha fin */}
|
fecha fin
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-labeñ fw-semibold block font-medium mb-1">Fecha de fin</label>
|
<label className="form-labeñ fw-semibold block font-medium mb-1">Fecha de fin</label>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
@@ -316,6 +432,7 @@ export default function EditarServicio({
|
|||||||
className="border rounded p-2 w-full"
|
className="border rounded p-2 w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
*/}
|
||||||
|
|
||||||
{/* Dirección */}
|
{/* Dirección */}
|
||||||
{servicio.direccion && (
|
{servicio.direccion && (
|
||||||
@@ -346,7 +463,8 @@ export default function EditarServicio({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{servicio.fechaNacimiento && (
|
{/*
|
||||||
|
{servicio.fechaNacimiento && (
|
||||||
<Col>
|
<Col>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>Fecha de nacimiento</FormLabel>
|
<FormLabel>Fecha de nacimiento</FormLabel>
|
||||||
@@ -359,7 +477,7 @@ export default function EditarServicio({
|
|||||||
</Col>
|
</Col>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Fecha nacimiento */}
|
|
||||||
{servicio.fechaNacimiento && (
|
{servicio.fechaNacimiento && (
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold block font-medium mb-1">
|
<label className="form-label fw-semibold block font-medium mb-1">
|
||||||
@@ -368,13 +486,14 @@ export default function EditarServicio({
|
|||||||
<DatePicker
|
<DatePicker
|
||||||
selected={fechaFin}
|
selected={fechaFin}
|
||||||
onChange={(date: Date | null) => {
|
onChange={(date: Date | null) => {
|
||||||
if (date) setFechaFin(date);
|
if (date) setFechaNacimiento(date);
|
||||||
}}
|
}}
|
||||||
minDate={fechaInicio}
|
minDate={fechaInicio}
|
||||||
className="border rounded p-2 w-full"
|
className="border rounded p-2 w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
*/}
|
||||||
|
|
||||||
<FormGroup className="mb-4">
|
<FormGroup className="mb-4">
|
||||||
<FormLabel>Carta de aceptaciòn</FormLabel>
|
<FormLabel>Carta de aceptaciòn</FormLabel>
|
||||||
@@ -382,7 +501,7 @@ export default function EditarServicio({
|
|||||||
<div
|
<div
|
||||||
className="border p-4 text-center rounded"
|
className="border p-4 text-center rounded"
|
||||||
style={{ cursor: "pointer" }}
|
style={{ cursor: "pointer" }}
|
||||||
onClick={() => document.getElementById("application/pdf")?.click()}
|
onClick={() => document.getElementById("pdfInput")?.click()}
|
||||||
>
|
>
|
||||||
<FaUpload size={40} className="mb-2"/>
|
<FaUpload size={40} className="mb-2"/>
|
||||||
<p className="mb-1">
|
<p className="mb-1">
|
||||||
@@ -395,7 +514,7 @@ export default function EditarServicio({
|
|||||||
<input
|
<input
|
||||||
id="pdfInput"
|
id="pdfInput"
|
||||||
type="file"
|
type="file"
|
||||||
accept=".pdf"
|
accept="application/pdf"
|
||||||
style={{ display: 'none'}}
|
style={{ display: 'none'}}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setCartaAceptacion(e.target.files ? e.target.files[0] : null)
|
setCartaAceptacion(e.target.files ? e.target.files[0] : null)
|
||||||
@@ -423,12 +542,7 @@ export default function EditarServicio({
|
|||||||
<div className="mt-6 flex gap-4 mb-5">
|
<div className="mt-6 flex gap-4 mb-5">
|
||||||
<button
|
<button
|
||||||
disabled={mostrar()}
|
disabled={mostrar()}
|
||||||
onClick={() =>
|
onClick={confirmarActualizarDatos}
|
||||||
imprimirWarning(
|
|
||||||
"¿Seguro(a) que quiere actualizar estos datos?",
|
|
||||||
actualizar
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className={`me-2 px-4 py-2 rounded text-white ${
|
className={`me-2 px-4 py-2 rounded text-white ${
|
||||||
mostrar()
|
mostrar()
|
||||||
? "bg-gray-400 cursor-not-allowed"
|
? "bg-gray-400 cursor-not-allowed"
|
||||||
@@ -440,14 +554,9 @@ export default function EditarServicio({
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
disabled={
|
disabled={
|
||||||
servicio.Status.idStatus === 1 || servicio.Status.idStatus === 7
|
servicio.status.idStatus === 1 || servicio.status.idStatus === 7
|
||||||
}
|
|
||||||
onClick={() =>
|
|
||||||
imprimirWarning(
|
|
||||||
"¿Seguro(a) que quieres cambiar/reenviar la contraseña de este alumno?",
|
|
||||||
password
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
onClick={confirmarEnvioPassword}
|
||||||
className="px-4 py-2 rounded bg-blue-500 hover:bg-blue-600 text-white"
|
className="px-4 py-2 rounded bg-blue-500 hover:bg-blue-600 text-white"
|
||||||
>
|
>
|
||||||
Cambiar/Reenviar contraseña
|
Cambiar/Reenviar contraseña
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useState } from "react";
|
|||||||
import { Col, FormGroup, FormLabel, FormSelect, InputGroup, Button } from "react-bootstrap";
|
import { Col, FormGroup, FormLabel, FormSelect, InputGroup, Button } from "react-bootstrap";
|
||||||
import { axiosInstance } from "@/api/config"; // tu config de axios
|
import { axiosInstance } from "@/api/config"; // tu config de axios
|
||||||
import { isAxiosError } from 'axios';
|
import { isAxiosError } from 'axios';
|
||||||
|
import Swal from "sweetalert2";
|
||||||
//import fileDownload from "js-file-download";
|
//import fileDownload from "js-file-download";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -52,15 +53,28 @@ export default function GustavoBazPrada({
|
|||||||
link.remove();
|
link.remove();
|
||||||
window.URL.revokeObjectURL(url);
|
window.URL.revokeObjectURL(url);
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Éxito',
|
||||||
|
text: 'Se descargo el archivo correctamente.',
|
||||||
|
icon: 'success',
|
||||||
|
})
|
||||||
|
|
||||||
//fileDownload(res.data, `${selectedYear}_gustavo_baz_prada.csv`);
|
//fileDownload(res.data, `${selectedYear}_gustavo_baz_prada.csv`);
|
||||||
|
|
||||||
setSelectedYear("");
|
setSelectedYear("");
|
||||||
updateIsLoading?.(false);
|
updateIsLoading?.(false);
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error',
|
||||||
|
text: 'No se pudo completar la descarga.',
|
||||||
|
icon: 'error',
|
||||||
|
})
|
||||||
|
|
||||||
updateIsLoading?.(false);
|
updateIsLoading?.(false);
|
||||||
if (isAxiosError(err)) imprimirError?.(String(err.response?.data) || err.message || 'Error al descargar');
|
// if (isAxiosError(err)) imprimirError?.(String(err.response?.data) || err.message || 'Error al descargar');
|
||||||
else if (err instanceof Error) imprimirError?.(err.message);
|
// else if (err instanceof Error) imprimirError?.(err.message);
|
||||||
else imprimirError?.('Error al descargar');
|
// else imprimirError?.('Error al descargar');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -43,10 +43,17 @@ export default function InformacionResponsable({ admin, imprimirError, updateIsL
|
|||||||
const obtenerResponsable = async () => {
|
const obtenerResponsable = async () => {
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
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 },
|
headers: { Authorization: admin.token },
|
||||||
});
|
});
|
||||||
setResponsable(res.data);
|
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();
|
obtenerProgramas();
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
if (isAxiosError(err)) imprimirError(String(err.response?.data) || err.message || 'Error al obtener responsable');
|
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
|
// Funcion para obtener programas
|
||||||
const obtenerProgramas = async () => {
|
const obtenerProgramas = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await axiosInstance.get(`/programa/programas_admin?idUsuario=${idResponsable}`, {
|
const res = await axiosInstance.get(`/programa/programas_admin/${idResponsable}`,);
|
||||||
headers: { Authorization: admin.token },
|
|
||||||
});
|
console.log("Esta es la info de la res de programas", res.data)
|
||||||
setProgramas(res.data);
|
console.log("Esta es la info con doble data de programas", res.data.data)
|
||||||
|
|
||||||
|
setProgramas(res.data.data);
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
if (isAxiosError(err)) imprimirError(String(err.response?.data) || err.message || 'Error al obtener programas');
|
if (isAxiosError(err)) {
|
||||||
else if (err instanceof Error) imprimirError(err.message);
|
console.error("ERROR COMPLETO:", err.response?.data);
|
||||||
else imprimirError('Error al obtener programas');
|
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
|
// Cargar al montar
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const id = Number(localStorage.getItem('idResponsable'));
|
const id = Number(localStorage.getItem('idResponsable'));
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
router.push('/administrador/responsables');
|
router.push('/administrador/responsables');
|
||||||
} else {
|
} else {
|
||||||
@@ -109,18 +121,18 @@ export default function InformacionResponsable({ admin, imprimirError, updateIsL
|
|||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Clave de programa:</label>
|
<label className="form-label fw-semibold">Clave de programa:</label>
|
||||||
<select
|
<select
|
||||||
className="form-select"
|
className="form-select"
|
||||||
value={programa.clavePrograma || ''}
|
value={programa.clavePrograma || ''}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setPrograma(programas.find((p) => p.clavePrograma === e.target.value) || {})
|
setPrograma(programas.find((p) => p.clavePrograma === e.target.value) || {})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<option value="">Elija una clave de programa</option>
|
<option value="">Elija una clave de programa</option>
|
||||||
{programas.map((p, i) => (
|
{programas.map((p, i) => (
|
||||||
<option key={i} value={p.clavePrograma}>
|
<option key={i} value={p.clavePrograma}>
|
||||||
{p.clavePrograma}
|
{p.clavePrograma}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import moment from "moment";
|
|||||||
import "moment/locale/es";
|
import "moment/locale/es";
|
||||||
import { Button, Row, Col, Form } from "react-bootstrap";
|
import { Button, Row, Col, Form } from "react-bootstrap";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
interface Usuario {
|
interface Usuario {
|
||||||
usuario?: string;
|
usuario?: string;
|
||||||
@@ -21,9 +22,10 @@ interface Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Alumno {
|
interface Alumno {
|
||||||
Usuario?: Usuario;
|
idCasoEspecial: number;
|
||||||
Carrera?: Carrera;
|
usuario?: Usuario;
|
||||||
Status?: Status;
|
carrera?: Carrera;
|
||||||
|
status?: Status;
|
||||||
creditos?: number;
|
creditos?: number;
|
||||||
correo?: string;
|
correo?: string;
|
||||||
fechaNacimiento?: string;
|
fechaNacimiento?: string;
|
||||||
@@ -56,23 +58,23 @@ export default function InformacionCasoEspecial({ alumno }: Props) {
|
|||||||
return (
|
return (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
{/* Título */}
|
{/* Título */}
|
||||||
<h2 className="fw-bold mb-3">{alumno.Status?.status}</h2>
|
<h2 className="fw-bold mb-3">{alumno.status?.status}</h2>
|
||||||
|
|
||||||
<h4 className="mb-4">Datos personales</h4>
|
<h4 className="mb-4">Datos personales</h4>
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Número de Cuenta: </label>
|
<label className="form-label fw-semibold">Número de Cuenta: </label>
|
||||||
<p className="form-control">{alumno.Usuario?.usuario || ''}</p>
|
<p className="form-control">{alumno.usuario?.usuario || ''}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="fw-semibold mb-3">
|
<div className="fw-semibold mb-3">
|
||||||
<label className="form-label">Nombre:</label>
|
<label className="form-label">Nombre:</label>
|
||||||
<p className="form-control">{alumno.Usuario?.nombre || ''}</p>
|
<p className="form-control">{alumno.usuario?.nombre || ''}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="fw-semibold mb-3">
|
<div className="fw-semibold mb-3">
|
||||||
<label className="form-label">Carrera:</label>
|
<label className="form-label">Carrera:</label>
|
||||||
<p className="form-control">{alumno.Carrera?.carrera || ''}</p>
|
<p className="form-control">{alumno.carrera?.carrera || ''}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="fw-semibold mb-3">
|
<div className="fw-semibold mb-3">
|
||||||
@@ -265,14 +267,15 @@ export default function InformacionCasoEspecial({ alumno }: Props) {
|
|||||||
</Form.Group>
|
</Form.Group>
|
||||||
*/}
|
*/}
|
||||||
|
|
||||||
{(alumno.Status?.idStatus === 11 || alumno.Status?.idStatus === 12) && (
|
{(alumno.status?.idStatus === 11 || alumno.status?.idStatus === 12) && (
|
||||||
<div className="text-end mt-4">
|
<div className="mt-4 mb-4">
|
||||||
<Button
|
<Link
|
||||||
variant="info"
|
// variant="primary"
|
||||||
onClick={() => router.push("/admin/casos_especiales/caso_especial/editar")}
|
href={`/administrador/casos_especiales/caso_especial/editar/${alumno.idCasoEspecial}`}
|
||||||
|
className="btn btn-outline-primary is-info is-light"
|
||||||
>
|
>
|
||||||
Editar información
|
<span>Editar información</span>
|
||||||
</Button>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { axiosInstance } from "@/api/config";
|
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
|
||||||
interface Admin {
|
interface Admin {
|
||||||
token?: string;
|
token?: string;
|
||||||
}
|
}
|
||||||
@@ -29,15 +29,15 @@ interface Programa {
|
|||||||
programa?: string;
|
programa?: string;
|
||||||
clavePrograma?: string;
|
clavePrograma?: string;
|
||||||
acatlan?: boolean;
|
acatlan?: boolean;
|
||||||
Usuario?: Usuario;
|
usuario?: Usuario;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Datos {
|
interface Datos {
|
||||||
idServicio?: number;
|
idServicio?: number;
|
||||||
Programa?: Programa;
|
programa?: Programa;
|
||||||
Carrera?: Carrera;
|
carrera?: Carrera;
|
||||||
Usuario?: Usuario;
|
usuario?: Usuario;
|
||||||
Status?: Status;
|
status?: Status;
|
||||||
creditos?: string;
|
creditos?: string;
|
||||||
correo?: string;
|
correo?: string;
|
||||||
createdAt?: string;
|
createdAt?: string;
|
||||||
@@ -47,6 +47,7 @@ interface Datos {
|
|||||||
fechaLiberacion?: string;
|
fechaLiberacion?: string;
|
||||||
telefono?: string;
|
telefono?: string;
|
||||||
direccion?: string;
|
direccion?: string;
|
||||||
|
responsableIntermo?: string;
|
||||||
/*
|
/*
|
||||||
cartaAceptacion?: boolean;
|
cartaAceptacion?: boolean;
|
||||||
cartaTermino?: boolean;
|
cartaTermino?: boolean;
|
||||||
@@ -75,7 +76,7 @@ export default function InformacionServicio({ admin, imprimirError, updateIsLoad
|
|||||||
const [info, setInfo] = useState<Usuario[]>([]);
|
const [info, setInfo] = useState<Usuario[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
const [programa, setPrograma] = useState<Datos>({});
|
// const [programa, setPrograma] = useState<Datos>({});
|
||||||
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -97,11 +98,11 @@ export default function InformacionServicio({ admin, imprimirError, updateIsLoad
|
|||||||
}, []);
|
}, []);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
console.log('✅ Datos cargados correctamente:', datos);
|
// console.log('✅ Datos cargados correctamente:', datos);
|
||||||
setPrograma(datos);
|
// // setPrograma(datos);
|
||||||
console.log('Programa establecido en InformacionServicio:', programa);
|
// // console.log('Programa establecido en InformacionServicio:', programa);
|
||||||
}, [datos]);
|
// }, [datos]);
|
||||||
|
|
||||||
|
|
||||||
// Funcion para editar la informacion del servicio
|
// Funcion para editar la informacion del servicio
|
||||||
@@ -136,32 +137,37 @@ export default function InformacionServicio({ admin, imprimirError, updateIsLoad
|
|||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Institucion:</label>
|
<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>
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Dependencias:</label>
|
<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>
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Programa:</label>
|
<label className="form-label fw-semibold">Programa interno:</label>
|
||||||
<p className="form-control">{datos.Programa?.programa}</p>
|
<p className="form-control">{datos.programa?.programa}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Clave de programa:</label>
|
<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>
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Responsable:</label>
|
<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">Profesor:</label>
|
||||||
|
<p className="form-control">{datos?.responsableIntermo || '-'}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Correo:</label>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -170,30 +176,58 @@ export default function InformacionServicio({ admin, imprimirError, updateIsLoad
|
|||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Numero de cuenta:</label>
|
<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>
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Nombre:</label>
|
<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>
|
||||||
|
|
||||||
|
{/*
|
||||||
|
<Col>
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>Seleccione una fecha de fin:</FormLabel>
|
||||||
|
<InputGroup>
|
||||||
|
<InputGroup.Text>
|
||||||
|
<FaRegCalendarAlt />
|
||||||
|
</InputGroup.Text>
|
||||||
|
<DatePicker
|
||||||
|
selected={selectedFin}
|
||||||
|
onChange={(date) => setSelectedFin(date)}
|
||||||
|
minDate={minDate}
|
||||||
|
maxDate={maxDate}
|
||||||
|
placeholderText="Seleccione una fecha de fin"
|
||||||
|
dateFormat="yyyy-MM-dd"
|
||||||
|
className="form-control"
|
||||||
|
wrapperClassName="flex-grow-1"
|
||||||
|
calendarClassName="mi-calendario"
|
||||||
|
/>
|
||||||
|
</InputGroup>
|
||||||
|
</FormGroup>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<div className="mb-3">
|
||||||
|
<label className="form-label fw-semibold">Fecha de termino:</label>
|
||||||
|
<p className="form-control">{formatDate(datos.fechaFin) || '-'}</p>
|
||||||
|
</div>
|
||||||
|
*/}
|
||||||
|
|
||||||
{datos.fechaNacimiento && (
|
{datos.fechaNacimiento && (
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Fecha de nacimiento:
|
<label className="form-label fw-semibold">Fecha de nacimiento:</label>
|
||||||
<p className="form-control">{formatDate(datos.fechaNacimiento)}</p>
|
<p className="form-control">{formatDate(datos.fechaNacimiento)}</p>
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Carrera:</label>
|
<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>
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Creditos:</label>
|
<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>
|
||||||
|
|
||||||
{datos.telefono && (
|
{datos.telefono && (
|
||||||
@@ -230,7 +264,6 @@ export default function InformacionServicio({ admin, imprimirError, updateIsLoad
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-semibold">Fecha de registro:</label>
|
<label className="form-label fw-semibold">Fecha de registro:</label>
|
||||||
<p className="form-control">{formatDate(datos.createdAt) || '-'}</p>
|
<p className="form-control">{formatDate(datos.createdAt) || '-'}</p>
|
||||||
@@ -272,7 +305,7 @@ function formatDate(value?: string | null): string {
|
|||||||
const d = new Date(value.includes("T") ? value : `${value}T00:00:00`);
|
const d = new Date(value.includes("T") ? value : `${value}T00:00:00`);
|
||||||
|
|
||||||
if (isNaN(d.getTime())) {
|
if (isNaN(d.getTime())) {
|
||||||
console.warn("⚠️ Fecha inválida:", value);
|
// console.warn("⚠️ Fecha inválida:", value);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,24 +26,24 @@ export default function LiberarCasoEspecial({
|
|||||||
const data = { idCasoEspecial };
|
const data = { idCasoEspecial };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res = await axiosInstance.put(`/caso_especial/liberacion`, data, { headers: { Authorization: `Bearer ${admin.token}` } });
|
const res = await axiosInstance.put(`/caso-especial/liberaciony/${idCasoEspecial}`, data);
|
||||||
imprimirMensaje(res.data.message);
|
imprimirMensaje(res.data.message);
|
||||||
router.push('/admin/casos_especiales');
|
router.replace('/administrador/casos_especiales');
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
let msg: unknown = 'Error';
|
let msg: unknown = 'Error';
|
||||||
if (typeof err === 'object' && err !== null && 'response' in err) {
|
if (typeof err === 'object' && err !== null && 'response' in err) {
|
||||||
const anyErr = err as { response?: { data?: unknown } };
|
const anyErr = err as { response?: { data?: unknown } };
|
||||||
if (anyErr.response?.data) msg = anyErr.response.data;
|
if (anyErr.response?.data) msg = anyErr.response.data;
|
||||||
} else if (err instanceof Error) msg = err.message;
|
} else if (err instanceof Error) msg = err.message;
|
||||||
imprimirError(msg);
|
imprimirError(msg);
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-2">
|
<div className="mt-2 mb-4">
|
||||||
<button
|
<button
|
||||||
className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600"
|
className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useState } from "react";
|
|||||||
import { axiosInstance } from "@/api/config";
|
import { axiosInstance } from "@/api/config";
|
||||||
import { isAxiosError } from 'axios';
|
import { isAxiosError } from 'axios';
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
//admin: { token: { headers: { token: string } } };
|
//admin: { token: { headers: { token: string } } };
|
||||||
@@ -35,24 +36,48 @@ export default function ReasignacionProgramas({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const confirmarActualizacion = () => {
|
||||||
|
Swal.fire({
|
||||||
|
title: `¿Seguro(a) que quiere eliminar a ${correoOtroResponsable} y pasar todos los programas a ${responsable.usuario}?`,
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Actualizar",
|
||||||
|
cancelButtonText: "Cancelar",
|
||||||
|
confirmButtonColor: "#0d6efd",
|
||||||
|
cancelButtonColor: "#dc3545",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
reasignarProgramas(); // 👈 aquí ejecutas la función
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Función principal: reasignar programas
|
// Función principal: reasignar programas
|
||||||
const reasignarProgramas = async () => {
|
const reasignarProgramas = async () => {
|
||||||
const data = {
|
const data = {
|
||||||
idUsuario: responsable.idUsuario,
|
//idUsuario: responsable.idUsuario,
|
||||||
correoOtroResponsable,
|
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 {
|
try {
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res = await axiosInstance.put(`/programa/reasignar_programas`, data);
|
const res = await axiosInstance.put(`/programa/reasignar_programas/${responsable.idUsuario}`, data);
|
||||||
|
|
||||||
|
Swal.fire('Exito', 'Se reasignaron los programas con exito', 'success')
|
||||||
|
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
imprimirMensaje(res.data.message);
|
// imprimirMensaje(res.data.message);
|
||||||
router.push("/admin/responsables/responsable");
|
router.replace("/administrador/responsables");
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
|
Swal.fire('Error', 'No se pudieron reasignar los programas', 'error')
|
||||||
|
// console.log("Esta entrando al catch no sale la peticion")
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
|
// if (isAxiosError(err)) imprimirError(err.response?.data || err.message);
|
||||||
else if (err instanceof Error) imprimirError(err.message);
|
// else if (err instanceof Error) imprimirError(err.message);
|
||||||
else imprimirError(err);
|
// else imprimirError(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -89,12 +114,7 @@ export default function ReasignacionProgramas({
|
|||||||
: "bg-blue-600 hover:bg-blue-700"
|
: "bg-blue-600 hover:bg-blue-700"
|
||||||
}`}
|
}`}
|
||||||
disabled={mostrarBoton()}
|
disabled={mostrarBoton()}
|
||||||
onClick={() =>
|
onClick={confirmarActualizacion}
|
||||||
imprimirWarning(
|
|
||||||
`¿Seguro(a) que quiere eliminar a ${correoOtroResponsable} y pasar todos los programas a ${responsable.usuario}?`,
|
|
||||||
reasignarProgramas
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
Reasignar
|
Reasignar
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { axiosInstance } from "@/api/config";
|
||||||
|
import moment from "moment";
|
||||||
|
import { title } from "process";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Button, Col, Form, InputGroup } from "react-bootstrap";
|
||||||
|
import { FaRegCalendar } from "react-icons/fa6";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
|
export default function ReporteCasoEspecial() {
|
||||||
|
const [selectedInicio, setSelectedInicio] = useState<Date | null>(null);
|
||||||
|
const [selectedFin, setSelectedFin] = useState<Date | null>(null);
|
||||||
|
|
||||||
|
const descargar = async () => {
|
||||||
|
console.log("Descargando reporte de caso especial...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await axiosInstance.get("/caso-especial/reporte", {
|
||||||
|
params: {
|
||||||
|
inicio: moment(selectedInicio).format("YYYY-MM-DD"), // Aquí puedes agregar los parámetros necesarios para el reporte de caso especial
|
||||||
|
fin: moment(selectedFin).format("YYYY-MM-DD"),
|
||||||
|
// Aquí puedes agregar los parámetros necesarios para el reporte de caso especial
|
||||||
|
},
|
||||||
|
responseType: "blob",
|
||||||
|
});
|
||||||
|
|
||||||
|
const blob = new Blob([res.data], { type: "text/csv" });
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = url;
|
||||||
|
link.download = "reporte_caso_especial.csv";
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: "Reporte de caso especial descargado",
|
||||||
|
text: "El reporte de caso especial se ha descargado correctamente.",
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
|
||||||
|
setSelectedInicio(null);
|
||||||
|
setSelectedFin(null);
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
Swal.fire({
|
||||||
|
title: "Error al descargar el reporte de caso especial",
|
||||||
|
text: "Hubo un error al descargar el reporte de caso especial. Por favor, inténtalo de nuevo.",
|
||||||
|
icon: "error",
|
||||||
|
});
|
||||||
|
// console.error("Error al descargar el reporte de caso especial.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="columns">
|
||||||
|
<h4 className="mb-3">Reporte Caso Especial</h4>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<Col>
|
||||||
|
<Form.Group>
|
||||||
|
<Form.Label>Seleccione una fecha de inicio:</Form.Label>
|
||||||
|
<InputGroup.Text>
|
||||||
|
<FaRegCalendar />
|
||||||
|
<Form.Control type="date" placeholder="Seleccione una fecha de inicio" value={selectedInicio ? moment(selectedInicio).format("YYYY-MM-DD") : ""} onChange={(e) => setSelectedInicio(e.target.value ? new Date(e.target.value) : null)} />
|
||||||
|
</InputGroup.Text>
|
||||||
|
|
||||||
|
</Form.Group>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col>
|
||||||
|
<Form.Group>
|
||||||
|
<Form.Label>Seleccione una fecha de fin:</Form.Label>
|
||||||
|
<InputGroup.Text>
|
||||||
|
<FaRegCalendar />
|
||||||
|
<Form.Control type="date" placeholder="Seleccione una fecha de fin" value={selectedFin ? moment(selectedFin).format("YYYY-MM-DD") : ""} onChange={(e) => setSelectedFin(e.target.value ? new Date(e.target.value) : null)} />
|
||||||
|
</InputGroup.Text>
|
||||||
|
</Form.Group>
|
||||||
|
</Col>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div className="mt-4 mb-3">
|
||||||
|
<Button onClick={descargar} disabled={false}>Descargar Reporte</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { axiosInstance } from "@/api/config";
|
import { axiosInstance } from "@/api/config";
|
||||||
import { Button, Col, FormGroup, FormLabel, InputGroup, Row } from "react-bootstrap";
|
import { Button, Col, FormGroup, FormLabel, InputGroup } from "react-bootstrap";
|
||||||
import DatePicker from "react-datepicker";
|
import DatePicker from "react-datepicker";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { FaCalendarAlt, FaRegCalendarAlt } from "react-icons/fa";
|
import { FaRegCalendar } from "react-icons/fa6";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
import { registerLocale } from "react-datepicker";
|
||||||
|
import { es } from "date-fns/locale/es";
|
||||||
|
|
||||||
|
registerLocale("es", es);
|
||||||
//import { saveAs } from "file-saver";
|
//import { saveAs } from "file-saver";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -32,10 +37,15 @@ export default function Reporte({ admin }: Props) {
|
|||||||
try {
|
try {
|
||||||
//updateIsLoading(true);
|
//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", {
|
const res = await axiosInstance.get("/servicio/reporte", {
|
||||||
params: {
|
params: {
|
||||||
inicio: moment(selectedInicio).format("YYYY-MM-DD"),
|
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"),
|
fin: moment(selectedFin).format("YYYY-MM-DD"), // Mandamos solo el año, quitamos el mes y día
|
||||||
},
|
},
|
||||||
responseType: "blob",
|
responseType: "blob",
|
||||||
});
|
});
|
||||||
@@ -59,6 +69,12 @@ export default function Reporte({ admin }: Props) {
|
|||||||
link.remove()
|
link.remove()
|
||||||
window.URL.revokeObjectURL(url)
|
window.URL.revokeObjectURL(url)
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Éxito',
|
||||||
|
text: 'Se descargo el reporte exitosamente.',
|
||||||
|
icon: 'success',
|
||||||
|
})
|
||||||
|
|
||||||
//saveAs(res.data, "reporte.csv");
|
//saveAs(res.data, "reporte.csv");
|
||||||
|
|
||||||
// reset
|
// reset
|
||||||
@@ -66,6 +82,13 @@ export default function Reporte({ admin }: Props) {
|
|||||||
setSelectedFin(null);
|
setSelectedFin(null);
|
||||||
//updateIsLoading(false);
|
//updateIsLoading(false);
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error',
|
||||||
|
text: 'No se pudo descargar el reporte.',
|
||||||
|
icon: 'error',
|
||||||
|
})
|
||||||
|
console.log("Error al descargar el reporte", err)
|
||||||
//updateIsLoading(false);
|
//updateIsLoading(false);
|
||||||
// optional: handle error
|
// optional: handle error
|
||||||
}
|
}
|
||||||
@@ -83,7 +106,7 @@ export default function Reporte({ admin }: Props) {
|
|||||||
<FormLabel>Seleccione una fecha de inicio:</FormLabel>
|
<FormLabel>Seleccione una fecha de inicio:</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text>
|
<InputGroup.Text>
|
||||||
<FaRegCalendarAlt />
|
<FaRegCalendar />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
selected={selectedInicio}
|
selected={selectedInicio}
|
||||||
@@ -95,6 +118,14 @@ export default function Reporte({ admin }: Props) {
|
|||||||
className="form-control"
|
className="form-control"
|
||||||
wrapperClassName="flex-grow-1"
|
wrapperClassName="flex-grow-1"
|
||||||
calendarClassName="mi-calendario"
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={15}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale='es'
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@@ -105,7 +136,7 @@ export default function Reporte({ admin }: Props) {
|
|||||||
<FormLabel>Seleccione una fecha de fin:</FormLabel>
|
<FormLabel>Seleccione una fecha de fin:</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text>
|
<InputGroup.Text>
|
||||||
<FaRegCalendarAlt />
|
<FaRegCalendar />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
selected={selectedFin}
|
selected={selectedFin}
|
||||||
@@ -117,6 +148,14 @@ export default function Reporte({ admin }: Props) {
|
|||||||
className="form-control"
|
className="form-control"
|
||||||
wrapperClassName="flex-grow-1"
|
wrapperClassName="flex-grow-1"
|
||||||
calendarClassName="mi-calendario"
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={15}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale='es'
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ import type { AxiosResponse } from 'axios';
|
|||||||
import { Button, Col, Form, FormGroup, FormLabel, FormSelect, InputGroup, Row, Spinner } from "react-bootstrap";
|
import { Button, Col, Form, FormGroup, FormLabel, FormSelect, InputGroup, Row, Spinner } from "react-bootstrap";
|
||||||
import ServicioSocialTabla from "../servicio-social-tabla";
|
import ServicioSocialTabla from "../servicio-social-tabla";
|
||||||
import { ServicioSocialResponse } from "@/types/responses";
|
import { ServicioSocialResponse } from "@/types/responses";
|
||||||
import { FaInfoCircle, FaSchool, FaUser } from "react-icons/fa";
|
import { FaCircleInfo, FaUser } from "react-icons/fa6";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
interface Admin {
|
interface Admin {
|
||||||
idTipoUsuario?: number;
|
idTipoUsuario?: number;
|
||||||
@@ -92,11 +93,12 @@ export default function TablaCasosEspeciales({ admin, imprimirError }: Props) {
|
|||||||
try {
|
try {
|
||||||
const config = admin?.token ? { headers: { Authorization: `Bearer ${admin.token}` } } : undefined;
|
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);
|
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);
|
console.debug('Respuesta casos especiales:', res.data);
|
||||||
setData(res.data.serviciosEspeciales || []);
|
setData(res.data.data.serviciosEspeciales ?? []);
|
||||||
setTotal(res.data.count);
|
setTotal(res.data.count);
|
||||||
console.log('Respuesta casos especiales:', res.data);
|
console.log('Respuesta casos especiales:', res.data);
|
||||||
|
console.log("Respuesta Caso especial con doble data", res.data.data)
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
if (imprimirError) {
|
if (imprimirError) {
|
||||||
if (isAxiosError(err)) {
|
if (isAxiosError(err)) {
|
||||||
@@ -162,7 +164,7 @@ export default function TablaCasosEspeciales({ admin, imprimirError }: Props) {
|
|||||||
|
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text className="rounded-4">
|
<InputGroup.Text className="rounded-4">
|
||||||
<FaSchool />
|
<Image src="/image/numCuenta.svg" width={24} height={24} alt="Icono de escuela" />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
|
|
||||||
<Form.Control
|
<Form.Control
|
||||||
@@ -194,7 +196,7 @@ export default function TablaCasosEspeciales({ admin, imprimirError }: Props) {
|
|||||||
placeholder="Nombre"
|
placeholder="Nombre"
|
||||||
value={search.nombre}
|
value={search.nombre}
|
||||||
onChange={(e) => setSearch({ ...search, nombre: e.target.value })}
|
onChange={(e) => setSearch({ ...search, nombre: e.target.value })}
|
||||||
onKeyDown={(e) => e.key === "Enter" && obtenerCasosEspeciales()}
|
onKeyDown={(e) => e.key === "Enter" && obtenerCasosEspeciales() }
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@@ -206,13 +208,14 @@ export default function TablaCasosEspeciales({ admin, imprimirError }: Props) {
|
|||||||
|
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text className="rounded-4">
|
<InputGroup.Text className="rounded-4">
|
||||||
<FaInfoCircle />
|
<FaCircleInfo />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
|
|
||||||
<FormSelect
|
<FormSelect
|
||||||
value={search.idStatus}
|
value={search.idStatus}
|
||||||
onChange={(e) => setSearch(prev => ({ ...prev, idStatus: e.target.value }))}
|
onChange={(e) => setSearch(prev => ({ ...prev, idStatus: e.target.value }))}
|
||||||
className="rounded-4"
|
className="rounded-4"
|
||||||
|
onKeyDown={(e) => { if (e.key === 'Enter') obtenerCasosEspeciales() }}
|
||||||
>
|
>
|
||||||
<option value="">Status</option>
|
<option value="">Status</option>
|
||||||
{status.map((s) => (
|
{status.map((s) => (
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Responsables } from "@/types/responses";
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Button, Col, Row, Table } from "react-bootstrap";
|
import { Button, Col, Row, Table } from "react-bootstrap";
|
||||||
import { FaEnvelope, FaUser } from "react-icons/fa";
|
import { FaEnvelope, FaUser } from "react-icons/fa6";
|
||||||
|
|
||||||
export default function TablaResponsables() {
|
export default function TablaResponsables() {
|
||||||
const [info, setInfo] = useState<Responsables[]>([]);
|
const [info, setInfo] = useState<Responsables[]>([]);
|
||||||
@@ -68,6 +68,7 @@ export default function TablaResponsables() {
|
|||||||
className="form-control border-0 rounded-4"
|
className="form-control border-0 rounded-4"
|
||||||
value={correo}
|
value={correo}
|
||||||
onChange={(e) => setCorreo(e.target.value)}
|
onChange={(e) => setCorreo(e.target.value)}
|
||||||
|
onKeyDown={(e) => {if (e.key === 'Enter') fetchData(correo, nombre)}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -80,6 +81,7 @@ export default function TablaResponsables() {
|
|||||||
className="form-control border-0 rounded-4"
|
className="form-control border-0 rounded-4"
|
||||||
value={nombre}
|
value={nombre}
|
||||||
onChange={(e) => setNombre(e.target.value)}
|
onChange={(e) => setNombre(e.target.value)}
|
||||||
|
onKeyDown={(e) => { if (e.key === 'Enter') fetchData(correo, nombre)}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { Form, FormGroup, FormLabel, FormControl, FormSelect, Button, InputGroup, Row, Col } from "react-bootstrap";
|
import { Form, FormGroup, FormLabel, FormControl, FormSelect, Button, InputGroup, Row, Col } from "react-bootstrap";
|
||||||
import { FaUser, FaSchool, FaInfoCircle } from "react-icons/fa";
|
import { FaUser, FaCircleInfo } from "react-icons/fa6";
|
||||||
import ServicioSocialTabla from "../servicio-social-tabla";
|
import ServicioSocialTabla from "../servicio-social-tabla";
|
||||||
import { axiosInstance } from "@/api/config";
|
import { axiosInstance } from "@/api/config";
|
||||||
import { ServicioSocialResponse } from "@/types/responses";
|
import { ServicioSocialResponse } from "@/types/responses";
|
||||||
import { Prev } from "react-bootstrap/esm/PageItem";
|
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
interface Admin {
|
interface Admin {
|
||||||
idTipoUsuario: number;
|
idTipoUsuario: number;
|
||||||
@@ -38,6 +38,8 @@ export default function TablaServicioSocial({ admin, imprimirError }: Props) {
|
|||||||
if (admin?.idTipoUsuario === 1) {
|
if (admin?.idTipoUsuario === 1) {
|
||||||
obtenerCatalogoStatus();
|
obtenerCatalogoStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("Esta es la info que tiene al guardar en la state", data)
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [admin?.idTipoUsuario]);
|
}, [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
|
// asegurar que enviamos Authorization si existe en admin, y loggear token para debug
|
||||||
const config = admin?.token ? { headers: { Authorization: `Bearer ${admin.token}` } } : undefined;
|
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);
|
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);
|
console.debug('Respuesta servicios_admin:', res.data);
|
||||||
setData(res.data.serviciosAdmin || []);
|
setData(res.data.serviciosAdmin || []);
|
||||||
|
//setData(res.data)
|
||||||
|
//setData(res.data.serviciosAdmin);
|
||||||
setTotal(res.data.count ?? 0);
|
setTotal(res.data.count ?? 0);
|
||||||
|
|
||||||
|
console.log("Esta es la info", res.data)
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
// manejar error
|
// manejar error
|
||||||
console.error('Error obtenerServicios', err);
|
console.error('Error obtenerServicios', err);
|
||||||
@@ -98,7 +104,6 @@ export default function TablaServicioSocial({ admin, imprimirError }: Props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<div className="columns">
|
<div className="columns">
|
||||||
@@ -107,12 +112,12 @@ export default function TablaServicioSocial({ admin, imprimirError }: Props) {
|
|||||||
<section className="container-fluid my-4">
|
<section className="container-fluid my-4">
|
||||||
<Form onSubmit={(e) => { e.preventDefault(); obtenerServicios(1); }}>
|
<Form onSubmit={(e) => { e.preventDefault(); obtenerServicios(1); }}>
|
||||||
<Row className="g-3">
|
<Row className="g-3">
|
||||||
<Col md={3}>
|
<Col xs={12} sm={6} lg={3}>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>Número de Cuenta</FormLabel>
|
<FormLabel>Número de Cuenta</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text className="rounded-4">
|
<InputGroup.Text className="rounded-4">
|
||||||
<FaSchool />
|
<Image src="/image/numCuenta.svg" width={24} height={24} alt="Icono de escuela" />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
<FormControl
|
<FormControl
|
||||||
type="text"
|
type="text"
|
||||||
@@ -127,7 +132,7 @@ export default function TablaServicioSocial({ admin, imprimirError }: Props) {
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col md={3}>
|
<Col xs={12} sm={6} lg={3}>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>Nombre</FormLabel>
|
<FormLabel>Nombre</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
@@ -146,17 +151,19 @@ export default function TablaServicioSocial({ admin, imprimirError }: Props) {
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col md={3}>
|
<Col xs={12} sm={6} lg={3}>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>Status</FormLabel>
|
<FormLabel>Status</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text className="rounded-4">
|
<InputGroup.Text className="rounded-4">
|
||||||
<FaInfoCircle />
|
<FaCircleInfo />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
<FormSelect
|
<FormSelect
|
||||||
|
suppressHydrationWarning
|
||||||
value={search.idStatus}
|
value={search.idStatus}
|
||||||
onChange={(e) => setSearch(Prev => ({ ...Prev, idStatus: e.target.value }))}
|
onChange={(e) => setSearch(Prev => ({ ...Prev, idStatus: e.target.value }))}
|
||||||
className="rounded-4"
|
className="rounded-4"
|
||||||
|
onKeyDown={(e) => { if (e.key === 'Enter') obtenerServicios()}}
|
||||||
>
|
>
|
||||||
<option value="">Status</option>
|
<option value="">Status</option>
|
||||||
{status.slice(0, 10).map((s) => (
|
{status.slice(0, 10).map((s) => (
|
||||||
@@ -167,7 +174,7 @@ export default function TablaServicioSocial({ admin, imprimirError }: Props) {
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col md={3} className="d-flex align-items-end">
|
<Col xs={12} sm={6} lg={3} className="d-flex align-items-end">
|
||||||
<Button type="submit" className="w-100 rounded-5" disabled={isLoading}>
|
<Button type="submit" className="w-100 rounded-5" disabled={isLoading}>
|
||||||
{isLoading ? 'Buscando...' : 'Buscar'}
|
{isLoading ? 'Buscando...' : 'Buscar'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ export default function TituloStatus({ status }: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
{idStatus === 1 && <h2 className="fw-bold mt-4">Confirmar el pre-registro del alumno</h2>}
|
{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 === 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>}
|
{idStatus === 5 && <h2 className="fw-bold mt-4">Validar el término del alumno</h2>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React from "react";
|
import { FaUserPlus, FaUserCheck, FaUser, FaUsers, FaUserClock, FaUserTie } from "react-icons/fa6";
|
||||||
import { FaUserPlus, FaUserCheck, FaUser, FaUsers, FaUserClock, FaUserTie } from "react-icons/fa";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
idStatus: number;
|
idStatus: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function BarraProgreso({ idStatus }: Props) {
|
export default function BarraProgreso({ idStatus }: Props) {
|
||||||
|
// Si el status es 7, mostrar como si fuera 1 (Pre Registro)
|
||||||
|
// Si el status es 8 o 9, mostrar como 5 (Termino)
|
||||||
|
const statusMapeado = idStatus === 7 ? 1 : (idStatus === 8 || idStatus === 9 ? 5 : idStatus);
|
||||||
|
|
||||||
const steps = [
|
const steps = [
|
||||||
{ label: "Pre Registro", icon: <FaUserPlus />, id: 1 },
|
{ label: "Pre Registro", icon: <FaUserPlus />, id: 1 },
|
||||||
{ label: "Pre Registro Validado", icon: <FaUserCheck />, id: 2 },
|
{ label: "Pre Registro Validado", icon: <FaUserCheck />, id: 2 },
|
||||||
@@ -21,8 +24,8 @@ export default function BarraProgreso({ idStatus }: Props) {
|
|||||||
<div className="container mt-5">
|
<div className="container mt-5">
|
||||||
<div className="d-flex justify-content-center align-items-center position-relative">
|
<div className="d-flex justify-content-center align-items-center position-relative">
|
||||||
{steps.map((step, index) => {
|
{steps.map((step, index) => {
|
||||||
const isActive = idStatus >= step.id;
|
const isActive = statusMapeado >= step.id;
|
||||||
const isCurrent = idStatus === step.id;
|
const isCurrent = statusMapeado === step.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={index} className="text-center position-relative flex-fill">
|
<div key={index} className="text-center position-relative flex-fill">
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import DatePicker from "react-datepicker";
|
|
||||||
import "react-datepicker/dist/react-datepicker.css";
|
import "react-datepicker/dist/react-datepicker.css";
|
||||||
import { axiosInstance } from '@/api/config';
|
import { axiosInstance } from '@/api/config';
|
||||||
import { isAxiosError } from 'axios';
|
|
||||||
import type { AxiosResponse } from 'axios';
|
import type { AxiosResponse } from 'axios';
|
||||||
import moment from "moment";
|
import { useRouter } from "next/navigation";
|
||||||
import { Col, FormGroup, FormLabel, InputGroup } from "react-bootstrap";
|
import Swal from "sweetalert2";
|
||||||
import { FaRegCalendarAlt } from "react-icons/fa";
|
|
||||||
|
|
||||||
interface Alumno {
|
interface Alumno {
|
||||||
token: { headers: Record<string, string> };
|
token: { headers: Record<string, string> };
|
||||||
@@ -19,7 +16,7 @@ interface Alumno {
|
|||||||
interface Props {
|
interface Props {
|
||||||
idServicio: number;
|
idServicio: number;
|
||||||
alumno: Alumno;
|
alumno: Alumno;
|
||||||
imprimirMensaje: (msg: string) => void;
|
imprimirMensaje: (message: string) => void;
|
||||||
imprimirWarning: (msg: string, onConfirm: () => void) => void;
|
imprimirWarning: (msg: string, onConfirm: () => void) => void;
|
||||||
imprimirError: (err: unknown) => void;
|
imprimirError: (err: unknown) => void;
|
||||||
obtenerServicio: () => void;
|
obtenerServicio: () => void;
|
||||||
@@ -30,11 +27,11 @@ interface PreRegistroData {
|
|||||||
idServicio: number;
|
idServicio: number;
|
||||||
direccion: string;
|
direccion: string;
|
||||||
telefono: string;
|
telefono: string;
|
||||||
fechaNacimiento: string;
|
// fechaNacimiento: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ApiResponse {
|
interface ApiResponse {
|
||||||
data: { message: string };
|
message: string ;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CompletarDatosPersonales({
|
export default function CompletarDatosPersonales({
|
||||||
@@ -51,28 +48,62 @@ export default function CompletarDatosPersonales({
|
|||||||
const [nacimiento, setNacimiento] = useState<Date>(new Date());
|
const [nacimiento, setNacimiento] = useState<Date>(new Date());
|
||||||
const maxDate = new Date();
|
const maxDate = new Date();
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const confirmarDatos = () => {
|
||||||
|
Swal.fire({
|
||||||
|
title: '¿Estas seguro(a) que tus datos son correctos?',
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Sí, actualizar",
|
||||||
|
cancelButtonText: "Cancelar",
|
||||||
|
confirmButtonColor: "#0d6efd",
|
||||||
|
cancelButtonColor: "#dc3545",
|
||||||
|
}).then((result) => {
|
||||||
|
if(result.isConfirmed) {
|
||||||
|
terminarPreRegistro();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const terminarPreRegistro = async () => {
|
const terminarPreRegistro = async () => {
|
||||||
const data: PreRegistroData = {
|
const data: PreRegistroData = {
|
||||||
idServicio,
|
idServicio,
|
||||||
direccion,
|
direccion,
|
||||||
telefono,
|
telefono,
|
||||||
fechaNacimiento: moment(nacimiento).format("YYYY-MM-DD"),
|
//fechaNacimiento: moment(nacimiento).format("YYYY-MM-DD"),
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res: AxiosResponse<ApiResponse> = await axiosInstance.put(`/servicio/registro_validado`, data, alumno.token);
|
|
||||||
imprimirMensaje(res.data.data.message);
|
console.log("Datos enviados:", data);
|
||||||
obtenerServicio();
|
|
||||||
} catch (err: unknown) {
|
const res: AxiosResponse<ApiResponse> = await axiosInstance.post(`/servicio/registro-validado`, data); // Preguntar si no crear el registro por error
|
||||||
if (isAxiosError(err)) {
|
|
||||||
imprimirError(err.response?.data || err.message);
|
|
||||||
} else {
|
|
||||||
imprimirError(err);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
|
|
||||||
|
// imprimirMensaje(res.data.message);
|
||||||
|
|
||||||
|
Swal.fire("Exito", "Se actualizaron tus datos correctamente", "success");
|
||||||
|
router.refresh();
|
||||||
|
|
||||||
|
await obtenerServicio();
|
||||||
|
setTimeout(() => {
|
||||||
|
router.replace("/"); //Estaria bien corregir esta parte.
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
Swal.fire("Error", "No se pudieron actualizar tur datos, por favor intentelo en otro momento", "error")
|
||||||
|
// if (isAxiosError(err)) {
|
||||||
|
// imprimirError(err.response?.data || err.message);
|
||||||
|
// } else {
|
||||||
|
// imprimirError(err);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
// } finally {
|
||||||
|
// updateIsLoading(false);
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -80,7 +111,7 @@ export default function CompletarDatosPersonales({
|
|||||||
<h2 className="text-xl fw-semibold">Formulario Pre-registro</h2>
|
<h2 className="text-xl fw-semibold">Formulario Pre-registro</h2>
|
||||||
|
|
||||||
{/* Fecha de nacimiento */}
|
{/* Fecha de nacimiento */}
|
||||||
<Col>
|
{/* <Col>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel className="form-label fw-semibold">Fecha de nacimiento:</FormLabel>
|
<FormLabel className="form-label fw-semibold">Fecha de nacimiento:</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
@@ -100,7 +131,7 @@ export default function CompletarDatosPersonales({
|
|||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col> */}
|
||||||
{/*
|
{/*
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="block mb-1 fw-semibold">Fecha de nacimiento</label>
|
<label className="block mb-1 fw-semibold">Fecha de nacimiento</label>
|
||||||
@@ -133,10 +164,10 @@ export default function CompletarDatosPersonales({
|
|||||||
|
|
||||||
{/* Dirección */}
|
{/* Dirección */}
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="block mb-1 form-label fw-semibold mb-2">Dirección</label>
|
<label className="block mb-1 form-label fw-semibold mb-2">Domicilio</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Dirección"
|
placeholder="Domicilio"
|
||||||
maxLength={200}
|
maxLength={200}
|
||||||
value={direccion}
|
value={direccion}
|
||||||
onChange={(e) => setDireccion(e.target.value)}
|
onChange={(e) => setDireccion(e.target.value)}
|
||||||
@@ -148,12 +179,7 @@ export default function CompletarDatosPersonales({
|
|||||||
<div className="text-center mt-4">
|
<div className="text-center mt-4">
|
||||||
<button
|
<button
|
||||||
disabled={!telefono || !direccion}
|
disabled={!telefono || !direccion}
|
||||||
onClick={() =>
|
onClick={confirmarDatos}
|
||||||
imprimirWarning(
|
|
||||||
"¿Estas seguro(a) que tus datos son correctos?",
|
|
||||||
terminarPreRegistro
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className={`px-4 py-2 rounded text-white mb-5 ${
|
className={`px-4 py-2 rounded text-white mb-5 ${
|
||||||
!telefono || !direccion
|
!telefono || !direccion
|
||||||
? "bg-gray-400 cursor-not-allowed"
|
? "bg-gray-400 cursor-not-allowed"
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { axiosInstance } from "@/api/config";
|
import { axiosInstance } from "@/api/config";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
import { AxiosError } from "axios";
|
||||||
|
|
||||||
type Pregunta = {
|
type Pregunta = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -25,9 +28,16 @@ type Tabla = {
|
|||||||
|
|
||||||
type Formulario = { titulo?: string; descripcion?: string; preguntas: Pregunta[]; tablas: Tabla[] };
|
type Formulario = { titulo?: string; descripcion?: string; preguntas: Pregunta[]; tablas: Tabla[] };
|
||||||
|
|
||||||
export default function FullCuestionario() {
|
interface Props{
|
||||||
|
idServicio: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FullCuestionario({ idServicio}: Props) {
|
||||||
const [respuestas, setRespuestas] = useState<Record<string, string | string[] | Record<number, string | null> | null>>({});
|
const [respuestas, setRespuestas] = useState<Record<string, string | string[] | Record<number, string | null> | null>>({});
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [isFormDisabled, setIsFormDisabled] = useState(false);
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
const formulario: Formulario = useMemo(
|
const formulario: Formulario = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@@ -97,6 +107,29 @@ export default function FullCuestionario() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Verificar si el cuestionario ya fue contestado
|
||||||
|
useEffect(() => {
|
||||||
|
const checkIfFormAlreadyCompleted = async () => {
|
||||||
|
try {
|
||||||
|
const idServicio = typeof window !== 'undefined' ? localStorage.getItem('idServicio') : null;
|
||||||
|
if (!idServicio) return;
|
||||||
|
|
||||||
|
const response = await axiosInstance.get(`/servicio/admin?idServicio=${idServicio}`);
|
||||||
|
const idCuestionarioAlumno2 = response.data?.idCuestionarioAlumno2;
|
||||||
|
|
||||||
|
// Si ya existe un cuestionario contestado, deshabilitar el formulario
|
||||||
|
if (idCuestionarioAlumno2 && idCuestionarioAlumno2 > 0) {
|
||||||
|
setIsFormDisabled(true);
|
||||||
|
window.alert('Este cuestionario ya ha sido contestado. No puedes modificar tus respuestas.');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error al verificar cuestionario:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
checkIfFormAlreadyCompleted();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const isMobile = () => typeof window !== 'undefined' && window.innerWidth < 576;
|
const isMobile = () => typeof window !== 'undefined' && window.innerWidth < 576;
|
||||||
|
|
||||||
const sortedItems = useMemo(() => {
|
const sortedItems = useMemo(() => {
|
||||||
@@ -242,20 +275,41 @@ export default function FullCuestionario() {
|
|||||||
if (!validateResponses()) return;
|
if (!validateResponses()) return;
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const data = { ...formatearRespuestas(respuestas), idServicio: typeof window !== 'undefined' ? localStorage.getItem('idServicio') : null };
|
// const idServicioStorage = typeof window !== 'undefined' ? localStorage.getItem('idServicio') : null;
|
||||||
await axiosInstance.post(`/cuestionario_alumno`, data);
|
// if (!idServicioStorage) {
|
||||||
window.alert('Se enviaron los datos correctamente');
|
// window.alert('No se encontró el ID del servicio. Por favor, vuelve a iniciar sesión.');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Para verificar las respuestas de las preguntas
|
||||||
|
console.log('Respuestas a enviar:', respuestas);
|
||||||
|
console.log('Respuestas formateadas:', formatearRespuestas(respuestas));
|
||||||
|
console.log('Respouesta pregunta p_12_C_5', formatearRespuestas(respuestas)['p12_C_5']);
|
||||||
|
|
||||||
|
const data = { ...formatearRespuestas(respuestas), idServicio };
|
||||||
|
|
||||||
|
console.log('Este es el id', data.idServicio)
|
||||||
|
const res = await axiosInstance.post(`/cuestionario-alumno2`, data);
|
||||||
|
|
||||||
|
const mensaje = res?.data?.message || 'Se subio el cuestionario correctamente.';
|
||||||
|
Swal.fire('Exito', mensaje, 'success')
|
||||||
|
|
||||||
|
// window.alert('Se enviaron los datos correctamente');
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
localStorage.removeItem('idCuestionarioAlumno');
|
localStorage.removeItem('idCuestionarioAlumno');
|
||||||
window.location.href = '/alumno';
|
// window.location.href = '/alumno';
|
||||||
|
router.replace('/alumno');
|
||||||
}
|
}
|
||||||
} catch (err: unknown) {
|
} catch (err) {
|
||||||
let message = 'Error al enviar el formulario';
|
|
||||||
if (typeof err === 'object' && err !== null && 'response' in err) {
|
const axiosErr = err as AxiosError<any>;
|
||||||
const anyErr = err as { response?: { data?: { message?: unknown } } };
|
const mensaje = axiosErr?.response?.data?.message || 'No se pudo enviar el cuestionario, por favor intentelo mas tarde.'
|
||||||
if (anyErr.response?.data?.message) message = String(anyErr.response.data.message);
|
Swal.fire('Error', mensaje, 'error')
|
||||||
} else if (err instanceof Error) message = err.message;
|
// let message = 'Error al enviar el formulario';
|
||||||
window.alert(message);
|
// if (typeof err === 'object' && err !== null && 'response' in err) {
|
||||||
|
// const anyErr = err as { response?: { data?: { message?: unknown } } };
|
||||||
|
// if (anyErr.response?.data?.message) message = String(anyErr.response.data.message);
|
||||||
|
// } else if (err instanceof Error) message = err.message;
|
||||||
|
// window.alert(message);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -290,7 +344,7 @@ export default function FullCuestionario() {
|
|||||||
{p.opciones?.map((op) => (
|
{p.opciones?.map((op) => (
|
||||||
<div key={p.id + '-' + op} className="SINO">
|
<div key={p.id + '-' + op} className="SINO">
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" name={p.id} checked={respuestas[p.id] === op} onChange={() => updateRespuestas(p.id, op)} /> {op}
|
<input type="radio" name={p.id} checked={respuestas[p.id] === op} onChange={() => updateRespuestas(p.id, op)} disabled={isFormDisabled} /> {op}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -301,7 +355,7 @@ export default function FullCuestionario() {
|
|||||||
{p.opciones?.map((op) => (
|
{p.opciones?.map((op) => (
|
||||||
<div key={op} className="SINO">
|
<div key={op} className="SINO">
|
||||||
<label className="mt-2">
|
<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}
|
<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)} disabled={isFormDisabled} /> {op}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -309,7 +363,7 @@ export default function FullCuestionario() {
|
|||||||
)}
|
)}
|
||||||
{p.tipo === 'texto' && (
|
{p.tipo === 'texto' && (
|
||||||
<div>
|
<div>
|
||||||
<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í" />
|
<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í" disabled={isFormDisabled} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -339,7 +393,7 @@ export default function FullCuestionario() {
|
|||||||
<td className="bg-transparent">{r.textoRenglon}</td>
|
<td className="bg-transparent">{r.textoRenglon}</td>
|
||||||
{r.opciones.map((op) => (
|
{r.opciones.map((op) => (
|
||||||
<td className="bg-transparent" 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)} />
|
<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)} disabled={isFormDisabled} />
|
||||||
</td>
|
</td>
|
||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
@@ -352,9 +406,14 @@ export default function FullCuestionario() {
|
|||||||
})}
|
})}
|
||||||
|
|
||||||
<div className="my-6 mb-6 text-center mb-5">
|
<div className="my-6 mb-6 text-center mb-5">
|
||||||
<button className="btn btn-success is-medium" onClick={submitForm} disabled={!isFormComplete}>
|
<button className="btn btn-success is-medium" onClick={submitForm} disabled={!isFormComplete || isFormDisabled || isLoading}>
|
||||||
{isLoading ? 'Enviando...' : 'Enviar'}
|
{isLoading ? 'Enviando...' : 'Enviar'}
|
||||||
</button>
|
</button>
|
||||||
|
{isFormDisabled && (
|
||||||
|
<div className="alert alert-info mt-3" role="alert">
|
||||||
|
Este cuestionario ya ha sido contestado y no puede ser modificado.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ interface Carrera {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Servicio {
|
export interface Servicio {
|
||||||
Programa: Programa;
|
programa: Programa;
|
||||||
Usuario: Usuario;
|
//usuario: Usuario;
|
||||||
Carrera: Carrera;
|
carrera: Carrera;
|
||||||
creditos?: string;
|
creditos?: string;
|
||||||
telefono?: string;
|
telefono?: string;
|
||||||
direccion?: string;
|
direccion?: string;
|
||||||
@@ -57,22 +57,22 @@ export default function InformacinoServicio({ servicio }: Props) {
|
|||||||
|
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<label className="form-label fw-semibold">Institución:</label>
|
<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>
|
||||||
|
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<label className="form-label fw-semibold">Dependencia:</label>
|
<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>
|
||||||
|
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<label className="form-label fw-semibold">Programa:</label>
|
<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>
|
||||||
|
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<label className="form-label fw-semibold">Clave de programa:</label>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -80,19 +80,20 @@ export default function InformacinoServicio({ servicio }: Props) {
|
|||||||
<div className="mb-5">
|
<div className="mb-5">
|
||||||
<h4 className="is-size-4 pb-2">Datos personales</h4>
|
<h4 className="is-size-4 pb-2">Datos personales</h4>
|
||||||
|
|
||||||
|
{/*
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<label className="form-label fw-semibold">Número de cuenta:</label>
|
<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>
|
||||||
|
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<label className="form-label fw-semibold">Nombre:</label>
|
<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>
|
||||||
|
*/}
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<label className="form-label fw-semibold">Carrera:</label>
|
<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>
|
||||||
|
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ interface Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
Status: Status;
|
status: Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MensajeAlumno({ Status }: Props) {
|
export default function MensajeAlumno({ status }: Props) {
|
||||||
return (
|
return (
|
||||||
<div className="container mb-6">
|
<div className="container mb-6">
|
||||||
<h4 className="block is-size-4 mb-4">Estimado alumno(a):</h4>
|
<h4 className="block is-size-4 mb-4">Estimado alumno(a):</h4>
|
||||||
|
|
||||||
<p className="has-text-justified is-size-6">
|
<p className="has-text-justified is-size-6">
|
||||||
{Status.idStatus === 2 && (
|
{status.idStatus === 2 && (
|
||||||
<>
|
<>
|
||||||
Estimado alumno(a): Para poder terminar con el registro de tu trámite
|
Estimado alumno(a): Para poder terminar con el registro de tu trámite
|
||||||
de servicio social te pedimos que verifiques que tus datos sean
|
de servicio social te pedimos que verifiques que tus datos sean
|
||||||
@@ -27,7 +27,7 @@ export default function MensajeAlumno({ Status }: Props) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{Status.idStatus === 3 && (
|
{status.idStatus === 3 && (
|
||||||
<>
|
<>
|
||||||
Estimado alumno(a): Te informamos que el Área de Registro y Control
|
Estimado alumno(a): Te informamos que el Área de Registro y Control
|
||||||
de Servicio Social ha validado tu solicitud de registro de servicio
|
de Servicio Social ha validado tu solicitud de registro de servicio
|
||||||
@@ -49,7 +49,7 @@ export default function MensajeAlumno({ Status }: Props) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{Status.idStatus === 4 && (
|
{status.idStatus === 4 && (
|
||||||
<>
|
<>
|
||||||
Estimado alumno(a): Para continuar con el proceso de término de tu
|
Estimado alumno(a): Para continuar con el proceso de término de tu
|
||||||
servicio social debes de subir tu informe global y contestar el
|
servicio social debes de subir tu informe global y contestar el
|
||||||
@@ -57,14 +57,14 @@ export default function MensajeAlumno({ Status }: Props) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{Status.idStatus === 5 && (
|
{status.idStatus === 5 && (
|
||||||
<>
|
<>
|
||||||
Estimado alumno(a): Espera a que tus documentos sean validados por
|
Estimado alumno(a): Espera a que tus documentos sean validados por
|
||||||
el Departamento de Servicio Social y Bolsa de Trabajo.
|
el Departamento de Servicio Social y Bolsa de Trabajo.
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{Status.idStatus === 6 && (
|
{status.idStatus === 6 && (
|
||||||
<>
|
<>
|
||||||
Estimado alumno(a): Te confirmamos que has concluido con los trámites
|
Estimado alumno(a): Te confirmamos que has concluido con los trámites
|
||||||
necesarios para la liberación de tu servicio social por lo que ahora
|
necesarios para la liberación de tu servicio social por lo que ahora
|
||||||
@@ -77,7 +77,7 @@ export default function MensajeAlumno({ Status }: Props) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{Status.idStatus === 8 && (
|
{status.idStatus === 8 && (
|
||||||
<>
|
<>
|
||||||
Estimado alumno(a): Te informamos que la carta de término que el(la)
|
Estimado alumno(a): Te informamos que la carta de término que el(la)
|
||||||
responsable de tu servicio social mandó fue rechazada. Espera a que
|
responsable de tu servicio social mandó fue rechazada. Espera a que
|
||||||
@@ -85,7 +85,7 @@ export default function MensajeAlumno({ Status }: Props) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{Status.idStatus === 9 && (
|
{status.idStatus === 9 && (
|
||||||
<>
|
<>
|
||||||
Estimado alumno(a): Te informamos que el informe global que mandaste
|
Estimado alumno(a): Te informamos que el informe global que mandaste
|
||||||
fue rechazado. Súbelo nuevamente y asegúrate de que cumpla con todos
|
fue rechazado. Súbelo nuevamente y asegúrate de que cumpla con todos
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { axiosInstance } from "@/api/config";
|
import axios from 'axios';
|
||||||
import { isAxiosError } from 'axios';
|
import { Button, FormGroup } from "react-bootstrap";
|
||||||
import { Button, FormGroup, FormLabel } from "react-bootstrap";
|
import { FaUpload } from "react-icons/fa6";
|
||||||
import { FaUpload } from "react-icons/fa";
|
import { useRouter } from "next/navigation";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
interface Alumno {
|
interface Alumno {
|
||||||
tokenArchivo: string;
|
tokenAlumno: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Servicio {
|
interface Servicio {
|
||||||
idServicio: number;
|
idServicio: number;
|
||||||
idCuestionarioAlumno?: number;
|
//idCuestionarioAlumno?: number;
|
||||||
idCuestionarioAlumno2?: number;
|
cuestionarioAlumno?: object;
|
||||||
|
//idCuestionarioAlumno2?: number;
|
||||||
|
cuestionarioAlumno2?: object;
|
||||||
informeGlobal?: string;
|
informeGlobal?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,14 +41,39 @@ export default function PreTermino({
|
|||||||
updateIsLoading,
|
updateIsLoading,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [file, setFile] = useState<File | null>(null);
|
const [file, setFile] = useState<File | null>(null);
|
||||||
|
const router = useRouter();
|
||||||
|
const [servicioLocal, setServicioLocal] = useState<Servicio>(servicio);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setServicioLocal(servicio);
|
||||||
|
}, [servicio]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("Esta es la informacion que se le pasa verificacion cuestionario alumno", servicio)
|
||||||
|
|
||||||
if (file && file.size >= 20000000) {
|
if (file && file.size >= 20000000) {
|
||||||
imprimirError({ message: "El tamaño del archivo excede los 20MB" });
|
imprimirError({ message: "El tamaño del archivo excede los 20MB" });
|
||||||
setFile(null);
|
setFile(null);
|
||||||
}
|
}
|
||||||
}, [file, imprimirError]);
|
}, [file, imprimirError]);
|
||||||
|
|
||||||
|
const confirmarInforme = () => {
|
||||||
|
Swal.fire({
|
||||||
|
title: "¿Estas seguro(a) de querer subir este informe global?",
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Sí, actualizar",
|
||||||
|
cancelButtonText: "Cancelar",
|
||||||
|
confirmButtonColor: "#0d6efd",
|
||||||
|
cancelButtonColor: "#dc3545",
|
||||||
|
}).then((result) => {
|
||||||
|
if(result.isConfirmed) {
|
||||||
|
enviarInformeGlobal();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const enviarInformeGlobal = async () => {
|
const enviarInformeGlobal = async () => {
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
@@ -54,18 +83,39 @@ export default function PreTermino({
|
|||||||
formData.append("data", JSON.stringify(data));
|
formData.append("data", JSON.stringify(data));
|
||||||
formData.append("informeGlobal", file);
|
formData.append("informeGlobal", file);
|
||||||
|
|
||||||
|
console.log("Token del alumno:", alumno.tokenAlumno);
|
||||||
|
console.log("Alumno completo: ", alumno)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res = await axiosInstance.put(`/servicio/informe_global`, formData, { headers: { "Content-Type": "multipart/form-data", Authorization: alumno.tokenArchivo } });
|
// Cambiamos a la otra direccion usamos variable de .env
|
||||||
imprimirMensaje(res.data.message);
|
const res = await axios.put(`${process.env.NEXT_PUBLIC_API_URL}/servicio/informe_global`, formData, {
|
||||||
obtenerServicio();
|
headers: {
|
||||||
|
// "Content-Type": "multipart/form-data",
|
||||||
|
Authorization: `Bearer ${alumno.tokenAlumno}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Swal.fire('Exito', 'Se envio el informe global correctamente.', 'success')
|
||||||
|
|
||||||
|
setServicioLocal(prev => ({
|
||||||
|
...prev,
|
||||||
|
informeGlobal: "uploaded"
|
||||||
|
}));
|
||||||
|
|
||||||
|
// await obtenerServicio();
|
||||||
setFile(null);
|
setFile(null);
|
||||||
} catch (err: unknown) {
|
// setTimeout(() => {
|
||||||
if (isAxiosError(err)) {
|
// router.refresh();
|
||||||
imprimirError((err.response?.data) || err.message);
|
// }, 1000);
|
||||||
} else {
|
//router.refresh(); // Para recargar la pagina y valide si tiene el informe.
|
||||||
imprimirError(err);
|
} catch (err) {
|
||||||
}
|
Swal.fire('Error', 'No se pudo enviar el archivo, por favor intentelo mas tarde.', 'error')
|
||||||
|
// if (isAxiosError(err)) {
|
||||||
|
// imprimirError((err.response?.data) || err.message);
|
||||||
|
// } else {
|
||||||
|
// imprimirError(err);
|
||||||
|
// }
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -77,17 +127,19 @@ export default function PreTermino({
|
|||||||
Cuestionario de evaluación del programa de servicio social.
|
Cuestionario de evaluación del programa de servicio social.
|
||||||
</h6>
|
</h6>
|
||||||
|
|
||||||
{!servicio.idCuestionarioAlumno && !servicio.idCuestionarioAlumno2 ? (
|
{/* !servicio.idCuestionarioAlumno && !servicio.idCuestionarioAlumno2 ? */}
|
||||||
|
|
||||||
|
{servicio.cuestionarioAlumno2 == null && servicio.cuestionarioAlumno == null ? (
|
||||||
<div className="mb-5">
|
<div className="mb-5">
|
||||||
<a
|
<Link
|
||||||
href="/alumno/cuestionario"
|
href={`/alumno/cuestionario/${servicio.idServicio}`}
|
||||||
className="btn btn-outline-primary is-info is-light"
|
className="btn btn-outline-primary is-info is-light"
|
||||||
>
|
>
|
||||||
<span className="icon">
|
<span className="icon">
|
||||||
<i className="fas fa-book-open"></i>
|
<i className="fas fa-book-open"></i>
|
||||||
</span>
|
</span>
|
||||||
<span>Cuestionario</span>
|
<span>Cuestionario</span>
|
||||||
</a>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
@@ -102,7 +154,7 @@ export default function PreTermino({
|
|||||||
|
|
||||||
<h6 className="label fw-semibold">
|
<h6 className="label fw-semibold">
|
||||||
Informe global de actividades{" "}
|
Informe global de actividades{" "}
|
||||||
{!servicio.informeGlobal && (
|
{servicioLocal.informeGlobal && (
|
||||||
<span>(en formato .PDF. No se aceptan fotos)</span>
|
<span>(en formato .PDF. No se aceptan fotos)</span>
|
||||||
)}
|
)}
|
||||||
.
|
.
|
||||||
@@ -141,7 +193,7 @@ Codigo anterior para el envio del archivo
|
|||||||
</div>
|
</div>
|
||||||
*/}
|
*/}
|
||||||
|
|
||||||
{!servicio.informeGlobal ? (
|
{!servicioLocal.informeGlobal ? (
|
||||||
<div className="ph-5">
|
<div className="ph-5">
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<div className="border p-4 text-center rounded"
|
<div className="border p-4 text-center rounded"
|
||||||
@@ -173,12 +225,7 @@ Codigo anterior para el envio del archivo
|
|||||||
<Button
|
<Button
|
||||||
className=""
|
className=""
|
||||||
disabled={!file}
|
disabled={!file}
|
||||||
onClick={() =>
|
onClick={confirmarInforme}
|
||||||
imprimirWarning(
|
|
||||||
"¿Estas seguro(a) de querer subir este informe global?",
|
|
||||||
enviarInformeGlobal
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>Enviar</Button>
|
>Enviar</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { axiosInstance } from '@/api/config';
|
import { axiosInstance } from '@/api/config';
|
||||||
import moment from 'moment';
|
|
||||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||||
import { Col, FormGroup, FormLabel, InputGroup } from 'react-bootstrap';
|
import { Col, FormGroup, FormLabel, InputGroup } from 'react-bootstrap';
|
||||||
import { FaRegCalendarAlt, FaUpload } from 'react-icons/fa';
|
import { FaRegCalendar, FaUpload } from 'react-icons/fa6';
|
||||||
import DatePicker from 'react-datepicker';
|
import DatePicker from 'react-datepicker';
|
||||||
import BotonRegresar from '../boton-regresar';
|
import BotonRegresar from '../boton-regresar';
|
||||||
|
import axios, { AxiosError } from "axios";
|
||||||
|
import Image from 'next/image';
|
||||||
|
import { registerLocale } from "react-datepicker";
|
||||||
|
import { es } from "date-fns/locale/es";
|
||||||
|
import Swal from 'sweetalert2';
|
||||||
|
|
||||||
// 🔹 Tipos estrictos
|
registerLocale("es", es);
|
||||||
|
|
||||||
|
|
||||||
|
5
|
||||||
interface Alumno {
|
interface Alumno {
|
||||||
idUsuario?: number;
|
idUsuario?: number;
|
||||||
idCarrera?: number;
|
idCarrera?: number;
|
||||||
@@ -18,21 +25,29 @@ interface Alumno {
|
|||||||
creditos?: string;
|
creditos?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// correo);
|
||||||
|
// formData.append("alumno[creditos]", alumno.creditos.toString());
|
||||||
|
// formData.append("alumno[telefono]", alumno.telefono);
|
||||||
|
// formData.append("alumno[fechaInicio]", alumno.fechaInicio);
|
||||||
|
// formData.append("alumno[fechaFin]", alumno.fechaFin);
|
||||||
|
// formData.append("alumno[fechaNacimiento]", alumno.fechaNacimiento);
|
||||||
|
// formData.append("alumno[direccion]", alumno.direccion);
|
||||||
|
|
||||||
interface Responsable {
|
interface Responsable {
|
||||||
//token: { headers: Record<string, string> };
|
//token: { headers: Record<string, string> };
|
||||||
tokenArchivo: { headers: Record<string, string> };
|
tokenArchivo: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
//responsable: Responsable;
|
// responsable: Responsable;
|
||||||
imprimirError: (msg: { message: string }) => void;
|
imprimirError: (msg: { message: string }) => void;
|
||||||
imprimirMensaje: (msg: string) => void;
|
imprimirMensaje: (msg: string) => void;
|
||||||
imprimirWarning: (msg: string, callback: () => void) => void;
|
imprimirWarning: (msg: string, callback: () => void, title: string) => void;
|
||||||
updateIsLoading: (value: boolean) => void;
|
updateIsLoading: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CasoEspecialForm({
|
export default function CasoEspecialForm({
|
||||||
//responsable,
|
// responsable,
|
||||||
imprimirError,
|
imprimirError,
|
||||||
imprimirMensaje,
|
imprimirMensaje,
|
||||||
imprimirWarning,
|
imprimirWarning,
|
||||||
@@ -50,11 +65,19 @@ export default function CasoEspecialForm({
|
|||||||
const [alumno, setAlumno] = useState<Alumno>({});
|
const [alumno, setAlumno] = useState<Alumno>({});
|
||||||
const [fechaInicio, setFechaInicio] = useState<Date>(new Date());
|
const [fechaInicio, setFechaInicio] = useState<Date>(new Date());
|
||||||
const [fechaFin, setFechaFin] = useState<Date>(new Date());
|
const [fechaFin, setFechaFin] = useState<Date>(new Date());
|
||||||
const [fechaNacimiento, setFechaNacimiento] = useState<Date>(new Date());
|
const [fechaNacimiento, setFechaNacimiento] = useState<Date | null>(null);
|
||||||
const [file, setFile] = useState<File | null>(null);
|
const [file, setFile] = useState<File | null>(null);
|
||||||
const [minDate, setMinDate] = useState<Date>(new Date('2020-01-02'));
|
const [minDate, setMinDate] = useState<Date>(new Date('2020-01-02'));
|
||||||
const [minDate2, setMinDate2] = useState<Date>(new Date());
|
const [minDate2, setMinDate2] = useState<Date>(new Date());
|
||||||
|
|
||||||
|
const [tokenArchivo, setTokenArchivo] = useState('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTokenArchivo(localStorage.getItem('token') || '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
console.log("Este es el tokenArchivo en caso especial form:", tokenArchivo);
|
||||||
|
|
||||||
// Para mostrar las fechas
|
// Para mostrar las fechas
|
||||||
const handleFechaInicioChange = (date: Date | null) => {
|
const handleFechaInicioChange = (date: Date | null) => {
|
||||||
setFechaInicio(date || new Date());
|
setFechaInicio(date || new Date());
|
||||||
@@ -65,7 +88,7 @@ export default function CasoEspecialForm({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleFechaNacimientoChange = (date: Date | null) => {
|
const handleFechaNacimientoChange = (date: Date | null) => {
|
||||||
setFechaNacimiento(date || new Date())
|
setFechaNacimiento(date)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Función para resetear campos
|
// Función para resetear campos
|
||||||
@@ -80,7 +103,7 @@ export default function CasoEspecialForm({
|
|||||||
setAlumno({});
|
setAlumno({});
|
||||||
setFechaInicio(new Date());
|
setFechaInicio(new Date());
|
||||||
setFechaFin(new Date());
|
setFechaFin(new Date());
|
||||||
setFechaNacimiento(new Date());
|
setFechaNacimiento(null);
|
||||||
setFile(null);
|
setFile(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -114,19 +137,27 @@ export default function CasoEspecialForm({
|
|||||||
const buscarAlumno = async (): Promise<void> => {
|
const buscarAlumno = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res = await axiosInstance.get(`/usuario/escolares?numeroCuenta=${numeroCuenta}`);
|
const res = await axiosInstance.post(`/usuario/escolares/${numeroCuenta}`);
|
||||||
resetear();
|
resetear();
|
||||||
|
console.log('Esta es la res:' , res)
|
||||||
setAlumno(res.data);
|
setAlumno(res.data);
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
resetear();
|
resetear();
|
||||||
setNumeroCuenta('');
|
setNumeroCuenta('');
|
||||||
let msg = { message: 'Error al buscar alumno.' };
|
const axiosErr = err as AxiosError<any>;
|
||||||
if (typeof err === 'object' && err !== null && 'response' in err) {
|
const mensaje = axiosErr?.response?.data?.message || 'El alumno no cumple con los requisitos para hacer el servicio social.'
|
||||||
const anyErr = err as { response?: { data?: { message?: unknown } } };
|
Swal.fire({
|
||||||
const m = anyErr.response?.data as { message?: unknown } | undefined;
|
icon: 'error',
|
||||||
msg = { message: m?.message ? String(m.message) : msg.message };
|
title: 'Error',
|
||||||
} else if (err instanceof Error) msg = { message: err.message };
|
text: mensaje,
|
||||||
imprimirError(msg);
|
})
|
||||||
|
// let msg = { message: 'Error al buscar alumno.' };
|
||||||
|
// if (typeof err === 'object' && err !== null && 'response' in err) {
|
||||||
|
// const anyErr = err as { response?: { data?: { message?: unknown } } };
|
||||||
|
// const m = anyErr.response?.data as { message?: unknown } | undefined;
|
||||||
|
// msg = { message: m?.message ? String(m.message) : msg.message };
|
||||||
|
// } else if (err instanceof Error) msg = { message: err.message };
|
||||||
|
// imprimirError(msg);
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -136,52 +167,179 @@ export default function CasoEspecialForm({
|
|||||||
const enviar = async (): Promise<void> => {
|
const enviar = async (): Promise<void> => {
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
|
if (!tokenArchivo) {
|
||||||
|
imprimirError({ message: "Sesión expirada. Vuelve a iniciar sesión." });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fechaNacimiento) {
|
||||||
|
imprimirError({ message: "Selecciona la fecha de nacimiento" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!alumno.idUsuario || !alumno.idCarrera) {
|
||||||
|
imprimirError({ message: "Busca primero un alumno válido" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
idUsuario: alumno.idUsuario,
|
idUsuario: Number(alumno.idUsuario),
|
||||||
idCarrera: alumno.idCarrera,
|
idCarrera: Number(alumno.idCarrera),
|
||||||
idStatus,
|
idStatus: Number(idStatus),
|
||||||
numeroCuenta,
|
numeroCuenta: numeroCuenta,
|
||||||
creditos: alumno.creditos,
|
creditos: alumno.creditos ? alumno.creditos.toString() : '',
|
||||||
correo,
|
correo: correo.trim(),
|
||||||
fechaInicio: moment(fechaInicio),
|
fechaInicio: formatDate(fechaInicio),
|
||||||
fechaFin: moment(fechaFin),
|
fechaFin: formatDate(fechaFin),
|
||||||
fechaNacimiento: moment(fechaNacimiento),
|
fechaNacimiento: formatDate(fechaNacimiento),
|
||||||
direccion,
|
direccion: direccion.trim(),
|
||||||
telefono,
|
telefono: telefono,
|
||||||
institucion,
|
...(idStatus === '12' && { institucion: institucion.trim() }),
|
||||||
dependencia,
|
...(idStatus === '12' && { dependencia: dependencia.trim() }),
|
||||||
motivo,
|
...(idStatus === '11' && { motivo }),
|
||||||
|
// idUsuario: Number('19839'),
|
||||||
|
// idCarrera: Number('16'),
|
||||||
|
// idStatus: Number('11'),
|
||||||
|
// numeroCuenta: '422016698',
|
||||||
|
// creditos: '100',
|
||||||
|
// correo: correo.trim(),
|
||||||
|
// fechaInicio: formatDate(fechaInicio),
|
||||||
|
// fechaFin: formatDate(fechaFin),
|
||||||
|
// fechaNacimiento: formatDate(fechaNacimiento),
|
||||||
|
// direccion: direccion.trim(),
|
||||||
|
// telefono: telefono,
|
||||||
|
// ...(idStatus === '12' && { institucion: institucion.trim() }),
|
||||||
|
// ...(idStatus === '12' && { dependencia: dependencia.trim() }),
|
||||||
|
// ...(idStatus === '11' && { motivo }),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log("Datos a enviar en caso especial:", data);
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('alumno', JSON.stringify(data));
|
// agregar el archivo.
|
||||||
formData.append('archivos', file);
|
formData.append("archivos", file);
|
||||||
|
formData.append("alumno", JSON.stringify(data));
|
||||||
|
|
||||||
|
// armas los datos para el dto
|
||||||
|
// formData.append("alumno[idUsuario]", alumno.idUsuario.toString());
|
||||||
|
// formData.append("alumno[idCarrera]", alumno.idCarrera.toString());
|
||||||
|
// formData.append("alumno[idStatus]", idStatus);
|
||||||
|
// formData.append("alumno[numeroCuenta]", numeroCuenta);
|
||||||
|
// formData.append("alumno[correo]", correo);
|
||||||
|
// formData.append("alumno[creditos]", alumno.creditos || "");
|
||||||
|
// formData.append("alumno[telefono]", telefono);
|
||||||
|
// formData.append("alumno[fechaInicio]", formatDate(fechaInicio));
|
||||||
|
// formData.append("alumno[fechaFin]", formatDate(fechaFin));
|
||||||
|
// formData.append("alumno[fechaNacimiento]", formatDate(fechaNacimiento));
|
||||||
|
// formData.append("alumno[direccion]", direccion);
|
||||||
|
|
||||||
|
// validaciones extra
|
||||||
|
// if (institucion) {
|
||||||
|
// formData.append("alumno[institucion]", institucion);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (dependencia) {
|
||||||
|
// formData.append("alumno[dependencia]", dependencia);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (motivo) {
|
||||||
|
// formData.append("alumno[motivo]", motivo);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!idStatus) {
|
||||||
|
// console.log('No se envio el idStatus')
|
||||||
|
// }
|
||||||
|
|
||||||
|
//const info = formData.append('alumno', new Blob([JSON.stringify(data)], { type: 'application/json' }));
|
||||||
|
// formData.append('archivos', file);
|
||||||
|
// formData.append("alumno[idUsuario]", alumno.idUsuario.toString());
|
||||||
|
// formData.append("alumno[idCarrera]", alumno.idCarrera.toString());
|
||||||
|
// formData.append("alumno[idStatus]", alumno.idStatus.toString());
|
||||||
|
// formData.append("alumno[numeroCuenta]", alumno.numeroCuenta);
|
||||||
|
// formData.append("alumno[correo]", alumno.correo);
|
||||||
|
// formData.append("alumno[creditos]", alumno.creditos.toString());
|
||||||
|
// formData.append("alumno[telefono]", alumno.telefono);
|
||||||
|
// formData.append("alumno[fechaInicio]", alumno.fechaInicio);
|
||||||
|
// formData.append("alumno[fechaFin]", alumno.fechaFin);
|
||||||
|
// formData.append("alumno[fechaNacimiento]", alumno.fechaNacimiento);
|
||||||
|
// formData.append("alumno[direccion]", alumno.direccion);
|
||||||
|
|
||||||
|
console.log("FormData a enviar en caso especial:", formData.getAll);
|
||||||
|
console.log("Esta es la info al registrar el servicio", formData);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
const res = await axiosInstance.post(`/caso_especial/nuevo`, formData);
|
// Cambiamos a axios normal para enviar la carta de aceptación
|
||||||
|
// const res = await axiosInstance.post(`/caso-especial`, formData);
|
||||||
|
const res = await axios.post(`${process.env.NEXT_PUBLIC_API_URL}/caso-especial`, formData, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
Authorization: tokenArchivo ? `Bearer ${tokenArchivo}` : '',
|
||||||
|
},
|
||||||
|
});
|
||||||
resetear();
|
resetear();
|
||||||
setNumeroCuenta('');
|
setNumeroCuenta('');
|
||||||
imprimirMensaje(res.data.message);
|
const mensaje = res?.data?.message || 'Se creo el servicio social con exito.'
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Exito',
|
||||||
|
text: mensaje,
|
||||||
|
})
|
||||||
|
// imprimirMensaje(res.data.message);
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
let msg: { message: string } = { message: 'Error al enviar formulario.' };
|
const axiosErr = err as AxiosError<any>;
|
||||||
if (typeof err === 'object' && err !== null && 'response' in err) {
|
const mensaje = axiosErr?.response?.data?.message || 'No se pudo completar el registro del servicio social, por favor intentelo mas tarde.'
|
||||||
const anyErr = err as { response?: { data?: unknown } };
|
|
||||||
if (anyErr.response && typeof anyErr.response.data === 'object' && anyErr.response.data !== null) {
|
Swal.fire({
|
||||||
const d = anyErr.response.data as { message?: unknown } | unknown;
|
icon: 'error',
|
||||||
if (d && typeof d === 'object' && 'message' in d && typeof (d as { message?: unknown }).message === 'string') {
|
title: 'Error',
|
||||||
msg = { message: (d as { message?: unknown }).message as string };
|
text: mensaje,
|
||||||
}
|
})
|
||||||
}
|
// Quitar esta parte
|
||||||
} else if (err instanceof Error) {
|
// if (axios.isAxiosError(err)) {
|
||||||
msg = { message: err.message };
|
|
||||||
}
|
// const backendMessage = err.response?.data?.message;
|
||||||
imprimirError(msg);
|
|
||||||
|
// if (backendMessage) {
|
||||||
|
|
||||||
|
// // Si el backend manda string
|
||||||
|
// if (typeof backendMessage === "string") {
|
||||||
|
// imprimirError({ message: backendMessage });
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Si el backend manda arreglo (NestJS validation)
|
||||||
|
// if (Array.isArray(backendMessage)) {
|
||||||
|
// imprimirError({ message: backendMessage.join("\n") });
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// Fallback SOLO si no vino nada del backend
|
||||||
|
// imprimirError({ message: "Error inesperado del servidor" });
|
||||||
|
// let msg: { message: string } = { message: 'Error al enviar formulario.' };
|
||||||
|
// if (typeof err === 'object' && err !== null && 'response' in err) {
|
||||||
|
// const anyErr = err as { response?: { data?: unknown } };
|
||||||
|
// if (anyErr.response && typeof anyErr.response.data === 'object' && anyErr.response.data !== null) {
|
||||||
|
// const d = anyErr.response.data as { message?: unknown } | unknown;
|
||||||
|
// if (d && typeof d === 'object' && 'message' in d && typeof (d as { message?: unknown }).message === 'string') {
|
||||||
|
// msg = { message: (d as { message?: unknown }).message as string };
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else if (err instanceof Error) {
|
||||||
|
// msg = { message: err.message };
|
||||||
|
// }
|
||||||
|
// imprimirError(msg);
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const formatDate = (date: Date) => {
|
||||||
|
return date.toISOString().split("T")[0];
|
||||||
|
};
|
||||||
|
|
||||||
// Actualizar fechas automáticamente
|
// Actualizar fechas automáticamente
|
||||||
const updateFechas = (): void => {
|
const updateFechas = (): void => {
|
||||||
const nuevaFin = new Date(
|
const nuevaFin = new Date(
|
||||||
@@ -201,11 +359,11 @@ export default function CasoEspecialForm({
|
|||||||
}, [idStatus]);
|
}, [idStatus]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (file && file.size >= 20_000_000) {
|
if (file && file.size > 20_000_000) {
|
||||||
imprimirError({ message: 'El tamaño del archivo excede los 20MB.' });
|
imprimirError({ message: 'El tamaño del archivo excede los 20MB.' });
|
||||||
setFile(null);
|
setFile(null);
|
||||||
} else if (file) {
|
} else if (file) {
|
||||||
validarExtencion(file);
|
validarExtencion(file);
|
||||||
}
|
}
|
||||||
}, [file]);
|
}, [file]);
|
||||||
|
|
||||||
@@ -220,9 +378,12 @@ export default function CasoEspecialForm({
|
|||||||
updateFechas();
|
updateFechas();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const confirmarCasoEspecial = () => {
|
||||||
|
Swal.fire({
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
{/* Validaciones del cuestionario */}
|
|
||||||
|
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
return (
|
return (
|
||||||
@@ -230,18 +391,21 @@ export default function CasoEspecialForm({
|
|||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">Número de Cuenta</label>
|
<label className="form-label">Número de Cuenta</label>
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
<input
|
<InputGroup.Text>
|
||||||
type="text"
|
<Image src='/image/numCuenta.svg' width={24} height={24} alt="Icono de escuela"/>
|
||||||
className="form-control"
|
</InputGroup.Text>
|
||||||
placeholder="Número de Cuenta"
|
<input
|
||||||
maxLength={9}
|
type="text"
|
||||||
value={numeroCuenta}
|
className="form-control"
|
||||||
onChange={(e) => setNumeroCuenta(e.target.value)}
|
placeholder="Número de Cuenta"
|
||||||
onKeyDown={(e) => e.key === 'Enter' && buscarAlumno()}
|
maxLength={9}
|
||||||
/>
|
value={numeroCuenta}
|
||||||
<button className="text-white rounded-1" onClick={buscarAlumno}>
|
onChange={(e) => setNumeroCuenta(e.target.value)}
|
||||||
Buscar
|
onKeyDown={(e) => e.key === 'Enter' && buscarAlumno()}
|
||||||
</button>
|
/>
|
||||||
|
<button className="text-white rounded-1" onClick={buscarAlumno}>
|
||||||
|
Buscar
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -269,6 +433,36 @@ export default function CasoEspecialForm({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<Col>
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>Fecha de nacimiento</FormLabel>
|
||||||
|
<InputGroup>
|
||||||
|
<InputGroup.Text>
|
||||||
|
<FaRegCalendar />
|
||||||
|
</InputGroup.Text>
|
||||||
|
|
||||||
|
<DatePicker
|
||||||
|
// selected={fechaNacimiento}
|
||||||
|
selected={fechaNacimiento}
|
||||||
|
// maxDate={new Date()}
|
||||||
|
onChange={handleFechaNacimientoChange}
|
||||||
|
dateFormat="dd-MM-yyyy"
|
||||||
|
className="form-control"
|
||||||
|
wrapperClassName="flex-grow-1"
|
||||||
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={60}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale='es'
|
||||||
|
/>
|
||||||
|
</InputGroup>
|
||||||
|
</FormGroup>
|
||||||
|
</Col>
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">Dirección</label>
|
<label className="form-label">Dirección</label>
|
||||||
<input
|
<input
|
||||||
@@ -306,7 +500,7 @@ export default function CasoEspecialForm({
|
|||||||
<FormLabel>Fecha de inicio</FormLabel>
|
<FormLabel>Fecha de inicio</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text>
|
<InputGroup.Text>
|
||||||
<FaRegCalendarAlt />
|
<FaRegCalendar />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
|
|
||||||
<DatePicker
|
<DatePicker
|
||||||
@@ -317,6 +511,14 @@ export default function CasoEspecialForm({
|
|||||||
className="form-control"
|
className="form-control"
|
||||||
wrapperClassName="flex-grow-1"
|
wrapperClassName="flex-grow-1"
|
||||||
calendarClassName="mi-calendario"
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={15}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale='es'
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@@ -328,45 +530,31 @@ export default function CasoEspecialForm({
|
|||||||
<FormLabel>Fecha de fin</FormLabel>
|
<FormLabel>Fecha de fin</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text>
|
<InputGroup.Text>
|
||||||
<FaRegCalendarAlt />
|
<FaRegCalendar />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
|
|
||||||
<DatePicker
|
<DatePicker
|
||||||
selected={fechaFin}
|
selected={fechaFin}
|
||||||
onChange={handleFechaFinChange}
|
onChange={handleFechaFinChange}
|
||||||
value={fechaFin.toISOString().substring(0,10)}
|
|
||||||
minDate={minDate2}
|
minDate={minDate2}
|
||||||
dateFormat="dd-MM-yyyy"
|
dateFormat="dd-MM-yyyy"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
wrapperClassName="flex-grow-1"
|
wrapperClassName="flex-grow-1"
|
||||||
calendarClassName="mi-calendario"
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={15}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale='es'
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</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">
|
<div className="mb-3">
|
||||||
<label className="form-label">Fecha de inicio</label>
|
<label className="form-label">Fecha de inicio</label>
|
||||||
@@ -469,12 +657,13 @@ export default function CasoEspecialForm({
|
|||||||
<p className='mb-1'>
|
<p className='mb-1'>
|
||||||
{file?.name || 'Arrastra aquí tu archivo o da click aquí para buscar'}
|
{file?.name || 'Arrastra aquí tu archivo o da click aquí para buscar'}
|
||||||
</p>
|
</p>
|
||||||
<p className='is-size-6'>Tmaño máximo 20MB</p>
|
<p className='is-size-6'>Tamañ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>
|
<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>
|
</div>
|
||||||
<input
|
<input
|
||||||
id='fileInput'
|
id='fileInput'
|
||||||
type="file"
|
type="file"
|
||||||
|
accept='.zip, .rar'
|
||||||
style={{ display: 'none'}}
|
style={{ display: 'none'}}
|
||||||
onChange={e => setFile(e.target.files ? e.target.files[0] : null)}
|
onChange={e => setFile(e.target.files ? e.target.files[0] : null)}
|
||||||
/>
|
/>
|
||||||
@@ -500,14 +689,13 @@ export default function CasoEspecialForm({
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
imprimirWarning(
|
imprimirWarning(
|
||||||
'¿Estás seguro(a) de querer crear un nuevo caso especial?',
|
'¿Estás seguro(a) de querer crear un nuevo caso especial?',
|
||||||
enviar
|
enviar,
|
||||||
)
|
'Aviso'
|
||||||
}
|
)}
|
||||||
>
|
>
|
||||||
Enviar
|
Enviar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BotonRegresar />
|
<BotonRegresar />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import React, { useEffect, useState, useCallback } from "react";
|
|||||||
import { axiosInstance } from "@/api/config";
|
import { axiosInstance } from "@/api/config";
|
||||||
import ServicioSocialTabla from "../servicio-social-tabla";
|
import ServicioSocialTabla from "../servicio-social-tabla";
|
||||||
import { Button, Col, Form, FormControl, FormGroup, FormLabel, InputGroup, Row } from "react-bootstrap";
|
import { Button, Col, Form, FormControl, FormGroup, FormLabel, InputGroup, Row } from "react-bootstrap";
|
||||||
import { FaInfoCircle, FaSchool, FaUser } from "react-icons/fa";
|
import { FaCircleInfo, FaUser } from "react-icons/fa6";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
interface Responsable {
|
interface Responsable {
|
||||||
idTipoUsuario: number;
|
idTipoUsuario: number;
|
||||||
@@ -20,7 +21,7 @@ interface ServicioEspecial {
|
|||||||
idServicio: number;
|
idServicio: number;
|
||||||
nombre: string;
|
nombre: string;
|
||||||
numeroCuenta: string;
|
numeroCuenta: string;
|
||||||
status: string;
|
Status: string;
|
||||||
// agrega más campos según lo que devuelva tu API
|
// agrega más campos según lo que devuelva tu API
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,13 +72,9 @@ export default function LiberarCasoEspecial({ responsable, imprimirError }: Prop
|
|||||||
if (search.nombre) query += `&nombre=${search.nombre}`;
|
if (search.nombre) query += `&nombre=${search.nombre}`;
|
||||||
if (search.numeroCuenta) query += `&numeroCuenta=${search.numeroCuenta}`;
|
if (search.numeroCuenta) query += `&numeroCuenta=${search.numeroCuenta}`;
|
||||||
|
|
||||||
const res = await axiosInstance.get(`/caso_especial/servicios_especiales?pagina=${page}${query}`, {
|
const res = await axiosInstance.get(`/caso-especial/servicios_especiales?pagina=${page}${query}`);
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${responsable.token}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
setData(res.data.serviciosEspeciales);
|
setData(res.data.data.serviciosEspeciales);
|
||||||
setTotal(res.data.count);
|
setTotal(res.data.count);
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
let msg = 'Error al obtener los casos especiales';
|
let msg = 'Error al obtener los casos especiales';
|
||||||
@@ -130,7 +127,7 @@ export default function LiberarCasoEspecial({ responsable, imprimirError }: Prop
|
|||||||
<FormLabel className="fw-semibold">Número de Cuenta</FormLabel>
|
<FormLabel className="fw-semibold">Número de Cuenta</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text className="rounded-4">
|
<InputGroup.Text className="rounded-4">
|
||||||
<FaSchool />
|
<Image src="/image/numCuenta.svg" width={24} height={24} alt="Icono de escuela" />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
<FormControl
|
<FormControl
|
||||||
type="text"
|
type="text"
|
||||||
@@ -169,7 +166,7 @@ export default function LiberarCasoEspecial({ responsable, imprimirError }: Prop
|
|||||||
<FormLabel className="fw-semibold">Status</FormLabel>
|
<FormLabel className="fw-semibold">Status</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text className="rounded-4">
|
<InputGroup.Text className="rounded-4">
|
||||||
<FaInfoCircle />
|
<FaCircleInfo />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
<Form.Select
|
<Form.Select
|
||||||
className="rounded-4"
|
className="rounded-4"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
'use client'
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ export default function Logout() {
|
|||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
localStorage.removeItem("token");
|
localStorage.removeItem("token");
|
||||||
localStorage.removeItem('usuario');
|
localStorage.removeItem('usuario');
|
||||||
|
localStorage.clear();
|
||||||
router.push("/");
|
router.push("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { axiosInstance } from "@/api/config";
|
import { axiosInstance } from "@/api/config";
|
||||||
|
import { routerServerGlobal } from "next/dist/server/lib/router-utils/router-server-context";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
type Responsable = { token?: string };
|
type Responsable = { token?: string };
|
||||||
|
|
||||||
@@ -44,6 +47,8 @@ export default function CuestionarioResponsbale2({
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [respuestas, setRespuestas] = useState<Respuestas>({});
|
const [respuestas, setRespuestas] = useState<Respuestas>({});
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
const formulario: Formulario = useMemo(() => ({
|
const formulario: Formulario = useMemo(() => ({
|
||||||
titulo: '2025 Evaluación de la institución receptora de servicio social',
|
titulo: '2025 Evaluación de la institución receptora de servicio social',
|
||||||
descripcion: `Estimado(a) responsable de programa de servicio social:\nTe solicitamos llenar cuidadosamente los campos solicitados a continuación para poder\nvalidar el término del servicio social de nuestro alumno(a).`,
|
descripcion: `Estimado(a) responsable de programa de servicio social:\nTe solicitamos llenar cuidadosamente los campos solicitados a continuación para poder\nvalidar el término del servicio social de nuestro alumno(a).`,
|
||||||
@@ -153,12 +158,16 @@ export default function CuestionarioResponsbale2({
|
|||||||
else answered = answer !== null && String(answer) !== '';
|
else answered = answer !== null && String(answer) !== '';
|
||||||
if (!answered) missing.push(`Pregunta ${p.numeroPregunta}`);
|
if (!answered) missing.push(`Pregunta ${p.numeroPregunta}`);
|
||||||
});
|
});
|
||||||
formulario.tablas.forEach((t) => {
|
|
||||||
|
formulario.tablas.forEach((t, index) => {
|
||||||
const allAnswered = t.renglones.every((r) => {
|
const allAnswered = t.renglones.every((r) => {
|
||||||
const tablaResp = respuestas[String(t.idTabla)] as Record<number, string | null> | undefined;
|
const tablaResp = respuestas[String(t.idTabla)] as Record<number, string | null> | undefined;
|
||||||
return tablaResp && tablaResp[r.idRenglon] !== null;
|
return tablaResp && tablaResp[r.idRenglon] !== null;
|
||||||
});
|
});
|
||||||
if (!allAnswered) missing.push(`Tabla ${t.numeroPregunta}`);
|
if (!allAnswered) {
|
||||||
|
const letra = String.fromCharCode(65 + index);
|
||||||
|
missing.push(`Tabla ${t.numeroPregunta}.${letra}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return missing;
|
return missing;
|
||||||
}, [formulario, respuestas]);
|
}, [formulario, respuestas]);
|
||||||
@@ -204,6 +213,7 @@ export default function CuestionarioResponsbale2({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const t of formulario.tablas) {
|
for (const t of formulario.tablas) {
|
||||||
for (const r of t.renglones) {
|
for (const r of t.renglones) {
|
||||||
const tablaResp = respuestas[String(t.idTabla)] as Record<number, string | null> | undefined;
|
const tablaResp = respuestas[String(t.idTabla)] as Record<number, string | null> | undefined;
|
||||||
@@ -235,12 +245,32 @@ export default function CuestionarioResponsbale2({
|
|||||||
const valor = respuestasTabla[idR as unknown as number];
|
const valor = respuestasTabla[idR as unknown as number];
|
||||||
let clave = `p${numPregunta}_${idR}`;
|
let clave = `p${numPregunta}_${idR}`;
|
||||||
if (subLetra) clave = `p${numPregunta}_${subLetra}_${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 {
|
} else {
|
||||||
const preguntaDef = formulario.preguntas.find((p) => p.id === key);
|
const preguntaDef = formulario.preguntas.find((p) => p.id === key);
|
||||||
if (!preguntaDef) continue;
|
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;
|
return resultado;
|
||||||
@@ -251,21 +281,36 @@ export default function CuestionarioResponsbale2({
|
|||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
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;
|
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 (_) {}
|
Swal.fire({
|
||||||
if (typeof window !== 'undefined') window.location.href = '/alumno';
|
title: 'Éxito',
|
||||||
} catch (err: unknown) {
|
text: 'Se subio el cuestionario correctamente.',
|
||||||
if (typeof err === 'object' && err !== null && 'response' in err) {
|
icon: 'success',
|
||||||
const anyErr = err as { response?: { data?: { message?: unknown } } };
|
})
|
||||||
imprimirError(String(anyErr.response?.data?.message) || 'Error al enviar el formulario');
|
|
||||||
} else if (err instanceof Error) {
|
//imprimirMensaje('Se enviaron los datos correctamente');
|
||||||
imprimirError(err.message);
|
// try { localStorage.removeItem('idCuestionarioAlumno'); } catch (_) {}
|
||||||
} else {
|
if (typeof window !== 'undefined') router.replace('/responsable'); //window.location.href = '/responsable';
|
||||||
imprimirError('Error al enviar el formulario');
|
} catch (err) {
|
||||||
}
|
Swal.fire({
|
||||||
|
title: 'Error',
|
||||||
|
text: 'No se pudo enviar el cuestionario.',
|
||||||
|
icon: 'error',
|
||||||
|
})
|
||||||
|
// if (typeof err === 'object' && err !== null && 'response' in err) {
|
||||||
|
// const anyErr = err as { response?: { data?: { message?: unknown } } };
|
||||||
|
// imprimirError(String(anyErr.response?.data?.message) || 'Error al enviar el formulario');
|
||||||
|
// } else if (err instanceof Error) {
|
||||||
|
// imprimirError(err.message);
|
||||||
|
// } else {
|
||||||
|
// imprimirError('Error al enviar el formulario');
|
||||||
|
// }
|
||||||
} finally {
|
} finally {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { axiosInstance } from "@/api/config";
|
import { axiosInstance } from "@/api/config";
|
||||||
import type { AxiosError } from "axios";
|
import type { AxiosError } from "axios";
|
||||||
import { Button, Col, Form, FormGroup, FormLabel, InputGroup } from "react-bootstrap";
|
import { Col, FormGroup, FormLabel, InputGroup } from "react-bootstrap";
|
||||||
import { FaRegCalendarAlt, FaSchool, FaUpload } from "react-icons/fa";
|
import { FaRegCalendar, FaUpload } from "react-icons/fa6";
|
||||||
import DatePicker from "react-datepicker";
|
import DatePicker from "react-datepicker";
|
||||||
import { PiDotFill } from "react-icons/pi";
|
import axios from "axios";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
import { registerLocale } from "react-datepicker";
|
||||||
|
import { es } from "date-fns/locale/es";
|
||||||
|
|
||||||
|
registerLocale("es", es);
|
||||||
|
|
||||||
|
|
||||||
type Responsable = {
|
type Responsable = {
|
||||||
idUsuario?: number;
|
idUsuario?: number;
|
||||||
@@ -61,11 +68,13 @@ export default function NuevoServicio({
|
|||||||
const [programa, setPrograma] = useState<Programa>({});
|
const [programa, setPrograma] = useState<Programa>({});
|
||||||
|
|
||||||
const handleFechaInicioChange = (date: Date | null) => {
|
const handleFechaInicioChange = (date: Date | null) => {
|
||||||
setFechaInicio(date || new Date());
|
// setFechaInicio(date || new Date());
|
||||||
|
if (date) setFechaInicio(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleFechaFinChange = (date: Date | null) => {
|
const handleFechaFinChange = (date: Date | null) => {
|
||||||
setFechaFin(date || new Date());
|
// setFechaFin(date || new Date());
|
||||||
|
if (date) setFechaFin(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetar = () => {
|
const resetar = () => {
|
||||||
@@ -79,6 +88,17 @@ export default function NuevoServicio({
|
|||||||
setPrograma({});
|
setPrograma({});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const confirmarServicioS = () => {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Warning',
|
||||||
|
text: '¿Esta seguro(a) de querer Pre-Registrar a este alumno?',
|
||||||
|
icon: 'warning',
|
||||||
|
confirmButtonText: 'Confirmar',
|
||||||
|
cancelButtonText: 'Cancelar',
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Validacion para mostrar el boton
|
// Validacion para mostrar el boton
|
||||||
const mostrarBoton = () => {
|
const mostrarBoton = () => {
|
||||||
if (!alumno.idUsuario) return true;
|
if (!alumno.idUsuario) return true;
|
||||||
@@ -94,18 +114,29 @@ export default function NuevoServicio({
|
|||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const headers = responsable?.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
|
const headers = responsable?.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
|
||||||
const res = await axiosInstance.get<Alumno>(`/usuario/escolares?numeroCuenta=${encodeURIComponent(numeroCuenta)}`, { headers });
|
// Enviar headers como tercer parámetro (config), no como body
|
||||||
|
const res = await axiosInstance.post<Alumno>(`/usuario/escolares/${numeroCuenta}`);
|
||||||
resetar();
|
resetar();
|
||||||
setAlumno(res.data);
|
setAlumno(res.data);
|
||||||
|
obtenerProgramas();
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
setNumeroCuenta("");
|
setNumeroCuenta("");
|
||||||
resetar();
|
resetar();
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
const axiosErr = err as AxiosError;
|
|
||||||
if (axiosErr?.response?.data) imprimirError(axiosErr.response.data as object);
|
const axiosErr = err as AxiosError<any>;
|
||||||
else if (err instanceof Error) imprimirError(err.message);
|
const mensaje = axiosErr?.response?.data?.message || 'Ocurrio un error inesperado';
|
||||||
else imprimirError({ message: "Error desconocido" });
|
console.log("mensaje de error", mensaje)
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'warning',
|
||||||
|
title: 'Aviso',
|
||||||
|
text: mensaje,
|
||||||
|
})
|
||||||
|
// 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" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -122,35 +153,76 @@ export default function NuevoServicio({
|
|||||||
correo,
|
correo,
|
||||||
programaInterno,
|
programaInterno,
|
||||||
profesor,
|
profesor,
|
||||||
fechaInicio: fechaInicio.toISOString(),
|
fechaInicio: formatDate(fechaInicio),
|
||||||
fechaFin: fechaFin.toISOString(),
|
fechaFin: formatDate(fechaFin),
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
formData.append("alumno", JSON.stringify(data));
|
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);
|
updateIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const headers = responsable?.tokenArchivo ? { Authorization: `Bearer ${responsable.tokenArchivo}`, 'Content-Type': 'multipart/form-data' } : { 'Content-Type': 'multipart/form-data' };
|
const headers = responsable?.tokenArchivo ? { Authorization: `Bearer ${responsable.tokenArchivo}` }: {};
|
||||||
const res = await axiosInstance.post("/servicio/nuevo", formData, { headers });
|
|
||||||
|
// Falta poner la variable de entorno
|
||||||
|
const res = await axios.post(`${process.env.NEXT_PUBLIC_API_URL}/servicio/nuevo`, formData, {
|
||||||
|
headers: {
|
||||||
|
...(responsable?.tokenArchivo && {
|
||||||
|
Authorization: `Bearer ${responsable.tokenArchivo}`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
setNumeroCuenta("");
|
setNumeroCuenta("");
|
||||||
resetar();
|
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
imprimirMensaje(res.data?.message || "Registrado");
|
Swal.fire('Exito', 'El alumno se registro en el servicio social', 'success')
|
||||||
|
// imprimirMensaje(res.data?.message || "Registrado");
|
||||||
|
resetar();
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
updateIsLoading(false);
|
updateIsLoading(false);
|
||||||
const axiosErr = err as AxiosError;
|
const axiosErr = err as AxiosError<any>;
|
||||||
if (axiosErr?.response?.data) imprimirError(axiosErr.response.data as object);
|
const mensaje = axiosErr?.response?.data?.message || 'No se pudo registrar al alumno';
|
||||||
else if (err instanceof Error) imprimirError(err.message);
|
|
||||||
else imprimirError({ message: "Error desconocido" });
|
Swal.fire({
|
||||||
|
icon: 'error',
|
||||||
|
title: 'Error',
|
||||||
|
text: mensaje,
|
||||||
|
})
|
||||||
|
// 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" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const obtenerProgramas = async () => {
|
const obtenerProgramas = async () => {
|
||||||
try {
|
try {
|
||||||
const headers = responsable?.token ? { Authorization: `Bearer ${responsable.token}` } : undefined;
|
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/programas_responsable/${responsable.idUsuario}`, { headers });
|
||||||
setProgramas(res.data);
|
|
||||||
|
// 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) {
|
} catch (err: unknown) {
|
||||||
const axiosErr = err as AxiosError;
|
const axiosErr = err as AxiosError;
|
||||||
if (axiosErr?.response?.data) imprimirError(axiosErr.response.data as object);
|
if (axiosErr?.response?.data) imprimirError(axiosErr.response.data as object);
|
||||||
@@ -182,34 +254,46 @@ export default function NuevoServicio({
|
|||||||
md.setDate(md.getDate() - 16);
|
md.setDate(md.getDate() - 16);
|
||||||
setMinDate(md);
|
setMinDate(md);
|
||||||
updateFechas();
|
updateFechas();
|
||||||
|
//obtenerProgramas();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [responsable.idTipoUsuario]);
|
||||||
|
|
||||||
|
// Fetch programas when responsable id is available
|
||||||
|
useEffect(() => {
|
||||||
|
if (responsable?.idUsuario) {
|
||||||
obtenerProgramas();
|
obtenerProgramas();
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, [responsable?.idUsuario]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateFechas();
|
updateFechas();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [fechaInicio]);
|
}, [fechaInicio]);
|
||||||
|
|
||||||
|
const formatDate = (date: Date) => {
|
||||||
|
return date.toISOString().split("T")[0];
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label className="form-label fw-bolder">Número de Cuenta</label>
|
<label className="form-label fw-bolder">Número de Cuenta</label>
|
||||||
<div className="d-flex gap-2">
|
<div className="d-flex">
|
||||||
<InputGroup.Text>
|
<InputGroup.Text>
|
||||||
<FaSchool />
|
<Image src="/image/numCuenta.svg" width={24} height={24} alt="Icono de escuela" />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Número de Cuenta"
|
placeholder="Número de Cuenta"
|
||||||
maxLength={9}
|
maxLength={9}
|
||||||
value={numeroCuenta}
|
value={numeroCuenta ?? ''}
|
||||||
onChange={(e) => setNumeroCuenta(e.target.value)}
|
onChange={(e) => setNumeroCuenta(e.target.value)}
|
||||||
onKeyDown={(e) => e.key === 'Enter' && buscarAlumno()}
|
onKeyDown={(e) => e.key === 'Enter' && buscarAlumno()}
|
||||||
className="form-control"
|
className="form-control"
|
||||||
/>
|
/>
|
||||||
<button className="" onClick={() => buscarAlumno()}>Buscar</button>
|
<button type="button" className="" onClick={() => buscarAlumno()}>Buscar</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -217,12 +301,14 @@ export default function NuevoServicio({
|
|||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-bolder">Nombre</label>
|
<label className="form-label fw-bolder">Nombre</label>
|
||||||
<p className="form-control">{alumno.nombre}</p>
|
<p className="form-control">{alumno.nombre}</p>
|
||||||
|
{/* <input className="form-control" value={alumno.nombre} disabled/> */}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{alumno.carrera && (
|
{alumno.carrera && (
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-bolder">Carrera</label>
|
<label className="form-label fw-bolder">Carrera</label>
|
||||||
|
{/* <input className="form-control" value={alumno.carrera ? String(alumno.carrera) : ''} disabled/> */}
|
||||||
<p className="form-control">{alumno.carrera ? String(alumno.carrera) : ''}</p>
|
<p className="form-control">{alumno.carrera ? String(alumno.carrera) : ''}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -230,20 +316,43 @@ export default function NuevoServicio({
|
|||||||
{alumno.creditos && (
|
{alumno.creditos && (
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-bolder">Créditos</label>
|
<label className="form-label fw-bolder">Créditos</label>
|
||||||
|
{/* <input className="form-control" value={alumno.creditos ? parseInt(String(alumno.creditos)) : '' + '%'} disabled/> */}
|
||||||
|
|
||||||
<p className="form-control">{alumno.creditos ? parseInt(String(alumno.creditos)) : ''}{alumno.creditos ? '%' : ''}</p>
|
<p className="form-control">{alumno.creditos ? parseInt(String(alumno.creditos)) : ''}{alumno.creditos ? '%' : ''}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-bolder">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({}); } }}>
|
<select className="form-select"
|
||||||
<option value={JSON.stringify({})} disabled>Seleccionar</option>
|
value={programa.idPrograma ?? ''}
|
||||||
{programas.map((p, i) => (
|
onChange={(e) => {
|
||||||
<option key={i} value={JSON.stringify(p)}>{p.programa}</option>
|
const prog = programas.find(p => p.idPrograma === Number(e.target.value));
|
||||||
|
setPrograma(prog ?? {})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value={''} disabled>Seleccionar</option>
|
||||||
|
{programas.map(p => (
|
||||||
|
<option key={p.idPrograma} value={p.idPrograma}>
|
||||||
|
{p.programa}
|
||||||
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* <div className="mb-3">
|
||||||
|
<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>
|
||||||
|
{(!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>
|
||||||
|
</div> */}
|
||||||
|
|
||||||
{programa.institucion && (
|
{programa.institucion && (
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label fw-bolder">Institución</label>
|
<label className="form-label fw-bolder">Institución</label>
|
||||||
@@ -332,7 +441,7 @@ export default function NuevoServicio({
|
|||||||
<FormLabel className="fw-bolder">Fecha de inicio</FormLabel>
|
<FormLabel className="fw-bolder">Fecha de inicio</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text>
|
<InputGroup.Text>
|
||||||
<FaRegCalendarAlt />
|
<FaRegCalendar />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
|
|
||||||
<DatePicker
|
<DatePicker
|
||||||
@@ -343,6 +452,14 @@ export default function NuevoServicio({
|
|||||||
className="form-control"
|
className="form-control"
|
||||||
wrapperClassName="flex-grow-1"
|
wrapperClassName="flex-grow-1"
|
||||||
calendarClassName="mi-calendario"
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={15}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale="es"
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@@ -353,18 +470,26 @@ export default function NuevoServicio({
|
|||||||
<FormLabel className="fw-bolder">Fecha de fin</FormLabel>
|
<FormLabel className="fw-bolder">Fecha de fin</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text>
|
<InputGroup.Text>
|
||||||
<FaRegCalendarAlt />
|
<FaRegCalendar />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
|
|
||||||
<DatePicker
|
<DatePicker
|
||||||
selected={fechaFin}
|
selected={fechaFin}
|
||||||
onChange={handleFechaFinChange}
|
onChange={handleFechaFinChange}
|
||||||
value={fechaFin.toISOString().substring(0,10)}
|
// value={fechaFin.toISOString().substring(0,10)}
|
||||||
minDate={minDate2}
|
minDate={minDate2}
|
||||||
dateFormat="dd-MM-yyyy"
|
dateFormat="dd-MM-yyyy"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
wrapperClassName="flex-grow-1"
|
wrapperClassName="flex-grow-1"
|
||||||
calendarClassName="mi-calendario"
|
calendarClassName="mi-calendario"
|
||||||
|
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
|
scrollableYearDropdown
|
||||||
|
yearDropdownItemNumber={15}
|
||||||
|
dropdownMode="select"
|
||||||
|
|
||||||
|
locale="es"
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@@ -391,16 +516,16 @@ export default function NuevoServicio({
|
|||||||
|
|
||||||
<FormGroup className="mb-3">
|
<FormGroup className="mb-3">
|
||||||
<FormLabel className="fw-bolder">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()}>
|
<div className="border p-4 text-center rounded" style={{ cursor: "pointer" }} onClick={() => document.getElementById("pdfInput")?.click()}>
|
||||||
<FaUpload size={40} className="mb-2"/>
|
<FaUpload size={40} className="mb-2"/>
|
||||||
<p className="mb-1">
|
<p className="mb-1">
|
||||||
{file?.name || 'Arrastra aquí tu archivo o da click aquí para buscar'}
|
{file?.name || 'Arrastra aquí tu archivo o da click aquí para buscar'}
|
||||||
</p>
|
</p>
|
||||||
<p className="is-size-6">Tamaño máximo 200</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>
|
<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>
|
</div>
|
||||||
<input
|
<input
|
||||||
id="fileInput"
|
id="pdfInput"
|
||||||
type="file"
|
type="file"
|
||||||
style={{ display: 'none'}}
|
style={{ display: 'none'}}
|
||||||
accept="application/pdf"
|
accept="application/pdf"
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
"use client";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { axiosInstance } from "@/api/config";
|
import { axiosInstance } from "@/api/config";
|
||||||
import type { AxiosError } from "axios";
|
import type { AxiosError } from "axios";
|
||||||
import { ServicioSocialResponse } from "@/types/responses";
|
import { ServicioSocialResponse } from "@/types/responses";
|
||||||
import ServicioSocialTabla from "../servicio-social-tabla";
|
import ServicioSocialTabla from "../servicio-social-tabla";
|
||||||
import { Button, Col, FormControl, FormGroup, FormLabel, FormSelect, InputGroup, Row } from "react-bootstrap";
|
import { Button, Col, FormControl, FormGroup, FormLabel, FormSelect, InputGroup, Row } from "react-bootstrap";
|
||||||
import { FaClipboardList, FaInfoCircle, FaSchool, FaUser } from "react-icons/fa";
|
import { FaCircleInfo, FaUser } from "react-icons/fa6";
|
||||||
import { Prev } from "react-bootstrap/esm/PageItem";
|
import Image from "next/image";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
type Responsable = { idUsuario?: number; token?: string; idTipoUsuario?: number };
|
type Responsable = { idUsuario?: number; token?: string; idTipoUsuario?: number };
|
||||||
type StatusItem = { idStatus: number; status: string };
|
type StatusItem = { idStatus: number; status: string };
|
||||||
@@ -23,14 +22,26 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
|
|||||||
const [total, setTotal] = useState(0);
|
const [total, setTotal] = useState(0);
|
||||||
const [data, setData] = useState<ServicioSocialResponse[]>([]);
|
const [data, setData] = useState<ServicioSocialResponse[]>([]);
|
||||||
const [status, setStatus] = useState<StatusItem[]>([]);
|
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 [searchAnterior, setSearchAnterior] = useState<{ numeroCuenta?: string; nombre?: string; idStatus?: string }>({});
|
||||||
|
const [mounted, setMounted] = useState(false);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
const onPageChange = (p: number) => {
|
const onPageChange = (p: number) => {
|
||||||
setPage(p);
|
setPage(p);
|
||||||
obtenerServicios(p);
|
obtenerServicios(p);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onRowAction = (item: ServicioSocialResponse, action: string) => {
|
||||||
|
if (action === "carta_aceptacion") {
|
||||||
|
localStorage.setItem("idServicio", String(item.idServicio));
|
||||||
|
router.push("/responsable/carta_aceptacion");
|
||||||
|
} else if (action === "carta_termino") {
|
||||||
|
localStorage.setItem("idServicio", String(item.idServicio));
|
||||||
|
router.push("/responsable/carta_termino");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const obtenerServicios = async (pagina = page) => {
|
const obtenerServicios = async (pagina = page) => {
|
||||||
let query = "";
|
let query = "";
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@@ -49,14 +60,21 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
|
|||||||
if (search.nombre) query += `&nombre=${encodeURIComponent(search.nombre)}`;
|
if (search.nombre) query += `&nombre=${encodeURIComponent(search.nombre)}`;
|
||||||
if (search.numeroCuenta) query += `&numeroCuenta=${encodeURIComponent(search.numeroCuenta)}`;
|
if (search.numeroCuenta) query += `&numeroCuenta=${encodeURIComponent(search.numeroCuenta)}`;
|
||||||
|
|
||||||
|
const idUsuario = localStorage.getItem("idUsuario")
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
console.log('Informacion en el componente hijo del responsable:', responsable);
|
console.log('Informacion en el componente hijo del responsable:', responsable);
|
||||||
console.log('Id del usuario responsable:', responsable.idUsuario);
|
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('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 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);
|
setData(res.data.serviciosResponsable);
|
||||||
setTotal(res.data.count);
|
setTotal(res.data.count);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@@ -87,6 +105,8 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
obtenerCatalogoStatus();
|
obtenerCatalogoStatus();
|
||||||
|
// mark as mounted to avoid rendering dynamic options during SSR hydration
|
||||||
|
setMounted(true);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -99,7 +119,7 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
|
|||||||
<FormLabel>Número de cuenta</FormLabel>
|
<FormLabel>Número de cuenta</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text className="rounded-4">
|
<InputGroup.Text className="rounded-4">
|
||||||
<FaSchool />
|
<Image src="/image/numCuenta.svg" width={24} height={24} alt="Icono de escuela" />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
<FormControl
|
<FormControl
|
||||||
type="text"
|
type="text"
|
||||||
@@ -133,21 +153,23 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
|
|||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
{/* llega hasta el 10 */}
|
{/* llega hasta el 10 */}
|
||||||
<Col md={3}>
|
<Col md={3}>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>Status</FormLabel>
|
<FormLabel>Status</FormLabel>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputGroup.Text className="rounded-4">
|
<InputGroup.Text className="rounded-4">
|
||||||
<FaInfoCircle />
|
<FaCircleInfo />
|
||||||
</InputGroup.Text>
|
</InputGroup.Text>
|
||||||
<FormSelect
|
<FormSelect
|
||||||
|
suppressHydrationWarning
|
||||||
value={search.idStatus}
|
value={search.idStatus}
|
||||||
onChange={(e) => setSearch(Prev => ({ ...Prev, idStatus: e.target.value}))}
|
onChange={(e) => setSearch(Prev => ({ ...Prev, idStatus: e.target.value}))}
|
||||||
className="rounded-4"
|
className="rounded-4"
|
||||||
|
onKeyDown={(e) => {if (e.key === 'Enter') obtenerServicios()}}
|
||||||
>
|
>
|
||||||
<option value="">Status</option>
|
<option value="">Status</option>
|
||||||
{status.slice(0, 9).map((s) => (
|
{mounted && status.slice(0, 9).map((s) => (
|
||||||
<option key={s.idStatus} value={s.idStatus}>
|
<option key={s.idStatus} value={s.idStatus}>
|
||||||
{s.status}
|
{s.status}
|
||||||
</option>
|
</option>
|
||||||
@@ -158,10 +180,13 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
|
|||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col md={3} className="d-flex align-items-end">
|
<Col md={3} className="d-flex align-items-end">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="submit"
|
||||||
className="w-100 rounded-5"
|
className="w-100 rounded-5"
|
||||||
disabled={isLoading}>{isLoading ? 'Buscando...' : 'Buscar'}
|
disabled={isLoading}
|
||||||
|
onClick={() => obtenerServicios(1)}
|
||||||
|
>
|
||||||
|
{isLoading ? 'Buscando...' : 'Buscar'}
|
||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@@ -184,6 +209,7 @@ export default function TablaServiciosResponsable({ responsable, imprimirError }
|
|||||||
columnasResponsable={true}
|
columnasResponsable={true}
|
||||||
columnaCuestionario={true}
|
columnaCuestionario={true}
|
||||||
columnaCartaTermino={true}
|
columnaCartaTermino={true}
|
||||||
|
onRowAction={onRowAction}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { axiosInstance } from "@/api/config";
|
import { Form } from "react-bootstrap";
|
||||||
import type { AxiosError } from "axios";
|
import { FaUpload } from "react-icons/fa6";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import axios from "axios";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
type Responsable = { tokenArchivo?: string };
|
type Responsable = { tokenArchivo?: string };
|
||||||
|
|
||||||
@@ -31,6 +34,26 @@ export default function UploadArchivo({
|
|||||||
}: Props) {
|
}: Props) {
|
||||||
const [file, setFile] = useState<File | null>(null);
|
const [file, setFile] = useState<File | null>(null);
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
console.log("Responsable en upload archivo:", responsable);
|
||||||
|
|
||||||
|
const confirmarEnvioArchivo = () => {
|
||||||
|
Swal.fire({
|
||||||
|
title: `¿Estas seguro(a) de querer subir esta carta de ${tipoCarta}?`,
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Sí, actualizar",
|
||||||
|
cancelButtonText: "Cancelar",
|
||||||
|
confirmButtonColor: "#0d6efd",
|
||||||
|
cancelButtonColor: "#dc3545",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
subir(); // 👈 aquí ejecutas la función
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const subir = async () => {
|
const subir = async () => {
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
@@ -38,20 +61,39 @@ export default function UploadArchivo({
|
|||||||
formData.append('data', JSON.stringify(data));
|
formData.append('data', JSON.stringify(data));
|
||||||
formData.append(variableName, file, file.name);
|
formData.append(variableName, file, file.name);
|
||||||
|
|
||||||
|
console.log("Esta es la info que se mandara al backend:", formData);
|
||||||
|
|
||||||
updateIsLoading(true);
|
updateIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const headers = responsable?.tokenArchivo ? { Authorization: `Bearer ${responsable.tokenArchivo}`, 'Content-Type': 'multipart/form-data' } : { 'Content-Type': 'multipart/form-data' };
|
// Cambiamos a la direccion de axios normal
|
||||||
const res = await axiosInstance.put(`/servicio/${path}`, formData, { headers });
|
const res = await axios.put(`${process.env.NEXT_PUBLIC_API_URL}/servicio/${path}`, formData, {
|
||||||
try { localStorage.removeItem('idServicio'); } catch (error) {}
|
headers: {
|
||||||
updateIsLoading(false);
|
Authorization: `Bearer ${responsable.tokenArchivo}`,
|
||||||
imprimirMensaje(res.data?.message || 'Archivo subido');
|
'Content-Type': 'multipart/form-data',
|
||||||
if (typeof window !== 'undefined') window.location.href = '/responsable';
|
},
|
||||||
} catch (err: unknown) {
|
});
|
||||||
updateIsLoading(false);
|
try { localStorage.removeItem('idServicio'); }
|
||||||
const axiosErr = err as AxiosError;
|
catch (error) {}
|
||||||
if (axiosErr?.response?.data) imprimirError(axiosErr.response.data as object);
|
|
||||||
else if (err instanceof Error) imprimirError(err.message);
|
updateIsLoading(false);
|
||||||
else imprimirError({ message: 'Error desconocido' });
|
Swal.fire({
|
||||||
|
title: 'Éxito',
|
||||||
|
text: 'Se subio el archivo correctamente',
|
||||||
|
icon: 'success',
|
||||||
|
})
|
||||||
|
//imprimirMensaje(res.data?.message || 'Archivo subido');
|
||||||
|
if (typeof window !== 'undefined') router.replace('/responsable') //window.location.href = '/responsable';
|
||||||
|
} catch (err) {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error',
|
||||||
|
text: 'Error al enviar el archivo',
|
||||||
|
icon: 'error',
|
||||||
|
})
|
||||||
|
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,20 +107,54 @@ export default function UploadArchivo({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="mb-3">
|
{/* <div className="mb-3">
|
||||||
<label className="form-label">Carta de {tipoCarta} (en formato .pdf, no se aceptan fotos).</label>
|
<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)} />
|
<input type="file" accept="application/pdf" className="form-control" onChange={(e) => setFile(e.target.files?.[0] ?? null)} />
|
||||||
<div className="mt-2 text-center">
|
<div className="mt-2 text-center">
|
||||||
<p className="h5">{file?.name || 'Arrastra aquí tu archivo o da click aquí para buscarlo.'}</p>
|
<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>
|
<p className="small">Tamaño máximo 20MB</p>
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
<div className="text-center my-4">
|
<div className="text-center my-4">
|
||||||
<button className="btn btn-success" disabled={!file?.name} onClick={() => imprimirWarning(`¿Estas seguro(a) de querer subir esta carta de ${tipoCarta}?`, subir)}>
|
<button className="btn btn-success" disabled={!file?.name} onClick={confirmarEnvioArchivo}>
|
||||||
Enviar
|
Enviar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,25 +46,49 @@ export default function ServicioSocialTabla({
|
|||||||
// 🔹 Cargar datos del padre si existen
|
// 🔹 Cargar datos del padre si existen
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data && data.length > 0) {
|
if (data && data.length > 0) {
|
||||||
setInfo(data);
|
setInfo(data);
|
||||||
}
|
}
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
// 🔹 Paginación simple
|
// 🔹 Paginación simple
|
||||||
function handlePrev() {
|
function handlePrev() {
|
||||||
if (currentPage > 1) {
|
if (currentPage > 1) {
|
||||||
const np = currentPage - 1;
|
const np = currentPage - 1;
|
||||||
setCurrentPage(np);
|
setCurrentPage(np);
|
||||||
onPageChange?.(np);
|
onPageChange?.(np);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleNext() {
|
function handleNext() {
|
||||||
const lastPage = Math.max(1, Math.ceil(total / 10));
|
const lastPage = Math.max(1, Math.ceil(total / 10));
|
||||||
if (currentPage < lastPage) {
|
if (currentPage < lastPage) {
|
||||||
const np = currentPage + 1;
|
const np = currentPage + 1;
|
||||||
setCurrentPage(np);
|
setCurrentPage(np);
|
||||||
onPageChange?.(np);
|
onPageChange?.(np);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +115,8 @@ export default function ServicioSocialTabla({
|
|||||||
//router.push("/administrador/servicio");
|
//router.push("/administrador/servicio");
|
||||||
//router.push('/administrador/casos_especiales/caso_especial')
|
//router.push('/administrador/casos_especiales/caso_especial')
|
||||||
|
|
||||||
|
} else if (idTipoUsuario === 2) {
|
||||||
|
servicioSelectedResponsable(row);
|
||||||
} else if (
|
} else if (
|
||||||
row.idServicio ||
|
row.idServicio ||
|
||||||
("idCasoEspecial" in row && row.idCasoEspecial)
|
("idCasoEspecial" in row && row.idCasoEspecial)
|
||||||
@@ -153,19 +179,19 @@ const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEsp
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="table-responsive">
|
<div className="table-responsive">
|
||||||
<table className="table table-striped">
|
<table className="table table-striped table-fixed">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
{columnaFechaRegistro && <th>Fecha Registro</th>}
|
{columnaFechaRegistro && <th className="text-center align-middle">Fecha Registro</th>}
|
||||||
<th>Número de Cuenta</th>
|
<th className="text-center align-middle">Número de Cuenta</th>
|
||||||
<th>Nombre</th>
|
<th className="text-center align-middle">Nombre</th>
|
||||||
<th>Carrera</th>
|
<th className="text-center align-middle">Carrera</th>
|
||||||
{columnaFechaInicio && <th>Fecha Inicio</th>}
|
{columnaFechaInicio && <th className="text-center align-middle">Fecha Inicio</th>}
|
||||||
{columnaFechaFin && <th>Fecha Fin</th>}
|
{columnaFechaFin && <th className="text-center align-middle">Fecha Fin</th>}
|
||||||
<th>Status</th>
|
<th className="text-center align-middle">Status</th>
|
||||||
{columnaCuestionarioCompleto && <th>Cuestionario Completo</th>}
|
{columnaCuestionarioCompleto && <th className="text-center align-middle">Cuestionario Completo</th>}
|
||||||
{columnaCartaTermino && <th>Carta Termino</th>}
|
{columnaCartaTermino && <th className="text-center align-middle">Carta Termino</th>}
|
||||||
{columnaCuestionario && <th>Cuestionario</th>}
|
{columnaCuestionario && <th className="text-center align-middle">Cuestionario</th>}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -182,18 +208,24 @@ const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEsp
|
|||||||
//idTipoUsuario === 1 ? servicioSelected(item) : undefined
|
//idTipoUsuario === 1 ? servicioSelected(item) : undefined
|
||||||
//}
|
//}
|
||||||
>
|
>
|
||||||
{columnaFechaRegistro && <td>{formatDate(item.createdAt)}</td>}
|
{columnaFechaRegistro && <td className="text-center align-middle">{formatDate(item.createdAt)}</td>}
|
||||||
<td>{item.Usuario?.usuario}</td>
|
<td className="text-center align-middle">{item.usuario?.usuario}</td>
|
||||||
<td>{item.Usuario?.nombre}</td>
|
<td className="text-center align-middle">{item.usuario?.nombre}</td>
|
||||||
<td>{item.Carrera?.carrera}</td>
|
<td className="text-center align-middle">{item.carrera?.carrera}</td>
|
||||||
|
|
||||||
|
{/*
|
||||||
|
Poner si quieres hacer condicional para no mostrar infromacion
|
||||||
|
? formatDate(item.fechaInicio) : "-" */}
|
||||||
{columnaFechaInicio && (
|
{columnaFechaInicio && (
|
||||||
<td>{formatDate(item.fechaInicio)}</td>
|
<td className="text-center align-middle">{formatDate(item.fechaInicio)}</td>
|
||||||
)}
|
)}
|
||||||
{columnaFechaFin && <td>{formatDate(item.fechaFin)}</td>}
|
|
||||||
<td>
|
{columnaFechaFin && <td className="text-center align-middle">{formatDate(item.fechaFin)}</td>}
|
||||||
{columnasResponsable && item.Status?.idStatus === 7 ? (
|
|
||||||
|
<td className="text-center align-middle">
|
||||||
|
{columnasResponsable && item.status?.idStatus === 7 ? (
|
||||||
<button
|
<button
|
||||||
className="btn btn-sm btn-danger"
|
className="badge bg-danger border-0"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
onRowAction?.(item, "carta_aceptacion")
|
onRowAction?.(item, "carta_aceptacion")
|
||||||
}
|
}
|
||||||
@@ -203,36 +235,71 @@ const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEsp
|
|||||||
) : (
|
) : (
|
||||||
<span
|
<span
|
||||||
className={`badge bg-${statusClass(
|
className={`badge bg-${statusClass(
|
||||||
item.Status?.idStatus
|
item.status?.idStatus
|
||||||
)}`}
|
)}`}
|
||||||
>
|
>
|
||||||
{item.Status?.status}
|
{item.status?.status}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
{columnaCartaTermino && (
|
{columnaCartaTermino && (
|
||||||
<td>{item.cartaTermino ? (
|
<td className="text-center align-middle"
|
||||||
<span className="badge bg-success">Completado</span>
|
style={{ cursor: (idTipoUsuario === 2 && (item.status?.idStatus === 4 || item.status?.idStatus === 8) && !item.cartaTermino) ? 'pointer' : 'default'}}
|
||||||
) : (
|
onClick={() => {
|
||||||
<span className="badge bg-danger">No Completado</span>
|
if (idTipoUsuario === 2 && item.status?.idStatus === 8) {
|
||||||
)}</td>
|
onRowAction?.(item, "carta_termino");
|
||||||
|
} else if (idTipoUsuario === 2 && item.status?.idStatus === 4 && !item.cartaTermino) {
|
||||||
|
servicioSelectedResponsableCartaTermino(item);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.status?.idStatus === 8 ? (
|
||||||
|
<button
|
||||||
|
className="badge bg-danger border-0"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
onRowAction?.(item, "carta_termino");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Carta Termino Rechazada
|
||||||
|
</button>
|
||||||
|
) : item.status?.idStatus === 4 ? (
|
||||||
|
item.cartaTermino ? (
|
||||||
|
<span className="badge">✅</span>
|
||||||
|
) : (
|
||||||
|
<span className="badge text-morado bg-light-morado">Carta Termino</span>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<span className="badge text-secondary"> </span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{columnaCuestionarioCompleto && (
|
{columnaCuestionarioCompleto && (
|
||||||
<td>{item.cuestionarioCompletado ? (
|
<td className="text-center align-middle"
|
||||||
|
>{item.cuestionarioCompletado ? (
|
||||||
<span className="badge bg-success">Completado</span>
|
<span className="badge bg-success">Completado</span>
|
||||||
) : (
|
) : (
|
||||||
<span className="badge bg-danger">No Completado</span>
|
<span className="badge text-morado bg-light-morado">No Completado</span>
|
||||||
)}</td>
|
)}</td>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
{columnaCuestionario && (
|
{columnaCuestionario && (
|
||||||
<td>
|
<td className="text-center align-middle"
|
||||||
{item.cuestionarioCompletado ? (
|
style={{ cursor: (idTipoUsuario === 2 && item.status?.idStatus === 4 && !item.cuestionarioCompletado) ? 'pointer' : 'default'}}
|
||||||
<span className="badge bg-success">Completado</span>
|
onClick={() => (
|
||||||
|
(idTipoUsuario === 2 && item.status?.idStatus === 4 && !item.cuestionarioCompletado) ? servicioSelectedResponsable(item) : undefined
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{item.status?.idStatus === 4 ? (
|
||||||
|
item.cuestionarioCompletado ? (
|
||||||
|
<span className="badge">✅</span>
|
||||||
|
) : (
|
||||||
|
<span className="badge text-morado bg-light-morado">Cuestionario</span>
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<span className="badge bg-danger">No Completado</span>
|
<span className="badge text-secondary"> </span>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
)}
|
)}
|
||||||
@@ -277,6 +344,7 @@ const servicioSelected = (row: ServicioSocialResponse | ServicioSocialConCasoEsp
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function formatDate(value?: string | null): string {
|
function formatDate(value?: string | null): string {
|
||||||
if (!value) return "";
|
if (!value) return "";
|
||||||
|
|
||||||
@@ -284,7 +352,7 @@ function formatDate(value?: string | null): string {
|
|||||||
const d = new Date(value.includes("T") ? value : `${value}T00:00:00`);
|
const d = new Date(value.includes("T") ? value : `${value}T00:00:00`);
|
||||||
|
|
||||||
if (isNaN(d.getTime())) {
|
if (isNaN(d.getTime())) {
|
||||||
console.warn("⚠️ Fecha inválida:", value);
|
// console.warn("⚠️ Fecha inválida:", value);
|
||||||
return "";
|
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
+36
-14
@@ -1,4 +1,4 @@
|
|||||||
@import 'bootstrap/scss/functions';
|
@import 'bootstrap/dist/css/bootstrap.min.css';
|
||||||
|
|
||||||
$azul: #003d79;
|
$azul: #003d79;
|
||||||
$dorado: #bd8c01;
|
$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',
|
'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
||||||
'Segoe UI Symbol';
|
'Segoe UI Symbol';
|
||||||
|
|
||||||
@import 'bootstrap/scss/variables';
|
|
||||||
@import 'bootstrap/scss/variables-dark';
|
|
||||||
|
|
||||||
$custom-colors: (
|
$custom-colors: (
|
||||||
'azul': $azul,
|
'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-registro {
|
||||||
.form-floating {
|
.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 {
|
.aviso {
|
||||||
@@ -137,7 +133,7 @@ $theme-colors: map-merge($theme-colors, $custom-colors);
|
|||||||
height: 2px;
|
height: 2px;
|
||||||
background-color: $azul;
|
background-color: $azul;
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
@media (min-width: 768px) {
|
||||||
left: 10rem;
|
left: 10rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,12 +204,12 @@ $theme-colors: map-merge($theme-colors, $custom-colors);
|
|||||||
}
|
}
|
||||||
|
|
||||||
.full-center {
|
.full-center {
|
||||||
//flex-grow-1 d-flex flex-column justify-content-center align-items-center
|
/* Equivalent of Bootstrap utility classes without using @extend */
|
||||||
@extend .flex-grow-1;
|
flex-grow: 1;
|
||||||
@extend .d-flex;
|
display: flex;
|
||||||
@extend .flex-column;
|
flex-direction: column;
|
||||||
@extend .justify-content-center;
|
justify-content: center;
|
||||||
@extend .align-items-center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.minNavbar {
|
.minNavbar {
|
||||||
@@ -268,3 +264,29 @@ $theme-colors: map-merge($theme-colors, $custom-colors);
|
|||||||
.imageFlip:hover {
|
.imageFlip:hover {
|
||||||
transform: rotateY(360deg);
|
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; }
|
||||||
|
.bg-light-morado { background-color: #d6c9f7 !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; }
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { axiosInstance } from "@/api/config"
|
||||||
|
import { CasoEspecial } from "@/types/responses"
|
||||||
|
|
||||||
|
export const getUserCasoEspecial = async (idCasoEspecial: number): Promise<CasoEspecial[]> => {
|
||||||
|
const res = await axiosInstance.get(`caso-especial/caso_especial/${idCasoEspecial}`)
|
||||||
|
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
Vendored
+16
-3
@@ -8,9 +8,9 @@ export interface ServicioSocialResponse {
|
|||||||
fechaFin?: string | null;
|
fechaFin?: string | null;
|
||||||
fechaInicio?: string | null;
|
fechaInicio?: string | null;
|
||||||
fecha_registro?: string | null;
|
fecha_registro?: string | null;
|
||||||
Usuario?: Usuario;
|
usuario?: Usuario;
|
||||||
Carrera?: Carrera;
|
carrera?: Carrera;
|
||||||
Status?: Status;
|
status?: Status;
|
||||||
cartaTermino?: boolean;
|
cartaTermino?: boolean;
|
||||||
idCuestionarioPrograma?: number | null;
|
idCuestionarioPrograma?: number | null;
|
||||||
idCuestionarioPrograma2?: number | null;
|
idCuestionarioPrograma2?: number | null;
|
||||||
@@ -57,4 +57,17 @@ export interface Responsables {
|
|||||||
|
|
||||||
interface ServicioSocialConCasoEspecial extends ServicioSocialResponse {
|
interface ServicioSocialConCasoEspecial extends ServicioSocialResponse {
|
||||||
idCasoEspecial?: number;
|
idCasoEspecial?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CasoEspecial {
|
||||||
|
idCasoEspecial: number;
|
||||||
|
correo?: string;
|
||||||
|
telefono?: string;
|
||||||
|
direccion?: string;
|
||||||
|
fechaInicio?: Date;
|
||||||
|
fechaFin?: Date;
|
||||||
|
fechaNacimiento?: Date;
|
||||||
|
motivo?: string;
|
||||||
|
dependencia?: string;
|
||||||
|
institucion?: string;
|
||||||
}
|
}
|
||||||
+19
-5
@@ -1,7 +1,11 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2017",
|
"target": "ES2017",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
@@ -11,7 +15,7 @@
|
|||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve",
|
"jsx": "react-jsx",
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
@@ -19,9 +23,19 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": [
|
||||||
|
"./src/*"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"include": [
|
||||||
"exclude": ["node_modules"]
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts",
|
||||||
|
".next/dev/types/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user