diff --git a/frontend/src/pages/Cobranza.jsx b/frontend/src/pages/Cobranza.jsx index 5b21f9c..1947c7c 100644 --- a/frontend/src/pages/Cobranza.jsx +++ b/frontend/src/pages/Cobranza.jsx @@ -19,8 +19,81 @@ const BG_ANT = "#fef3c7", BG_MES = "#d1fae5", BG_TOT = "#ede9fe"; // Versiones más oscuras para hover de cada cartera const HV_ANT = "#fde68a", HV_MES = "#a7f3d0", HV_TOT = "#ddd6fe"; +// Select de una opción con desplegable custom (mismo estilo que Ocupabilidad/Rentabilidad). +function SelectBonito({ label, value, options, onChange, minWidth = 150 }) { + const [abierto, setAbierto] = useState(false); + const ref = useRef(null); + const opts = options.map((o) => (typeof o === "object" ? o : { value: o, label: String(o) })); + const actual = opts.find((o) => String(o.value) === String(value)); + useEffect(() => { + const fuera = (e) => { if (ref.current && !ref.current.contains(e.target)) setAbierto(false); }; + document.addEventListener("mousedown", fuera); + return () => document.removeEventListener("mousedown", fuera); + }, []); + return ( +
+ + + {abierto && ( +
+ {opts.map((o) => { + const on = String(o.value) === String(value); + return ( +
{ onChange(o.value); setAbierto(false); }} + style={{ padding: "8px 10px", borderRadius: 6, cursor: "pointer", fontSize: 13, + fontWeight: on ? 700 : 500, color: on ? "#1e3a5f" : "#334155", + background: on ? "#eff6ff" : "transparent" }} + onMouseEnter={(e) => { if (!on) e.currentTarget.style.background = "#f8fafc"; }} + onMouseLeave={(e) => { if (!on) e.currentTarget.style.background = "transparent"; }}> + {o.label} +
+ ); + })} +
+ )} +
+ ); +} + function toMonto(s){ const n = parseFloat(String(s).replace("S/","").replace(/,/g,"").trim()); return isNaN(n)?0:n; } function toPct(s){ const n = parseFloat(String(s).replace("%","").trim()); return isNaN(n)?0:n; } + +// ── Ordenamiento de tablas (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" ? "▲" : "▼"}; +} // Formato moneda SIN decimales (solo visualización) function fmtMoneda(s){ if (s == null) return ""; @@ -419,14 +492,14 @@ export default function Cobranza() {

📋 Cobranza

- ({value:i+1,label:m}))} onChange={(v)=>setMes(+v)} /> - - {esPrograma && } - {(agrupacion==="SEDE"||agrupacion==="ASESOR") && {setProgFiltro(v);setExpandidas(new Set());}} />} + setAno(+v)} minWidth={110} /> + ({value:i+1,label:m}))} onChange={(v)=>setMes(+v)} minWidth={150} /> + {setAgrupacion(v);setSede("TODOS");setFrec("TODOS");setSedeFiltro("TODOS");setProgFiltro("TODOS");}} minWidth={150} /> + + {esPrograma && } + {esPrograma && } + {(agrupacion==="SEDE"||agrupacion==="ASESOR") && {setSedeFiltro(v);setExpandidas(new Set());}} minWidth={140} />} + {(agrupacion==="SEDE"||agrupacion==="ASESOR") && {setProgFiltro(v);setExpandidas(new Set());}} minWidth={150} />}