From aba498cdf0e6b8d64b6d9042af641e15b9bb8a55 Mon Sep 17 00:00:00 2001 From: SirRobert-1 Date: Sun, 15 Jun 2025 20:31:52 -0600 Subject: [PATCH 1/5] feat: enhance Diploma component layout and styling; update course details display --- diplomas/src/components/Diploma.jsx | 163 +++++++++++++++++++--------- 1 file changed, 114 insertions(+), 49 deletions(-) diff --git a/diplomas/src/components/Diploma.jsx b/diplomas/src/components/Diploma.jsx index 7e14251..7865241 100644 --- a/diplomas/src/components/Diploma.jsx +++ b/diplomas/src/components/Diploma.jsx @@ -8,84 +8,149 @@ import { Image, } from "@react-pdf/renderer"; +// Ajusta la ruta de tu logo si es necesario +const LOGO_SRC = "/encabezado.png"; + const styles = StyleSheet.create({ - page: { fontFamily: "Helvetica" }, - title: { fontSize: 24, textAlign: "center", marginBottom: 20 }, - nombre: { + page: { + fontFamily: "Helvetica", + padding: 0, + backgroundColor: "#fff", + position: "relative", + }, + title: { fontSize: 18, textAlign: "center", + marginTop: 40, marginBottom: 10, + fontWeight: "normal", + }, + constancia: { + fontSize: 20, + textAlign: "center", + letterSpacing: 4, + marginBottom: 18, + fontWeight: "normal", + }, + label: { + fontSize: 13, + textAlign: "center", + marginBottom: 6, + fontWeight: "normal", + }, + nombre: { + fontSize: 28, + textAlign: "center", + marginBottom: 16, + fontFamily: "Times-Roman", fontStyle: "italic", }, - curso: { - fontSize: 30, + participacion: { + fontSize: 13, textAlign: "center", - marginBottom: 10, - fontWeight: "bold", + marginBottom: 8, + fontWeight: "normal", }, - section: { padding: 40, fontSize: 14 }, - competencias: { marginLeft: 20, marginTop: 5 }, - competencia: { fontSize: 12, marginBottom: 2 }, - footer: { - position: "absolute", - bottom: 20, - right: 40, + curso: { + fontSize: 15, + textAlign: "center", + fontWeight: "bold", + marginBottom: 6, + }, + detalle: { + fontSize: 11, + textAlign: "center", + marginBottom: 30, + fontWeight: "normal", + }, + nombreDirector: { fontSize: 10, - color: "#888", + textAlign: "center", + marginTop: 40, + marginBottom: 2, + }, + director: { + fontSize: 10, + textAlign: "center", + marginBottom: 18, + }, + footer: { + fontSize: 9, + textAlign: "center", + color: "#444", + position: "absolute", + bottom: 30, + left: 0, + right: 0, }, qr: { - marginTop: 30, - alignSelf: "center", width: 100, height: 100, + alignSelf: "center", + marginTop: 30, }, }); export default function Diploma({ alumno, formacion, fecha, qr }) { - // formacion: { tipo, nombre, competencias } - let tipoTexto = "formación"; - if (formacion?.tipo === "curso") tipoTexto = "curso"; - else if (formacion?.tipo === "inyeccion") tipoTexto = "inyección"; - else if (formacion?.tipo === "pildora") tipoTexto = "píldora educativa"; + // formacion: { tipo, nombre, horas, modalidad } + // Puedes ajustar estos valores según tu modelo de datos + const nombreCurso = + formacion?.nombre || + formacion?.curso?.nombre || + formacion?.inyeccion?.nombre || + formacion?.pildora?.nombre || + "Sin curso"; + const horas = formacion?.horas || 30; + const modalidad = formacion?.modalidad || "remota"; return ( - + {/* Logo */} + + + {/* Título */} Otorga la presente - CONSTANCIA - a: - {alumno?.nombre} - - Por su asistencia{" "} + CONSTANCIA + a: + + {/* Nombre del alumno */} + {alumno?.nombre} + + {/* Participación */} + + Por su participación en el{" "} {formacion?.tipo === "curso" - ? "al curso" + ? "curso" : formacion?.tipo === "inyeccion" - ? "a la inyección" + ? "taller" : formacion?.tipo === "pildora" - ? "a la píldora educativa" - : "a la formación"} + ? "píldora" + : "programa"} - {formacion?.nombre || "Sin formación"} - {(formacion?.tipo === "curso" || formacion?.tipo === "inyeccion") && - formacion?.competencias?.length > 0 && ( - - - Competencias acreditadas: - - {formacion.competencias.map((comp) => ( - - - {comp.descripcion} - - ))} - - )} - - Se expide en la ciudad de Xalapa, Ver., {fecha} + + {/* Nombre del curso/formación */} + “{nombreCurso}” + + {/* Detalle de horas y modalidad */} + + con duración de {horas} horas, modalidad {modalidad}. + + {/* Firma */} + + Dr. Juan Manuel Gutiérrez Méndez + + Director de Proyectos + + {/* QR */} {qr && } + + {/* Footer con fecha */} - Verifica este diploma en: http://localhost:3000/alumno/{alumno?.id} + Se expide en la ciudad de Xalapa, Ver., a los {fecha} + {"\n"} + {/*Verifica este diploma en: http://localhost:3000/alumno/{alumno?.id}*/} From 575dcf2448c8ceaba80670cf47873144338a156e Mon Sep 17 00:00:00 2001 From: SirRobert-1 Date: Sun, 15 Jun 2025 21:24:08 -0600 Subject: [PATCH 2/5] feat: add next-themes and sonner dependencies; implement Toaster component for notifications --- diplomas/package-lock.json | 20 ++++++++++++++++ diplomas/package.json | 2 ++ .../dialogs/vistaPreviaDiplomaDialog.jsx | 6 +++-- diplomas/src/components/ui/sonner.jsx | 24 +++++++++++++++++++ diplomas/src/pages/_app.js | 8 ++++++- diplomas/src/pages/alumnosVista.jsx | 2 +- diplomas/src/pages/diplomasVista.jsx | 2 +- 7 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 diplomas/src/components/ui/sonner.jsx diff --git a/diplomas/package-lock.json b/diplomas/package-lock.json index c90d0ae..9c0b691 100644 --- a/diplomas/package-lock.json +++ b/diplomas/package-lock.json @@ -28,11 +28,13 @@ "lucide-react": "^0.488.0", "mysql2": "^3.14.1", "next": "15.3.0", + "next-themes": "^0.4.6", "papaparse": "^5.5.2", "qrcode": "^1.5.4", "react": "^19.0.0", "react-dom": "^19.0.0", "react-hook-form": "^7.56.2", + "sonner": "^2.0.5", "tailwind-merge": "^3.2.0", "tw-animate-css": "^1.2.5", "xlsx": "^0.18.5", @@ -6317,6 +6319,15 @@ } } }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -7399,6 +7410,15 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/sonner": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.5.tgz", + "integrity": "sha512-YwbHQO6cSso3HBXlbCkgrgzDNIhws14r4MO87Ofy+cV2X7ES4pOoAK3+veSmVTvqNx1BWUxlhPmZzP00Crk2aQ==", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", diff --git a/diplomas/package.json b/diplomas/package.json index c322137..c6c37ed 100644 --- a/diplomas/package.json +++ b/diplomas/package.json @@ -29,11 +29,13 @@ "lucide-react": "^0.488.0", "mysql2": "^3.14.1", "next": "15.3.0", + "next-themes": "^0.4.6", "papaparse": "^5.5.2", "qrcode": "^1.5.4", "react": "^19.0.0", "react-dom": "^19.0.0", "react-hook-form": "^7.56.2", + "sonner": "^2.0.5", "tailwind-merge": "^3.2.0", "tw-animate-css": "^1.2.5", "xlsx": "^0.18.5", diff --git a/diplomas/src/components/dialogs/vistaPreviaDiplomaDialog.jsx b/diplomas/src/components/dialogs/vistaPreviaDiplomaDialog.jsx index 25aa7cc..f8be412 100644 --- a/diplomas/src/components/dialogs/vistaPreviaDiplomaDialog.jsx +++ b/diplomas/src/components/dialogs/vistaPreviaDiplomaDialog.jsx @@ -13,6 +13,7 @@ import { useForm } from "react-hook-form"; import { mensajesSchema } from "@/schemas/mensajesSchema"; import { Textarea } from "../ui/textarea"; import QRCode from "qrcode"; +import { toast } from "sonner"; function VistaPreviaDiplomaDialog({ open, @@ -105,6 +106,7 @@ function VistaPreviaDiplomaDialog({ } setMensaje("Mensajes guardados correctamente."); + toast.success("Mensajes guardados correctamente."); }; useEffect(() => { @@ -216,7 +218,7 @@ function VistaPreviaDiplomaDialog({ return ( - + Diploma @@ -331,7 +333,7 @@ function VistaPreviaDiplomaDialog({ {/* Vista previa PDF */} {mostrarVistaPrevia && (
-
+
{ + const { theme = "system" } = useTheme() + + return ( + () + ); +} + +export { Toaster } diff --git a/diplomas/src/pages/_app.js b/diplomas/src/pages/_app.js index b97e52f..79d88a9 100644 --- a/diplomas/src/pages/_app.js +++ b/diplomas/src/pages/_app.js @@ -1,5 +1,11 @@ import "@/styles/globals.css"; +import { Toaster } from "sonner"; export default function App({ Component, pageProps }) { - return ; + return ( + <> + + ; + + ); } diff --git a/diplomas/src/pages/alumnosVista.jsx b/diplomas/src/pages/alumnosVista.jsx index c7f607b..0fe726f 100644 --- a/diplomas/src/pages/alumnosVista.jsx +++ b/diplomas/src/pages/alumnosVista.jsx @@ -334,7 +334,7 @@ export default function AlumnosVista() { {alumno.tipo_formacion === "pildora" && alumno.pildoras?.nombre} - + + {mensaje &&
{mensaje}
} + + ); +} \ No newline at end of file diff --git a/diplomas/src/components/pildorasManualForm.jsx b/diplomas/src/components/pildorasManualForm.jsx new file mode 100644 index 0000000..2b5291d --- /dev/null +++ b/diplomas/src/components/pildorasManualForm.jsx @@ -0,0 +1,60 @@ +import React, { useState } from "react"; +import { supabaseClient } from "@/utils/supabase"; +import { Button } from "@/components/ui/button"; + +export function PildoraManualForm({ nombreSugerido = "" }) { + const [nombre, setNombre] = useState(nombreSugerido); + const [descripcion, setDescripcion] = useState(""); + const [horas, setHoras] = useState(""); + const [mensaje, setMensaje] = useState(""); + + const handleSubmit = async (e) => { + e.preventDefault(); + const { error } = await supabaseClient.from("pildoras").insert([ + { + nombre, + descripcion, + horas: horas ? parseInt(horas) : null, + }, + ]); + if (error) { + setMensaje("Error al registrar la píldora: " + error.message); + } else { + setMensaje("¡Píldora registrada correctamente!"); + setNombre(""); + setDescripcion(""); + setHoras(""); + } + }; + + return ( +
+ setNombre(e.target.value)} + required + className="border rounded px-2 py-1" + /> + setDescripcion(e.target.value)} + className="border rounded px-2 py-1" + /> + setHoras(e.target.value)} + className="border rounded px-2 py-1" + /> + + {mensaje &&
{mensaje}
} +
+ ); +} \ No newline at end of file diff --git a/diplomas/src/pages/alumnosArchivo.jsx b/diplomas/src/pages/alumnosArchivo.jsx index c201a0a..f02775e 100644 --- a/diplomas/src/pages/alumnosArchivo.jsx +++ b/diplomas/src/pages/alumnosArchivo.jsx @@ -15,6 +15,8 @@ import { import { CursosManualForm } from "@/components/cursosManualForm"; import { supabaseClient } from "@/utils/supabase"; import { useRouter } from "next/router"; +import { InyeccionManualForm } from "@/components/inyeccionesManualForm"; +import { PildoraManualForm } from "@/components/pildorasManualForm"; export default function AlumnosArchivo() { const [archivo, setArchivo] = useState(null); @@ -25,6 +27,8 @@ export default function AlumnosArchivo() { const [cursoFaltante, setCursoFaltante] = useState(""); const [dialogoAdvertencia, setDialogoAdvertencia] = useState(false); const [rutaPendiente, setRutaPendiente] = useState(null); + const [mostrarDialogFormacion, setMostrarDialogFormacion] = useState(false); + const [formacionFaltante, setFormacionFaltante] = useState(null); const router = useRouter(); useEffect(() => { @@ -55,40 +59,92 @@ export default function AlumnosArchivo() { const errores = []; for (const alumno of datos) { - // 1. Verifica si el curso existe - const { data: cursosEncontrados, error: errorCurso } = - await supabaseClient + let formacionId = null; + let tipo = (alumno.tipo || "").toLowerCase(); + + if (tipo === "curso") { + const { data: curso, error } = await supabaseClient .from("curso") .select("id") - .eq("nombre", alumno.nombreCurso) + .eq("nombre", alumno.formacion) .maybeSingle(); - - if (errorCurso) { - errores.push({ alumno, error: "Error al buscar el curso" }); + if (error) { + errores.push({ alumno, error: "Error al buscar el curso" }); + continue; + } + if (!curso) { + setFormacionFaltante({ tipo: "curso", nombre: alumno.formacion }); + setMostrarDialogFormacion(true); + setMensajeDialogo( + `El curso "${alumno.formacion}" no existe. Por favor, regístralo primero.` + ); + setDialogoAbierto(true); + return; + } + formacionId = curso.id; + } else if (tipo === "inyeccion") { + const { data: inyeccion, error } = await supabaseClient + .from("inyeccion") + .select("id") + .eq("nombre", alumno.formacion) + .maybeSingle(); + if (error) { + errores.push({ alumno, error: "Error al buscar la inyección" }); + continue; + } + if (!inyeccion) { + setFormacionFaltante({ tipo: "inyeccion", nombre: alumno.formacion }); + setMostrarDialogFormacion(true); + setMensajeDialogo( + `La inyección "${alumno.formacion}" no existe. Por favor, regístrala primero.` + ); + setDialogoAbierto(true); + return; + } + formacionId = inyeccion.id; + } else if (tipo === "pildora") { + const { data: pildora, error } = await supabaseClient + .from("pildoras") + .select("id") + .eq("nombre", alumno.formacion) + .maybeSingle(); + if (error) { + errores.push({ alumno, error: "Error al buscar la píldora" }); + continue; + } + if (!pildora) { + setFormacionFaltante({ tipo: "pildora", nombre: alumno.formacion }); + setMostrarDialogFormacion(true); + setMensajeDialogo( + `La píldora "${alumno.formacion}" no existe. Por favor, regístrala primero.` + ); + setDialogoAbierto(true); + return; + } + formacionId = pildora.id; + } else { + errores.push({ alumno, error: "Tipo de formación no válido" }); continue; } - if (!cursosEncontrados) { - // Si no existe el curso, muestra el dialog para registrar el curso - setCursoFaltante(alumno.nombreCurso); - setMostrarDialogCurso(true); - setMensajeDialogo( - `El curso "${alumno.nombreCurso}" no existe. Por favor, regístralo primero.` - ); - setDialogoAbierto(true); - return; // Detiene el registro de alumnos - } + // Registrar alumno con el campo correcto según tipo + let body = { + nombre: alumno.nombre, + correo: alumno.correo, + telefono: alumno.telefono, + tipo_formacion: tipo, + curso_id: null, + inyeccion_id: null, + pildoras_id: null, + }; + if (tipo === "curso") body.curso_id = formacionId; + if (tipo === "inyeccion") body.inyeccion_id = formacionId; + if (tipo === "pildora") body.pildoras_id = formacionId; - // 2. Si existe, registra el alumno con el curso_id correcto const res = await fetch("/api/alumno", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - nombre: alumno.nombre, - correo: alumno.correo, - telefono: alumno.telefono, - curso_id: cursosEncontrados.id, - }), + body: JSON.stringify(body), }); const resultado = await res.json(); @@ -289,6 +345,36 @@ export default function AlumnosArchivo() {
+ + {/* Dialog para formacion faltante */} + + + + + Registrar {formacionFaltante?.tipo} faltante + + + La {formacionFaltante?.tipo} {formacionFaltante?.nombre} no + existe. Por favor, regístrala antes de continuar. + + + {formacionFaltante?.tipo === "curso" && ( + + )} + {formacionFaltante?.tipo === "inyeccion" && ( + + )} + {formacionFaltante?.tipo === "pildora" && ( + + )} + + + + + ); } diff --git a/diplomas/src/pages/api/alumno.js b/diplomas/src/pages/api/alumno.js index f85b413..73f38d4 100644 --- a/diplomas/src/pages/api/alumno.js +++ b/diplomas/src/pages/api/alumno.js @@ -6,23 +6,43 @@ export default async function handler(req, res) { return res.status(405).json({ error: "Método no permitido" }); } + const { nombre, correo, telefono, tipo_formacion, curso_id, inyeccion_id, pildoras_id } = req.body; + + if (!nombre || !correo || !telefono || !tipo_formacion) { + return res.status(400).json({ error: "Faltan datos del alumno" }); + } + + // Validar que llegue el ID correcto según el tipo + if ( + (tipo_formacion === "curso" && !curso_id) || + (tipo_formacion === "inyeccion" && !inyeccion_id) || + (tipo_formacion === "pildora" && !pildoras_id) + ) { + return res.status(400).json({ error: "Faltan datos del alumno" }); + } + try { const supabase = createClient({ req, res }); - const { nombre, correo, telefono, curso_id } = req.body; - - if (!nombre || !correo || !telefono || !curso_id) { - return res.status(400).json({ error: "Faltan datos del alumno" }); - } + // Aquí tu lógica para insertar el alumno en la base de datos + // Ejemplo con Supabase: const { data, error } = await supabase.from("alumno").insert([ - { nombre, correo, telefono, curso_id }, + { + nombre, + correo, + telefono, + tipo_formacion, + curso_id: tipo_formacion === "curso" ? curso_id : null, + inyeccion_id: tipo_formacion === "inyeccion" ? inyeccion_id : null, + pildoras_id: tipo_formacion === "pildora" ? pildoras_id : null, + }, ]); if (error) { - return res.status(500).json({ error: "Error al insertar en Supabase", detalles: error.message }); + return res.status(500).json({ error: error.message }); } - return res.status(200).json({ mensaje: "Alumno registrado", data }); + return res.status(200).json({ ok: true, data }); } catch (err) { return res.status(500).json({ error: "Error interno del servidor", detalles: err.message }); } diff --git a/diplomas/src/pages/inyeccionesArchivo.jsx b/diplomas/src/pages/inyeccionesArchivo.jsx index 21f3709..2fb5fc7 100644 --- a/diplomas/src/pages/inyeccionesArchivo.jsx +++ b/diplomas/src/pages/inyeccionesArchivo.jsx @@ -3,6 +3,7 @@ import Papa from "papaparse"; import * as XLSX from "xlsx"; import Layout from "@/components/layout/Layout"; import { Button } from "@/components/ui/button"; +import { supabaseClient } from "@/utils/supabase"; import { Dialog, DialogContent, @@ -52,22 +53,79 @@ export default function InyeccionesArchivo() { const errores = []; for (const inyeccion of datos) { - const res = await fetch("/api/inyeccion", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - nombre: inyeccion.nombre, - horas: inyeccion.horas, - descripcion: inyeccion.descripcion, - }), - }); + // 1. Procesar competencias (si existen) + let competenciasIds = []; + if (inyeccion.competencias) { + const competenciasArr = inyeccion.competencias + .split(",") + .map((c) => c.trim()) + .filter(Boolean); - const resultado = await res.json(); - if (!res.ok) { + for (const desc of competenciasArr) { + // Buscar si ya existe la competencia + let { data: existente } = await supabaseClient + .from("competencia_inyeccion") + .select("id") + .eq("descripcion", desc) + .maybeSingle(); + + let compId = existente?.id; + if (!compId) { + // Insertar si no existe + const { data: insertada, error: errorInsert } = await supabaseClient + .from("competencia_inyeccion") + .insert([{ descripcion: desc }]) + .select("id") + .single(); + if (errorInsert) { + errores.push({ + inyeccion, + error: `Error insertando competencia "${desc}": ${errorInsert.message}`, + }); + continue; + } + compId = insertada.id; + } + competenciasIds.push(compId); + } + } + + // 2. Insertar la inyección + const { data: inyeccionInsertada, error: errorIny } = await supabaseClient + .from("inyeccion") + .insert([ + { + nombre: inyeccion.nombre, + horas: inyeccion.horas, + descripcion: inyeccion.descripcion, + }, + ]) + .select("id") + .single(); + + if (errorIny) { errores.push({ inyeccion, - error: resultado.error || "Error desconocido", + error: errorIny.message || "Error desconocido al insertar inyección", }); + continue; + } + + // 3. Relacionar competencias con la inyección + if (inyeccionInsertada && competenciasIds.length > 0) { + const relaciones = competenciasIds.map((cid) => ({ + inyeccion_id: inyeccionInsertada.id, + competencia_inyeccion_id: cid, + })); + const { error: errorRel } = await supabaseClient + .from("inyeccion_competencia_inyeccion") + .insert(relaciones); + if (errorRel) { + errores.push({ + inyeccion, + error: `Error relacionando competencias: ${errorRel.message}`, + }); + } } } diff --git a/diplomas/src/pages/inyeccionesVista.jsx b/diplomas/src/pages/inyeccionesVista.jsx index cbba56f..8ef7274 100644 --- a/diplomas/src/pages/inyeccionesVista.jsx +++ b/diplomas/src/pages/inyeccionesVista.jsx @@ -123,6 +123,29 @@ export default function InyeccionesVista() { }; const eliminarInyeccion = async () => { + // 1. Buscar si hay alumnos asociados a esta inyección + const { data: alumnos, error: errorAlumnos } = await supabaseClient + .from("alumno") + .select("id") + .eq("inyeccion_id", inyeccionAEliminar); + + if (errorAlumnos) { + setModalMensaje("Error al verificar alumnos asociados: " + errorAlumnos.message); + setConfirmarEliminar(false); + setMostrarModal(true); + return; + } + + if (alumnos && alumnos.length > 0) { + setModalMensaje( + "No se puede eliminar la inyección porque hay alumnos inscritos. Primero elimina o reasigna a los alumnos asociados." + ); + setConfirmarEliminar(false); + setMostrarModal(true); + return; + } + + // 2. Si no hay alumnos, eliminar la inyección const { error } = await supabaseClient .from("inyeccion") .delete() diff --git a/diplomas/src/pages/pildorasVista.jsx b/diplomas/src/pages/pildorasVista.jsx index 7571947..33497ba 100644 --- a/diplomas/src/pages/pildorasVista.jsx +++ b/diplomas/src/pages/pildorasVista.jsx @@ -80,6 +80,31 @@ export default function PildorasVista() { }; const eliminarPildora = async () => { + // 1. Buscar si hay alumnos asociados a esta píldora + const { data: alumnos, error: errorAlumnos } = await supabaseClient + .from("alumno") + .select("id") + .eq("pildoras_id", pildoraAEliminar); + + if (errorAlumnos) { + setModalMensaje( + "Error al verificar alumnos asociados: " + errorAlumnos.message + ); + setConfirmarEliminar(false); + setMostrarModal(true); + return; + } + + if (alumnos && alumnos.length > 0) { + setModalMensaje( + "No se puede eliminar la píldora porque hay alumnos inscritos. Primero elimina o reasigna a los alumnos asociados." + ); + setConfirmarEliminar(false); + setMostrarModal(true); + return; + } + + // 2. Si no hay alumnos, eliminar la píldora const { error } = await supabaseClient .from("pildoras") .delete() From d10b4d348db9f163756a5dbf06b39889e7fa0d9a Mon Sep 17 00:00:00 2001 From: SirRobert-1 Date: Sun, 15 Jun 2025 23:00:57 -0600 Subject: [PATCH 5/5] fix: format button text for better readability in AlumnosArchivo component --- diplomas/src/pages/alumnosArchivo.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/diplomas/src/pages/alumnosArchivo.jsx b/diplomas/src/pages/alumnosArchivo.jsx index f02775e..f5b4652 100644 --- a/diplomas/src/pages/alumnosArchivo.jsx +++ b/diplomas/src/pages/alumnosArchivo.jsx @@ -371,7 +371,9 @@ export default function AlumnosArchivo() { )} - +