Volver a la wiki

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ámetroTipoDescripción
authorstringAutor exacto (Edu / Dani / Txell)
target_userstringMatch en JSON array target_user_ids
task_idintTarea exacta
task_titlestringLIKE en título de la tarea
qstringLIKE en body del comentario
start_dateYYYY-MM-DDRango de fecha inicio
end_dateYYYY-MM-DDRango de fecha fin
limitintDefault 50, máx 200
offsetintDefault 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:

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

ArchivoTipoDescripción
functions/api/tasks/comments.tsNuevoEndpoint GET /api/tasks/comments
functions/api/tasks/index.tsModificado+comment_count subquery
src/components/tasks/TaskCommentsView.tsxNuevoVista gestor comentarios (333 LOC)
src/components/tasks/TaskKanban.tsxModificado+badge comentarios
src/components/tasks/TaskManager.tsxModificado+vista comments, fix race condition, URL sync
src/components/tasks/TaskModal.tsxModificado+comment_count, enlace nota→tarea
src/components/variants/desktop/DesktopA.tsxModificadohref widget → ?task=new
src/components/widgets/KanbanMini.tsxModificado+badge comentarios
src/lib/types.tsModificado+comment_count en interface Task
src/styles/globals.cssModificado+.task-link-badge-comment, +.task-comment-card

Véase también

Subir