Ejercicios de refuerzo: detalle, paginación y filtros

Contexto de la clase

En esta clase no añadimos una gran pieza nueva a la aplicación, sino que dejamos ejercicios de refuerzo para que termines de consolidar todo lo que hemos visto hasta ahora:

  • Página de detalle de trabajo
  • Navegación y estado activo en los enlaces
  • Paginación de resultados
  • Sincronización de filtros con la URL usando URLSearchParams o la API del router

La idea es que, al acabar estos ejercicios, tu aplicación se sienta mucho más pulida y coherente con lo que ya hemos construido.


Ejercicio 1 - Mejorar la página de detalle de trabajo

En el vídeo comento que la página de detalle “está bastante bien, pero hay que arreglarle los estilos totalmente”. El objetivo es que la página deje de parecer un prototipo y se convierta en una vista que podrías enseñar a alguien sin pedir perdón.

Objetivos del ejercicio

  • Pulir el diseño visual de la página de detalle de trabajo.
  • Asegurarte de que la información importante se lee bien y rápido.
  • Mantener consistencia con el listado y el resto de la aplicación.

Puntos a trabajar

Jerarquía visual

  • Título del puesto bien destacado (tamaño, peso de fuente).
  • Subtítulo con empresa, ubicación y tipo de contrato.
  • Secciones claras para descripción, requisitos, beneficios, etc.

Layout

Usa un layout que se adapte bien a escritorio y móvil.

Por ejemplo, en escritorio puedes tener:

  • Columna principal con descripción
  • Columna lateral con datos clave (salario, ubicación, botón de aplicar)

Tipografía y espaciado

  • Ajusta márgenes y paddings para que el contenido respire.
  • Asegúrate de que no haya bloques de texto muy densos sin separación.

Botones y acciones

  • El botón de “Aplicar” debe ser muy visible.
  • Si hay acciones secundarias (guardar, compartir, volver al listado), que se vean pero no compitan con la principal.

Responsive

  • En móvil, asegúrate de que todo sea legible sin hacer zoom.
  • Comprueba que no haya scroll horizontal raro.

💡 Pista

Puedes hacer una pequeña revisión de diseño:

  1. Mirar la página durante 5 segundos
  2. Preguntarte: “¿Qué se entiende primero?, ¿qué sobra?, ¿qué falta?”

Ejercicio 2 - Navegación y estado activo

En el vídeo comento que hay que “implementar bien los breaks” y detectar cuando estemos en esa página para que cualquier enlace de navegación refleje que estamos ahí.

Aquí puedes plantearlo como dos subejercicios opcionales, dependiendo de cómo esté tu proyecto:

2.1. Breadcrumbs de navegación (opcional pero recomendable)

Objetivo: que el usuario sepa en qué parte de la aplicación está.

💡 Pista sobre estructura

Un breadcrumb típico podría verse así en JSX:

<nav aria-label="Ruta de navegación">
  <ol>
    <li>{/* Enlace a la lista de ofertas */}</li>
    <li aria-current="page">{/* Título del trabajo actual */}</li>
  </ol>
</nav>

Puntos importantes

  • Los breadcrumbs ayudan a la UX mostrando la jerarquía de navegación
  • Usa aria-label y aria-current para mejorar la accesibilidad
  • El último elemento del breadcrumb no debería ser un enlace

2.2. Marcar el enlace activo en la navegación

En el vídeo también pido que cualquier enlace de navegación detecte si estamos en esa página y se marque correctamente.

Ejercicio

  • Usar la información de la URL para marcar como “activo” el enlace correspondiente del menú.

💡 Pista de implementación

Necesitarás:

  1. Obtener la ruta actual (piensa en hooks del router que has usado)
  2. Comparar la ruta actual con la ruta del enlace
  3. Aplicar una clase CSS diferente cuando coincidan
  4. Añadir aria-current="page" para accesibilidad

Un patrón común es crear un componente NavLink que envuelva tu componente Link y añada esta lógica.


Ejercicio 3 - Implementar la paginación correctamente

En el vídeo, otro punto clave es “implementar la paginación correctamente”. No es solo mostrar botones de “Siguiente” y “Anterior”, sino que funcione bien en combinación con filtros y URL.

Objetivos

  • Tener un componente de paginación reutilizable.
  • Sincronizar la página actual con la URL para que:
    • Al refrescar se mantenga la página.
    • Se pueda compartir la URL con una página concreta.

💡 Esqueleto de componente

Tu componente de paginación debería manejar:

function Pagination({ currentPage, totalPages, onPageChange }) {
  // ¿Cuándo se puede ir a la página anterior?
  // ¿Cuándo se puede ir a la siguiente?

  return (
    <nav aria-label="Paginación de resultados">
      {/* Botón anterior */}
      {/* Indicador de página actual */}
      {/* Botón siguiente */}
    </nav>
  )
}

Integración con la URL

Ejercicio sugerido:

  1. Guardar la página actual en la query string, por ejemplo ?page=2
  2. Al cambiar de página, actualizar la URL
  3. Al cargar la página, leer page de la URL y usarlo como estado inicial

💡 Pistas para trabajar con URL

  • Puedes usar URLSearchParams para leer y modificar los parámetros de la URL
  • window.location.search te da la query string actual
  • Para actualizar la URL sin recargar: window.history.pushState()
  • O mejor aún, usa los métodos que te proporciona React Router

💡 Ejemplo de lectura de parámetros

// Para leer un parámetro de la URL:
const searchParams = new URLSearchParams(window.location.search)
const pageFromUrl = searchParams.get('page') // devuelve string o null

Ejercicio 4 - Revisar e inicializar todos los filtros desde la URL

En el vídeo remarco que los filtros “funcionan, pero cuando refresco este y este y este no se están inicializando correctamente” y recuerdo que ya hemos visto cómo hacerlo con el filtro de texto. La idea es que apliques la misma lógica al resto de filtros.

Recordatorio de lo visto con el buscador de texto

  1. Al escribir en el input, actualizábamos la URL.
  2. Al recargar la página, leíamos la URL para saber el valor inicial del input.

Lo que se pide en el ejercicio

Para cada filtro que tengas (por ejemplo):

  • Modalidad (remote, hybrid, onsite)
  • Tipo de contrato (full-time, part-time)
  • Rango salarial

Debes:

  1. Definir un nombre de parámetro en la URL

    • Ejemplos: mode, contract, salaryMin, salaryMax, etc.
  2. Al cambiar el filtro en la UI:

    • Actualizar el estado en React
    • Actualizar la URL con el nuevo valor
  3. Al cargar o refrescar la página:

    • Leer ese parámetro de la URL
    • Inicializar el estado del filtro con ese valor

💡 Pista de implementación

Puedes crear custom hooks para cada filtro siguiendo este patrón:

function useModeFilter() {
  const [mode, setMode] = useState('')

  // useEffect para leer la URL al montar
  // función para actualizar mode y URL

  return { mode, updateMode }
}

💡 Pista para actualizar URL

Cuando cambies un filtro:

const updateFilter = (value) => {
  // 1. Actualiza el estado local
  // 2. Obtén los searchParams actuales
  // 3. Si hay valor, añádelo: searchParams.set(name, value)
  // 4. Si no hay valor, elimínalo: searchParams.delete(name)
  // 5. Actualiza la URL
}

Ejemplo de uso en un componente

function Filters() {
  const { mode, updateMode } = useModeFilter()

  return (
    <select value={mode} onChange={(e) => updateMode(e.target.value)}>
      <option value="">Cualquiera</option>
      <option value="remote">Remoto</option>
      <option value="hybrid">Híbrido</option>
      <option value="onsite">Presencial</option>
    </select>
  )
}

Cierre de la clase

Recapitulación

Estos ejercicios no introducen conceptos totalmente nuevos, pero te obligan a aplicar de verdad lo que hemos visto.

Son perfectos para:

  • ✅ Entender cómo se combinan router, URL y estado
  • ✅ Pulir la experiencia de usuario de la app
  • ✅ Acostumbrarte a pensar en estado inicial a partir de la URL en lugar de inventártelo dentro del componente

Recordatorio importante

  • En la próxima clase daré por hecho que esto está hecho
  • Cuanto más mimes estos detalles, más se parecerá tu proyecto a una app real y menos a un ejercicio de clase.
  • La URL como fuente de verdad es un patrón fundamental en aplicaciones web modernas.

🎯 Checklist de ejercicios

Antes de dar por terminada esta clase, asegúrate de:

  • La página de detalle tiene un diseño visual pulido y profesional
  • Los breadcrumbs (si los implementas) muestran la ruta de navegación
  • Los enlaces del menú principal se marcan como activos correctamente
  • La paginación funciona y se sincroniza con la URL
  • Todos los filtros se inicializan correctamente desde la URL
  • Al refrescar la página, se mantiene el estado de filtros y paginación
  • Las URLs son compartibles (contienen toda la información necesaria)