diff --git a/app/(private)/Inscritos/Inscripciones.tsx b/app/(private)/Inscritos/Inscripciones.tsx index 2c4093c..2b3fa12 100644 --- a/app/(private)/Inscritos/Inscripciones.tsx +++ b/app/(private)/Inscritos/Inscripciones.tsx @@ -10,6 +10,7 @@ import { saveAs } from "file-saver"; interface Periodo { id_periodo: number; semestre: string; + fecha_inicio_servicio: string; } interface ApiResponse { @@ -21,6 +22,8 @@ interface ApiResponse { total: string; } +type Tipo = "periodo" | "mes" | "anio"; + type TipoConteo = "WINDOWS" | "MACINTOSH" | "LINUX" | "PROFESORES"; interface TablaRow { @@ -37,13 +40,20 @@ interface TablaRow { export default function Inscripciones() { const [periodo, setPeriodo] = useState([]); - const [periodoInicio, setPeriodoInicio] = useState(null); - const [periodoFin, setPeriodoFin] = useState(null); + const [tipo, setTipo] = useState("periodo"); + + const [periodoInicio, setPeriodoInicio] = useState(null); + const [periodoFin, setPeriodoFin] = useState(null); + + const [anio, setAnio] = useState(null); + const [tablaData, setTablaData] = useState([]); - const [rawData, setRawData] = useState([]); + const [rawData, setRawData] = useState([]); + const token = Cookies.get("token"); const headers = { Authorization: `Bearer ${token}` }; + // Obtener periodos useEffect(() => { const getPeriodo = async () => { const response = await axios.get(`${envConfig.apiUrl}/periodo`, { headers }); @@ -52,77 +62,101 @@ export default function Inscripciones() { getPeriodo(); }, []); - const handleBuscar = async (e: React.FormEvent) => { - e.preventDefault(); + // Obtener años desde fechas + const aniosDisponibles = Array.from( + new Set( + periodo.map((p) => + new Date(p.fecha_inicio_servicio).getFullYear() + ) + ) + ).sort(); - if (!periodoInicio || !periodoFin) { - alert("Selecciona ambos periodos"); - return; - } + // ============================ + // 🔍 BUSCAR + // ============================ + const handleBuscar = async (e: React.FormEvent) => { + e.preventDefault(); - if (periodoInicio > periodoFin) { - alert("El periodo inicio no puede ser mayor al final"); - return; - } + let url = ""; - 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 key = `${item.carrera}-${item.semestre}`; - - if (!agrupado[key]) { - agrupado[key] = { - carrera: item.carrera, - semestre: item.semestre, - WINDOWS: 0, - MACINTOSH: 0, - LINUX: 0, - PROFESORES: 0, - TOTAL: 0, - femenino: 0, - masculino: 0, - }; + if (tipo === "periodo") { + if (!periodoInicio || !periodoFin) { + alert("Selecciona ambos periodos"); + return; } - const fila = agrupado[key]; - const tipoProfesor = item.profesor as TipoConteo; + url = `${envConfig.apiUrl}/alumno-inscrito/inscritos/periodo/${periodoInicio}/${periodoFin}`; + } - const total = Number(item.total); - const fem = Number(item.femenino); - const masc = Number(item.masculino); + if (tipo === "anio") { + if (!periodoInicio || !periodoFin) { + alert("Selecciona ambos años"); + return; + } - fila[tipoProfesor] += total; - fila.TOTAL += total; - fila.femenino += fem; - fila.masculino += masc; - }); + url = `${envConfig.apiUrl}/alumno-inscrito/inscritos/anio/${periodoInicio}/${periodoFin}`; + } - setTablaData(Object.values(agrupado)); - } catch (error) { - console.error("Error al obtener inscritos", error); +if (tipo === "mes") { + if (!anio) { + alert("Selecciona un año"); + return; } -}; - // Export Excel + url = `${envConfig.apiUrl}/alumno-inscrito/inscritos/mes/${anio}`; +} + try { + console.log("URL:", url); + + const response = await axios.get(url, { headers }); + const data: ApiResponse[] = response.data; + + setRawData(data); + + const agrupado: Record = {}; + + data.forEach((item) => { + const key = `${item.carrera}-${item.semestre}`; + + if (!agrupado[key]) { + agrupado[key] = { + carrera: item.carrera, + semestre: item.semestre, + WINDOWS: 0, + MACINTOSH: 0, + LINUX: 0, + PROFESORES: 0, + TOTAL: 0, + femenino: 0, + masculino: 0, + }; + } + + 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] += total; + fila.TOTAL += total; + fila.femenino += fem; + fila.masculino += masc; + }); + + setTablaData(Object.values(agrupado)); + } catch (error) { + console.error("Error al obtener inscritos", error); + } + }; + 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)) @@ -132,8 +166,6 @@ export default function Inscripciones() { const fila: any = { Carrera: carrera }; let totalFila = 0; - let totalFemenino = 0; - let totalMasculino = 0; periodosUnicos.forEach((periodo) => { const items = rawData.filter( @@ -147,36 +179,16 @@ export default function Inscripciones() { 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, { @@ -196,41 +208,87 @@ export default function Inscripciones() {

INSCRITOS

- + + + {/* Selector tipo */} +
- + {/* PERIODO */} + {tipo === "periodo" && ( + <> + - + + + )} + + {/* AÑO */} + {tipo === "anio" && ( + <> + + + + + )} + + {/* MES */} +{tipo === "mes" && ( + <> + + +)} -
+ {/* TABLA */}
@@ -250,7 +308,7 @@ export default function Inscripciones() { {tablaData.map((row, index) => ( - + diff --git a/package-lock.json b/package-lock.json index 8b66014..581806f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -696,6 +696,7 @@ "version": "2.5.6", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -735,6 +736,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -755,6 +757,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -775,6 +778,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -795,6 +799,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -815,6 +820,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -835,6 +841,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -855,6 +862,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -875,6 +883,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -895,6 +904,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -915,6 +925,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -935,6 +946,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -955,6 +967,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -975,6 +988,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2635,6 +2649,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", "optional": true, "engines": { @@ -2677,6 +2692,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -3190,6 +3206,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, "license": "MIT", "optional": true }, @@ -3290,6 +3307,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, "license": "MIT", "optional": true, "engines": {
{row.carrera}{row.carrera} {row.semestre} {row.femenino} {row.masculino}