addded dowload

This commit is contained in:
2026-01-15 14:24:02 -06:00
parent adae53fb06
commit d9cf535de7
6 changed files with 173 additions and 46 deletions
+6
View File
@@ -67,3 +67,9 @@
.resetButton:hover {
background-color: #cc0000;
}
.download{
display: flex;
align-items: end;
justify-content: end;
}
+16 -11
View File
@@ -1,12 +1,17 @@
'use client';
"use client";
import { useState } from 'react';
import Toggle from '@/app/Components/Global/Toggle/Toggle';
import SearchDateBetween from '@/app/Components/SearchDateBetween/SearchDateBetween';
import PorServicios from '@/app/Components/Reportes/porServicio';
import PorRecibos from '@/app/Components/Reportes/porRecibo';
import { useState } from "react";
import Toggle from "@/app/Components/Global/Toggle/Toggle";
import SearchDateBetween from "@/app/Components/SearchDateBetween/SearchDateBetween";
import PorServicios from "@/app/Components/Reportes/porServicio";
import PorRecibos from "@/app/Components/Reportes/porRecibo";
import DownloadReporteXLSX from "@/app/Components/Dowload/Reporte";
export default function ReportesClient({ defaultKey }: { defaultKey?: string }) {
export default function ReportesClient({
defaultKey,
}: {
defaultKey?: string;
}) {
const [desde, setDesde] = useState<string | null>(null);
const [hasta, setHasta] = useState<string | null>(null);
@@ -18,8 +23,8 @@ export default function ReportesClient({ defaultKey }: { defaultKey?: string })
defaultView={defaultKey}
options={[
{
key: 'Por recibo',
label: 'Por recibo',
key: "Por recibo",
label: "Por recibo",
content: (
<>
<SearchDateBetween
@@ -33,8 +38,8 @@ export default function ReportesClient({ defaultKey }: { defaultKey?: string })
),
},
{
key: 'Por Servicio',
label: 'Por Servicio',
key: "Por Servicio",
label: "Por Servicio",
content: (
<>
<SearchDateBetween
+59
View File
@@ -0,0 +1,59 @@
"use client";
import styles from "./style.module.css";
import Cookies from "js-cookie";
import { useState } from "react";
import toast from "react-hot-toast";
export default function DownloadReporteXLSX() {
const [loading, setLoading] = useState(false);
const handleDownload = async () => {
setLoading(true);
const token = Cookies.get("token");
const headers = { Authorization: `Bearer ${token}` };
try {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/equipos/reporteXLSX`,//Modificar
{ headers }
);
if (!response.ok) {
toast.error("Error al descargar el archivo");
return;
}
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "Reporte Recibos.xlsx";
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
} catch (error) {
console.error(error);
toast.error("Hubo un problema al descargar el archivo.");
} finally {
setLoading(false);
}
};
return (
<button
className={styles.downloadBtn}
onClick={handleDownload}
disabled={loading}
>
{loading ? (
<div className={styles.loader}></div>
) : (
<img src="/excel.svg" alt="Excel" className={styles.iconExcel} width={30} height={30}/>
)}
</button>
);
}
+46
View File
@@ -0,0 +1,46 @@
.downloadBtn {
position: absolute;
right: 15px;
top:-35px;
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
background: #ffffff;
border: 1px solid #ddd;
border-bottom: none;
padding: 5px 5px;
cursor: pointer;
border-radius: 10px 10px 0 0;
font-size: 14px;
font-weight: 600;
transition: background 0.2s ease;
min-width: 50px;
}
.downloadBtn:hover {
background: #95d2b0;
}
.downloadBtn:disabled {
background: #a5a5a5;
cursor: not-allowed;
}
.loader {
border: 3px solid #ffffff55;
border-top: 3px solid white;
border-radius: 50%;
width: 16px;
height: 16px;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
+45 -35
View File
@@ -1,7 +1,8 @@
'use client';
"use client";
import { useEffect, useState } from 'react';
import axios from 'axios';
import { useEffect, useState } from "react";
import axios from "axios";
import DownloadReporteXLSX from "../Dowload/Reporte";
interface Recibo {
id_recibo: number;
@@ -9,9 +10,9 @@ interface Recibo {
fecha_recibo: string;
fecha_registro: string;
monto: string;
user:{
nombre:string;
}
user: {
nombre: string;
};
}
interface Props {
@@ -36,7 +37,7 @@ function PorRecibos({ desde, hasta }: Props) {
setRecibos(res.data);
} catch (error) {
console.error('Error al obtener recibos', error);
console.error("Error al obtener recibos", error);
} finally {
setLoading(false);
}
@@ -46,38 +47,47 @@ function PorRecibos({ desde, hasta }: Props) {
}, [desde, hasta]);
return (
<div style={{overflow:"auto",height:"270px", scrollbarColor:"#2563eb white"}}>
{loading && <p>Cargando...</p>}
<div style={{ position: "relative" }}>
{recibos.length > 0 && <DownloadReporteXLSX />}
<div
style={{
overflow: "auto",
height: "270px",
scrollbarColor: "#2563eb white",
}}
>
{loading && <p>Cargando...</p>}
<table>
<thead>
<tr>
<th>Folio</th>
<th>Monto</th>
<th>fecha recibo</th>
<th>fecha registro</th>
<th>Usuario</th>
</tr>
</thead>
<tbody>
{!loading && recibos.length === 0 && (
<table>
<thead>
<tr>
<td colSpan={2}>No hay recibos en este rango</td>
<th>Folio</th>
<th>Monto</th>
<th>fecha recibo</th>
<th>fecha registro</th>
<th>Usuario</th>
</tr>
)}
</thead>
{recibos.map((recibo) => (
<tr key={recibo.id_recibo}>
<td>{recibo.folio_recibo}</td>
<td>${Number(recibo.monto).toFixed(2)}</td>
<td>{recibo.fecha_recibo}</td>
<td>{recibo.fecha_registro}</td>
<td>{recibo.user.nombre}</td>
</tr>
))}
</tbody>
</table>
<tbody>
{!loading && recibos.length === 0 && (
<tr>
<td colSpan={2}>No hay recibos en este rango</td>
</tr>
)}
{recibos.map((recibo) => (
<tr key={recibo.id_recibo}>
<td>{recibo.folio_recibo}</td>
<td>${Number(recibo.monto).toFixed(2)}</td>
<td>{recibo.fecha_recibo}</td>
<td>{recibo.fecha_registro}</td>
<td>{recibo.user.nombre}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><path fill="#169154" d="M29,6H15.744C14.781,6,14,6.781,14,7.744v7.259h15V6z"/><path fill="#18482a" d="M14,33.054v7.202C14,41.219,14.781,42,15.743,42H29v-8.946H14z"/><path fill="#0c8045" d="M14 15.003H29V24.005000000000003H14z"/><path fill="#17472a" d="M14 24.005H29V33.055H14z"/><g><path fill="#29c27f" d="M42.256,6H29v9.003h15V7.744C44,6.781,43.219,6,42.256,6z"/><path fill="#27663f" d="M29,33.054V42h13.257C43.219,42,44,41.219,44,40.257v-7.202H29z"/><path fill="#19ac65" d="M29 15.003H44V24.005000000000003H29z"/><path fill="#129652" d="M29 24.005H44V33.055H29z"/></g><path fill="#0c7238" d="M22.319,34H5.681C4.753,34,4,33.247,4,32.319V15.681C4,14.753,4.753,14,5.681,14h16.638 C23.247,14,24,14.753,24,15.681v16.638C24,33.247,23.247,34,22.319,34z"/><path fill="#fff" d="M9.807 19L12.193 19 14.129 22.754 16.175 19 18.404 19 15.333 24 18.474 29 16.123 29 14.013 25.07 11.912 29 9.526 29 12.719 23.982z"/></svg>

After

Width:  |  Height:  |  Size: 998 B