Actualizar frontend/src/pages/Comisiones.jsx

This commit is contained in:
2026-09-22 10:27:04 -05:00
parent 8e87d6581a
commit f07c7e000b

View File

@@ -22,6 +22,30 @@ const OPCIONES_POPUP = [
function toNum(v){ const n=parseFloat(String(v).replace("S/","").replace(/,/g,"").trim()); return isNaN(n)?0:n; }
// Formatea cualquier monto a "S/ 1,234" (sin decimales)
function fmt(v){ return "S/ " + toNum(v).toLocaleString("es-PE",{maximumFractionDigits:0}); }
// ── Ordenamiento (detecta monto S/, %, fecha dd-mm-yyyy, número o texto) ──
function _valorOrden(v) {
const s = String(v ?? "").trim();
if (s === "" || s === "—" || s === "-") return { t: "vacio", n: 0, s: "" };
const mf = s.match(/^(\d{1,2})[-/](\d{1,2})[-/](\d{4})$/);
if (mf) { const [, d, m, y] = mf; return { t: "fecha", n: new Date(+y, +m - 1, +d).getTime(), s }; }
const limpio = s.replace(/S\/|%|,/g, "").replace(/\s/g, "").trim();
if (limpio !== "" && !isNaN(Number(limpio))) return { t: "num", n: Number(limpio), s };
return { t: "texto", n: 0, s: s.toLowerCase() };
}
function _cmp(a, b, dir) {
const mult = dir === "asc" ? 1 : -1;
const va = _valorOrden(a), vb = _valorOrden(b);
if (va.t === "vacio" && vb.t === "vacio") return 0;
if (va.t === "vacio") return 1;
if (vb.t === "vacio") return -1;
if (va.t === "texto" || vb.t === "texto") return mult * va.s.localeCompare(vb.s, "es");
return mult * (va.n - vb.n);
}
function _flecha(activo, dir) {
if (!activo) return <span style={{ opacity: 0.3, marginLeft: 4 }}>⇅</span>;
return <span style={{ marginLeft: 4 }}>{dir === "asc" ? "▲" : "▼"}</span>;
}
// True si la fecha de matrícula (dd/mm/yyyy) es >= 01/01/2025
function fechaMatDesde2025(fch){
const s = String(fch || "").trim();
@@ -48,6 +72,16 @@ export default function Comisiones() {
const [modalBuscar, setModalBuscar] = useState(false);
const [modalConfig, setModalConfig] = useState(false);
const cols = useColumnasAjustables([200, 160, 150, 160, 150, 130, 160]);
const [ordCol, setOrdCol] = useState(null);
const [ordDir, setOrdDir] = useState(null);
// Mapa columna visible -> índice real en el array de la fila.
const IDX_COM = [0, 3, 4, 5, 6, 7];
const clickOrden = (i) => {
if (i === 6) return; // columna OPCIONES no se ordena
if (ordCol !== i) { setOrdCol(i); setOrdDir("asc"); }
else if (ordDir === "asc") setOrdDir("desc");
else { setOrdCol(null); setOrdDir(null); }
};
// Carga TODOS los manuales del año (una sola vez por año) → cambio de mes instantáneo
function cargarManuales() {
@@ -83,7 +117,14 @@ export default function Comisiones() {
useEffect(() => { cargarManuales(); }, [ano]);
const total = useMemo(() => filas.find((f) => f[0] === "TOTAL GENERAL"), [filas]);
const datos = useMemo(() => filas.filter((f) => f[0] !== "TOTAL GENERAL"), [filas]);
const datos = useMemo(() => {
let base = filas.filter((f) => f[0] !== "TOTAL GENERAL");
if (ordCol != null && ordDir) {
const idx = IDX_COM[ordCol];
base = [...base].sort((a, b) => _cmp(a[idx], b[idx], ordDir));
}
return base;
}, [filas, ordCol, ordDir]);
// Agrupar vendedores manuales por nombre (cada nombre = 1 fila, suma de montos)
const manualesAgrupados = useMemo(() => {
@@ -129,7 +170,15 @@ export default function Comisiones() {
<div className="table-wrap" style={{overflowX:"auto"}}>
<table {...cols.tableProps}>
<cols.ColGroup />
<thead><tr>{COLS.map((c, i) => <th key={c} style={{position:"relative"}}>{c}<cols.Resizer index={i} /></th>)}</tr></thead>
<thead><tr>{COLS.map((c, i) => {
const ordenable = i !== 6;
return (
<th key={c} onClick={()=>clickOrden(i)}
style={{position:"relative", cursor: ordenable?"pointer":"default", userSelect:"none"}}>
{c}{ordenable && _flecha(ordCol===i, ordDir)}<cols.Resizer index={i} />
</th>
);
})}</tr></thead>
<tbody>
{datos.map((f, i) => (
<tr key={i}>