cambios
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
{
|
||||
"pollutionMeasurements": {
|
||||
"city": "Ciudad de M\\u00e9xico",
|
||||
"cityCode": "MEX",
|
||||
"country": "M\\u00e9xico",
|
||||
"mesurementAgency": "SIMAT",
|
||||
"unit": { "RH": "%", "TMP": "C", "WSP": "m/s", "WDR": "o" },
|
||||
"date": {
|
||||
"2023-01-01 01:00": {
|
||||
"RH": {
|
||||
"ACO": "81",
|
||||
"AJU": "100",
|
||||
"MON": "56",
|
||||
"CHO": "",
|
||||
"CUA": "61",
|
||||
"CUT": "73",
|
||||
"FAC": "73",
|
||||
"HGM": "58",
|
||||
"MER": "66",
|
||||
"NEZ": "57",
|
||||
"PED": "63",
|
||||
"SAG": "74",
|
||||
"SFE": "",
|
||||
"TAH": "65",
|
||||
"TLA": "60",
|
||||
"UAX": "71",
|
||||
"UIZ": "74",
|
||||
"VIF": "69",
|
||||
"XAL": "",
|
||||
"MGH": "",
|
||||
"AJM": "64",
|
||||
"MPA": "71",
|
||||
"BJU": "66",
|
||||
"INN": "87",
|
||||
"GAM": "68",
|
||||
"LAA": "70"
|
||||
},
|
||||
"TMP": {
|
||||
"ACO": "9.3",
|
||||
"AJU": "2.5",
|
||||
"MON": "13.9",
|
||||
"CHO": "",
|
||||
"CUA": "10.9",
|
||||
"CUT": "8.4",
|
||||
"FAC": "8.5",
|
||||
"HGM": "13.2",
|
||||
"MER": "13.1",
|
||||
"NEZ": "13.8",
|
||||
"PED": "10.9",
|
||||
"SAG": "13.7",
|
||||
"SFE": "",
|
||||
"TAH": "9.3",
|
||||
"TLA": "12.2",
|
||||
"UAX": "10",
|
||||
"UIZ": "12.7",
|
||||
"VIF": "9.4",
|
||||
"XAL": "",
|
||||
"MGH": "",
|
||||
"AJM": "7.2",
|
||||
"MPA": "",
|
||||
"BJU": "12.2",
|
||||
"INN": "3.2",
|
||||
"GAM": "13.3",
|
||||
"LAA": "12.5"
|
||||
},
|
||||
"WDR": {
|
||||
"ACO": "319",
|
||||
"AJU": "36",
|
||||
"MON": "177",
|
||||
"CHO": "",
|
||||
"CUA": "258",
|
||||
"CUT": "246",
|
||||
"FAC": "245",
|
||||
"HGM": "43",
|
||||
"MER": "178",
|
||||
"NEZ": "156",
|
||||
"PED": "227",
|
||||
"SAG": "247",
|
||||
"SFE": "",
|
||||
"TAH": "9",
|
||||
"TLA": "347",
|
||||
"UAX": "139",
|
||||
"UIZ": "168",
|
||||
"VIF": "269",
|
||||
"XAL": "",
|
||||
"MGH": "",
|
||||
"AJM": "",
|
||||
"MPA": "155",
|
||||
"BJU": "170",
|
||||
"INN": "105",
|
||||
"GAM": "66",
|
||||
"LAA": "58",
|
||||
"FAR": "159",
|
||||
"SAC": "141"
|
||||
},
|
||||
"WSP": {
|
||||
"ACO": "1.3",
|
||||
"AJU": "2.4",
|
||||
"MON": "1.8",
|
||||
"CHO": "",
|
||||
"CUA": "1.7",
|
||||
"CUT": "1.4",
|
||||
"FAC": "0.8",
|
||||
"HGM": "1.4",
|
||||
"MER": "0.9",
|
||||
"NEZ": "2.2",
|
||||
"PED": "1.9",
|
||||
"SAG": "0",
|
||||
"SFE": "",
|
||||
"TAH": "0.3",
|
||||
"TLA": "0.9",
|
||||
"UAX": "1.3",
|
||||
"UIZ": "0.6",
|
||||
"VIF": "0",
|
||||
"XAL": "",
|
||||
"MGH": "",
|
||||
"AJM": "",
|
||||
"MPA": "3.1",
|
||||
"BJU": "0.8",
|
||||
"INN": "0.5",
|
||||
"GAM": "0.3",
|
||||
"LAA": "0.6",
|
||||
"FAR": "1.4",
|
||||
"SAC": "2.4"
|
||||
},
|
||||
"PBa": { "MER": "" },
|
||||
"2023-01-01 02:00": {
|
||||
"RH": {
|
||||
"ACO": "85",
|
||||
"AJU": "100",
|
||||
"MON": "63",
|
||||
"CHO": "",
|
||||
"CUA": "67",
|
||||
"CUT": "73",
|
||||
"FAC": "78",
|
||||
"HGM": "61",
|
||||
"MER": "67",
|
||||
"NEZ": "60",
|
||||
"PED": "58",
|
||||
"SAG": "79",
|
||||
"SFE": "",
|
||||
"TAH": "67",
|
||||
"TLA": "62",
|
||||
"UAX": "73",
|
||||
"UIZ": "75",
|
||||
"VIF": "72",
|
||||
"XAL": "",
|
||||
"MGH": "",
|
||||
"AJM": "61",
|
||||
"MPA": "73",
|
||||
"BJU": "67",
|
||||
"INN": "87",
|
||||
"GAM": "69",
|
||||
"LAA": "74"
|
||||
},
|
||||
"TMP": {
|
||||
"ACO": "8.2",
|
||||
"AJU": "3.1",
|
||||
"MON": "11.7",
|
||||
"CHO": "",
|
||||
"CUA": "10.6",
|
||||
"CUT": "7.9",
|
||||
"FAC": "7.2",
|
||||
"HGM": "12.4",
|
||||
"MER": "12.8",
|
||||
"NEZ": "13.1",
|
||||
"PED": "10.8",
|
||||
"SAG": "12.7",
|
||||
"SFE": "",
|
||||
"TAH": "8.9",
|
||||
"TLA": "11.1",
|
||||
"UAX": "9.6",
|
||||
"UIZ": "12.1",
|
||||
"VIF": "8.5",
|
||||
"XAL": "",
|
||||
"MGH": "",
|
||||
"AJM": "6.7",
|
||||
"MPA": "",
|
||||
"BJU": "11.7",
|
||||
"INN": "3.2",
|
||||
"GAM": "13",
|
||||
"LAA": "11.6"
|
||||
},
|
||||
"WDR": {
|
||||
"ACO": "355",
|
||||
"AJU": "6",
|
||||
"MON": "49",
|
||||
"CHO": "",
|
||||
"CUA": "265",
|
||||
"CUT": "223",
|
||||
"FAC": "235",
|
||||
"HGM": "39",
|
||||
"MER": "208",
|
||||
"NEZ": "205",
|
||||
"PED": "212",
|
||||
"SAG": "92",
|
||||
"SFE": "",
|
||||
"TAH": "288",
|
||||
"TLA": "318",
|
||||
"UAX": "184",
|
||||
"UIZ": "196",
|
||||
"VIF": "312",
|
||||
"XAL": "",
|
||||
"MGH": "",
|
||||
"AJM": "",
|
||||
"MPA": "165",
|
||||
"BJU": "169",
|
||||
"INN": "66",
|
||||
"GAM": "37",
|
||||
"LAA": "277",
|
||||
"FAR": "59",
|
||||
"SAC": "153"
|
||||
},
|
||||
"WSP": {
|
||||
"ACO": "1.3",
|
||||
"AJU": "1.7",
|
||||
"MON": "1.1",
|
||||
"CHO": "",
|
||||
"CUA": "2.4",
|
||||
"CUT": "1.4",
|
||||
"FAC": "1",
|
||||
"HGM": "0.7",
|
||||
"MER": "1.1",
|
||||
"NEZ": "0.9",
|
||||
"PED": "2.1",
|
||||
"SAG": "0.1",
|
||||
"SFE": "",
|
||||
"TAH": "1.3",
|
||||
"TLA": "1.3",
|
||||
"UAX": "0.8",
|
||||
"UIZ": "0.8",
|
||||
"VIF": "0",
|
||||
"XAL": "",
|
||||
"MGH": "",
|
||||
"AJM": "",
|
||||
"MPA": "2",
|
||||
"BJU": "0.9",
|
||||
"INN": "0.2",
|
||||
"GAM": "0",
|
||||
"LAA": "0.2",
|
||||
"FAR": "1.1",
|
||||
"SAC": "1.7"
|
||||
},
|
||||
"PBa": { "MER": "" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,24 +18,32 @@ export default function Page() {
|
||||
const [enableScan, setEnableScan] = useState(true);
|
||||
const [statusMessage, setStatusMessage] = useState('');
|
||||
|
||||
const handleScan = (rawValue: string) => {
|
||||
const [participante, setParticipante] = useState('');
|
||||
|
||||
const handleScan = async (rawValue: string) => {
|
||||
if (!enableScan) return;
|
||||
|
||||
try {
|
||||
const data = JSON.parse(rawValue);
|
||||
if (data.id_participante && data.id_evento) {
|
||||
setScannedData({
|
||||
id_participante: data.id_participante,
|
||||
id_evento: data.id_evento,
|
||||
});
|
||||
setEnableScan(false);
|
||||
setShowModal(true);
|
||||
try {
|
||||
const response = await axiosInstance.get(
|
||||
`/participante-evento/${data.id_participante}/${data.id_evento}`
|
||||
);
|
||||
|
||||
console.log(response.data);
|
||||
} catch (err) {
|
||||
console.warn('Participante no registrado en el evento:', err);
|
||||
setStatusMessage(
|
||||
'❌ El participante no está registrado en este evento.'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
setStatusMessage('El QR no contiene los campos requeridos');
|
||||
setStatusMessage('⚠️ El QR no contiene los campos requeridos');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('QR malformado:', err);
|
||||
setStatusMessage('Error al leer el QR: formato inválido');
|
||||
setStatusMessage('❌ Error al leer el QR: formato inválido');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -53,18 +53,18 @@ export default function Input(props: InputProps) {
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
<div className='input-group'>
|
||||
<div className="input-group">
|
||||
<input
|
||||
id={inputId}
|
||||
name={name}
|
||||
type={inputType}
|
||||
className={`form-control bg-white ${className?.input || ''}`}
|
||||
className={`form-control ${className?.input || ''}`}
|
||||
{...rest}
|
||||
/>
|
||||
{isPassword && (
|
||||
<button
|
||||
type='button'
|
||||
className='btn btn-light border'
|
||||
type="button"
|
||||
className="btn btn-light border"
|
||||
onClick={togglePasswordVisibility}
|
||||
aria-label={
|
||||
showPassword ? 'Ocultar contraseña' : 'Mostrar contraseña'
|
||||
|
||||
+142
-34
@@ -9,6 +9,15 @@ import { validarRespuesta } from '@/utils/validador';
|
||||
import toast from 'react-hot-toast';
|
||||
import axiosInstance from '@/utils/api-config';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { getAxiosError } from '@/utils/errors-utils';
|
||||
|
||||
interface DatosAlumno {
|
||||
id_ncuenta: number;
|
||||
nombre: string;
|
||||
apellidos: string;
|
||||
carrera: string;
|
||||
genero: 'M' | 'F';
|
||||
}
|
||||
|
||||
export default function Formulario({
|
||||
id_formulario,
|
||||
@@ -24,6 +33,7 @@ export default function Formulario({
|
||||
nombre: string;
|
||||
apellidos: string;
|
||||
correo: string;
|
||||
genero: 'M' | 'F';
|
||||
}>(null);
|
||||
const [respuestas, setRespuestas] = useState<Record<string, string>>({});
|
||||
const [isSubmitting, setIsSubmitting] = useState(false); // New state for submission
|
||||
@@ -34,16 +44,71 @@ export default function Formulario({
|
||||
|
||||
useEffect(() => {
|
||||
if (esDeFES && cuenta.length === 9) {
|
||||
fetch(`/datos/alumnos/${cuenta}`)
|
||||
.then((res) => res.json())
|
||||
.then((data) => setDatosAuto(data))
|
||||
.catch((err) => {
|
||||
console.error('Error al obtener datos del alumno:', err);
|
||||
(async () => {
|
||||
try {
|
||||
setDatosAuto(null);
|
||||
});
|
||||
const { data } = await axiosInstance.get<DatosAlumno>(
|
||||
`/alumnos/${cuenta}`
|
||||
);
|
||||
console.log('Datos del alumno:', data);
|
||||
if (data) {
|
||||
setDatosAuto({
|
||||
nombre: data.nombre.toString(),
|
||||
apellidos: data.apellidos.toString(),
|
||||
correo: data.id_ncuenta + '@pcpuma.acatlan.unam.mx',
|
||||
genero: data.genero,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
const msg = getAxiosError(err);
|
||||
toast.error(msg.message);
|
||||
setDatosAuto(null);
|
||||
}
|
||||
})();
|
||||
}
|
||||
}, [cuenta, esDeFES]);
|
||||
|
||||
useEffect(() => {
|
||||
if (esDeFES && datosAuto) {
|
||||
const nuevasRespuestas: Record<string, string> = {};
|
||||
|
||||
secciones.forEach((seccion) => {
|
||||
seccion.preguntas.forEach(({ pregunta }) => {
|
||||
const id = pregunta.id_pregunta;
|
||||
|
||||
if (pregunta.validacion === 'nombre') {
|
||||
nuevasRespuestas[`pregunta_${id}`] = pregunta.pregunta
|
||||
.toLowerCase()
|
||||
.includes('apellido')
|
||||
? datosAuto.apellidos.toString()
|
||||
: datosAuto.nombre.toString();
|
||||
}
|
||||
|
||||
if (pregunta.validacion === 'correo') {
|
||||
nuevasRespuestas[`pregunta_${id}`] = datosAuto.correo;
|
||||
}
|
||||
|
||||
if (pregunta.validacion === 'cuenta_alumno') {
|
||||
nuevasRespuestas[`pregunta_${id}`] = cuenta;
|
||||
}
|
||||
|
||||
if (
|
||||
pregunta.pregunta
|
||||
.toLowerCase()
|
||||
.includes('institución de procedencia')
|
||||
) {
|
||||
nuevasRespuestas[`pregunta_${id}`] = 'FES Acatlán';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
setRespuestas((prev) => ({
|
||||
...prev,
|
||||
...nuevasRespuestas,
|
||||
}));
|
||||
}
|
||||
}, [datosAuto, esDeFES, cuenta, secciones]);
|
||||
|
||||
// Encuentra preguntas por texto o validación
|
||||
const todasPreguntas = secciones.flatMap((s) =>
|
||||
s.preguntas.map((p) => p.pregunta)
|
||||
@@ -123,6 +188,7 @@ export default function Formulario({
|
||||
const validarRespuestasObligatorias = (): boolean => {
|
||||
const faltantes: number[] = [];
|
||||
const errores: { id: number; mensaje: string }[] = [];
|
||||
console.log(secciones);
|
||||
console.log('Validando respuestas:', respuestas);
|
||||
|
||||
secciones.forEach((seccion) => {
|
||||
@@ -132,6 +198,14 @@ export default function Formulario({
|
||||
const tipo = pregunta.tipo_pregunta.tipo_pregunta;
|
||||
const validacion = pregunta.validacion;
|
||||
|
||||
console.log('Validando pregunta:', pregunta.pregunta);
|
||||
console.table({
|
||||
id,
|
||||
valor,
|
||||
tipo,
|
||||
validacion,
|
||||
});
|
||||
|
||||
const respondida =
|
||||
(tipo === 'Abierta' &&
|
||||
typeof valor === 'string' &&
|
||||
@@ -183,19 +257,16 @@ export default function Formulario({
|
||||
}))}
|
||||
selectedValue={respuestaFES ? Number(respuestaFES) : undefined}
|
||||
onChange={(opt) => {
|
||||
const idSeleccionado = opt.value;
|
||||
const opcionSeleccionada = preguntaFES.opciones.find(
|
||||
(o) => o.id_opcion === idSeleccionado
|
||||
);
|
||||
const id = opt.value;
|
||||
const value = opt?.label ?? '';
|
||||
|
||||
const valorTexto = opcionSeleccionada?.opcion.opcion ?? '';
|
||||
setEsDeFES(valorTexto === 'Si'); // Se actualiza esDeFES con el texto
|
||||
setEsDeFES(value === 'Si'); // Se actualiza esDeFES con el texto
|
||||
setCuenta('');
|
||||
setDatosAuto(null);
|
||||
|
||||
actualizarRespuesta(
|
||||
`pregunta_${preguntaFES.id_pregunta}`,
|
||||
String(idSeleccionado)
|
||||
String(id)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
@@ -209,6 +280,7 @@ export default function Formulario({
|
||||
label={preguntaCuenta.pregunta}
|
||||
name={`pregunta_${preguntaCuenta.id_pregunta}`}
|
||||
value={cuenta}
|
||||
maxLength={10}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
setCuenta(value);
|
||||
@@ -238,34 +310,70 @@ export default function Formulario({
|
||||
defaultValue = datosAuto.correo;
|
||||
disabled = true;
|
||||
}
|
||||
if (p.validacion === 'cuenta_alumno') {
|
||||
defaultValue = cuenta;
|
||||
disabled = true;
|
||||
}
|
||||
if (
|
||||
p.pregunta.toLowerCase().includes('institución de procedencia')
|
||||
) {
|
||||
defaultValue = 'FES Acatlán';
|
||||
disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Input
|
||||
key={p.id_pregunta}
|
||||
label={p.pregunta}
|
||||
name={`pregunta_${p.id_pregunta}`}
|
||||
defaultValue={defaultValue}
|
||||
disabled={disabled}
|
||||
onChange={(e) =>
|
||||
actualizarRespuesta(
|
||||
`pregunta_${p.id_pregunta}`,
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
<React.Fragment key={p.id_pregunta}>
|
||||
<Input
|
||||
label={p.pregunta}
|
||||
name={`pregunta_${p.id_pregunta}`}
|
||||
defaultValue={defaultValue}
|
||||
disabled={disabled}
|
||||
onChange={(e) =>
|
||||
actualizarRespuesta(
|
||||
`pregunta_${p.id_pregunta}`,
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
{p.validacion === 'correo' && (
|
||||
<div className="alert alert-info">
|
||||
Este es el correo donde enviaremos la validación de registro{' '}
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
if (p.tipo_pregunta.tipo_pregunta === 'Cerrada') {
|
||||
const opciones: RadioOption<number>[] = p.opciones.map(
|
||||
(op) => ({
|
||||
label: op.opcion.opcion,
|
||||
value: op.id_opcion,
|
||||
})
|
||||
);
|
||||
const opciones: RadioOption<number>[] = p.opciones.map((op) => ({
|
||||
label: op.opcion.opcion,
|
||||
value: op.id_opcion,
|
||||
}));
|
||||
|
||||
const respuestaActual = respuestas[`pregunta_${p.id_pregunta}`];
|
||||
let respuestaActual = respuestas[`pregunta_${p.id_pregunta}`];
|
||||
|
||||
// Si es de FES y hay datos automáticos, intentar preseleccionar género
|
||||
if (
|
||||
esDeFES &&
|
||||
datosAuto &&
|
||||
!respuestaActual &&
|
||||
p.pregunta.toLowerCase().includes('género')
|
||||
) {
|
||||
const generoTexto =
|
||||
datosAuto.genero === 'M' ? 'Masculino' : 'Femenino';
|
||||
const opcionGenero = p.opciones.find(
|
||||
(op) =>
|
||||
op.opcion.opcion.toLowerCase() === generoTexto.toLowerCase()
|
||||
);
|
||||
if (opcionGenero) {
|
||||
respuestaActual = String(opcionGenero.id_opcion);
|
||||
actualizarRespuesta(
|
||||
`pregunta_${p.id_pregunta}`,
|
||||
String(respuestaActual)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={p.id_pregunta}>
|
||||
@@ -275,7 +383,7 @@ export default function Formulario({
|
||||
options={opciones}
|
||||
selectedValue={
|
||||
respuestaActual ? Number(respuestaActual) : undefined
|
||||
} // ✅ Aquí se fija la opción
|
||||
}
|
||||
onChange={(opt) =>
|
||||
actualizarRespuesta(
|
||||
`pregunta_${p.id_pregunta}`,
|
||||
|
||||
@@ -32,13 +32,6 @@ export const plantillasDisponibles: Plantilla[] = [
|
||||
opciones: [{ valor: 'Si' }, { valor: 'No' }],
|
||||
obligatoria: true,
|
||||
},
|
||||
{
|
||||
titulo: 'Correo electrónico',
|
||||
tipo: 'Abierta',
|
||||
obligatoria: true,
|
||||
limite: 250,
|
||||
validacion: 'correo',
|
||||
},
|
||||
{
|
||||
titulo: 'Numero de cuenta',
|
||||
tipo: 'Abierta',
|
||||
@@ -46,6 +39,13 @@ export const plantillasDisponibles: Plantilla[] = [
|
||||
limite: 250,
|
||||
validacion: 'cuenta_alumno',
|
||||
},
|
||||
{
|
||||
titulo: 'Correo electrónico',
|
||||
tipo: 'Abierta',
|
||||
obligatoria: true,
|
||||
limite: 250,
|
||||
validacion: 'correo',
|
||||
},
|
||||
{
|
||||
titulo: 'Nombre(s)',
|
||||
tipo: 'Abierta',
|
||||
|
||||
Vendored
+5
-1
@@ -120,4 +120,8 @@ ul.list-unstyled li {
|
||||
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
--bs-body-bg: #fff;
|
||||
}
|
||||
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
interface User {
|
||||
id_usuario: number;
|
||||
id_tipo_usuario: number;
|
||||
tipo_usuario: string;
|
||||
nombre: string;
|
||||
cuenta?: string;
|
||||
carrera?: string;
|
||||
}
|
||||
|
||||
interface ErrorState {
|
||||
status: boolean;
|
||||
message: string;
|
||||
code: number;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { AxiosError } from 'axios';
|
||||
|
||||
export const getAxiosError = (error: unknown): ErrorState => {
|
||||
console.error('AXIOS ERROR', error);
|
||||
|
||||
if (error instanceof AxiosError) {
|
||||
if (error.response?.data?.message) {
|
||||
if (error.response.data.message === 'Internal server error') {
|
||||
return {
|
||||
code: 500,
|
||||
message:
|
||||
'Ocurrió un error inesperado, por favor intenta de nuevo más tarde',
|
||||
status: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: error.response.status,
|
||||
message: error.response.data.message,
|
||||
status: true,
|
||||
};
|
||||
}
|
||||
|
||||
if (error.message === 'Network Error') {
|
||||
return {
|
||||
code: 0,
|
||||
message: 'Error de conexión, por favor verifica tu conexión a internet',
|
||||
status: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 0,
|
||||
message: 'Ocurrió un error inesperado',
|
||||
status: true,
|
||||
};
|
||||
};
|
||||
+44
-36
@@ -20,18 +20,18 @@ export class ValidadorCorreo extends Validador {
|
||||
if (!valor) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'El correo electrónico es requerido'
|
||||
mensaje: 'El correo electrónico es requerido',
|
||||
};
|
||||
}
|
||||
|
||||
// Expresión regular para validar correos
|
||||
// Valida el formato básico de correos: usuario@dominio.extensión
|
||||
const regex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
|
||||
|
||||
if (!regex.test(valor)) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'El formato del correo electrónico no es válido'
|
||||
mensaje: 'El formato del correo electrónico no es válido',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -39,18 +39,19 @@ export class ValidadorCorreo extends Validador {
|
||||
if (this.validarDominioInstitucional) {
|
||||
const dominios = ['acatlan.unam.mx', 'unam.mx', 'comunidad.unam.mx'];
|
||||
const dominio = valor.split('@')[1];
|
||||
|
||||
|
||||
if (!dominios.includes(dominio)) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'Debe ser un correo institucional (@acatlan.unam.mx, @unam.mx, @comunidad.unam.mx)'
|
||||
mensaje:
|
||||
'Debe ser un correo institucional (@acatlan.unam.mx, @unam.mx, @comunidad.unam.mx)',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
valido: true,
|
||||
mensaje: 'Correo electrónico válido'
|
||||
mensaje: 'Correo electrónico válido',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -66,32 +67,32 @@ export class ValidadorTelefono extends Validador {
|
||||
if (!valor) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'El número telefónico es requerido'
|
||||
mensaje: 'El número telefónico es requerido',
|
||||
};
|
||||
}
|
||||
|
||||
// Eliminar espacios, guiones y paréntesis para la validación
|
||||
const numeroLimpio = valor.replace(/[\s\-()]/g, '');
|
||||
|
||||
|
||||
// Verificar que solo contenga dígitos
|
||||
if (!/^\d+$/.test(numeroLimpio)) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'El número telefónico solo debe contener dígitos'
|
||||
mensaje: 'El número telefónico solo debe contener dígitos',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Verificar longitud (para México, 10 dígitos)
|
||||
if (numeroLimpio.length !== 10) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'El número telefónico debe tener 10 dígitos'
|
||||
mensaje: 'El número telefónico debe tener 10 dígitos',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valido: true,
|
||||
mensaje: 'Número telefónico válido'
|
||||
mensaje: 'Número telefónico válido',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -99,10 +100,13 @@ export class ValidadorTelefono extends Validador {
|
||||
// Clase para validar nombres
|
||||
export class ValidadorNombre extends Validador {
|
||||
validar(valor: string): ResultadoValidacion {
|
||||
const regex = new RegExp(
|
||||
'/^[A-Za-zÁÉÍÓÚáéíóúÑñ]+(?: [A-Za-zÁÉÍÓÚáéíóúÑñ]+)*$/'
|
||||
);
|
||||
if (!valor) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'El nombre es requerido'
|
||||
mensaje: 'El nombre es requerido',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -110,21 +114,21 @@ export class ValidadorNombre extends Validador {
|
||||
if (valor.trim().length < 2) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'El nombre debe tener al menos 2 caracteres'
|
||||
mensaje: 'El nombre debe tener al menos 2 caracteres',
|
||||
};
|
||||
}
|
||||
|
||||
// Verificar que solo contenga letras y espacios
|
||||
if (!/^[a-zA-ZáéíóúÁÉÍÓÚñÑüÜ\\s]+$/.test(valor)) {
|
||||
if (regex.test(valor)) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'El nombre solo debe contener letras y espacios'
|
||||
mensaje: 'El nombre solo debe contener letras y espacios',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valido: true,
|
||||
mensaje: 'Nombre válido'
|
||||
mensaje: 'Nombre válido',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -142,7 +146,7 @@ export class ValidadorEntero extends Validador {
|
||||
if (!valor) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'El valor numérico es requerido'
|
||||
mensaje: 'El valor numérico es requerido',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -150,23 +154,23 @@ export class ValidadorEntero extends Validador {
|
||||
if (!/^-?\d+$/.test(valor)) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'El valor debe ser un número entero'
|
||||
mensaje: 'El valor debe ser un número entero',
|
||||
};
|
||||
}
|
||||
|
||||
const numero = parseInt(valor, 10);
|
||||
|
||||
|
||||
// Verificar rango
|
||||
if (numero < this.min || numero > this.max) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: `El valor debe estar entre ${this.min} y ${this.max}`
|
||||
mensaje: `El valor debe estar entre ${this.min} y ${this.max}`,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valido: true,
|
||||
mensaje: 'Número entero válido'
|
||||
mensaje: 'Número entero válido',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -185,7 +189,7 @@ export class ValidadorDecimal extends Validador {
|
||||
if (!valor) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'El valor numérico es requerido'
|
||||
mensaje: 'El valor numérico es requerido',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -193,17 +197,17 @@ export class ValidadorDecimal extends Validador {
|
||||
if (!/^-?\d+(\.\d+)?$/.test(valor)) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'El valor debe ser un número decimal válido'
|
||||
mensaje: 'El valor debe ser un número decimal válido',
|
||||
};
|
||||
}
|
||||
|
||||
const numero = parseFloat(valor);
|
||||
|
||||
|
||||
// Verificar rango
|
||||
if (numero < this.min || numero > this.max) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: `El valor debe estar entre ${this.min} y ${this.max}`
|
||||
mensaje: `El valor debe estar entre ${this.min} y ${this.max}`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -212,13 +216,13 @@ export class ValidadorDecimal extends Validador {
|
||||
if (partes.length > 1 && partes[1].length > this.decimales) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: `El valor debe tener máximo ${this.decimales} decimales`
|
||||
mensaje: `El valor debe tener máximo ${this.decimales} decimales`,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valido: true,
|
||||
mensaje: 'Número decimal válido'
|
||||
mensaje: 'Número decimal válido',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -229,7 +233,7 @@ export class ValidadorCuentaAlumno extends Validador {
|
||||
if (!valor) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'La cuenta de alumno es requerida'
|
||||
mensaje: 'La cuenta de alumno es requerida',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -237,13 +241,14 @@ export class ValidadorCuentaAlumno extends Validador {
|
||||
if (!/^\d{9}$/.test(valor)) {
|
||||
return {
|
||||
valido: false,
|
||||
mensaje: 'La cuenta de alumno debe tener exactamente 9 dígitos numéricos'
|
||||
mensaje:
|
||||
'La cuenta de alumno debe tener exactamente 9 dígitos numéricos',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valido: true,
|
||||
mensaje: 'Cuenta de alumno válida'
|
||||
mensaje: 'Cuenta de alumno válida',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -273,15 +278,18 @@ export class FabricaValidadores {
|
||||
}
|
||||
|
||||
// Función auxiliar para validar respuestas basada en el tipo de validación
|
||||
export function validarRespuesta(respuesta: string, tipoValidacion: string): ResultadoValidacion {
|
||||
export function validarRespuesta(
|
||||
respuesta: string,
|
||||
tipoValidacion: string
|
||||
): ResultadoValidacion {
|
||||
const validador = FabricaValidadores.crear(tipoValidacion);
|
||||
|
||||
|
||||
if (!validador) {
|
||||
return {
|
||||
valido: true, // Si no hay validador, consideramos válida la respuesta
|
||||
mensaje: 'No se requiere validación específica'
|
||||
mensaje: 'No se requiere validación específica',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return validador.validar(respuesta);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user