"use client"; import { useState, useEffect } from "react"; import axios from "axios"; import Cookies from "js-cookie"; import styles from "./pregunta3.module.scss"; import ToggleButton from "../Toggle/ToggleButton"; import { PROCESADORES_POR_EQUIPO } from "@/data/procesadores"; /* ---------- types ---------- */ type ProcessorEntry = { tipo: string; alumnos: string; profesores: string; tecnicos: string; investigadores: string; administrativos: string; total: string; isTotal?: boolean; }; type PlatformKey = | "pc-desktop" | "apple-desktop" | "pc-laptop" | "apple-laptop" | "servers"; type PlatformData = Record; /* ---------- labels ---------- */ const PLATFORM_LABELS: Record = { "pc-desktop": "Computadoras de escritorio Plataforma PC", "apple-desktop": "Computadoras de escritorio Plataforma Apple", "pc-laptop": "Computadoras portátiles Plataforma PC", "apple-laptop": "Computadoras portátiles Plataforma Apple", servers: "Alto rendimiento Servidores", }; /* ---------- mapeo uso -> campo ---------- */ const USO_TO_FIELD: Record< string, keyof Omit > = { ALUMNO: "alumnos", PROFESOR: "profesores", "TÉCNICO ACADEMICO": "tecnicos", INVESTIGADOR: "investigadores", ADMINISTRATIVO: "administrativos", }; /* ---------- mapa platformKey -> PROCESADORES_POR_EQUIPO keys ---------- */ /* Este mapa indica qué conjuntos de procesadores corresponden a cada PlatformKey. Ajusta si quieres incluir/excluir grupos. */ const PLATFORM_PROCESSOR_GROUPS: Record = { "pc-desktop": [1, 3], // escritorio PC + escritorio Linux (ambos comparten procesadores) "apple-desktop": [2], "pc-laptop": [4, 5], "apple-laptop": [6], servers: [10], }; /* ---------- helpers ---------- */ function cleanName(str: string) { return ( String(str) .normalize?.("NFKD") .replace?.(/\u00A0/g, " ") .replace?.(/\s+/g, " ") .trim?.() ?? String(str) ); } /* Devuelve la lista "oficial" de procesadores (strings) para la plataforma */ function getOfficialProcessors(platform: PlatformKey): string[] { const groups = PLATFORM_PROCESSOR_GROUPS[platform] || []; const names: string[] = []; for (const g of groups) { const arr = PROCESADORES_POR_EQUIPO[g] || []; for (const p of arr) { names.push(p.procesador); } } // dedupe preserving order const seen = new Set(); return names.filter((n) => { const c = cleanName(n).toLowerCase(); if (seen.has(c)) return false; seen.add(c); return true; }); } /* ---------- transformación de datos ---------- */ function transformProcessorDataWithOfficial( rawArray: { procesador: string; uso: string; total: string }[], platform: PlatformKey ): ProcessorEntry[] { // 1) crear mapa cleanedName -> aggregated numbers por uso const mapRaw: Record = {}; for (const r of rawArray) { const name = cleanName(r.procesador); const usoKey = String(r.uso).toUpperCase(); const field = USO_TO_FIELD[usoKey]; if (!mapRaw[name]) { mapRaw[name] = {}; } const prev = parseInt(r.total || "0") || 0; if (field) { mapRaw[name][field] = (mapRaw[name][field] || 0) + prev; } } // 2) obtener lista oficial y construir filas fijas primero const official = getOfficialProcessors(platform); const fixedRows: ProcessorEntry[] = official.map((proc) => { const c = cleanName(proc); const sums = mapRaw[c] || {}; const alumnos = (sums["alumnos"] || 0).toString(); const profesores = (sums["profesores"] || 0).toString(); const tecnicos = (sums["tecnicos"] || 0).toString(); const investigadores = (sums["investigadores"] || 0).toString(); const administrativos = (sums["administrativos"] || 0).toString(); const total = (parseInt(alumnos) || 0) + (parseInt(profesores) || 0) + (parseInt(tecnicos) || 0) + (parseInt(investigadores) || 0) + (parseInt(administrativos) || 0); return { tipo: proc, alumnos, profesores, tecnicos, investigadores, administrativos, total: total.toString(), }; }); // 3) extras: procesadores del backend que no están en official const officialSet = new Set(official.map((p) => cleanName(p).toLowerCase())); const extras = Object.keys(mapRaw) .filter((k) => !officialSet.has(k.toLowerCase())) .sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" })) .map((cleaned) => { const sums = mapRaw[cleaned] || {}; const alumnos = (sums["alumnos"] || 0).toString(); const profesores = (sums["profesores"] || 0).toString(); const tecnicos = (sums["tecnicos"] || 0).toString(); const investigadores = (sums["investigadores"] || 0).toString(); const administrativos = (sums["administrativos"] || 0).toString(); const total = (parseInt(alumnos) || 0) + (parseInt(profesores) || 0) + (parseInt(tecnicos) || 0) + (parseInt(investigadores) || 0) + (parseInt(administrativos) || 0); return { tipo: cleaned, // mostrar cleaned name (luego puedes mostrar raw si tienes map) alumnos, profesores, tecnicos, investigadores, administrativos, total: total.toString(), } as ProcessorEntry; }); // 4) concatenar fixedRows + extras, luego grand total const allRows = [...fixedRows, ...extras]; const grandTotal: ProcessorEntry = { tipo: "Total", alumnos: allRows .reduce((sum, r) => sum + (parseInt(r.alumnos || "0") || 0), 0) .toString(), profesores: allRows .reduce((sum, r) => sum + (parseInt(r.profesores || "0") || 0), 0) .toString(), tecnicos: allRows .reduce((sum, r) => sum + (parseInt(r.tecnicos || "0") || 0), 0) .toString(), investigadores: allRows .reduce((sum, r) => sum + (parseInt(r.investigadores || "0") || 0), 0) .toString(), administrativos: allRows .reduce((sum, r) => sum + (parseInt(r.administrativos || "0") || 0), 0) .toString(), total: allRows .reduce((sum, r) => sum + (parseInt(r.total || "0") || 0), 0) .toString(), isTotal: true, }; return [...allRows, grandTotal]; } /* ---------- componente ---------- */ export default function Pregunta3_2() { const [activeTab, setActiveTab] = useState("pc-desktop"); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const cargarDatos = async (baja: boolean) => { setLoading(true); const token = Cookies.get("token"); if (!token) { console.error("Token no encontrado"); setLoading(false); return; } const body = baja ? ["BAJA"] : ["EN DESUSO", "EN USO"]; const headers = { Authorization: `Bearer ${token}` }; axios .post( `${process.env.NEXT_PUBLIC_API_URL}/equipos/reporte/tipoEquipos_procesador`, body, { headers } ) .then((res) => { const json = res.data; // array con 5 arrays const formatted: PlatformData = { "pc-desktop": transformProcessorDataWithOfficial( json[0] || [], "pc-desktop" ), "apple-desktop": transformProcessorDataWithOfficial( json[1] || [], "apple-desktop" ), "pc-laptop": transformProcessorDataWithOfficial( json[2] || [], "pc-laptop" ), "apple-laptop": transformProcessorDataWithOfficial( json[3] || [], "apple-laptop" ), servers: transformProcessorDataWithOfficial(json[4] || [], "servers"), }; setData(formatted); }) .catch((err) => { console.error("Error cargando datos de procesadores", err); // en error, dejamos listas vacías pero con rows oficiales (0) const empty: PlatformData = { "pc-desktop": transformProcessorDataWithOfficial([], "pc-desktop"), "apple-desktop": transformProcessorDataWithOfficial( [], "apple-desktop" ), "pc-laptop": transformProcessorDataWithOfficial([], "pc-laptop"), "apple-laptop": transformProcessorDataWithOfficial( [], "apple-laptop" ), servers: transformProcessorDataWithOfficial([], "servers"), }; setData(empty); }) .finally(() => setLoading(false)); }; useEffect(() => { cargarDatos(false); }, []); const currentData = data?.[activeTab] ?? []; const isInvalidProcessor = (tipo: string, platform: PlatformKey) => { if (tipo === "Total") return false; const official = getOfficialProcessors(platform).map((p) => cleanName(p).toLowerCase() ); return !official.includes(cleanName(tipo).toLowerCase()); }; return (
Censo de equipos de cómputo - Plataforma y tipo procesador
Cantidad de población beneficiada por plataforma y tipo de procesador. { cargarDatos(estado); }} />
{Object.entries(PLATFORM_LABELS).map(([key, label]) => ( ))}
{currentData.map((item, idx) => { const invalid = isInvalidProcessor(item.tipo, activeTab); const rowClass = item.isTotal ? styles.totalRow_P3 : invalid ? styles.invalidRow_P3 : styles.dataRow_P3; return ( ); })}
{activeTab.includes("apple") ? "Plataforma Apple" : "Plataforma PC"}{" "}
Tipo de procesador
Población Beneficiada Total
Alumnos Profesores Técnicos Académicos Investigadores Administrativos
{item.tipo} {loading ? (
) : ( )}
{loading ? (
) : ( )}
{loading ? (
) : ( )}
{loading ? (
) : ( )}
{loading ? (
) : ( )}
{loading ? (
) : ( item.total )}
{currentData.length === 0 && (
No hay datos disponibles para esta plataforma.
)}
); }