feat: implement diploma creation and preview dialogs, enhancing diploma management for students
This commit is contained in:
parent
6a4a44bdbc
commit
8c85ec396d
|
@ -0,0 +1,98 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { supabaseClient } from "@/utils/supabase";
|
||||
|
||||
// Puedes reemplazar esto por tus propios diseños
|
||||
const DISEÑOS = [
|
||||
{ id: 1, nombre: "Diseño Clásico" },
|
||||
{ id: 2, nombre: "Diseño Moderno" },
|
||||
];
|
||||
|
||||
export default function CrearDiplomaDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
alumno,
|
||||
competencias,
|
||||
setCompetencias,
|
||||
competenciasAcreditadas,
|
||||
setCompetenciasAcreditadas,
|
||||
fecha,
|
||||
setFecha,
|
||||
}) {
|
||||
const [diseñoSeleccionado, setDiseñoSeleccionado] = useState(DISEÑOS[0]?.id || null);
|
||||
|
||||
const toggleCompetencia = (id) => {
|
||||
setCompetenciasAcreditadas((prev) =>
|
||||
prev.includes(id)
|
||||
? prev.filter((cid) => cid !== id)
|
||||
: [...prev, id]
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (alumno && alumno.curso?.id) {
|
||||
supabaseClient
|
||||
.from("curso_competencia")
|
||||
.select("competencia(id, descripcion)")
|
||||
.eq("curso_id", alumno.curso.id)
|
||||
.then(({ data }) => {
|
||||
const comps = data?.map((c) => c.competencia) || [];
|
||||
setCompetencias(comps);
|
||||
setCompetenciasAcreditadas(comps.map((c) => c.id)); // todas seleccionadas por default
|
||||
});
|
||||
}
|
||||
}, [alumno]);
|
||||
|
||||
const handleCrearDiploma = async () => {
|
||||
// Aquí va la lógica para crear el diploma en la base de datos
|
||||
// 1. Insertar en Diploma
|
||||
// 2. Insertar en Diploma_Competencia
|
||||
// 3. (Opcional) Generar PDF y enviar
|
||||
|
||||
// Ejemplo de inserción (ajusta según tu lógica real)
|
||||
// await supabaseClient.from("Diploma").insert({...});
|
||||
// await supabaseClient.from("Diploma_Competencia").insert([...]);
|
||||
|
||||
onOpenChange(false);
|
||||
// Aquí puedes mostrar un mensaje de éxito o iniciar la generación del PDF
|
||||
};
|
||||
|
||||
if (!open || !alumno) return null;
|
||||
|
||||
return (
|
||||
<div className="bg-white border shadow-lg rounded p-8 w-[400px] mx-4 flex flex-col text-black">
|
||||
<h2 className="text-xl font-bold mb-4">Crear Diploma</h2>
|
||||
<div className="mb-2">
|
||||
<label className="block text-sm font-semibold mb-1">Competencias:</label>
|
||||
{competencias.map((comp) => (
|
||||
<div key={comp.id} className="flex items-center mb-1">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={competenciasAcreditadas.includes(comp.id)}
|
||||
onChange={() => toggleCompetencia(comp.id)}
|
||||
className="mr-2"
|
||||
/>
|
||||
<span>{comp.descripcion}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2 mt-4">
|
||||
<Button onClick={handleCrearDiploma} className="bg-green-500 hover:bg-green-700 text-white">
|
||||
Crear Diploma
|
||||
</Button>
|
||||
<Button onClick={() => onOpenChange(false)} className="bg-gray-400 hover:bg-gray-600 text-white">
|
||||
Cancelar
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,12 +1,106 @@
|
|||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Layout from "@/components/layout/Layout";
|
||||
import { supabaseClient } from "@/utils/supabase";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import CrearDiplomaDialog from "./crearDiplomaDialog"; // Importa tu dialog
|
||||
import VistaPreviaDiplomaDialog from "./vistaPreviaDiplomaDialog";
|
||||
|
||||
export default function DiplomasVista() {
|
||||
const [alumnos, setAlumnos] = useState([]);
|
||||
const [alumnoSeleccionado, setAlumnoSeleccionado] = useState(null);
|
||||
const [mostrarDialog, setMostrarDialog] = useState(false);
|
||||
|
||||
// Estado compartido para los datos del diploma
|
||||
const [competencias, setCompetencias] = useState([]);
|
||||
const [competenciasAcreditadas, setCompetenciasAcreditadas] = useState([]);
|
||||
const [fecha, setFecha] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const cargarAlumnos = async () => {
|
||||
const { data, error } = await supabaseClient
|
||||
.from("alumno")
|
||||
.select("id, nombre, correo, telefono, curso(id, nombre)")
|
||||
.order("id", { ascending: true });
|
||||
if (!error) setAlumnos(data);
|
||||
};
|
||||
cargarAlumnos();
|
||||
}, []);
|
||||
|
||||
// Limpiar datos al cerrar dialog
|
||||
const handleCloseDialog = (open) => {
|
||||
setMostrarDialog(open);
|
||||
if (!open) {
|
||||
setAlumnoSeleccionado(null);
|
||||
setCompetencias([]);
|
||||
setCompetenciasAcreditadas([]); // limpiar al cerrar
|
||||
setFecha("");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<div className="text-black">
|
||||
<h1>Vista de diplomas</h1>
|
||||
<div className="w-[80vw] pt-10 flex flex-col items-center text-black">
|
||||
<h1 className="text-2xl font-semibold mb-6">Vista de Diplomas</h1>
|
||||
<table className="min-w-full bg-white border">
|
||||
<thead>
|
||||
<tr className="bg-gray-100">
|
||||
<th className="py-2 border-b">ID</th>
|
||||
<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">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{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.curso?.nombre || "Sin curso"}</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>
|
||||
{/* Dialog para crear diploma */}
|
||||
{mostrarDialog && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||||
<div className="flex gap-8 bg-black bg-opacity-30 p-8 rounded">
|
||||
<CrearDiplomaDialog
|
||||
open={mostrarDialog}
|
||||
onOpenChange={handleCloseDialog}
|
||||
alumno={alumnoSeleccionado}
|
||||
competencias={competencias}
|
||||
setCompetencias={setCompetencias}
|
||||
competenciasAcreditadas={competenciasAcreditadas}
|
||||
setCompetenciasAcreditadas={setCompetenciasAcreditadas}
|
||||
fecha={fecha}
|
||||
setFecha={setFecha}
|
||||
/>
|
||||
<VistaPreviaDiplomaDialog
|
||||
open={mostrarDialog}
|
||||
alumno={alumnoSeleccionado}
|
||||
competencias={competencias}
|
||||
fecha={fecha}
|
||||
competenciasAcreditadas={competenciasAcreditadas}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import React from "react";
|
||||
|
||||
export default function VistaPreviaDiplomaDialog({ open, alumno, competencias, fecha, competenciasAcreditadas }) {
|
||||
if (!open || !alumno) return null;
|
||||
|
||||
// Filtra solo las competencias seleccionadas si se pasa el array de acreditadas
|
||||
const competenciasMostradas = competenciasAcreditadas
|
||||
? competencias.filter((comp) => competenciasAcreditadas.includes(comp.id))
|
||||
: competencias;
|
||||
|
||||
return (
|
||||
<div className="bg-white border shadow-lg rounded p-8 w-[500px] h-[350px] mx-4 flex flex-col text-black">
|
||||
<h2 className="text-2xl font-bold text-center mb-6">Diploma</h2>
|
||||
<div className="text-lg mb-2"><b>Alumno:</b> {alumno.nombre}</div>
|
||||
<div className="text-lg mb-2"><b>Curso:</b> {alumno.curso?.nombre || "Sin curso"}</div>
|
||||
<div className="text-lg mb-2">
|
||||
<b>Competencias Acreditadas:</b>
|
||||
<ul className="list-disc ml-6">
|
||||
{competenciasMostradas.map((comp) => (
|
||||
<li key={comp.id}>{comp.descripcion}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="text-lg mb-2">
|
||||
<b>Fecha:</b> {fecha || new Date().toLocaleDateString()}
|
||||
</div>
|
||||
<div className="mt-auto text-gray-400 text-xs text-right">Vista previa</div>
|
||||
</div>
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue