feat: enhance diploma dialogs with improved state management and user feedback, including PDF generation and course competency handling
This commit is contained in:
parent
d2c7bddf18
commit
bb02cf3830
|
@ -27,13 +27,13 @@ export default function CrearDiplomaDialog({
|
|||
fecha,
|
||||
setFecha,
|
||||
}) {
|
||||
const [diseñoSeleccionado, setDiseñoSeleccionado] = useState(DISEÑOS[0]?.id || null);
|
||||
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]
|
||||
prev.includes(id) ? prev.filter((cid) => cid !== id) : [...prev, id]
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -68,7 +68,9 @@ export default function CrearDiplomaDialog({
|
|||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="mb-2">
|
||||
<label className="block text-sm font-semibold mb-1">Competencias:</label>
|
||||
<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
|
||||
|
@ -87,14 +89,20 @@ export default function CrearDiplomaDialog({
|
|||
type="date"
|
||||
className="border p-1 w-full"
|
||||
value={fecha}
|
||||
onChange={e => setFecha(e.target.value)}
|
||||
onChange={(e) => setFecha(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button onClick={handleCrearDiploma} className="bg-green-500 hover:bg-green-700 text-white">
|
||||
<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">
|
||||
<Button
|
||||
onClick={() => onOpenChange(false)}
|
||||
className="bg-gray-400 hover:bg-gray-600 text-white"
|
||||
>
|
||||
Cancelar
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
|
@ -6,57 +6,164 @@ import {
|
|||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import Diploma from "@/components/Diploma";
|
||||
import { PDFDownloadLink, PDFViewer } from "@react-pdf/renderer";
|
||||
import { Button } from "../ui/button";
|
||||
import { PDFDownloadLink, PDFViewer, pdf } from "@react-pdf/renderer";
|
||||
import { supabaseClient } from "@/utils/supabase";
|
||||
|
||||
function VistaPreviaDiplomaDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
alumno,
|
||||
competencias,
|
||||
competencias: competenciasProp,
|
||||
fecha,
|
||||
competenciasAcreditadas,
|
||||
}) {
|
||||
const [mostrarVistaPrevia, setMostrarVistaPrevia] = useState(false);
|
||||
const [enviando, setEnviando] = useState(false);
|
||||
const [mensaje, setMensaje] = useState("");
|
||||
const [competencias, setCompetencias] = useState([]);
|
||||
|
||||
if (!open || !alumno) return null;
|
||||
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).filter(Boolean) || [];
|
||||
setCompetencias(comps);
|
||||
});
|
||||
}
|
||||
}, [alumno]);
|
||||
|
||||
// Filtra solo las competencias seleccionadas si se pasa el array de acreditadas
|
||||
const competenciasMostradas = Array.isArray(competenciasAcreditadas)
|
||||
? (Array.isArray(competencias) ? competencias : []).filter((comp) =>
|
||||
competenciasAcreditadas.includes(comp.id)
|
||||
)
|
||||
: (Array.isArray(competencias) ? competencias : []);
|
||||
if (!alumno) return null;
|
||||
|
||||
const competenciasParaPDF =
|
||||
Array.isArray(competenciasMostradas) && competenciasMostradas.length > 0
|
||||
? competenciasMostradas
|
||||
: [];
|
||||
const competenciasMostradas = competenciasAcreditadas
|
||||
? competencias.filter((comp) => competenciasAcreditadas.includes(comp.id))
|
||||
: competencias;
|
||||
|
||||
// Simulación de envío de PDF por correo y WhatsApp
|
||||
const handleEnviar = async () => {
|
||||
setEnviando(true);
|
||||
setMensaje("");
|
||||
// Simula la generación del PDF
|
||||
const blob = await pdf(
|
||||
<Diploma
|
||||
alumno={alumno}
|
||||
curso={alumno.curso}
|
||||
competencias={competenciasMostradas}
|
||||
fecha={fecha || new Date().toLocaleDateString()}
|
||||
/>
|
||||
).toBlob();
|
||||
|
||||
// Simula el envío por correo (espera 2 segundos)
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
|
||||
// Enviar mensaje real por WhatsApp usando la API de WhatsApp (abrirá una nueva ventana)
|
||||
const telefono = alumno.telefono.replace(/\D/g, ""); // Solo números
|
||||
const mensajeWhatsapp = encodeURIComponent(
|
||||
`Hola ${alumno.nombre}, tu diploma ha sido generado y enviado a tu correo (${alumno.correo}). ¡Felicidades!`
|
||||
);
|
||||
window.open(`https://wa.me/${telefono}?text=${mensajeWhatsapp}`, "_blank");
|
||||
|
||||
setMensaje(
|
||||
`Diploma enviado por correo a ${alumno.correo} y mensaje enviado por WhatsApp al ${alumno.telefono}.`
|
||||
);
|
||||
setEnviando(false);
|
||||
};
|
||||
|
||||
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>
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-lg text-black">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Diploma</DialogTitle>
|
||||
</DialogHeader>
|
||||
<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 className="mt-4 flex gap-2 justify-center flex-wrap">
|
||||
<PDFDownloadLink
|
||||
document={
|
||||
<Diploma
|
||||
alumno={alumno}
|
||||
curso={alumno.curso}
|
||||
competencias={competenciasMostradas}
|
||||
fecha={fecha || new Date().toLocaleDateString()}
|
||||
/>
|
||||
}
|
||||
fileName={`Diploma_${alumno.nombre}.pdf`}
|
||||
>
|
||||
{({ loading }) =>
|
||||
loading ? (
|
||||
<button className="bg-gray-300 px-4 py-2 rounded" disabled>
|
||||
Generando PDF...
|
||||
</button>
|
||||
) : (
|
||||
<button className="bg-green-500 hover:bg-green-700 text-white px-4 py-2 rounded">
|
||||
Descargar PDF
|
||||
</button>
|
||||
)
|
||||
}
|
||||
</PDFDownloadLink>
|
||||
<button
|
||||
className="bg-blue-500 hover:bg-blue-700 text-white px-4 py-2 rounded"
|
||||
onClick={() => setMostrarVistaPrevia(true)}
|
||||
>
|
||||
Ver vista previa PDF
|
||||
</button>
|
||||
<button
|
||||
className="bg-purple-600 hover:bg-purple-800 text-white px-4 py-2 rounded"
|
||||
onClick={handleEnviar}
|
||||
disabled={enviando}
|
||||
>
|
||||
{enviando ? "Enviando..." : "Enviar por correo y WhatsApp"}
|
||||
</button>
|
||||
</div>
|
||||
{mensaje && (
|
||||
<div className="mt-4 text-green-700 font-semibold text-center">
|
||||
{mensaje}
|
||||
</div>
|
||||
)}
|
||||
{mostrarVistaPrevia && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-60 flex flex-col items-center justify-center z-50">
|
||||
<div className="bg-white rounded shadow-lg p-4 flex flex-col items-center">
|
||||
<div className="w-[80vw] h-[80vh] lg:h-[90vh] mb-4 border">
|
||||
<PDFViewer width="100%" height="100%">
|
||||
<Diploma
|
||||
alumno={alumno}
|
||||
curso={alumno.curso}
|
||||
competencias={competenciasMostradas}
|
||||
fecha={fecha || new Date().toLocaleDateString()}
|
||||
/>
|
||||
</PDFViewer>
|
||||
</div>
|
||||
<button
|
||||
className="bg-red-500 hover:bg-red-700 text-white px-4 py-2 rounded"
|
||||
onClick={() => setMostrarVistaPrevia(false)}
|
||||
>
|
||||
Cerrar vista previa
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,20 @@ export default function DiplomasVista() {
|
|||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (alumnoSeleccionado && alumnoSeleccionado.curso?.id) {
|
||||
supabaseClient
|
||||
.from("curso_competencia")
|
||||
.select("competencia(id, descripcion)")
|
||||
.eq("curso_id", alumnoSeleccionado.curso.id)
|
||||
.then(({ data }) => {
|
||||
const comps = data?.map((c) => c.competencia).filter(Boolean) || [];
|
||||
setCompetencias(comps);
|
||||
setCompetenciasAcreditadas(comps.map((c) => c.id)); // Opcional: selecciona todas por default
|
||||
});
|
||||
}
|
||||
}, [alumnoSeleccionado]);
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<div className="w-[80vw] pt-10 flex flex-col items-center text-black">
|
||||
|
@ -82,7 +96,7 @@ export default function DiplomasVista() {
|
|||
{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
|
||||
{/*<CrearDiplomaDialog
|
||||
open={mostrarDialog}
|
||||
onOpenChange={handleCloseDialog}
|
||||
alumno={alumnoSeleccionado}
|
||||
|
@ -92,9 +106,10 @@ export default function DiplomasVista() {
|
|||
setCompetenciasAcreditadas={setCompetenciasAcreditadas}
|
||||
fecha={fecha}
|
||||
setFecha={setFecha}
|
||||
/>
|
||||
/>*/}
|
||||
<VistaPreviaDiplomaDialog
|
||||
open={mostrarDialog}
|
||||
onOpenChange={handleCloseDialog}
|
||||
alumno={alumnoSeleccionado}
|
||||
competencias={competencias}
|
||||
fecha={fecha}
|
||||
|
|
Loading…
Reference in New Issue