From 27498051eeb06fac2e99463a9dac82cc4b693d81 Mon Sep 17 00:00:00 2001 From: SirRobert-1 <rviverosgonzalez@gmail.com> Date: Thu, 13 Mar 2025 00:14:17 -0600 Subject: [PATCH] Refactor Reporte component to enhance data fetching and improve PDF generation; implement ShadcnTabs for date filtering --- .../src/components/vistas/Reporte.jsx | 107 ++++++++++-------- ventaboletos/src/pages/carrito.jsx | 58 +++++----- 2 files changed, 92 insertions(+), 73 deletions(-) diff --git a/ventaboletos/src/components/vistas/Reporte.jsx b/ventaboletos/src/components/vistas/Reporte.jsx index fde5bc7..a57510d 100644 --- a/ventaboletos/src/components/vistas/Reporte.jsx +++ b/ventaboletos/src/components/vistas/Reporte.jsx @@ -2,7 +2,7 @@ import { useState, useEffect } from "react"; import { supabaseClient } from "@/utils/supabase"; import { Tab, Tabs, TabList, TabPanel } from "react-tabs"; import "react-tabs/style/react-tabs.css"; -import dynamic from "next/dynamic"; +import { Tabs as ShadcnTabs, TabsList, TabsTrigger } from "@/components/ui/tabs" import { BarChart, Bar, @@ -13,10 +13,6 @@ import { } from "recharts"; import { Button } from "@/components/ui/button"; -const html2canvas = dynamic(() => import("html2canvas"), { - ssr: false, -}); - export default function Reporte() { const [ventas, setVentas] = useState([]); const [filtro, setFiltro] = useState("diario"); // Estado para el filtro de fecha (diario, semanal, mensual) @@ -24,7 +20,27 @@ export default function Reporte() { // Función para obtener los datos de ventas de Supabase useEffect(() => { const fetchVentas = async () => { - const { data, error } = await supabaseClient.from("ventas").select("*"); + const { data, error } = await supabaseClient.from("ventas").select(` + venta_id, + fecha_venta, + monto, + boletos ( + boleto_id, + comprador_nombre, + comprador_email, + conciertos ( + nombre, + fecha, + salas ( + nombre + ) + ), + asientos ( + numero, + categoria + ) + ) + `); if (error) { console.error("Error al obtener las ventas:", error.message); } else { @@ -69,17 +85,24 @@ export default function Reporte() { // Función para generar el PDF const generarPDF = async () => { try { - const input = document.getElementById("reporte"); - const canvas = await html2canvas(input); - const imgData = canvas.toDataURL("image/png"); + // Dynamic imports for both libraries + const html2canvas = (await import('html2canvas')).default; + const jsPDF = (await import('jspdf')).default; - // Dynamic import of jsPDF - const { default: jsPDF } = await import("jspdf"); - const pdf = new jsPDF("p", "mm", "a4"); - pdf.addImage(imgData, "PNG", 10, 10, 190, 0); + const element = document.getElementById("reporte"); + const canvas = await html2canvas(element); + const data = canvas.toDataURL('image/png'); + + const pdf = new jsPDF(); + const imgProperties = pdf.getImageProperties(data); + const pdfWidth = pdf.internal.pageSize.getWidth(); + const pdfHeight = (imgProperties.height * pdfWidth) / imgProperties.width; + + pdf.addImage(data, 'PNG', 0, 0, pdfWidth, pdfHeight); pdf.save("Reporte_Ventas.pdf"); } catch (error) { - console.error("Error generating PDF:", error); + console.error("Error al generar PDF:", error); + alert("Error al generar el PDF"); } }; @@ -96,60 +119,50 @@ export default function Reporte() { </Button> {/* Filtros de fechas */} - <div> - <button onClick={() => setFiltro("diario")}>Diario</button> - <button onClick={() => setFiltro("semanal")}>Semanal</button> - <button onClick={() => setFiltro("mensual")}>Mensual</button> - </div> + <ShadcnTabs + defaultValue="diario" + className="w-[400px] mb-4" + onValueChange={(value) => setFiltro(value)} + > + <TabsList className="grid w-full grid-cols-3"> + <TabsTrigger value="diario">Diario</TabsTrigger> + <TabsTrigger value="semanal">Semanal</TabsTrigger> + <TabsTrigger value="mensual">Mensual</TabsTrigger> + </TabsList> + </ShadcnTabs> <Tabs> <TabList> <Tab>Tabla</Tab> - <Tab>Gráfico de Ventas</Tab> </TabList> {/* Sección de Tabla */} <TabPanel> <div id="reporte"> - <table border="1"> + <table border="1" className="m-10"> <thead> <tr> - <th>ID Venta</th> - <th>ID Boleto</th> - <th>ID Vendedor</th> - <th>Fecha Venta</th> - <th>Monto</th> + <th className="pr-5">ID Venta</th> + <th className="pr-5">Fecha Venta</th> + <th className="pr-5">Asiento</th> + <th className="pr-5">Categoría</th> + <th className="pr-5">Monto</th> </tr> </thead> <tbody> {ventasFiltradas.map((venta) => ( <tr key={venta.venta_id}> - <td>{venta.venta_id}</td> - <td>{venta.boleto_id}</td> - <td>{venta.vendedor_id}</td> - <td>{new Date(venta.fecha_venta).toLocaleString()}</td> - <td>${venta.monto}</td> - </tr> + <td className="pr-5">{venta.venta_id}</td> + <td className="pr-5">{new Date(venta.fecha_venta).toLocaleString()}</td> + <td className="pr-5">{venta.boletos.asientos.numero}</td> + <td className="pr-5">{venta.boletos.asientos.categoria}</td> + <td className="pr-5">${venta.monto}</td> + </tr> ))} </tbody> </table> </div> </TabPanel> - - {/* Sección de Gráfico */} - <TabPanel> - <ResponsiveContainer width="100%" height={300}> - <BarChart - data={ventasFiltradas} - margin={{ top: 20, right: 30, left: 20, bottom: 5 }} - > - <XAxis dataKey="venta_id" /> - <YAxis /> - <Tooltip /> - <Bar dataKey="monto" fill="#8884d8" /> - </BarChart> - </ResponsiveContainer> - </TabPanel> </Tabs> </div> ); diff --git a/ventaboletos/src/pages/carrito.jsx b/ventaboletos/src/pages/carrito.jsx index 319e560..5a47544 100644 --- a/ventaboletos/src/pages/carrito.jsx +++ b/ventaboletos/src/pages/carrito.jsx @@ -52,37 +52,43 @@ export default function Carrito() { } try { - // Create sales records for each item in cart - const ventasData = carrito.map((item) => ({ - concierto_id: item.id, - asiento_numero: parseInt(item.asiento), - precio: item.precio, - metodo_pago: selectedPaymentMethod, - fecha_venta: new Date().toISOString(), - estado: "completado", - })); + // Create sales and ticket records for each item in cart + for (const item of carrito) { + // First create the ticket record + const { data: boletoData, error: boletoError } = await supabaseClient + .from("boletos") + .insert({ + concierto_id: item.id, + categoria: "General", // You might want to make this dynamic + comprador_nombre: "Usuario", // Add form fields for this + comprador_email: "usuario@example.com", // Add form fields for this + asiento_id: item.asiento, + estado: "disponible", + }) + .select() + .single(); - const { data, error } = await supabaseClient - .from("ventas") - .insert(ventasData) - .select(); + if (boletoError) throw boletoError; - if (error) { - throw error; - } + // Then create the sale record + const { data: ventaData, error: ventaError } = await supabaseClient + .from("ventas") + .insert({ + boleto_id: boletoData.boleto_id, + fecha_venta: new Date().toISOString(), + monto: item.precio, + }) + .select(); - // Update asientos estado to 'ocupado' - const asientosUpdates = carrito.map((item) => ({ - numero: parseInt(item.asiento), - estado: "ocupado", - })); + if (ventaError) throw ventaError; - const { error: asientosError } = await supabaseClient - .from("asientos") - .upsert(asientosUpdates, { onConflict: "numero" }); + // Update asiento status + const { error: asientoError } = await supabaseClient + .from("asientos") + .update({ estado: "ocupado" }) + .eq("numero", item.asiento); - if (asientosError) { - throw asientosError; + if (asientoError) throw asientoError; } alert("Pago realizado con éxito");