feat(web): filtro "solo pegas con sueldo publicado" en el listado - #2
Conversation
Solo ~1 de cada 6 pegas activas publica sueldo (36 de 214 en la muestra con la que se probó), y casi todas vienen de GetOnBoard. Buscarlas a mano entre las que no lo traen era incómodo en un listado de 25 por página. El filtro va en el servidor, como categoría y fuente -- no filtrando en el cliente una página ya paginada, que habría dado páginas de tamaño irregular y un contador mentiroso. La condición SQL lleva `TRIM(sueldo) <> ''` además del IS NOT NULL: los parsers de n8n guardan NULL o string vacío según la fuente, y un '' no es un sueldo publicado. Es el único filtro sin parametrizar del query, porque no hay entrada de usuario en la condición -- solo el booleano decide si se agrega. Se aceptan `1` y `true` en el query param: la URL del listado escribe `?sueldo=1` (más legible al compartir el link) y useFetch serializa el booleano como `true`. El estado vive en useState como los otros filtros, así que sobrevive la navegación entre / y /categoria/X, es deep-linkable via `?sueldo=1` y resetea a la página 1 al cambiar. Probado contra Postgres local con datos reales de producción más filas borde (`''` y solo espacios): 214 pegas → 36 con el filtro, ninguna sin sueldo real, y las filas borde correctamente excluidas. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rz4NWDSrLMFD8dggQbWTdk
… la derecha Sobre el filtro que trae el PR #2: el check se alinea a la derecha, bajo el select de Fuente, en vez de quedar a la izquierda a todo el ancho. En móvil vuelve a la izquierda -- ahí el grid colapsa a una columna y no hay select con el cual alinearse, así que pegado al borde derecho quedaba suelto. El label pasa a "💰 con sueldo publicado" y se saca el hint "La mayoría de los avisos no lo publica.": con el label corto, el hint pesaba más que el propio filtro. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
¡Gracias @muZk! 🙌 Mergeado en main y ya desplegado en producción. Lo probamos contra una base local con 858 pegas (194 con sueldo) y quedó todo en orden. Sobre lo que dejaste marcado como no verificado (el click real después de hidratar): quedó resuelto sin browser, porque hay precedente directo — ChSelect, tres líneas más arriba en ese mismo archivo, ya usa @ch-change="source = $event.detail ?? $event" y está en producción. El wrapper declara defineContainer('ch-checkbox', …, ['chChange']) con chChange: EventEmitter: Vue normaliza @ch-change al mismo listener, el detail es booleano y el ?? preserva el false al desmarcar. Buen detalle haberle puesto un test a eso. Se agradece especialmente que el filtro fuera al servidor y no al cliente, y el TRIM(...) <> '' — efectivamente hay filas con string vacío según la fuente. Encima del merge fueron tres ajustes cosméticos de nuestra parte (commit 9ffe6c9), nada de lógica:
Un detalle menor por si lo retomas: ?sueldo=true filtra bien en la API pero no deja el check marcado, porque el cliente solo acepta 1. No genera desajuste entre lo que se muestra y los datos, así que lo dejamos como está. Sólo te queda apoyar aún más a la comunidad, acá puedes aportar: https://tienda.devschile.cl/p/prod_3d15d557dc 💚 |
Qué hace
Agrega un check "Solo pegas con sueldo publicado" a la barra de filtros del listado, al lado de Buscar y Fuente.
Cómo está hecho
Servidor (
web/server/api/pegas/index.get.ts) — nuevo paramconSueldoenListJobsParams. El filtro va en el servidor igual quecategoriayfuente; filtrar en el cliente una página ya paginada habría dado páginas de tamaño irregular y un contador mentiroso.La condición es
(sueldo IS NOT NULL AND TRIM(sueldo) <> ''). ElTRIMimporta: los parsers de n8n guardanNULLo string vacío según la fuente, y un''no es un sueldo publicado. Es el único filtro sin parametrizar del query — no hay entrada de usuario en la condición, solo el booleano decide si se agrega.Se aceptan
1ytrue: la URL del listado escribe?sueldo=1(más legible al compartir el link) yuseFetchserializa el booleano comotrue.Cliente —
withSalaryenuseJobsListingsobreuseState, así sobrevive la navegación entre/y/categoria/Xcomo los demás filtros. Es deep-linkable via?sueldo=1, resetea a página 1 al cambiar, entra en el conteo propio del layout (el "N de M pegas"), enresetFilters()y en el eventofiltro_usadode PostHog. La UI usaChCheckboxde chucao.Cómo lo probé
Además de los tests, lo corrí contra un Postgres local con 200 filas reales traídas de producción más filas borde (
sueldo = ''y solo espacios):conSueldo=trueconSueldo=1conSueldo=falseconSueldo=basura''y' 'quedaron correctamente excluidas.categoria=Backend32 → 3;q=developer28 → 4./?sueldo=1renderiza el check ya marcado y el contador dice "36 de 214" sin JS.1–25 de 36, y?sueldo=1&pagina=2→26–36 de 36.Tests
205 pasando, cobertura 84.65% statements (sobre el gate de 80%). Se agregaron casos para: la cláusula SQL construida/omitida según el booleano, el parseo de
1/true/false/0, el reset de página al togglear, el sync de la query string incluyendo la vuelta a sin-param, y el check emitiendofalseal desmarcarse (el??solo cae con null/undefined, vale la pena fijarlo).Lo que no está verificado
El click en el check en un browser real, después de hidratar. Los tests cubren el emit en ambas direcciones y el SSR cubre el estado
checked, pero esa ruta no se ejerció.🤖 Generated with Claude Code