feat: update Alumnos schema to clarify type selection and enhance data loading in AlumnosVista and AlumnosManual

This commit is contained in:
SirRobert-1 2025-06-13 20:41:18 -06:00
parent 814354baac
commit d7562fa4ab
3 changed files with 197 additions and 59 deletions

View File

@ -11,7 +11,6 @@ import {
} from "@/components/ui/select";
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
@ -24,61 +23,99 @@ import { alumnoSchema } from "@/schemas/AlumnosSchema";
export default function AlumnosManual() {
const [cursos, setCursos] = useState([]);
const [isDialogOpen, setIsDialogOpen] = useState(false); // Estado para controlar el diálogo
const [inyecciones, setInyecciones] = useState([]);
const [pildoras, setPildoras] = useState([]);
const [isDialogOpen, setIsDialogOpen] = useState(false);
// Configurar React Hook Form con zod
const {
register,
handleSubmit,
setValue,
watch,
formState: { errors },
reset,
clearErrors,
} = useForm({
resolver: zodResolver(alumnoSchema),
defaultValues: {
nombre: "",
correo: "",
telefono: "",
tipo: "",
cursoSeleccionado: "",
},
});
// Cargar cursos al iniciar el componente
const tipo = watch("tipo");
const cursoSeleccionado = watch("cursoSeleccionado");
// Cargar opciones según tipo seleccionado
useEffect(() => {
const cargarCursos = async () => {
const { data, error } = await supabaseClient
.from("curso")
.select("id, nombre");
if (error) {
console.error("Error al cargar cursos:", error.message);
} else {
setCursos(data);
}
};
cargarCursos();
}, []);
if (!tipo) {
setValue("cursoSeleccionado", "");
clearErrors("cursoSeleccionado");
return;
}
setValue("cursoSeleccionado", "");
clearErrors("cursoSeleccionado");
if (tipo === "curso") {
cargarCursos();
} else if (tipo === "inyeccion") {
cargarInyecciones();
} else if (tipo === "pildora") {
cargarPildoras();
}
// eslint-disable-next-line
}, [tipo]);
const cargarCursos = async () => {
const { data, error } = await supabaseClient
.from("curso")
.select("id, nombre");
if (!error) setCursos(data || []);
};
const cargarInyecciones = async () => {
const { data, error } = await supabaseClient
.from("inyeccion")
.select("id, nombre");
if (!error) setInyecciones(data || []);
};
const cargarPildoras = async () => {
const { data, error } = await supabaseClient
.from("pildoras")
.select("id, nombre");
if (!error) setPildoras(data || []);
};
// Guardar alumno
const manejarGuardar = async (data) => {
try {
const { error } = await supabaseClient.from("alumno").insert([
{
nombre: data.nombre,
correo: data.correo,
telefono: data.telefono,
curso_id: Number(data.cursoSeleccionado), // Guardar el ID del curso
},
]);
let campos = {
nombre: data.nombre,
correo: data.correo,
telefono: data.telefono,
tipo_formacion: data.tipo,
curso_id: null,
inyeccion_id: null,
pildoras_id: null,
};
if (data.tipo === "curso")
campos.curso_id = Number(data.cursoSeleccionado);
if (data.tipo === "inyeccion")
campos.inyeccion_id = Number(data.cursoSeleccionado);
if (data.tipo === "pildora")
campos.pildoras_id = Number(data.cursoSeleccionado);
const { error } = await supabaseClient.from("alumno").insert([campos]);
if (error) {
console.error("Error al guardar:", error.message);
setIsDialogOpen(false); // Asegurarse de cerrar el diálogo en caso de error
setIsDialogOpen(false);
} else {
setIsDialogOpen(true); // Mostrar el diálogo al guardar exitosamente
reset(); // Reiniciar el formulario
setIsDialogOpen(true);
reset();
}
} catch (err) {
console.error("Error inesperado:", err);
// Manejo de error inesperado
}
};
@ -118,20 +155,77 @@ export default function AlumnosManual() {
{errors.telefono.message}
</p>
)}
{/* Select para tipo de formación */}
<Select
onValueChange={(value) => setValue("cursoSeleccionado", value)}
value={tipo}
onValueChange={(value) => setValue("tipo", value)}
>
<SelectTrigger className="w-full px-3 py-2 border border-gray-300 rounded-md mb-3">
<SelectValue placeholder="Selecciona un curso" />
<SelectValue placeholder="Selecciona tipo de formación" />
</SelectTrigger>
<SelectContent>
{cursos.map((curso) => (
<SelectItem key={curso.id} value={curso.id.toString()}>
{curso.nombre}
</SelectItem>
))}
<SelectItem value="curso">Curso</SelectItem>
<SelectItem value="inyeccion">Inyección</SelectItem>
<SelectItem value="pildora">Píldora</SelectItem>
</SelectContent>
</Select>
{errors.tipo && (
<p className="text-red-500 text-sm mt-1">{errors.tipo.message}</p>
)}
{/* Select para la opción según tipo */}
{tipo === "curso" && (
<Select
value={cursoSeleccionado}
onValueChange={(value) => setValue("cursoSeleccionado", value)}
>
<SelectTrigger className="w-full px-3 py-2 border border-gray-300 rounded-md mb-3">
<SelectValue placeholder="Selecciona un curso" />
</SelectTrigger>
<SelectContent>
{cursos.map((curso) => (
<SelectItem key={curso.id} value={curso.id.toString()}>
{curso.nombre}
</SelectItem>
))}
</SelectContent>
</Select>
)}
{tipo === "inyeccion" && (
<Select
value={cursoSeleccionado}
onValueChange={(value) => setValue("cursoSeleccionado", value)}
>
<SelectTrigger className="w-full px-3 py-2 border border-gray-300 rounded-md mb-3">
<SelectValue placeholder="Selecciona una inyección" />
</SelectTrigger>
<SelectContent>
{inyecciones.map((iny) => (
<SelectItem key={iny.id} value={iny.id.toString()}>
{iny.nombre}
</SelectItem>
))}
</SelectContent>
</Select>
)}
{tipo === "pildora" && (
<Select
value={cursoSeleccionado}
onValueChange={(value) => setValue("cursoSeleccionado", value)}
>
<SelectTrigger className="w-full px-3 py-2 border border-gray-300 rounded-md mb-3">
<SelectValue placeholder="Selecciona una píldora" />
</SelectTrigger>
<SelectContent>
{pildoras.map((p) => (
<SelectItem key={p.id} value={p.id.toString()}>
{p.nombre}
</SelectItem>
))}
</SelectContent>
</Select>
)}
{errors.cursoSeleccionado && (
<p className="text-red-500 text-sm mt-1">
{errors.cursoSeleccionado.message}

View File

@ -45,6 +45,9 @@ export default function AlumnosVista() {
useEffect(() => {
cargarAlumnos();
// ...cargar cursos, inyecciones, pildoras...
cargarCursos();
cargarInyecciones();
cargarPildoras();
}, []);
const cargarCursos = async () => {
@ -56,10 +59,21 @@ export default function AlumnosVista() {
}
};
const cargarInyecciones = async () => {
const { data, error } = await supabaseClient.from("inyeccion").select("*");
if (!error) setInyecciones(data || []);
};
const cargarPildoras = async () => {
const { data, error } = await supabaseClient.from("pildoras").select("*");
if (!error) setPildoras(data || []);
};
const cargarAlumnos = async () => {
const { data, error } = await supabaseClient
.from("alumno")
.select(`
.select(
`
id,
nombre,
correo,
@ -71,7 +85,8 @@ export default function AlumnosVista() {
inyeccion(nombre),
pildoras_id,
pildoras(nombre)
`)
`
)
.order("id", { ascending: true });
setAlumnos(data || []);
};
@ -100,9 +115,12 @@ export default function AlumnosVista() {
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) : "");
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("");
};
@ -126,7 +144,8 @@ export default function AlumnosVista() {
};
if (nuevoTipo === "curso") updateObj.curso_id = Number(nuevaFormacion);
if (nuevoTipo === "inyeccion") updateObj.inyeccion_id = Number(nuevaFormacion);
if (nuevoTipo === "inyeccion")
updateObj.inyeccion_id = Number(nuevaFormacion);
if (nuevoTipo === "pildora") updateObj.pildoras_id = Number(nuevaFormacion);
const { error } = await supabaseClient
@ -188,25 +207,37 @@ export default function AlumnosVista() {
</tr>
</thead>
<tbody>
{alumnos.map(alumno =>
{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 value={nuevoNombre} onChange={e => setNuevoNombre(e.target.value)} className="border rounded px-2 py-1 text-black" />
<input
value={nuevoNombre}
onChange={(e) => setNuevoNombre(e.target.value)}
className="border rounded px-2 py-1 text-black"
/>
</td>
<td className="py-2 px-4 border-b">
<input value={nuevoCorreo} onChange={e => setNuevoCorreo(e.target.value)} className="border rounded px-2 py-1 text-black" />
<input
value={nuevoCorreo}
onChange={(e) => setNuevoCorreo(e.target.value)}
className="border rounded px-2 py-1 text-black"
/>
</td>
<td className="py-2 px-4 border-b">
<input value={nuevoNumero} onChange={e => setNuevoNumero(e.target.value)} className="border rounded px-2 py-1 text-black" />
<input
value={nuevoNumero}
onChange={(e) => setNuevoNumero(e.target.value)}
className="border rounded px-2 py-1 text-black"
/>
</td>
<td className="py-2 px-4 border-b">
<select
value={nuevoTipo}
onChange={e => {
onChange={(e) => {
setNuevoTipo(e.target.value);
setNuevaFormacion("");
}}
@ -222,12 +253,12 @@ export default function AlumnosVista() {
{nuevoTipo === "curso" && (
<select
value={nuevaFormacion}
onChange={e => setNuevaFormacion(e.target.value)}
onChange={(e) => setNuevaFormacion(e.target.value)}
className="border rounded px-2 py-1 text-black"
required
>
<option value="">Selecciona curso</option>
{cursos.map(curso => (
{cursos.map((curso) => (
<option key={curso.id} value={curso.id}>
{curso.nombre}
</option>
@ -237,12 +268,12 @@ export default function AlumnosVista() {
{nuevoTipo === "inyeccion" && (
<select
value={nuevaFormacion}
onChange={e => setNuevaFormacion(e.target.value)}
onChange={(e) => setNuevaFormacion(e.target.value)}
className="border rounded px-2 py-1 text-black"
required
>
<option value="">Selecciona inyección</option>
{inyecciones.map(inyeccion => (
{inyecciones.map((inyeccion) => (
<option key={inyeccion.id} value={inyeccion.id}>
{inyeccion.nombre}
</option>
@ -252,12 +283,12 @@ export default function AlumnosVista() {
{nuevoTipo === "pildora" && (
<select
value={nuevaFormacion}
onChange={e => setNuevaFormacion(e.target.value)}
onChange={(e) => setNuevaFormacion(e.target.value)}
className="border rounded px-2 py-1 text-black"
required
>
<option value="">Selecciona píldora</option>
{pildoras.map(pildora => (
{pildoras.map((pildora) => (
<option key={pildora.id} value={pildora.id}>
{pildora.nombre}
</option>
@ -266,8 +297,18 @@ export default function AlumnosVista() {
)}
</td>
<td className="py-2 px-4 border-b">
<button onClick={() => guardarEdicion(alumno.id)} className="bg-green-500 hover:bg-green-700 text-white px-3 py-1 rounded mr-2">Guardar</button>
<button onClick={() => setAlumnoEditando(null)} className="bg-gray-400 hover:bg-gray-600 text-white px-3 py-1 rounded">Cancelar</button>
<button
onClick={() => guardarEdicion(alumno.id)}
className="bg-green-500 hover:bg-green-700 text-white px-3 py-1 rounded mr-2"
>
Guardar
</button>
<button
onClick={() => setAlumnoEditando(null)}
className="bg-gray-400 hover:bg-gray-600 text-white px-3 py-1 rounded"
>
Cancelar
</button>
</td>
</tr>
) : (
@ -286,9 +327,12 @@ export default function AlumnosVista() {
: ""}
</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}
{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

@ -12,6 +12,6 @@ export const alumnoSchema = z.object({
.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"),
//tipo: z.string().nonempty("Selecciona un tipo de asignación"),
tipo: z.string().nonempty("Selecciona un tipo de formación"),
cursoSeleccionado: z.string().nonempty("Selecciona una opción"),
});