feat: implement form validation for alumno editing using Zod schema

This commit is contained in:
SirRobert-1 2025-05-22 11:41:25 -06:00
parent 6c5a04aec4
commit 65893bf052
2 changed files with 80 additions and 42 deletions

View File

@ -19,14 +19,16 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { set } from "react-hook-form";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { alumnoSchema } from "@/schemas/AlumnosSchema";
export default function AlumnosVista() {
const [alumnos, setAlumnos] = useState([]);
const [alumnoEditando, setAlumnoEditando] = useState(null);
const [nuevoNombre, setNuevoNombre] = useState("");
const [nuevoCorreo, setNuevoCorreo] = useState("");
const [nuevoNumero, setNuevoNumero] = useState("");
const [nuevoNumero, setNuevoNumero] = useState("");
const [mostrarModal, setMostrarModal] = useState(false);
const [modalMensaje, setModalMensaje] = useState("");
const [nuevoCurso, setNuevoCurso] = useState("");
@ -62,38 +64,50 @@ export default function AlumnosVista() {
}
};
const {
register,
handleSubmit,
setValue,
reset,
formState: { errors },
} = useForm({
resolver: zodResolver(alumnoSchema),
defaultValues: {
nombre: "",
correo: "",
telefono: "",
cursoSeleccionado: "",
},
});
// Iniciar edición
const iniciarEdicion = (alumno) => {
setAlumnoEditando(alumno.id);
setNuevoNombre(alumno.nombre);
setNuevoCorreo(alumno.correo);
setNuevoNumero(alumno.telefono);
setNuevoCurso(alumno.curso_id);
setValue("nombre", alumno.nombre);
setValue("correo", alumno.correo);
setValue("telefono", alumno.telefono);
setValue("cursoSeleccionado", alumno.curso_id?.toString() || "");
};
// Cancelar edición
const cancelarEdicion = () => {
setAlumnoEditando(null);
setNuevoNombre("");
setNuevoCorreo("");
setNuevoNumero("");
setNuevoCurso("");
reset();
};
// Guardar cambios
const guardarEdicion = async (id) => {
const guardarEdicion = async (data) => {
const { error } = await supabaseClient
.from("alumno")
.update({
nombre: nuevoNombre,
correo: nuevoCorreo,
telefono: nuevoNumero,
curso_id: nuevoCurso,
nombre: data.nombre,
correo: data.correo,
telefono: data.telefono,
curso_id: data.cursoSeleccionado,
})
.eq("id", id);
.eq("id", alumnoEditando);
if (error) {
console.error("Error actualizando alumno:", error.message);
setModalMensaje("Error al actualizar el alumno");
} else {
setModalMensaje("Alumno actualizado exitosamente");
@ -111,7 +125,10 @@ export default function AlumnosVista() {
// Eliminar alumno
const eliminarAlumno = async () => {
const { error } = await supabaseClient.from("alumno").delete().eq("id", alumnoAEliminar);
const { error } = await supabaseClient
.from("alumno")
.delete()
.eq("id", alumnoAEliminar);
if (error) {
console.error("Error eliminando alumno:", error.message);
setModalMensaje("Error al eliminar el alumno");
@ -148,47 +165,61 @@ export default function AlumnosVista() {
{alumno.id}
</td>
<td className="py-2 px-4 border-b">
<Input
type="text"
value={nuevoNombre}
onChange={(e) => setNuevoNombre(e.target.value)}
/>
<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"
value={nuevoCorreo}
onChange={(e) => setNuevoCorreo(e.target.value)}
/>
<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"
value={nuevoNumero}
onChange={(e) => setNuevoNumero(e.target.value)}
/>
<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={nuevoCurso}
onValueChange={(value) => setNuevoCurso(value)}
value={undefined}
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()}>
<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-2 rounded"
onClick={() => guardarEdicion(alumno.id)}
onClick={handleSubmit(guardarEdicion)}
>
Guardar
</Button>
@ -206,7 +237,9 @@ export default function AlumnosVista() {
<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">
{alumno.curso?.nombre || "Sin curso"}
</td>
<td className="py-2 px-4 border-b space-x-2">
<Button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-3 rounded"
@ -233,9 +266,12 @@ export default function AlumnosVista() {
<Dialog open={confirmarEliminar} onOpenChange={setConfirmarEliminar}>
<DialogContent>
<DialogHeader>
<DialogTitle className="text-black">Confirmar eliminación</DialogTitle>
<DialogTitle className="text-black">
Confirmar eliminación
</DialogTitle>
<DialogDescription>
¿Estás seguro de que deseas eliminar este alumno? Esta acción no se puede deshacer.
¿Estás seguro de que deseas eliminar este alumno? Esta acción no
se puede deshacer.
</DialogDescription>
</DialogHeader>
<DialogFooter>
@ -271,4 +307,4 @@ export default function AlumnosVista() {
</Dialog>
</Layout>
);
}
}

View File

@ -9,6 +9,8 @@ export const alumnoSchema = z.object({
telefono: z
.string()
.nonempty("Escribe el número de teléfono")
.regex(/^\d+$/, "Solo se permiten números en el teléfono"),
.regex(/^\d+$/, "El número de teléfono solo puede contener dígitos")
.min(10, "El número de teléfono debe tener al menos 10 dígitos")
.max(10, "El número de teléfono no puede tener más de 10 dígitos"),
cursoSeleccionado: z.string().nonempty("Selecciona un curso"),
});