From ee808c35bf1882f416f09899a0bd2da842de7c15 Mon Sep 17 00:00:00 2001
From: Benito <zs22016070@estudiantes.uv.mx>
Date: Wed, 12 Mar 2025 19:56:23 -0600
Subject: [PATCH] Add react-tabs for improved report visualization and
 integrate Supabase for sales data fetching

---
 ventaboletos/package-lock.json                |  13 ++
 ventaboletos/package.json                     |   1 +
 .../src/components/vistas/Reporte.jsx         | 198 ++++++++++--------
 ventaboletos/src/pages/api/comprar-boletos.js |  43 ++--
 4 files changed, 154 insertions(+), 101 deletions(-)

diff --git a/ventaboletos/package-lock.json b/ventaboletos/package-lock.json
index f7e1d44..3fd4bb6 100644
--- a/ventaboletos/package-lock.json
+++ b/ventaboletos/package-lock.json
@@ -23,6 +23,7 @@
         "next": "15.1.7",
         "react": "^19.0.0",
         "react-dom": "^19.0.0",
+        "react-tabs": "^6.1.0",
         "recharts": "^2.15.1",
         "tailwind-merge": "^3.0.2",
         "tailwindcss-animate": "^1.0.7",
@@ -5400,6 +5401,18 @@
         }
       }
     },
+    "node_modules/react-tabs": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-6.1.0.tgz",
+      "integrity": "sha512-6QtbTRDKM+jA/MZTTefvigNxo0zz+gnBTVFw2CFVvq+f2BuH0nF0vDLNClL045nuTAdOoK/IL1vTP0ZLX0DAyQ==",
+      "dependencies": {
+        "clsx": "^2.0.0",
+        "prop-types": "^15.5.0"
+      },
+      "peerDependencies": {
+        "react": "^18.0.0 || ^19.0.0"
+      }
+    },
     "node_modules/react-transition-group": {
       "version": "4.4.5",
       "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
diff --git a/ventaboletos/package.json b/ventaboletos/package.json
index c943a37..3430c76 100644
--- a/ventaboletos/package.json
+++ b/ventaboletos/package.json
@@ -24,6 +24,7 @@
     "next": "15.1.7",
     "react": "^19.0.0",
     "react-dom": "^19.0.0",
+    "react-tabs": "^6.1.0",
     "recharts": "^2.15.1",
     "tailwind-merge": "^3.0.2",
     "tailwindcss-animate": "^1.0.7",
diff --git a/ventaboletos/src/components/vistas/Reporte.jsx b/ventaboletos/src/components/vistas/Reporte.jsx
index 7d2ccf3..9062889 100644
--- a/ventaboletos/src/components/vistas/Reporte.jsx
+++ b/ventaboletos/src/components/vistas/Reporte.jsx
@@ -1,106 +1,138 @@
-import React, { useState, useRef } from "react";
-import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { useState, useEffect } from "react";
+import { createClient } from "@supabase/supabase-js";
+import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
+import "react-tabs/style/react-tabs.css";
 import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer } from "recharts";
-import jsPDF from "jspdf";
 import html2canvas from "html2canvas";
+import jsPDF from "jspdf";
 
-const Reporte = () => {
-  const chartRef = useRef(null); // Referencia para capturar la gráfica
+const supabase = createClient(
+  process.env.NEXT_PUBLIC_SUPABASE_URL,
+  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
+);
 
-  // Datos simulados de ventas
-  const ventasDiarias = [
-    { fecha: "2025-03-01", boletos: 20 },
-    { fecha: "2025-03-02", boletos: 35 },
-    { fecha: "2025-03-03", boletos: 50 },
-  ];
+export default function Reporte() {
+  const [ventas, setVentas] = useState([]);
+  const [filtro, setFiltro] = useState("diario"); // Estado para el filtro de fecha (diario, semanal, mensual)
 
-  const ventasSemanales = [
-    { semana: "Semana 1", boletos: 120 },
-    { semana: "Semana 2", boletos: 150 },
-    { semana: "Semana 3", boletos: 170 },
-  ];
+  // Función para obtener los datos de ventas de Supabase
+  useEffect(() => {
+    const fetchVentas = async () => {
+      const { data, error } = await supabase.from("ventas").select("*");
+      if (error) {
+        console.error("Error al obtener las ventas:", error.message);
+      } else {
+        console.log("Datos obtenidos:", data);
+        setVentas(data);
+      }
+    };
 
-  const ventasMensuales = [
-    { mes: "Enero", boletos: 500 },
-    { mes: "Febrero", boletos: 650 },
-    { mes: "Marzo", boletos: 700 },
-  ];
+    fetchVentas();
+  }, []);
 
-  const [selectedTab, setSelectedTab] = useState("diario");
+  // Función para filtrar las ventas según el rango de fechas
+  const filtrarVentas = () => {
+    const hoy = new Date();
+    let fechaInicio;
 
-  // Obtener datos según la pestaña activa
-  const getData = () => {
-    switch (selectedTab) {
+    switch (filtro) {
       case "diario":
-        return ventasDiarias;
+        fechaInicio = new Date(hoy.setHours(0, 0, 0, 0)); // Inicio del día
+        return ventas.filter((venta) => {
+          const fechaVenta = new Date(venta.fecha_venta);
+          return fechaVenta >= fechaInicio;
+        });
       case "semanal":
-        return ventasSemanales;
+        const inicioSemana = hoy.getDate() - hoy.getDay(); // Día lunes de esta semana
+        fechaInicio = new Date(hoy.setDate(inicioSemana));
+        return ventas.filter((venta) => {
+          const fechaVenta = new Date(venta.fecha_venta);
+          return fechaVenta >= fechaInicio;
+        });
       case "mensual":
-        return ventasMensuales;
+        fechaInicio = new Date(hoy.getFullYear(), hoy.getMonth(), 1); // Primer día del mes
+        return ventas.filter((venta) => {
+          const fechaVenta = new Date(venta.fecha_venta);
+          return fechaVenta >= fechaInicio;
+        });
       default:
-        return [];
+        return ventas;
     }
   };
 
-  // Calcular el total de boletos vendidos
-  const totalBoletos = getData().reduce((acc, item) => acc + item.boletos, 0);
-
-  // Función para generar y descargar el PDF
+  // Función para generar el PDF
   const generarPDF = async () => {
-    const pdf = new jsPDF();
-    pdf.setFontSize(18);
-    pdf.text("Reporte de Ventas", 10, 10);
-    pdf.setFontSize(14);
-    pdf.text(`Tipo de Reporte: ${selectedTab.toUpperCase()}`, 10, 20);
-    pdf.text(`Total de Boletos Vendidos: ${totalBoletos}`, 10, 30);
-
-    // Capturar la gráfica como imagen
-    if (chartRef.current) {
-      const canvas = await html2canvas(chartRef.current);
-      const imgData = canvas.toDataURL("image/png");
-      pdf.addImage(imgData, "PNG", 10, 40, 180, 90);
-    }
-
-    pdf.save(`reporte_${selectedTab}.pdf`);
+    const input = document.getElementById("reporte");
+    const canvas = await html2canvas(input);
+    const imgData = canvas.toDataURL("image/png");
+    const pdf = new jsPDF("p", "mm", "a4");
+    pdf.addImage(imgData, "PNG", 10, 10, 190, 0);
+    pdf.save("Reporte_Ventas.pdf");
   };
 
+  // Datos filtrados según el filtro seleccionado
+  const ventasFiltradas = filtrarVentas();
+
   return (
-    <div className="w-full max-w-3xl mx-auto p-4">
-      <h2 className="text-2xl font-bold mb-4">Reporte de Ventas</h2>
-      <Tabs defaultValue="diario" onValueChange={setSelectedTab} className="w-full">
-        <TabsList className="flex space-x-2 mb-4">
-          <TabsTrigger value="diario">Diario</TabsTrigger>
-          <TabsTrigger value="semanal">Semanal</TabsTrigger>
-          <TabsTrigger value="mensual">Mensual</TabsTrigger>
-          <img
-            src="/pdf.svg"
-            alt="pdf"
-            className="h-7 w-7 cursor-pointer"
-            onClick={generarPDF}
-          />
-        </TabsList>
+    <div>
+      <h1>Reporte de Ventas</h1>
 
-        <Card>
-          <CardHeader>
-            <CardTitle>
-              Total de Boletos Vendidos: <span className="text-blue-600">{totalBoletos}</span>
-            </CardTitle>
-          </CardHeader>
-          <CardContent ref={chartRef}>
-            <ResponsiveContainer width="100%" height={300}>
-              <BarChart data={getData()}>
-                <XAxis dataKey={selectedTab === "diario" ? "fecha" : selectedTab === "semanal" ? "semana" : "mes"} />
-                <YAxis />
-                <Tooltip />
-                <Bar dataKey="boletos" fill="#3b82f6" />
-              </BarChart>
-            </ResponsiveContainer>
-          </CardContent>
-        </Card>
+      {/* Botón para generar PDF */}
+      <button onClick={generarPDF}>Descargar PDF</button>
+
+      {/* Filtros de fechas */}
+      <div>
+        <button onClick={() => setFiltro("diario")}>Diario</button>
+        <button onClick={() => setFiltro("semanal")}>Semanal</button>
+        <button onClick={() => setFiltro("mensual")}>Mensual</button>
+      </div>
+
+      <Tabs>
+        <TabList>
+          <Tab>Tabla</Tab>
+          <Tab>Gráfico de Ventas</Tab>
+        </TabList>
+
+        {/* Sección de Tabla */}
+        <TabPanel>
+          <div id="reporte">
+            <table border="1">
+              <thead>
+                <tr>
+                  <th>ID Venta</th>
+                  <th>ID Boleto</th>
+                  <th>ID Vendedor</th>
+                  <th>Fecha Venta</th>
+                  <th>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>
+                ))}
+              </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>
   );
-};
-
-export default Reporte;
+}
diff --git a/ventaboletos/src/pages/api/comprar-boletos.js b/ventaboletos/src/pages/api/comprar-boletos.js
index 93e484a..204f5a0 100644
--- a/ventaboletos/src/pages/api/comprar-boletos.js
+++ b/ventaboletos/src/pages/api/comprar-boletos.js
@@ -1,24 +1,31 @@
-import { supabaseClient } from "@/utils/supabase";
+import { createClient } from "@supabase/supabase-js";
+
+const supabase = createClient(
+  process.env.NEXT_PUBLIC_SUPABASE_URL,
+  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
+);
 
 export default async function handler(req, res) {
-  if (req.method === "POST") {
+  if (req.method !== "POST") {
+    return res.status(405).json({ error: "Método no permitido" });
+  }
+
+  try {
     const { boletos } = req.body;
 
-    try {
-      const { data, error } = await supabaseClient
-        .from("boletos_comprados")
-        .insert(boletos);
-
-      if (error) {
-        throw error;
-      }
-
-      res.status(200).json({ message: "Compra realizada con éxito", data });
-    } catch (error) {
-      console.error("Error al insertar boletos:", error);
-      res.status(500).json({ message: "Error al procesar la compra", error });
+    if (!boletos || boletos.length === 0) {
+      return res.status(400).json({ error: "No hay boletos para procesar" });
     }
-  } else {
-    res.status(405).json({ message: "Método no permitido" });
+
+    const { data, error } = await supabase.from("ventas").insert(boletos);
+
+    if (error) {
+      throw error;
+    }
+
+    res.status(200).json({ message: "Boletos comprados con éxito", data });
+  } catch (error) {
+    console.error("Error en la API de compra:", error.message);
+    res.status(500).json({ error: error.message });
   }
-}
\ No newline at end of file
+}