Tareas s77: deep-link widget · badge comentarios · gestor transversal · enlace nota
Tareas s77: deep-link widget · badge comentarios · gestor transversal · enlace nota
Cinco mejoras del menú Tareas implementadas en el commit b07fd73 (2026-05-20), solicitadas por Edu. Afectan al widget KanbanMini, al componente TaskManager, al endpoint /api/tasks y a un nuevo endpoint /api/tasks/comments.
Item 1 — Widget click en card abre TaskModal (fix race condition)
Problema: Llegar a /tasks?task=N desde el widget KanbanMini abría la URL correctamente pero el modal no se mostraba. La causa era una race condition en TaskManager: el useEffect que sincroniza modalTask → URL borraba el parámetro ?task=N antes de que el useEffect que lo lee hubiera tenido oportunidad de ejecutarse (en el primer render loading=true y modalTask === null).
Solución: Guard if (loading && modalTask === null) return en el useEffect de sincronización. También se añadió loading al array de dependencias de ese efecto.
// TaskManager.tsx — guard race condition
useEffect(() => {
if (typeof window === 'undefined') return;
if (loading && modalTask === null) return; // ← guard s77
// … sincroniza modalTask → URL
}, [modalTask, loading]);
Impacto: DesktopA.tsx también actualizó el href del botón “Nueva” del widget: href="/tasks" → href="/tasks?task=new", de forma que el botón abre directamente el modal de creación.
Item 2 — Badge comentarios en cards (KanbanMini + TaskKanban)
El endpoint GET /api/tasks añadió un cuarto subquery al SELECT:
(SELECT COUNT(*) FROM task_comments WHERE task_id = tasks.id) AS comment_count
El campo comment_count?: number se añadió al interface Task en TaskModal.tsx y en src/lib/types.ts.
Ambos componentes de cards (KanbanMini y TaskKanban) renderizan un chip cuando comment_count > 0:
{(task.comment_count ?? 0) > 0 && (
<span className="task-link-badge task-link-badge-comment">
{task.comment_count} {task.comment_count === 1 ? 'comentario' : 'comentarios'}
</span>
)}
Estilo: .task-link-badge-comment usa color-mix(in srgb, var(--accent-2) 14%, transparent) — tinte cyan accent-2 para distinguirlo visualmente de los badges de eventos Zoho (emails, calendar).
Item 3 — Vista “Comentarios” en /tasks (?view=comments)
Nuevo endpoint: GET /api/tasks/comments
Endpoint transversal en functions/api/tasks/comments.ts. Devuelve comentarios de todas las tareas con paginación { results, total }. Filtros disponibles:
| Parámetro | Tipo | Descripción |
|---|---|---|
author | string | Autor exacto (Edu / Dani / Txell) |
target_user | string | Match en JSON array target_user_ids |
task_id | int | Tarea exacta |
task_title | string | LIKE en título de la tarea |
q | string | LIKE en body del comentario |
start_date | YYYY-MM-DD | Rango de fecha inicio |
end_date | YYYY-MM-DD | Rango de fecha fin |
limit | int | Default 50, máx 200 |
offset | int | Default 0 |
Nota de seguridad de filtro: target_user_ids se filtra con LIKE %"${name}"% (comillas dobles incluidas) para evitar matches parciales en el JSON array.
Nuevo componente: TaskCommentsView
src/components/tasks/TaskCommentsView.tsx (333 LOC). Renderiza:
- Filter bar con inputs reactivos: búsqueda en body, selector autor, selector destinatario, búsqueda por título de tarea, rangos de fecha.
- Cards clickables (
.task-comment-card): al hacer clic abren elTaskModalde la tarea origen víaonOpenTask. Si la tarea no está en el store local, redirige a/tasks?task=N. - Paginación “Cargar más” con
PAGE_SIZE = 50.
URL ?view=comments
TaskManager añade la vista 'comments' al tipo View ('board' | 'list' | 'calendar' | 'comments'). La vista activa se persiste en la URL con replaceState (mismo patrón que ?task=N). Al montar, lee ?view= de la URL para restaurar la vista.
// TaskManager.tsx — deep-link view
useEffect(() => {
const v = params.get('view');
if (v === 'comments' || v === 'board' || v === 'list' || v === 'calendar') {
setView(v as View);
}
}, []);
Item 4 — Botón “Nueva” del widget abre modal nueva tarea
DesktopA.tsx: el <a> del widget KanbanMini cambió de href="/tasks" a href="/tasks?task=new". El texto también cambió de "Nueva" a "+ Nueva". TaskManager ya leía ?task=new para abrir el modal de creación (patrón s69).
Item 5 — Enlace nota → modal tarea
TaskModal.createAndLinkNote ahora inyecta un markdown link al inicio del content de la nota recién creada, solo cuando la tarea ya existe (modo edit, task.id disponible):
const initialContent = task?.id
? `[Nota asociada a tarea #${task.id}](/tasks?task=${task.id})\n\n`
: '';
En preview markdown el link es clickable y navega a /tasks?task=N, donde el deep-link (fix Item 1) abre el modal. El word_count se calcula dinámicamente sobre initialContent.
Estilos añadidos (globals.css)
/* Badge comentarios */
.task-link-badge-comment {
background: color-mix(in srgb, var(--accent-2) 14%, transparent);
color: var(--accent-2);
}
/* Card gestor transversal de comentarios */
.task-comment-card {
background: var(--bg-raised);
border: 1px solid var(--border-soft);
border-left: 3px solid var(--accent-2);
border-radius: var(--radius);
padding: 10px 14px;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
}
.task-comment-card:hover {
background: var(--bg-raised-2, var(--bg-raised));
border-color: var(--accent-2);
}
Archivos modificados
| Archivo | Tipo | Descripción |
|---|---|---|
functions/api/tasks/comments.ts | Nuevo | Endpoint GET /api/tasks/comments |
functions/api/tasks/index.ts | Modificado | +comment_count subquery |
src/components/tasks/TaskCommentsView.tsx | Nuevo | Vista gestor comentarios (333 LOC) |
src/components/tasks/TaskKanban.tsx | Modificado | +badge comentarios |
src/components/tasks/TaskManager.tsx | Modificado | +vista comments, fix race condition, URL sync |
src/components/tasks/TaskModal.tsx | Modificado | +comment_count, enlace nota→tarea |
src/components/variants/desktop/DesktopA.tsx | Modificado | href widget → ?task=new |
src/components/widgets/KanbanMini.tsx | Modificado | +badge comentarios |
src/lib/types.ts | Modificado | +comment_count en interface Task |
src/styles/globals.css | Modificado | +.task-link-badge-comment, +.task-comment-card |
Véase también
- [[entity—tasks—endpoint—comments]]
- [[workspace—tareas-notas]]
- [[workspace—que-es-workspace]]