Skip to content

feat(web): filtro "solo pegas con sueldo publicado" en el listado - #2

Merged
juanbrujo merged 1 commit into
devschile:mainfrom
muZk:feat/filtro-sueldo
Aug 29, 2026
Merged

feat(web): filtro "solo pegas con sueldo publicado" en el listado#2
juanbrujo merged 1 commit into
devschile:mainfrom
muZk:feat/filtro-sueldo

Conversation

@muZk

@muZk muZk commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Qué hace

Agrega un check "Solo pegas con sueldo publicado" a la barra de filtros del listado, al lado de Buscar y Fuente.

CleanShot 2026-08-28 at 12 04 17

Cómo está hecho

Servidor (web/server/api/pegas/index.get.ts) — nuevo param conSueldo en ListJobsParams. El filtro va en el servidor igual que categoria y fuente; 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) <> ''). El TRIM importa: 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 — no hay entrada de usuario en la condición, solo el booleano decide si se agrega.

Se aceptan 1 y true: la URL del listado escribe ?sueldo=1 (más legible al compartir el link) y useFetch serializa el booleano como true.

ClientewithSalary en useJobsListing sobre useState, así sobrevive la navegación entre / y /categoria/X como 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"), en resetFilters() y en el evento filtro_usado de PostHog. La UI usa ChCheckbox de 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):

Request Total
sin filtro 214
conSueldo=true 36
conSueldo=1 36
conSueldo=false 214
conSueldo=basura 214
  • De las 36 filas devueltas, ninguna sin sueldo real. Las filas '' y ' ' quedaron correctamente excluidas.
  • Combinaciones: categoria=Backend 32 → 3; q=developer 28 → 4.
  • SSR: /?sueldo=1 renderiza el check ya marcado y el contador dice "36 de 214" sin JS.
  • Paginación con el filtro: 1–25 de 36, y ?sueldo=1&pagina=226–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 emitiendo false al 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

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
juanbrujo added a commit that referenced this pull request Aug 29, 2026
… 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>
@juanbrujo
juanbrujo merged commit 133c321 into devschile:main Aug 29, 2026
1 check passed
@juanbrujo

Copy link
Copy Markdown
Member

¡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:

  • El check se alinea a la derecha, bajo el select de Fuente (en móvil vuelve a la izquierda, donde el grid colapsa a una columna).
  • El label pasó a "💰 con sueldo publicado" por espacio.
  • Se sacó el hint "La mayoría de los avisos no lo publica.", que con el label corto pesaba más que el propio filtro.

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 💚

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants