Merge branch 'benito' of https://git.gumoio.com/benito.rodriguez/SIDAC into roberto
This commit is contained in:
commit
0718f041a0
File diff suppressed because it is too large
Load Diff
|
@ -21,8 +21,11 @@
|
|||
"@supabase/supabase-js": "^2.49.4",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cors": "^2.8.5",
|
||||
"diplomas": "file:",
|
||||
"express": "^5.1.0",
|
||||
"lucide-react": "^0.488.0",
|
||||
"mysql2": "^3.14.1",
|
||||
"next": "15.3.0",
|
||||
"papaparse": "^5.5.2",
|
||||
"react": "^19.0.0",
|
||||
|
|
|
@ -52,6 +52,15 @@ const data = {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Diplomas",
|
||||
items: [
|
||||
{
|
||||
title: "Creación de diplomas",
|
||||
url: "/diplomasVista",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
@ -1,34 +1,75 @@
|
|||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Papa from "papaparse";
|
||||
import * as XLSX from "xlsx";
|
||||
import Layout from "@/components/layout/Layout";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
|
||||
|
||||
export default function AlumnosArchivo() {
|
||||
const [archivo, setArchivo] = useState(null);
|
||||
const [datos, setDatos] = useState([]);
|
||||
const [dialogoAbierto, setDialogoAbierto] = useState(false);
|
||||
const [mensajeDialogo, setMensajeDialogo] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
if (archivo) extraerContenido();
|
||||
}, [archivo]);
|
||||
|
||||
const registrarAlumnos = async () => {
|
||||
if (datos.length === 0) return;
|
||||
|
||||
const errores = [];
|
||||
|
||||
for (const alumno of datos) {
|
||||
const res = await fetch("/api/alumno", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
nombre: alumno.nombre,
|
||||
correo: alumno.correo,
|
||||
nombreCurso: alumno.nombreCurso,
|
||||
}),
|
||||
});
|
||||
|
||||
const resultado = await res.json();
|
||||
if (!res.ok) {
|
||||
errores.push({ alumno, error: resultado.error || "Error desconocido" });
|
||||
}
|
||||
}
|
||||
|
||||
if (errores.length > 0) {
|
||||
setMensajeDialogo(`Se registraron algunos errores:\n${JSON.stringify(errores, null, 2)}`);
|
||||
} else {
|
||||
setMensajeDialogo("Todos los alumnos fueron registrados correctamente.");
|
||||
setArchivo(null);
|
||||
setDatos([]);
|
||||
}
|
||||
setDialogoAbierto(true);
|
||||
};
|
||||
|
||||
const manejarArchivo = (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (file && (file.name.endsWith(".csv") || file.name.endsWith(".xlsx"))) {
|
||||
setArchivo(file);
|
||||
} else {
|
||||
alert("Solo se permiten archivos .csv o .xlsx");
|
||||
}
|
||||
if (validarArchivo(file)) setArchivo(file);
|
||||
};
|
||||
|
||||
const manejarSoltar = (e) => {
|
||||
e.preventDefault();
|
||||
const file = e.dataTransfer.files[0];
|
||||
if (file && (file.name.endsWith(".csv") || file.name.endsWith(".xlsx"))) {
|
||||
setArchivo(file);
|
||||
} else {
|
||||
alert("Solo se permiten archivos .csv o .xlsx");
|
||||
}
|
||||
if (validarArchivo(file)) setArchivo(file);
|
||||
};
|
||||
|
||||
const manejarArrastrar = (e) => e.preventDefault();
|
||||
|
||||
const validarArchivo = (file) => {
|
||||
if (file && (file.name.endsWith(".csv") || file.name.endsWith(".xlsx"))) {
|
||||
return true;
|
||||
} else {
|
||||
setMensajeDialogo("Solo se permiten archivos .csv o .xlsx");
|
||||
setDialogoAbierto(true);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const extraerContenido = () => {
|
||||
if (!archivo) return;
|
||||
|
||||
|
@ -39,7 +80,6 @@ export default function AlumnosArchivo() {
|
|||
header: true,
|
||||
skipEmptyLines: true,
|
||||
complete: (result) => {
|
||||
console.log("Contenido CSV:", result.data);
|
||||
setDatos(result.data);
|
||||
},
|
||||
error: (error) => {
|
||||
|
@ -55,7 +95,6 @@ export default function AlumnosArchivo() {
|
|||
const contenido = XLSX.utils.sheet_to_json(workbook.Sheets[hoja], {
|
||||
defval: "",
|
||||
});
|
||||
console.log("Contenido XLSX:", contenido);
|
||||
setDatos(contenido);
|
||||
};
|
||||
reader.readAsArrayBuffer(archivo);
|
||||
|
@ -64,7 +103,7 @@ export default function AlumnosArchivo() {
|
|||
|
||||
return (
|
||||
<Layout>
|
||||
<div className="w-[60vw] pt-10 flex flex-col items-end justify-center">
|
||||
<div className="w-[60vw] pt-10 flex flex-col items-end justify-center text-black">
|
||||
<div className="bg-white p-8 font-sans text-center w-[70%] flex flex-col items-center">
|
||||
<h1 className="text-xl font-semibold mb-4 text-black">
|
||||
Nuevo alumno
|
||||
|
@ -90,22 +129,47 @@ export default function AlumnosArchivo() {
|
|||
</label>
|
||||
|
||||
<Button
|
||||
onClick={extraerContenido}
|
||||
className="bg-green-400 hover:bg-green-500 text-white font-bold py-2 px-4 rounded-md"
|
||||
onClick={registrarAlumnos}
|
||||
className="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-md mt-4"
|
||||
>
|
||||
Extraer contenido
|
||||
Registrar alumnos
|
||||
</Button>
|
||||
|
||||
{datos.length > 0 && (
|
||||
<div className="mt-6 text-left w-full max-w-md">
|
||||
<h3 className="font-bold mb-2">Contenido extraído:</h3>
|
||||
<pre className="bg-gray-100 p-2 rounded overflow-x-auto text-sm">
|
||||
{JSON.stringify(datos, null, 2)}
|
||||
</pre>
|
||||
<div className="mt-6 text-left w-full overflow-auto">
|
||||
<h3 className="font-bold mb-2">Vista previa del archivo:</h3>
|
||||
<table className="min-w-full bg-white border border-gray-300 text-sm">
|
||||
<thead className="bg-gray-100 text-gray-700">
|
||||
<tr>
|
||||
{Object.keys(datos[0]).map((columna, index) => (
|
||||
<th key={index} className="border px-4 py-2">{columna}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{datos.map((fila, index) => (
|
||||
<tr key={index}>
|
||||
{Object.values(fila).map((valor, i) => (
|
||||
<td key={i} className="border px-4 py-1">{valor}</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Dialog Component */}
|
||||
<Dialog open={dialogoAbierto} onOpenChange={setDialogoAbierto}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-black">Información</DialogTitle>
|
||||
<DialogDescription>{mensajeDialogo}</DialogDescription>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -20,7 +20,6 @@ import {
|
|||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
|
||||
export default function AlumnosVista() {
|
||||
const [alumnos, setAlumnos] = useState([]);
|
||||
const [alumnoEditando, setAlumnoEditando] = useState(null);
|
||||
|
@ -28,10 +27,13 @@ export default function AlumnosVista() {
|
|||
const [nuevoCorreo, setNuevoCorreo] = useState("");
|
||||
const [mostrarModal, setMostrarModal] = useState(false);
|
||||
const [modalMensaje, setModalMensaje] = useState("");
|
||||
const [nuevoCurso, setNuevoCurso] = useState("");
|
||||
|
||||
const [nuevoCurso, setNuevoCurso] = useState("");
|
||||
const [cursos, setCursos] = useState([]);
|
||||
|
||||
// Estado para confirmación de eliminación
|
||||
const [confirmarEliminar, setConfirmarEliminar] = useState(false);
|
||||
const [alumnoAEliminar, setAlumnoAEliminar] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
cargarAlumnos();
|
||||
cargarCursos();
|
||||
|
@ -60,7 +62,7 @@ export default function AlumnosVista() {
|
|||
setAlumnoEditando(alumno.id);
|
||||
setNuevoNombre(alumno.nombre);
|
||||
setNuevoCorreo(alumno.correo);
|
||||
setNuevoCurso(alumno.nombreCurso); // Asumiendo que tienes un campo cursoId en el alumno
|
||||
setNuevoCurso(alumno.nombreCurso);
|
||||
};
|
||||
|
||||
// Cancelar edición
|
||||
|
@ -78,7 +80,7 @@ export default function AlumnosVista() {
|
|||
.update({
|
||||
nombre: nuevoNombre,
|
||||
correo: nuevoCorreo,
|
||||
nombreCurso: nuevoCurso, // Asumiendo que tienes un campo cursoId en el alumno
|
||||
nombreCurso: nuevoCurso,
|
||||
})
|
||||
.eq("id", id);
|
||||
|
||||
|
@ -93,9 +95,15 @@ export default function AlumnosVista() {
|
|||
setMostrarModal(true);
|
||||
};
|
||||
|
||||
// Confirmar eliminación
|
||||
const confirmarEliminacion = (id) => {
|
||||
setAlumnoAEliminar(id);
|
||||
setConfirmarEliminar(true);
|
||||
};
|
||||
|
||||
// Eliminar alumno
|
||||
const eliminarAlumno = async (id) => {
|
||||
const { error } = await supabaseClient.from("alumno").delete().eq("id", id);
|
||||
const eliminarAlumno = async () => {
|
||||
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");
|
||||
|
@ -103,6 +111,7 @@ export default function AlumnosVista() {
|
|||
setModalMensaje("Alumno eliminado exitosamente");
|
||||
await cargarAlumnos();
|
||||
}
|
||||
setConfirmarEliminar(false);
|
||||
setMostrarModal(true);
|
||||
};
|
||||
|
||||
|
@ -191,7 +200,7 @@ export default function AlumnosVista() {
|
|||
|
||||
<Button
|
||||
className="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-3 rounded"
|
||||
onClick={() => eliminarAlumno(alumno.id)}
|
||||
onClick={() => confirmarEliminacion(alumno.id)}
|
||||
>
|
||||
Eliminar
|
||||
</Button>
|
||||
|
@ -203,7 +212,33 @@ export default function AlumnosVista() {
|
|||
</table>
|
||||
</div>
|
||||
|
||||
{/* Modal */}
|
||||
{/* Modal de confirmación */}
|
||||
<Dialog open={confirmarEliminar} onOpenChange={setConfirmarEliminar}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<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.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
className="bg-red-500 hover:bg-red-700 text-white"
|
||||
onClick={eliminarAlumno}
|
||||
>
|
||||
Eliminar
|
||||
</Button>
|
||||
<Button
|
||||
className="bg-gray-400 hover:bg-gray-600 text-white"
|
||||
onClick={() => setConfirmarEliminar(false)}
|
||||
>
|
||||
Cancelar
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Modal de resultado */}
|
||||
<Dialog open={mostrarModal} onOpenChange={setMostrarModal}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
|
@ -219,4 +254,4 @@ export default function AlumnosVista() {
|
|||
</Dialog>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// pages/api/alumno.js
|
||||
import { createClient } from "@/utils/supabase";
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({ error: "Método no permitido" });
|
||||
}
|
||||
|
||||
try {
|
||||
const supabase = createClient({ req, res });
|
||||
const { nombre, correo, nombreCurso } = req.body;
|
||||
|
||||
if (!nombre || !correo || !nombreCurso) {
|
||||
return res.status(400).json({ error: "Faltan datos del alumno" });
|
||||
}
|
||||
|
||||
const { data, error } = await supabase.from("alumno").insert([
|
||||
{ nombre, correo, nombreCurso },
|
||||
]);
|
||||
|
||||
if (error) {
|
||||
return res.status(500).json({ error: "Error al insertar en Supabase", detalles: error.message });
|
||||
}
|
||||
|
||||
return res.status(200).json({ mensaje: "Alumno registrado", data });
|
||||
} catch (err) {
|
||||
return res.status(500).json({ error: "Error interno del servidor", detalles: err.message });
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// pages/api/curso.js
|
||||
import { createClient } from "@/utils/supabase";
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({ error: "Método no permitido" });
|
||||
}
|
||||
|
||||
try {
|
||||
const supabase = createClient({ req, res });
|
||||
const { nombre, horas, descripcion, competencias } = req.body;
|
||||
|
||||
if (!nombre || !horas || !descripcion || !competencias) {
|
||||
return res.status(400).json({ error: "Faltan datos del curso" });
|
||||
}
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from("curso")
|
||||
.insert([{ nombre, horas, descripcion, competencias }]);
|
||||
|
||||
if (error) {
|
||||
return res.status(500).json({ error: "Error al insertar en Supabase", detalles: error.message });
|
||||
}
|
||||
|
||||
return res.status(200).json({ mensaje: "Curso registrado", data });
|
||||
} catch (err) {
|
||||
return res.status(500).json({ error: "Error interno del servidor", detalles: err.message });
|
||||
}
|
||||
}
|
|
@ -1,80 +1,178 @@
|
|||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Papa from "papaparse";
|
||||
import * as XLSX from "xlsx";
|
||||
import Layout from "@/components/layout/Layout";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
|
||||
|
||||
export default function CursosArchivo() {
|
||||
export default function cursosArchivo() {
|
||||
const [archivo, setArchivo] = useState(null);
|
||||
const [datosCSV, setDatosCSV] = useState([]);
|
||||
const [datos, setDatos] = useState([]);
|
||||
const [dialogoAbierto, setDialogoAbierto] = useState(false);
|
||||
const [mensajeDialogo, setMensajeDialogo] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
if (archivo) extraerContenido();
|
||||
}, [archivo]);
|
||||
|
||||
const registrarCursos = async () => {
|
||||
if (datos.length === 0) return;
|
||||
|
||||
const errores = [];
|
||||
|
||||
for (const curso of datos) {
|
||||
const res = await fetch("/api/curso", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
nombre: curso.nombre,
|
||||
horas: curso.horas,
|
||||
descripcion: curso.descripcion,
|
||||
competencias: curso.competencias
|
||||
? curso.competencias.split(",").map(c => c.trim())
|
||||
: [],
|
||||
}),
|
||||
});
|
||||
|
||||
const resultado = await res.json();
|
||||
if (!res.ok) {
|
||||
errores.push({ curso, error: resultado.error || "Error desconocido" });
|
||||
}
|
||||
}
|
||||
|
||||
if (errores.length > 0) {
|
||||
setMensajeDialogo(`Se registraron algunos errores:\n${JSON.stringify(errores, null, 2)}`);
|
||||
} else {
|
||||
setMensajeDialogo("Todos los cursos fueron registrados correctamente.");
|
||||
setArchivo(null);
|
||||
setDatos([]);
|
||||
}
|
||||
setDialogoAbierto(true);
|
||||
};
|
||||
|
||||
const manejarArchivo = (e) => {
|
||||
const file = e.target.files[0];
|
||||
setArchivo(file);
|
||||
if (validarArchivo(file)) setArchivo(file);
|
||||
};
|
||||
|
||||
const manejarSoltar = (e) => {
|
||||
e.preventDefault();
|
||||
const file = e.dataTransfer.files[0];
|
||||
setArchivo(file);
|
||||
if (validarArchivo(file)) setArchivo(file);
|
||||
};
|
||||
|
||||
const manejarArrastrar = (e) => {
|
||||
e.preventDefault();
|
||||
const manejarArrastrar = (e) => e.preventDefault();
|
||||
|
||||
const validarArchivo = (file) => {
|
||||
if (file && (file.name.endsWith(".csv") || file.name.endsWith(".xlsx"))) {
|
||||
return true;
|
||||
} else {
|
||||
setMensajeDialogo("Solo se permiten archivos .csv o .xlsx");
|
||||
setDialogoAbierto(true);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const extraerContenido = () => {
|
||||
if (!archivo) return;
|
||||
|
||||
Papa.parse(archivo, {
|
||||
header: true,
|
||||
skipEmptyLines: true,
|
||||
complete: (result) => {
|
||||
console.log("Contenido CSV:", result.data);
|
||||
setDatosCSV(result.data);
|
||||
},
|
||||
error: (error) => {
|
||||
console.error("Error al leer el CSV:", error.message);
|
||||
},
|
||||
});
|
||||
const extension = archivo.name.split(".").pop().toLowerCase();
|
||||
|
||||
if (extension === "csv") {
|
||||
Papa.parse(archivo, {
|
||||
header: true,
|
||||
skipEmptyLines: true,
|
||||
complete: (result) => {
|
||||
setDatos(result.data);
|
||||
},
|
||||
error: (error) => {
|
||||
console.error("Error al leer el CSV:", error.message);
|
||||
},
|
||||
});
|
||||
} else if (extension === "xlsx") {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const data = new Uint8Array(e.target.result);
|
||||
const workbook = XLSX.read(data, { type: "array" });
|
||||
const hoja = workbook.SheetNames[0];
|
||||
const contenido = XLSX.utils.sheet_to_json(workbook.Sheets[hoja], {
|
||||
defval: "",
|
||||
});
|
||||
setDatos(contenido);
|
||||
};
|
||||
reader.readAsArrayBuffer(archivo);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<div className="w-[60vw] pt-10 flex flex-col items-end justify-center">
|
||||
<div className="w-[60vw] pt-10 flex flex-col items-end justify-center text-black">
|
||||
<div className="bg-white p-8 font-sans text-center w-[70%] flex flex-col items-center">
|
||||
<h1 className="text-xl font-semibold mb-4 text-black">Nuevo curso</h1>
|
||||
<h1
|
||||
<h1 className="text-xl font-semibold mb-4 text-black">
|
||||
Nuevo curso
|
||||
</h1>
|
||||
<label
|
||||
htmlFor="archivo"
|
||||
onDrop={manejarSoltar}
|
||||
onDragOver={manejarArrastrar}
|
||||
className="border-2 border-gray-300 rounded-md p-8 text-gray-600 cursor-pointer w-80 text-center mb-4"
|
||||
>
|
||||
Arrastra y suelta un archivo o busca un archivo
|
||||
{archivo ? (
|
||||
<span className="text-black font-medium">{archivo.name}</span>
|
||||
) : (
|
||||
<span>Arrastra y suelta un archivo o haz clic para seleccionarlo</span>
|
||||
)}
|
||||
<input
|
||||
type="file"
|
||||
id="archivo"
|
||||
accept=".csv"
|
||||
accept=".csv, .xlsx"
|
||||
onChange={manejarArchivo}
|
||||
className="hidden"
|
||||
/>
|
||||
</h1>
|
||||
</label>
|
||||
|
||||
<Button
|
||||
onClick={extraerContenido}
|
||||
className="bg-green-400 hover:bg-green-500 text-white font-bold py-2 px-4 rounded-md"
|
||||
onClick={registrarCursos}
|
||||
className="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-md mt-4"
|
||||
>
|
||||
Extraer contenido
|
||||
Registrar cursos
|
||||
</Button>
|
||||
|
||||
{datosCSV.length > 0 && (
|
||||
<div className="mt-6 text-left w-full max-w-md">
|
||||
<h3 className="font-bold mb-2">Contenido extraído:</h3>
|
||||
<pre className="bg-gray-100 p-2 rounded overflow-x-auto text-sm">
|
||||
{JSON.stringify(datosCSV, null, 2)}
|
||||
</pre>
|
||||
{datos.length > 0 && (
|
||||
<div className="mt-6 text-left w-full overflow-auto">
|
||||
<h3 className="font-bold mb-2">Vista previa del archivo:</h3>
|
||||
<table className="min-w-full bg-white border border-gray-300 text-sm">
|
||||
<thead className="bg-gray-100 text-gray-700">
|
||||
<tr>
|
||||
{Object.keys(datos[0]).map((columna, index) => (
|
||||
<th key={index} className="border px-4 py-2">{columna}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{datos.map((fila, index) => (
|
||||
<tr key={index}>
|
||||
{Object.values(fila).map((valor, i) => (
|
||||
<td key={i} className="border px-4 py-1">{valor}</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Dialog Component */}
|
||||
<Dialog open={dialogoAbierto} onOpenChange={setDialogoAbierto}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-black">Información</DialogTitle>
|
||||
<DialogDescription>{mensajeDialogo}</DialogDescription>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -21,6 +21,10 @@ export default function CursosVista() {
|
|||
const [mostrarModal, setMostrarModal] = useState(false);
|
||||
const [modalMensaje, setModalMensaje] = useState("");
|
||||
|
||||
// Estado para confirmación de eliminación
|
||||
const [confirmarEliminar, setConfirmarEliminar] = useState(false);
|
||||
const [cursoAEliminar, setCursoAEliminar] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
cargarCursos();
|
||||
}, []);
|
||||
|
@ -69,8 +73,13 @@ export default function CursosVista() {
|
|||
setMostrarModal(true);
|
||||
};
|
||||
|
||||
const eliminarCurso = async (id) => {
|
||||
const { error } = await supabaseClient.from("curso").delete().eq("id", id);
|
||||
const confirmarEliminacion = (id) => {
|
||||
setCursoAEliminar(id);
|
||||
setConfirmarEliminar(true);
|
||||
};
|
||||
|
||||
const eliminarCurso = async () => {
|
||||
const { error } = await supabaseClient.from("curso").delete().eq("id", cursoAEliminar);
|
||||
if (error) {
|
||||
console.error("Error eliminando curso:", error.message);
|
||||
setModalMensaje("Error al eliminar el curso");
|
||||
|
@ -78,6 +87,7 @@ export default function CursosVista() {
|
|||
setModalMensaje("Curso eliminado exitosamente");
|
||||
await cargarCursos();
|
||||
}
|
||||
setConfirmarEliminar(false);
|
||||
setMostrarModal(true);
|
||||
};
|
||||
|
||||
|
@ -149,7 +159,7 @@ export default function CursosVista() {
|
|||
</Button>
|
||||
<Button
|
||||
className="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-3 rounded"
|
||||
onClick={() => eliminarCurso(curso.id)}
|
||||
onClick={() => confirmarEliminacion(curso.id)}
|
||||
>
|
||||
Eliminar
|
||||
</Button>
|
||||
|
@ -161,7 +171,33 @@ export default function CursosVista() {
|
|||
</table>
|
||||
</div>
|
||||
|
||||
{/* Modal */}
|
||||
{/* Modal de confirmación */}
|
||||
<Dialog open={confirmarEliminar} onOpenChange={setConfirmarEliminar}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-black">Confirmar eliminación</DialogTitle>
|
||||
<DialogDescription>
|
||||
¿Estás seguro de que deseas eliminar este curso? Esta acción no se puede deshacer.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
className="bg-red-500 hover:bg-red-700 text-white"
|
||||
onClick={eliminarCurso}
|
||||
>
|
||||
Eliminar
|
||||
</Button>
|
||||
<Button
|
||||
className="bg-gray-400 hover:bg-gray-600 text-white"
|
||||
onClick={() => setConfirmarEliminar(false)}
|
||||
>
|
||||
Cancelar
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Modal de resultado */}
|
||||
<Dialog open={mostrarModal} onOpenChange={setMostrarModal}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
|
@ -177,4 +213,4 @@ export default function CursosVista() {
|
|||
</Dialog>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue