Files

336 lines
9.9 KiB
TypeScript

"use client";
import { envConfig } from "@/app/lib/config";
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;
semestre: string;
fecha_inicio_servicio: string;
}
interface ApiResponse {
semestre: string;
carrera: string;
profesor: string;
femenino: string;
masculino: string;
total: string;
}
type Tipo = "periodo" | "mes" | "anio";
type TipoConteo = "WINDOWS" | "MACINTOSH" | "LINUX" | "PROFESORES";
interface TablaRow {
carrera: string;
semestre: string;
WINDOWS: number;
MACINTOSH: number;
LINUX: number;
PROFESORES: number;
TOTAL: number;
femenino: number;
masculino: number;
}
export default function Inscripciones() {
const [periodo, setPeriodo] = useState<Periodo[]>([]);
const [tipo, setTipo] = useState<Tipo>("periodo");
const [periodoInicio, setPeriodoInicio] = useState<any>(null);
const [periodoFin, setPeriodoFin] = useState<any>(null);
const [anio, setAnio] = useState<number | null>(null);
const [tablaData, setTablaData] = useState<TablaRow[]>([]);
const [periodosUnicos, setPeriodosUnicos] = useState<string[]>([]);
const [tablaResumen, setTablaResumen] = useState<any[]>([]);
const [rawData, setRawData] = useState<ApiResponse[]>([]);
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 });
setPeriodo(response.data);
};
getPeriodo();
}, []);
// Obtener años desde fechas
const aniosDisponibles = Array.from(
new Set(
periodo.map((p) =>
new Date(p.fecha_inicio_servicio).getFullYear()
)
)
).sort();
// ============================
// 🔍 BUSCAR
// ============================
const handleBuscar = async (e: React.FormEvent) => {
e.preventDefault();
let url = "";
if (tipo === "periodo") {
if (!periodoInicio || !periodoFin) {
alert("Selecciona ambos periodos");
return;
}
url = `${envConfig.apiUrl}/alumno-inscrito/inscritos/periodo/${periodoInicio}/${periodoFin}`;
}
if (tipo === "anio") {
if (!periodoInicio || !periodoFin) {
alert("Selecciona ambos años");
return;
}
url = `${envConfig.apiUrl}/alumno-inscrito/inscritos/anio/${periodoInicio}/${periodoFin}`;
}
try {
console.log("URL:", url);
const response = await axios.get(url, { headers });
const data: ApiResponse[] = response.data;
setRawData(data);
const agrupado: Record<string, TablaRow> = {};
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));
const periodosUnicosList = Array.from(new Set(data.map((t) => t.semestre)));
setPeriodosUnicos(periodosUnicosList);
const carrerasUnicas = Array.from(new Set(data.map((t) => t.carrera)));
const resumen = carrerasUnicas.map((carrera) => {
const fila: any = { Carrera: carrera };
let totalFila = 0;
periodosUnicosList.forEach((periodo) => {
const items = data.filter((t) => t.carrera === carrera && t.semestre === periodo);
const totalPeriodo = items.reduce((acc, item) => acc + Number(item.total), 0);
fila[periodo] = totalPeriodo;
totalFila += totalPeriodo;
});
fila["Total"] = totalFila;
return fila;
});
setTablaResumen(resumen);
} catch (error) {
console.error("Error al obtener inscritos", error);
}
};
const exportarExcel = () => {
if (!rawData.length || !tablaResumen.length) return;
// HOJA 1: Inscritos (resumen)
const worksheet1 = XLSX.utils.json_to_sheet(tablaResumen);
const carrerasUnicas = Array.from(new Set(rawData.map((t) => t.carrera)));
// HOJA 2: genero
const dataGenero = carrerasUnicas.map((carrera) => {
const fila: any = { Carrera: carrera };
periodosUnicos.forEach((periodo) => {
const items = rawData.filter((t) => t.carrera === carrera && t.semestre === periodo);
const masc = items.reduce((acc, item) => acc + Number(item.masculino), 0);
const fem = items.reduce((acc, item) => acc + Number(item.femenino), 0);
fila[`Masculino - ${periodo}`] = masc;
fila[`Femenino - ${periodo}`] = fem;
});
return fila;
});
const worksheet2 = XLSX.utils.json_to_sheet(dataGenero);
// HOJA 3: areas
const dataAreas = carrerasUnicas.map((carrera) => {
const fila: any = { Carrera: carrera };
periodosUnicos.forEach((periodo) => {
const items = rawData.filter((t) => t.carrera === carrera && t.semestre === periodo);
let windows = 0, mac = 0, linux = 0, profes = 0;
items.forEach((item) => {
if (item.profesor === "WINDOWS") windows += Number(item.total);
if (item.profesor === "MACINTOSH") mac += Number(item.total);
if (item.profesor === "LINUX") linux += Number(item.total);
if (item.profesor === "PROFESORES") profes += Number(item.total);
});
fila[`WINDOWS - ${periodo}`] = windows;
fila[`MACINTOSH - ${periodo}`] = mac;
fila[`LINUX - ${periodo}`] = linux;
fila[`PROFESORES - ${periodo}`] = profes;
});
return fila;
});
const worksheet3 = XLSX.utils.json_to_sheet(dataAreas);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet1, "Inscritos");
XLSX.utils.book_append_sheet(workbook, worksheet2, "genero");
XLSX.utils.book_append_sheet(workbook, worksheet3, "areas");
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 (
<section className="containerSection">
<h2 className="title">INSCRITOS</h2>
<form className="containerForm" onSubmit={handleBuscar}>
<label>Filtro</label>
{/* Selector tipo */}
<select value={tipo} onChange={(e) => setTipo(e.target.value as Tipo)}>
<option value="periodo">Periodo</option>
<option value="anio">Año</option>
</select>
<div className="groupInput">
{/* PERIODO */}
{tipo === "periodo" && (
<>
<select onChange={(e) => setPeriodoInicio(Number(e.target.value))}>
<option value="">Inicio</option>
{periodo.map((p) => (
<option key={p.id_periodo} value={p.id_periodo}>
{p.semestre}
</option>
))}
</select>
<select onChange={(e) => setPeriodoFin(Number(e.target.value))}>
<option value="">Fin</option>
{periodo.map((p) => (
<option key={p.id_periodo} value={p.id_periodo}>
{p.semestre}
</option>
))}
</select>
</>
)}
{/* AÑO */}
{tipo === "anio" && (
<>
<select onChange={(e) => setPeriodoInicio(Number(e.target.value))}>
<option value="">Año inicio</option>
{aniosDisponibles.map((a) => (
<option key={a} value={a}>
{a}
</option>
))}
</select>
<select onChange={(e) => setPeriodoFin(Number(e.target.value))}>
<option value="">Año fin</option>
{aniosDisponibles.map((a) => (
<option key={a} value={a}>
{a}
</option>
))}
</select>
</>
)}
<button className="button buttonSearch" type="submit">
Buscar
</button>
<button type="button" className="button buttonSearch" onClick={exportarExcel}>
Exportar Excel
</button>
</div>
</form>
{/* TABLA */}
<div className="containerTable">
<table>
<thead>
<tr>
<th>Carrera</th>
<th>Periodo</th>
<th>Femenino</th>
<th>Masculino</th>
<th>WINDOWS</th>
<th>MACINTOSH</th>
<th>LINUX</th>
<th>Profesores</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{tablaData.map((row, index) => (
<tr key={index}>
<td>{row.carrera}</td>
<td>{row.semestre}</td>
<td>{row.femenino}</td>
<td>{row.masculino}</td>
<td>{row.WINDOWS}</td>
<td>{row.MACINTOSH}</td>
<td>{row.LINUX}</td>
<td>{row.PROFESORES}</td>
<td>{row.TOTAL}</td>
</tr>
))}
</tbody>
</table>
</div>
</section>
);
}