From 1f29e72ad2907e0c441fbf4ab135ef4076d416a7 Mon Sep 17 00:00:00 2001 From: Tyrannusss Date: Thu, 19 Mar 2026 18:33:56 -0600 Subject: [PATCH] se modifico el reporte de inscritos para poder buscar por rango ademas de agregar la columna del periodo y porder descargar un excel --- app/(private)/Inscritos/Inscripciones.tsx | 173 +++++++++++++++++----- app/(private)/Periodo-Graficas/page.tsx | 2 +- 2 files changed, 141 insertions(+), 34 deletions(-) diff --git a/app/(private)/Inscritos/Inscripciones.tsx b/app/(private)/Inscritos/Inscripciones.tsx index 7ef9c70..2c4093c 100644 --- a/app/(private)/Inscritos/Inscripciones.tsx +++ b/app/(private)/Inscritos/Inscripciones.tsx @@ -4,7 +4,8 @@ import { useEffect, useState } from "react"; import axios from "axios"; import Cookies from "js-cookie"; import "./inscripciones.css"; - +import * as XLSX from "xlsx"; +import { saveAs } from "file-saver"; interface Periodo { id_periodo: number; @@ -12,18 +13,19 @@ interface Periodo { } interface ApiResponse { + semestre: string; carrera: string; - profesor: string; + profesor: string; femenino: string; masculino: string; total: string; } - type TipoConteo = "WINDOWS" | "MACINTOSH" | "LINUX" | "PROFESORES"; interface TablaRow { carrera: string; + semestre: string; WINDOWS: number; MACINTOSH: number; LINUX: number; @@ -35,13 +37,13 @@ interface TablaRow { export default function Inscripciones() { const [periodo, setPeriodo] = useState([]); - const [selectedPeriodo, setSelectedPeriodo] = useState(null); + const [periodoInicio, setPeriodoInicio] = useState(null); + const [periodoFin, setPeriodoFin] = useState(null); const [tablaData, setTablaData] = useState([]); - + const [rawData, setRawData] = useState([]); const token = Cookies.get("token"); const headers = { Authorization: `Bearer ${token}` }; - useEffect(() => { const getPeriodo = async () => { const response = await axios.get(`${envConfig.apiUrl}/periodo`, { headers }); @@ -50,29 +52,41 @@ export default function Inscripciones() { getPeriodo(); }, []); - - const handleBuscar = async (e: React.FormEvent) => { - e.preventDefault(); + const handleBuscar = async (e: React.FormEvent) => { + e.preventDefault(); - if (!selectedPeriodo) return; + if (!periodoInicio || !periodoFin) { + alert("Selecciona ambos periodos"); + return; + } - const response = await axios.get( - `${envConfig.apiUrl}/alumno-inscrito/inscritos/${selectedPeriodo}`, - { headers } - ); + if (periodoInicio > periodoFin) { + alert("El periodo inicio no puede ser mayor al final"); + return; + } + + const esMismoPeriodo = periodoInicio === periodoFin; + + try { + const url = esMismoPeriodo + ? `${envConfig.apiUrl}/alumno-inscrito/inscritos/${periodoInicio}` // 👈 uno solo + : `${envConfig.apiUrl}/alumno-inscrito/inscritos/${periodoInicio}/${periodoFin}`; // 👈 rango + + const response = await axios.get(url, { headers }); const data: ApiResponse[] = response.data; + setRawData(data); const agrupado: Record = {}; data.forEach((item) => { - const carrera = item.carrera; + const key = `${item.carrera}-${item.semestre}`; - - if (!agrupado[carrera]) { - agrupado[carrera] = { - carrera: carrera, + if (!agrupado[key]) { + agrupado[key] = { + carrera: item.carrera, + semestre: item.semestre, WINDOWS: 0, MACINTOSH: 0, LINUX: 0, @@ -83,20 +97,98 @@ export default function Inscripciones() { }; } - const fila = agrupado[carrera]; - const tipoProfesor = item.profesor as TipoConteo; - const totalPlataforma = Number(item.total); + const fila = agrupado[key]; + const tipoProfesor = item.profesor as TipoConteo; + + const total = Number(item.total); const fem = Number(item.femenino); const masc = Number(item.masculino); - - fila[tipoProfesor] += totalPlataforma; - fila.TOTAL += totalPlataforma; + fila[tipoProfesor] += total; + fila.TOTAL += total; fila.femenino += fem; fila.masculino += masc; }); setTablaData(Object.values(agrupado)); + } catch (error) { + console.error("Error al obtener inscritos", error); + } +}; + + // Export Excel + const exportarExcel = () => { + if (!rawData.length) return; + + const periodosUnicos = Array.from( + new Set(rawData.map((t) => t.semestre)) + ).sort((a, b) => a.localeCompare(b, undefined, { numeric: true })); + + const carrerasUnicas = Array.from( + new Set(rawData.map((t) => t.carrera)) + ); + + const dataExcel = carrerasUnicas.map((carrera) => { + const fila: any = { Carrera: carrera }; + + let totalFila = 0; + let totalFemenino = 0; + let totalMasculino = 0; + + periodosUnicos.forEach((periodo) => { + const items = rawData.filter( + (t) => t.carrera === carrera && t.semestre === periodo + ); + + const totalPeriodo = items.reduce( + (acc, item) => acc + Number(item.total), + 0 + ); + + fila[periodo] = totalPeriodo; + totalFila += totalPeriodo; + + totalFemenino += items.reduce( + (acc, item) => acc + Number(item.femenino), + 0 + ); + + totalMasculino += items.reduce( + (acc, item) => acc + Number(item.masculino), + 0 + ); + }); + + fila["Femenino"] = totalFemenino; + fila["Masculino"] = totalMasculino; + fila["Total"] = totalFila; + + return fila; + }); + + const worksheet = XLSX.utils.json_to_sheet(dataExcel); + + worksheet["!cols"] = [ + { wch: 25 }, + ...periodosUnicos.map(() => ({ wch: 15 })), + { wch: 15 }, + { wch: 15 }, + { wch: 15 }, + ]; + + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, "Inscritos"); + + const excelBuffer = XLSX.write(workbook, { + bookType: "xlsx", + type: "array", + }); + + const blob = new Blob([excelBuffer], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + + saveAs(blob, "reporte_inscritos.xlsx"); }; return ( @@ -104,15 +196,20 @@ export default function Inscripciones() {

INSCRITOS

- + +
- setPeriodoInicio(Number(e.target.value))} defaultValue=""> + + {periodo.map((p) => ( + + ))} + + +