se agrego la vista para el monto total por periodo y tipo de servicio

This commit is contained in:
2026-03-03 17:26:16 -06:00
parent 1de700902a
commit 6c80ecf3db
+150
View File
@@ -0,0 +1,150 @@
"use client";
import { useState, useEffect } from "react";
import { envConfig } from "@/app/lib/config";
import axios from "axios";
import Cookies from "js-cookie";
interface TotalServicioPeriodo {
nombre_servicio: string;
periodo: string;
monto_total: number;
}
interface Servicio {
id_servicio: number;
servicio: string;
}
interface Periodo {
id_periodo: number;
semestre: string;
}
export default function ReporteTotalesPage() {
const [totales, setTotales] = useState<TotalServicioPeriodo[]>([]);
const [servicios, setServicios] = useState<Servicio[]>([]);
const [periodos, setPeriodos] = useState<Periodo[]>([]);
const [cargando, setCargando] = useState(true);
// Estados para los filtros
const [periodoInicio, setPeriodoInicio] = useState<string>("");
const [periodoFin, setPeriodoFin] = useState<string>("");
const [servicioId, setServicioId] = useState<string>("");
const token = Cookies.get("token");
const headers = { Authorization: `Bearer ${token}` };
// Obtener lista de servicios y periodos para los selects
useEffect(() => {
const fetchData = async () => {
try {
const [serviciosRes, periodosRes] = await Promise.all([
axios.get(`${envConfig.apiUrl}/servicio`, { headers }),
axios.get(`${envConfig.apiUrl}/periodo`, { headers }),
]);
setServicios(serviciosRes.data);
setPeriodos(periodosRes.data);
} catch (error) {
console.error("Error al cargar servicios o periodos", error);
}
};
fetchData();
}, []);
const obtenerTotales = async () => {
setCargando(true);
try {
// Construir query params
const params = new URLSearchParams();
if (periodoInicio) params.append("periodoInicio", periodoInicio);
if (periodoFin) params.append("periodoFin", periodoFin);
if (servicioId) params.append("servicioId", servicioId);
const url = `${envConfig.apiUrl}/detalle-servicio/totales-por-periodo?${params.toString()}`;
const res = await axios.get(url, { headers });
setTotales(res.data);
} catch (error) {
console.error("Error al obtener totales", error);
} finally {
setCargando(false);
}
};
// Llamar cuando cambien los filtros (podría ser con un botón o automático con debounce)
const aplicarFiltros = () => {
obtenerTotales();
};
return (
<div>
<h1 style={{ color: "rgb(3, 1, 72)" }}>REPORTE DE TOTALES POR SERVICIO Y PERIODO</h1>
{/* Filtros */}
<div style={{ marginBottom: "20px", display: "flex", gap: "10px", flexWrap: "wrap" }}>
<select
value={periodoInicio}
onChange={(e) => setPeriodoInicio(e.target.value)}
>
<option value="">Periodo inicio (todos)</option>
{periodos.map((p) => (
<option key={p.id_periodo} value={p.id_periodo}>
{p.semestre}
</option>
))}
</select>
<select
value={periodoFin}
onChange={(e) => setPeriodoFin(e.target.value)}
>
<option value="">Periodo fin (todos)</option>
{periodos.map((p) => (
<option key={p.id_periodo} value={p.id_periodo}>
{p.semestre}
</option>
))}
</select>
<select
value={servicioId}
onChange={(e) => setServicioId(e.target.value)}
>
<option value="">Todos los servicios</option>
{servicios.map((s) => (
<option key={s.id_servicio} value={s.id_servicio}>
{s.servicio}
</option>
))}
</select>
<button onClick={aplicarFiltros}>Filtrar</button>
</div>
{cargando ? (
<p>Cargando...</p>
) : (
<div style={{ overflow: "auto", maxHeight: "500px" }}>
<table>
<thead>
<tr>
<th>Servicio</th>
<th>Periodo</th>
<th>Monto Total</th>
</tr>
</thead>
<tbody>
{totales.map((item, index) => (
<tr key={index}>
<td>{item.nombre_servicio}</td>
<td>{item.periodo}</td>
<td>${item.monto_total.toFixed(2)}</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
);
}