diff --git a/frontend/src/pages/Comisiones.jsx b/frontend/src/pages/Comisiones.jsx index 5639ffd..b1b4748 100644 --- a/frontend/src/pages/Comisiones.jsx +++ b/frontend/src/pages/Comisiones.jsx @@ -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 ⇅; + return {dir === "asc" ? "▲" : "▼"}; +} // 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() {
| {c} | )}
|---|
| clickOrden(i)}
+ style={{position:"relative", cursor: ordenable?"pointer":"default", userSelect:"none"}}>
+ {c}{ordenable && _flecha(ordCol===i, ordDir)} |
+ );
+ })}