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:
- Deep-link
?task=NenTaskManager. - KanbanMini widget: click en card, polling silencioso cada 60s, accesibilidad.
- (Gobernanza) Derogación Regla 7 para el workspace — ver [[decision—20260518—regla-7-iconos-workspace]].
1. Deep-link ?task=N — TaskManager
Comportamiento
| URL | Resultado |
|---|---|
/tasks?task=42 | Abre el TaskModal con la tarea id=42 |
/tasks?task=new | Abre 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 llamasetLoading(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
| Archivo | LOC añadidas | Descripción |
|---|---|---|
src/components/tasks/TaskManager.tsx | +62 | 3 useEffects de deep-link |
src/components/widgets/KanbanMini.tsx | +41 | click, 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]]