feat: enhance AlumnosVista and DiplomasVista with new data handling for inyecciones and pildoras, including editing capabilities and improved UI for displaying types and formations

This commit is contained in:
BenitoBB 2025-06-13 16:51:22 -06:00
parent 010ac8fa6d
commit a744fb083d
4 changed files with 399 additions and 155 deletions

View File

@ -33,6 +33,10 @@ export default function AlumnosVista() {
const [modalMensaje, setModalMensaje] = useState("");
const [nuevoCurso, setNuevoCurso] = useState("");
const [cursos, setCursos] = useState([]);
const [nuevoTipo, setNuevoTipo] = useState("");
const [nuevaFormacion, setNuevaFormacion] = useState("");
const [inyecciones, setInyecciones] = useState([]);
const [pildoras, setPildoras] = useState([]);
// Estado para confirmación de eliminación
const [confirmarEliminar, setConfirmarEliminar] = useState(false);
@ -41,6 +45,14 @@ export default function AlumnosVista() {
useEffect(() => {
cargarAlumnos();
cargarCursos();
supabaseClient
.from("pildoras")
.select("id, nombre")
.then(({ data }) => setPildoras(data || []));
supabaseClient
.from("inyeccion")
.select("id, nombre")
.then(({ data }) => setInyecciones(data || []));
}, []);
const cargarCursos = async () => {
@ -55,13 +67,21 @@ export default function AlumnosVista() {
const cargarAlumnos = async () => {
const { data, error } = await supabaseClient
.from("alumno")
.select("id, nombre, correo, telefono, curso_id, curso(nombre)")
.select(`
id,
nombre,
correo,
telefono,
tipo_formacion,
curso_id,
curso(id, nombre),
inyeccion_id,
inyeccion(id, nombre),
pildoras_id,
pildoras(id, nombre)
`)
.order("id", { ascending: true });
if (error) {
console.error("Error al cargar alumnos:", error.message);
} else {
setAlumnos(data);
}
setAlumnos(data || []);
};
const {
@ -83,10 +103,15 @@ export default function AlumnosVista() {
// Iniciar edición
const iniciarEdicion = (alumno) => {
setAlumnoEditando(alumno.id);
setValue("nombre", alumno.nombre);
setValue("correo", alumno.correo);
setValue("telefono", alumno.telefono);
setValue("cursoSeleccionado", alumno.curso_id?.toString() || "");
setNuevoNombre(alumno.nombre || "");
setNuevoCorreo(alumno.correo || "");
setNuevoNumero(alumno.telefono || "");
setNuevoTipo(alumno.tipo_formacion || "");
// Detecta la formación actual según el tipo
if (alumno.tipo_formacion === "curso") setNuevaFormacion(alumno.curso_id ? String(alumno.curso_id) : "");
else if (alumno.tipo_formacion === "inyeccion") setNuevaFormacion(alumno.inyeccion_id ? String(alumno.inyeccion_id) : "");
else if (alumno.tipo_formacion === "pildora") setNuevaFormacion(alumno.pildoras_id ? String(alumno.pildoras_id) : "");
else setNuevaFormacion("");
};
// Cancelar edición
@ -96,25 +121,36 @@ export default function AlumnosVista() {
};
// Guardar cambios
const guardarEdicion = async (data) => {
const guardarEdicion = async (id) => {
// Prepara el objeto de actualización
let updateObj = {
tipo_formacion: nuevoTipo,
curso_id: null,
inyeccion_id: null,
pildoras_id: null,
nombre: nuevoNombre,
correo: nuevoCorreo,
telefono: nuevoNumero,
};
if (nuevoTipo === "curso") updateObj.curso_id = Number(nuevaFormacion);
if (nuevoTipo === "inyeccion") updateObj.inyeccion_id = Number(nuevaFormacion);
if (nuevoTipo === "pildora") updateObj.pildoras_id = Number(nuevaFormacion);
const { error } = await supabaseClient
.from("alumno")
.update({
nombre: data.nombre,
correo: data.correo,
telefono: data.telefono,
curso_id: data.cursoSeleccionado,
})
.eq("id", alumnoEditando);
.update(updateObj)
.eq("id", id);
if (error) {
setModalMensaje("Error al actualizar el alumno");
if (!error) {
setModalMensaje("Alumno actualizado correctamente");
setMostrarModal(true);
setAlumnoEditando(null);
await cargarAlumnos(); // <--- Refresca la tabla
} else {
setModalMensaje("Alumno actualizado exitosamente");
await cargarAlumnos();
cancelarEdicion();
setModalMensaje("Error al actualizar el alumno");
setMostrarModal(true);
}
setMostrarModal(true);
};
// Confirmar eliminación
@ -154,111 +190,45 @@ export default function AlumnosVista() {
<th className="py-2 border-b">Nombre</th>
<th className="py-2 border-b">Correo</th>
<th className="py-2 border-b">Teléfono</th>
<th className="py-2 border-b">Curso</th>
<th className="py-2 border-b">Tipo</th>
<th className="py-2 border-b">Formación</th>
<th className="py-2 border-b">Acciones</th>
</tr>
</thead>
<tbody>
{alumnos.map((alumno) =>
alumnoEditando === alumno.id ? (
<tr key={alumno.id}>
<td className="py-2 px-4 border-b text-center">
{alumno.id}
</td>
<td className="py-2 px-4 border-b">
<Input type="text" {...register("nombre")} />
{errors.nombre && (
<span className="text-red-500 text-xs">
{errors.nombre.message}
</span>
)}
</td>
<td className="py-2 px-4 border-b">
<Input type="email" {...register("correo")} />
{errors.correo && (
<span className="text-red-500 text-xs">
{errors.correo.message}
</span>
)}
</td>
<td className="py-2 px-4 border-b">
<Input type="text" {...register("telefono")} />
{errors.telefono && (
<span className="text-red-500 text-xs">
{errors.telefono.message}
</span>
)}
</td>
<td className="py-2 px-4 border-b">
<Select
value={(alumno.curso_id || "").toString()}
onValueChange={(value) =>
setValue("cursoSeleccionado", value)
}
{...register("cursoSeleccionado")}
>
<SelectTrigger>
<SelectValue placeholder="Selecciona un curso" />
</SelectTrigger>
<SelectContent>
{cursos.map((curso) => (
<SelectItem
key={curso.id}
value={curso.id.toString()}
>
{curso.nombre}
</SelectItem>
))}
</SelectContent>
</Select>
{errors.cursoSeleccionado && (
<span className="text-red-500 text-xs">
{errors.cursoSeleccionado.message}
</span>
)}
</td>
<td className="py-2 px-4 border-b flex justify-center">
<Button
className="bg-green-500 hover:bg-green-700 text-white font-bold py-1 px-3 m-1 rounded"
onClick={handleSubmit(guardarEdicion)}
>
Guardar
</Button>
<Button
className="bg-gray-400 hover:bg-gray-600 text-white font-bold py-1 px-3 m-1 rounded"
onClick={cancelarEdicion}
>
Cancelar
</Button>
</td>
</tr>
) : (
<tr key={alumno.id}>
<td className="py-2 px-4 border-b">{alumno.id}</td>
<td className="py-2 px-4 border-b">{alumno.nombre}</td>
<td className="py-2 px-4 border-b">{alumno.correo}</td>
<td className="py-2 px-4 border-b">{alumno.telefono}</td>
<td className="py-2 px-4 border-b">
{alumno.curso?.nombre || "Sin curso"}
</td>
<td className="py-2 px-4 border-b flex justify-center">
<Button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-3 m-1 rounded"
onClick={() => iniciarEdicion(alumno)}
>
Editar
</Button>
<Button
className="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-3 m-1 rounded"
onClick={() => confirmarEliminacion(alumno.id)}
>
Eliminar
</Button>
</td>
</tr>
)
)}
{alumnos.map((alumno) => (
<tr key={alumno.id}>
<td className="py-2 px-4 border-b">{alumno.id}</td>
<td className="py-2 px-4 border-b">{alumno.nombre}</td>
<td className="py-2 px-4 border-b">{alumno.correo}</td>
<td className="py-2 px-4 border-b">{alumno.telefono}</td>
<td className="py-2 px-4 border-b">
{alumno.tipo_formacion === "curso"
? "Curso"
: alumno.tipo_formacion === "inyeccion"
? "Inyección"
: alumno.tipo_formacion === "pildora"
? "Píldora"
: ""}
</td>
<td className="py-2 px-4 border-b">
{alumno.tipo_formacion === "curso" && alumno.curso?.nombre}
{alumno.tipo_formacion === "inyeccion" && alumno.inyeccion?.nombre}
{alumno.tipo_formacion === "pildora" && alumno.pildoras?.nombre}
</td>
<td className="py-2 px-4 border-b">
<Button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-3 rounded"
onClick={() => {
setAlumnoSeleccionado(alumno);
setMostrarDialog(true);
}}
>
Crear Diploma
</Button>
</td>
</tr>
))}
</tbody>
</table>
</div>

View File

@ -18,9 +18,21 @@ export default function DiplomasVista() {
const cargarAlumnos = async () => {
const { data, error } = await supabaseClient
.from("alumno")
.select("id, nombre, correo, telefono, curso(id, nombre)")
.select(`
id,
nombre,
correo,
telefono,
tipo_formacion,
curso_id,
curso(id, nombre),
inyeccion_id,
inyeccion(id, nombre),
pildoras_id,
pildoras(id, nombre)
`)
.order("id", { ascending: true });
if (!error) setAlumnos(data);
setAlumnos(data || []);
};
cargarAlumnos();
}, []);
@ -62,7 +74,8 @@ export default function DiplomasVista() {
<th className="py-2 border-b">Nombre</th>
<th className="py-2 border-b">Correo</th>
<th className="py-2 border-b">Teléfono</th>
<th className="py-2 border-b">Curso</th>
<th className="py-2 border-b">Tipo</th>
<th className="py-2 border-b">Formación</th>
<th className="py-2 border-b">Acciones</th>
</tr>
</thead>
@ -74,7 +87,18 @@ export default function DiplomasVista() {
<td className="py-2 px-4 border-b">{alumno.correo}</td>
<td className="py-2 px-4 border-b">{alumno.telefono}</td>
<td className="py-2 px-4 border-b">
{alumno.curso?.nombre || "Sin curso"}
{alumno.tipo_formacion === "curso"
? "Curso"
: alumno.tipo_formacion === "inyeccion"
? "Inyección"
: alumno.tipo_formacion === "pildora"
? "Píldora"
: ""}
</td>
<td className="py-2 px-4 border-b">
{alumno.tipo_formacion === "curso" && alumno.curso?.nombre}
{alumno.tipo_formacion === "inyeccion" && alumno.inyeccion?.nombre}
{alumno.tipo_formacion === "pildora" && alumno.pildoras?.nombre}
</td>
<td className="py-2 px-4 border-b">
<Button

View File

@ -1,7 +1,6 @@
import React, { useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Schema } from "@/schemas/Schema";
import Layout from "@/components/layout/Layout";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@ -16,35 +15,99 @@ import {
DialogFooter,
} from "@/components/ui/dialog";
// Puedes usar tu propio esquema de validación
const schema = {/* ...tu esquema Zod aquí... */};
export default function InyeccionesManual() {
const [competencias, setCompetencias] = useState([]); // [{id, descripcion}]
const [showDialog, setShowDialog] = useState(false);
const [dialogMsg, setDialogMsg] = useState("");
const [loading, setLoading] = useState(false);
const [addCompetencia, setAddCompetencia] = useState(false);
const form = useForm({
resolver: zodResolver(Schema),
resolver: zodResolver(schema),
defaultValues: {
nombre: "",
descripcion: "",
horas: 0,
nuevaCompetencia: "",
},
});
const {
register,
handleSubmit,
setValue,
getValues,
formState: { errors },
reset,
} = form;
// Añadir competencia (busca o crea en BD)
const handleSaveCompetencia = async (e) => {
e.preventDefault();
const desc = getValues("nuevaCompetencia").trim();
if (!desc) return;
if (competencias.some((c) => c.descripcion === desc)) {
setDialogMsg("La competencia ya fue agregada.");
setShowDialog(true);
return;
}
try {
let { data: existente } = await supabaseClient
.from("competencia_inyeccion")
.select("id")
.eq("descripcion", desc)
.maybeSingle();
let id = existente?.id;
if (!id) {
const { data: insertada, error } = await supabaseClient
.from("competencia_inyeccion")
.insert([{ descripcion: desc }])
.select("id")
.single();
if (error) throw error;
id = insertada.id;
}
setCompetencias([...competencias, { id, descripcion: desc }]);
setAddCompetencia(false);
setValue("nuevaCompetencia", "");
setDialogMsg("¡La competencia fue agregada exitosamente!");
setShowDialog(true);
} catch (err) {
setDialogMsg("Error al guardar la competencia: " + (err.message || err));
setShowDialog(true);
}
};
// Eliminar competencia
const handleDeleteCompetencia = (index) => {
setCompetencias(competencias.filter((_, i) => i !== index));
};
// Guardar inyección y asociar competencias
const onSubmit = async (data) => {
setLoading(true);
try {
const { nombre, descripcion, horas } = data;
const { error } = await supabaseClient
const { data: inyeccion, error: errorIny } = await supabaseClient
.from("inyeccion")
.insert([{ nombre, descripcion, horas: parseInt(horas, 10) }]);
if (error) throw error;
.insert([{ nombre, descripcion, horas: parseInt(horas, 10) }])
.select("id")
.single();
if (errorIny) throw errorIny;
if (competencias.length) {
const relaciones = competencias.map((c) => ({
inyeccion_id: inyeccion.id,
competencia_inyeccion_id: c.id,
}));
const { error: errorPivote } = await supabaseClient
.from("inyeccion_competencia_inyeccion")
.insert(relaciones);
if (errorPivote) throw errorPivote;
}
setDialogMsg("Inyección guardada exitosamente");
setCompetencias([]);
reset();
} catch (err) {
setDialogMsg("Error: " + (err.message || err));
@ -57,9 +120,7 @@ export default function InyeccionesManual() {
return (
<Layout>
<div className="w-full bg-white pt-5 font-sans text-center md:w-[80%] flex flex-col items-center justify-start text-black">
<h1 className="text-xl font-semibold mb-10 text-black">
Nueva inyección
</h1>
<h1 className="text-xl font-semibold mb-10 text-black">Nueva inyección</h1>
<form onSubmit={handleSubmit(onSubmit)} className="w-full">
<Input
type="text"
@ -90,6 +151,78 @@ export default function InyeccionesManual() {
<p className="text-red-500 text-sm">{errors.horas.message}</p>
)}
<h2 className="text-lg font-semibold mb-3 text-black">
Competencias de Inyección
</h2>
<p className="text-xs text-gray-500 mb-2">
Puedes agregar competencias nuevas exclusivas para inyecciones.
</p>
{competencias.length > 0 && (
<div className="mt-5 w-full flex-wrap">
{competencias.map((c, i) => (
<div
key={i}
className="w-full flex justify-between items-center px-2 mb-2"
>
<span className="text-black">{c.descripcion}</span>
<Button
type="button"
onClick={() => handleDeleteCompetencia(i)}
className="bg-red-400 hover:bg-red-500 text-white font-bold py-1 px-3 rounded-md"
>
X
</Button>
</div>
))}
</div>
)}
{addCompetencia && (
<div className="w-full flex flex-col md:flex-row mt-5">
<div className="flex flex-col">
<Input
type="text"
placeholder="Nueva competencia"
{...register("nuevaCompetencia")}
className="w-80 px-3 py-2 border border-gray-300 rounded-md mb-3 text-black"
/>
{errors.nuevaCompetencia && (
<p className="text-red-500 text-sm">
{errors.nuevaCompetencia.message}
</p>
)}
</div>
<div className="flex flex-row">
<Button
type="button"
onClick={handleSaveCompetencia}
className="bg-green-400 hover:bg-green-500 text-white font-bold py-2 px-4 rounded-md mr-2"
>
Guardar
</Button>
<Button
type="button"
onClick={() => {
setAddCompetencia(false);
setValue("nuevaCompetencia", "");
}}
className="bg-gray-400 hover:bg-gray-500 text-white font-bold py-2 px-4 rounded-md"
>
Cancelar
</Button>
</div>
</div>
)}
<Button
type="button"
onClick={() => setAddCompetencia(true)}
className="w-full bg-blue-400 hover:bg-blue-500 text-white font-bold py-2 px-4 rounded-md mt-5"
>
Agregar competencia
</Button>
<div className="flex justify-center w-full mt-5">
<Button
type="submit"

View File

@ -22,6 +22,8 @@ export default function InyeccionesVista() {
const [modalMensaje, setModalMensaje] = useState("");
const [confirmarEliminar, setConfirmarEliminar] = useState(false);
const [inyeccionAEliminar, setInyeccionAEliminar] = useState(null);
const [competenciasDisponibles, setCompetenciasDisponibles] = useState([]);
const [competenciasEditando, setCompetenciasEditando] = useState([]);
useEffect(() => {
cargarInyecciones();
@ -30,7 +32,18 @@ export default function InyeccionesVista() {
const cargarInyecciones = async () => {
const { data, error } = await supabaseClient
.from("inyeccion")
.select("*")
.select(`
id,
nombre,
descripcion,
horas,
inyeccion_competencia_inyeccion (
competencia_inyeccion (
id,
descripcion
)
)
`)
.order("id", { ascending: true });
if (error) {
setModalMensaje("Error al cargar inyecciones: " + error.message);
@ -40,11 +53,24 @@ export default function InyeccionesVista() {
}
};
const iniciarEdicion = (inyeccion) => {
const iniciarEdicion = async (inyeccion) => {
setInyeccionEditando(inyeccion.id);
setNuevoNombre(inyeccion.nombre);
setNuevaDescripcion(inyeccion.descripcion);
setNuevaHoras(inyeccion.horas);
// Cargar todas las competencias posibles
const { data: todas, error: errorTodas } = await supabaseClient
.from("competencia_inyeccion")
.select("*");
setCompetenciasDisponibles(todas || []);
// Cargar las competencias ya asociadas a la inyección
setCompetenciasEditando(
(inyeccion.inyeccion_competencia_inyeccion || []).map(
(ic) => ic.competencia_inyeccion?.id
)
);
};
const cancelarEdicion = () => {
@ -52,6 +78,7 @@ export default function InyeccionesVista() {
setNuevoNombre("");
setNuevaDescripcion("");
setNuevaHoras("");
setCompetenciasEditando([]);
};
const guardarEdicion = async (id) => {
@ -64,12 +91,28 @@ export default function InyeccionesVista() {
})
.eq("id", id);
if (error) {
setModalMensaje("Error al actualizar la inyección");
} else {
if (!error) {
// Elimina relaciones viejas
await supabaseClient
.from("inyeccion_competencia_inyeccion")
.delete()
.eq("inyeccion_id", id);
// Inserta las nuevas
if (competenciasEditando.length) {
const relaciones = competenciasEditando.map((cid) => ({
inyeccion_id: id,
competencia_inyeccion_id: cid,
}));
await supabaseClient
.from("inyeccion_competencia_inyeccion")
.insert(relaciones);
}
setModalMensaje("Inyección actualizada exitosamente");
await cargarInyecciones();
cancelarEdicion();
} else {
setModalMensaje("Error al actualizar la inyección");
}
setMostrarModal(true);
};
@ -98,22 +141,25 @@ export default function InyeccionesVista() {
return (
<Layout>
<div className="w-full pt-10 flex flex-col items-center text-black">
<h1 className="text-2xl font-semibold mb-6">Lista de Inyecciones</h1>
<h1 className="text-2xl font-semibold mb-6 text-black">
Lista de Inyecciones
</h1>
<div className="overflow-x-auto w-full">
<table className="min-w-full bg-white border">
<table className="min-w-full bg-white border text-black">
<thead>
<tr className="bg-gray-100">
<tr className="bg-gray-100 text-black">
<th className="py-2 border-b">ID</th>
<th className="py-2 border-b">Nombre</th>
<th className="py-2 border-b">Descripción</th>
<th className="py-2 border-b">Horas</th>
<th className="py-2 border-b">Competencias</th>
<th className="py-2 border-b">Acciones</th>
</tr>
</thead>
<tbody>
{inyecciones.map((inyeccion) =>
inyeccionEditando === inyeccion.id ? (
<tr key={inyeccion.id}>
<tr key={inyeccion.id} className="text-black">
<td className="py-2 px-4 border-b text-center">
{inyeccion.id}
</td>
@ -121,12 +167,14 @@ export default function InyeccionesVista() {
<Input
value={nuevoNombre}
onChange={(e) => setNuevoNombre(e.target.value)}
className="text-black"
/>
</td>
<td className="py-2 px-4 border-b">
<Input
value={nuevaDescripcion}
onChange={(e) => setNuevaDescripcion(e.target.value)}
className="text-black"
/>
</td>
<td className="py-2 px-4 border-b">
@ -134,8 +182,71 @@ export default function InyeccionesVista() {
type="number"
value={nuevaHoras}
onChange={(e) => setNuevaHoras(e.target.value)}
className="text-black"
/>
</td>
<td className="py-2 px-4 border-b align-top">
<div className="flex flex-col gap-2">
{competenciasEditando.map((compId, idx) => (
<div key={idx} className="flex items-center gap-2 mb-1">
<select
value={compId}
onChange={(e) => {
const nuevaLista = [...competenciasEditando];
nuevaLista[idx] = Number(e.target.value);
setCompetenciasEditando(nuevaLista);
}}
className="border rounded px-2 py-1 text-black"
>
{competenciasDisponibles.map((comp) => (
<option key={comp.id} value={comp.id}>
{comp.descripcion}
</option>
))}
</select>
<button
type="button"
className="bg-red-500 hover:bg-red-700 text-white px-3 py-1 rounded"
onClick={() => {
setCompetenciasEditando(
competenciasEditando.filter((_, i) => i !== idx)
);
}}
>
Quitar
</button>
</div>
))}
<button
type="button"
className="bg-blue-500 hover:bg-blue-700 text-white px-4 py-2 rounded mt-2"
onClick={() => {
if (competenciasEditando.length >= 3) {
setModalMensaje(
"Ya llegaste al límite de 3 competencias para esta inyección."
);
setMostrarModal(true);
return;
}
// Agrega la primera competencia disponible que no esté ya seleccionada
const disponibles = competenciasDisponibles
.map((c) => c.id)
.filter((id) => !competenciasEditando.includes(id));
if (disponibles.length > 0) {
setCompetenciasEditando([
...competenciasEditando,
disponibles[0],
]);
}
}}
disabled={
competenciasEditando.length >= competenciasDisponibles.length
}
>
Agregar competencia
</button>
</div>
</td>
<td className="py-2 px-4 border-b flex justify-center">
<Button
className="bg-green-500 hover:bg-green-700 text-white font-bold py-1 px-3 m-2 rounded"
@ -152,13 +263,21 @@ export default function InyeccionesVista() {
</td>
</tr>
) : (
<tr key={inyeccion.id}>
<tr key={inyeccion.id} className="text-black">
<td className="py-2 px-4 border-b">{inyeccion.id}</td>
<td className="py-2 px-4 border-b">{inyeccion.nombre}</td>
<td className="py-2 px-4 border-b">
{inyeccion.descripcion}
</td>
<td className="py-2 px-4 border-b">{inyeccion.descripcion}</td>
<td className="py-2 px-4 border-b">{inyeccion.horas}</td>
<td className="py-2 px-4 border-b">
<ul className="list-disc ml-5">
{(inyeccion.inyeccion_competencia_inyeccion || [])
.map((ic) => ic.competencia_inyeccion?.descripcion)
.filter(Boolean)
.map((desc, idx) => (
<li key={idx}>{desc}</li>
))}
</ul>
</td>
<td className="py-2 px-4 border-b flex justify-center">
<Button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-3 m-1 rounded"
@ -188,7 +307,7 @@ export default function InyeccionesVista() {
<DialogTitle className="text-black">
Confirmar eliminación
</DialogTitle>
<DialogDescription>
<DialogDescription className="text-black">
¿Estás seguro de que deseas eliminar esta inyección? Esta acción
no se puede deshacer.
</DialogDescription>
@ -214,10 +333,8 @@ export default function InyeccionesVista() {
<Dialog open={mostrarModal} onOpenChange={setMostrarModal}>
<DialogContent>
<DialogHeader>
<DialogTitle className="text-black">
Resultado de la operación
</DialogTitle>
<DialogDescription>{modalMensaje}</DialogDescription>
<DialogTitle className="text-black">Aviso</DialogTitle>
<DialogDescription className="text-black">{modalMensaje}</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button onClick={() => setMostrarModal(false)}>Cerrar</Button>