From 0fb44d046c89a8db0555d02daf996198eb5bfd2a Mon Sep 17 00:00:00 2001 From: Administrator Date: Wed, 23 Sep 2026 10:42:24 -0500 Subject: [PATCH] Actualizar frontend/src/pages/Cobranza.jsx --- frontend/src/pages/Cobranza.jsx | 84 +++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 14 deletions(-) diff --git a/frontend/src/pages/Cobranza.jsx b/frontend/src/pages/Cobranza.jsx index 1947c7c..7adfcd0 100644 --- a/frontend/src/pages/Cobranza.jsx +++ b/frontend/src/pages/Cobranza.jsx @@ -10,6 +10,8 @@ const MESES = ["ENERO","FEBRERO","MARZO","ABRIL","MAYO","JUNIO","JULIO","AGOSTO" const ANOS = [2024, 2025, 2026]; const AGRUPACIONES = [{value:"SEDE",label:"Por Sede"},{value:"ASESOR",label:"Por Asesor"}]; const SEDES = ["TODOS","LIMA","AREQUIPA","PIURA","TRUJILLO"]; +const SEDES_MULTI = ["LIMA","AREQUIPA","PIURA","TRUJILLO"]; +const PROGRAMAS_MULTI = ["TEAC","TERC","SEMINARIOS","OTROS"]; const FRECS = ["TODOS","DOM","SAB","NOC","MAN","VIR","TAR"]; const PROGRAMAS_FILTRO = ["TODOS","TEAC","TERC","SEMINARIOS","OTROS"]; @@ -68,6 +70,56 @@ function SelectBonito({ label, value, options, onChange, minWidth = 150 }) { ); } +// Filtro multi-selección con casillas (Sectorista, Sede, Programa). Vacío = todos. +function ListaMulti({ label, opciones, seleccion, onChange, plural = "opciones", minWidth = 150 }) { + const [abierto, setAbierto] = useState(false); + const ref = useRef(null); + useEffect(() => { + const fuera = (e) => { if (ref.current && !ref.current.contains(e.target)) setAbierto(false); }; + document.addEventListener("mousedown", fuera); + return () => document.removeEventListener("mousedown", fuera); + }, []); + const toggle = (v) => { + const set = new Set(seleccion); + set.has(v) ? set.delete(v) : set.add(v); + onChange([...set]); + }; + const texto = seleccion.length === 0 ? "— Todos —" + : seleccion.length === 1 ? seleccion[0] + : `${seleccion.length} ${plural}`; + return ( +
+ + + {abierto && ( +
+ {opciones.length === 0 &&
Sin opciones.
} + {opciones.map((o) => { + const on = seleccion.includes(o); + return ( + + ); + })} +
+ )} +
+ ); +} + 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; } @@ -122,12 +174,16 @@ export default function Cobranza() { const [ano, setAno] = useState(hoy.getFullYear()); const [mes, setMes] = useState(hoy.getMonth() + 1); const [agrupacion, setAgrupacion] = useState("SEDE"); - const [sectorista, setSectorista] = useState("TODOS"); + const [sectoristasSel, setSectoristasSel] = useState([]); // multi; vacío = todos const [sede, setSede] = useState("TODOS"); const [frec, setFrec] = useState("TODOS"); - // Filtros extra para la vista "Por Sede" (usan JSON REPLACE_META) - const [sedeFiltro, setSedeFiltro] = useState("TODOS"); - const [progFiltro, setProgFiltro] = useState("TODOS"); + // Filtros extra para la vista "Por Sede" (usan JSON REPLACE_META). Multi; vacío = todos. + const [sedesSel, setSedesSel] = useState([]); + const [progsSel, setProgsSel] = useState([]); + // Claves string (coma) para dependencias y para pasar al backend. Vacío = "TODOS". + const sectorista = sectoristasSel.length ? sectoristasSel.join(",") : "TODOS"; + const sedeFiltro = sedesSel.length ? sedesSel.join(",") : "TODOS"; + const progFiltro = progsSel.length ? progsSel.join(",") : "TODOS"; const [filas, setFilas] = useState([]); const [sectoristas, setSectoristas] = useState(["TODOS"]); const [loading, setLoading] = useState(true); @@ -357,7 +413,7 @@ export default function Cobranza() { return filasPrograma.filter((fp) => { const ip = infoProg(fp[0]); if (String(ip.sede).toUpperCase() !== key) return false; - if (progFiltro !== "TODOS" && String(ip.filtro).toUpperCase() !== progFiltro) return false; + if (progsSel.length && !progsSel.includes(String(ip.filtro).toUpperCase())) return false; return true; }); }; @@ -369,15 +425,15 @@ export default function Cobranza() { if (sede !== "TODOS") arr = arr.filter((a) => String(a.sede).toUpperCase() === sede.toUpperCase()); if (frec !== "TODOS") arr = arr.filter((a) => String(a.frecuencia).toUpperCase() === frec); } - // Filtros Sede / Programa (REPLACE_META) — aplican en Por Sede y Por Asesor - if (sedeFiltro !== "TODOS") { + // Filtros Sede / Programa (REPLACE_META) — multi; aplican en Por Sede y Por Asesor + if (sedesSel.length) { arr = arr.filter((a) => { const s = (progClasif[String(a.programa)]?.sede || a.sede || "LIMA"); - return String(s).toUpperCase() === sedeFiltro.toUpperCase(); + return sedesSel.includes(String(s).toUpperCase()); }); } - if (progFiltro !== "TODOS") { - arr = arr.filter((a) => String(progClasif[String(a.programa)]?.filtro || "").toUpperCase() === progFiltro); + if (progsSel.length) { + arr = arr.filter((a) => progsSel.includes(String(progClasif[String(a.programa)]?.filtro || "").toUpperCase())); } // Filtro por F. Vencimiento (<=). Cuotas sin fecha se incluyen siempre. if (vencHasta !== "TODOS") { @@ -494,12 +550,12 @@ export default function Cobranza() { 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} /> - + {setAgrupacion(v);setSede("TODOS");setFrec("TODOS");setSedesSel([]);setProgsSel([]);}} minWidth={150} /> + s!=="TODOS")} seleccion={sectoristasSel} onChange={setSectoristasSel} plural="sectoristas" minWidth={250} /> {esPrograma && } {esPrograma && } - {(agrupacion==="SEDE"||agrupacion==="ASESOR") && {setSedeFiltro(v);setExpandidas(new Set());}} minWidth={140} />} - {(agrupacion==="SEDE"||agrupacion==="ASESOR") && {setProgFiltro(v);setExpandidas(new Set());}} minWidth={150} />} + {(agrupacion==="SEDE"||agrupacion==="ASESOR") && {setSedesSel(v);setExpandidas(new Set());}} plural="sedes" minWidth={140} />} + {(agrupacion==="SEDE"||agrupacion==="ASESOR") && {setProgsSel(v);setExpandidas(new Set());}} plural="programas" minWidth={150} />}