CreaRack-SL

Tasks: deep-link ?task=N, KanbanMini click y polling 60s (s69)

Resumen

Cierre del ciclo de rediseño TaskModal s69 (iniciado en commits 27aa041 + 7625dd0). Tres mejoras ortogonales que convierten el sistema de tareas del workspace en un flujo linkeable, colaborativo y accesible:

  1. Deep-link ?task=N en TaskManager.
  2. KanbanMini widget: click en card, polling silencioso cada 60s, accesibilidad.
  3. (Gobernanza) Derogación Regla 7 para el workspace — ver [[decision—20260518—regla-7-iconos-workspace]].

Comportamiento

URLResultado
/tasks?task=42Abre el TaskModal con la tarea id=42
/tasks?task=newAbre el TaskModal en modo CREAR
/tasks (sin param)Vista normal sin modal

Implementación (3 efectos)

useEffect — carga inicial

// Se dispara cuando loading=false y tasks[] ya está populado.
// Si hay ?task=N busca la tarea y llama setModalTask(found).
// Si hay ?task=new llama setModalTask('new').
// Guard: si ya hay un modal abierto (modalTask !== null) no lo pisa.

useEffect — sync modalTask → URL

// Cada cambio de modalTask actualiza la URL con history.replaceState
// sin recargar la página. Si el modal se cierra, elimina el param.

useEffect — popstate

// Back/forward del browser sincroniza el estado del modal.
// Suscribe window.addEventListener('popstate', ...) y hace cleanup.

Botón “Copiar enlace”

El TaskModal tiene un botón que genera workspace.crearack.com/tasks?task=<id> y lo copia al portapapeles. Ahora ese enlace es funcional: cualquier miembro del staff puede pegarlo y abre el modal directamente.


2. KanbanMini widget — click, polling y a11y

Click en card

const onCardClick = (taskId: number, e: MouseEvent) => {
  if (dragging !== null) return;  // drag en curso → no navegar
  if (e.defaultPrevented) return; // botón interior → no navegar
  window.location.href = `/tasks?task=${taskId}`;
};
  • Navega a /tasks?task=N, que el deep-link de TaskManager resuelve abriendo el modal.
  • Guard anti-drag: si dragging !== null (optimistic UI activo), el click se ignora.

Polling silencioso 60s

const fetchTasks = async (silent = false) => { … };
fetchTasks(false);                               // carga inicial
const intervalId = window.setInterval(() => fetchTasks(true), 60_000);
return () => window.clearInterval(intervalId);   // cleanup en unmount
  • silent=true → no llama setLoading(false), evita flash de spinner.
  • Refleja tareas creadas/editadas por otros miembros sin reload manual.
  • El optimistic UI del drag-drop sigue intacto (las columnas de estado local no se resetean si el servidor devuelve el mismo estado).

Accesibilidad (a11y)

role="button"
tabIndex={0}
onKeyDown={(e) => {
  if (e.key === 'Enter' || e.key === ' ') {
    e.preventDefault();
    window.location.href = `/tasks?task=${taskId}`;
  }
}}
style={{ cursor: 'pointer' }}

Los cards de tarea ahora son navigables por teclado, cumpliendo WCAG 2.1 criterio 2.1.1 (Keyboard).


Flujo completo

Usuario abre workspace → KanbanMini visible en dashboard
  └─ Click en card (o Enter/Space) → /tasks?task=42
       └─ TaskManager useEffect[loading, tasks]
            └─ encontrado → setModalTask(task) → TaskModal abre
                  └─ "Copiar enlace" → clipboard con ?task=42
                       └─ Otro miembro pega URL → mismo flujo

Archivos modificados

ArchivoLOC añadidasDescripción
src/components/tasks/TaskManager.tsx+623 useEffects de deep-link
src/components/widgets/KanbanMini.tsx+41click, polling, a11y

Pendiente

  • Banner detector de versión (opción B): tras deploy, los browsers abiertos deben avisar al usuario sin requerir reload manual. Previsto en próximos commits.

Véase también

  • [[decision—20260518—regla-7-iconos-workspace]]
  • [[workspace—tareas-notas]]
  • [[workspace—que-es-workspace]]