Skip to content

lib/actividad.ts — Agregación por fecha (Actividad)

Última actualización: 06-01-2026 09:01 PM

lib/actividad.ts — Agregación por fecha (Actividad)

Section titled “lib/actividad.ts — Agregación por fecha (Actividad)”

Este módulo centraliza la lógica para construir métricas por fecha a partir de los retos:

  • Convertir/validar fechas a YYYY-MM-DD.
  • Sumar minutos por día para un proyecto o de forma global (todos los proyectos).
  • Derivar años disponibles a partir de actividad detectada.

Es una capa sin UI y sin dependencias de React, diseñada para ser:

  • testable,
  • reutilizable,
  • estable.

  • ActividadPorDia = Record<string, number>
    • key: YYYY-MM-DD
    • value: minutos acumulados ese día
  • NodoReto.fecha (string)
  • NodoReto.minutos (number)
  • (opcional) NodoReto.estado si algún consumo decide “onlyDone”.

Reglas actuales:

  • Si fecha es inválida → se ignora.
  • Si minutos es inválido o < 0 → se normaliza a 0 y se ignora si queda 0.

3.1 normalizarFechaISO(fecha?: string): string | null

Section titled “3.1 normalizarFechaISO(fecha?: string): string | null”

Responsabilidad:

  • Acepta strings con o sin tiempo (por ejemplo YYYY-MM-DDTHH:mm...).
  • Recorta a 10 chars y valida YYYY-MM-DD.
  • Valida fecha real (evita 2025-02-31).
  • Devuelve YYYY-MM-DD o null si no pasa validación.

Motivo de diseño:

  • El resto del sistema trabaja con una clave normalizada y segura.
  • Evita propagar fechas “raras” a la UI.

3.2 actividadPorDia(proyecto: Proyecto, opts?: { onlyDone?: boolean }): ActividadPorDia

Section titled “3.2 actividadPorDia(proyecto: Proyecto, opts?: { onlyDone?: boolean }): ActividadPorDia”

Responsabilidad:

  • Recorre todos los nodos del proyecto.
  • Para cada reto:
    • normaliza fecha,
    • acumula minutos en out[fecha] += minutos.
  • Si onlyDone está activo → suma solo retos estado === "done".

Complejidad:

  • O(n) sobre el total de nodos/retos del proyecto.

3.3 actividadGlobalPorDia(proyectos: Proyecto[], opts?: { onlyDone?: boolean }): ActividadPorDia

Section titled “3.3 actividadGlobalPorDia(proyectos: Proyecto[], opts?: { onlyDone?: boolean }): ActividadPorDia”

Responsabilidad:

  • Ejecuta actividadPorDia por proyecto y hace merge/suma por clave YYYY-MM-DD.
  • Resultado es global.

Uso típico:

  • Calendario global del sidebar derecho.
  • Reportes (futuro).

3.4 yearsDesdeActividad(actividad: ActividadPorDia): number[]

Section titled “3.4 yearsDesdeActividad(actividad: ActividadPorDia): number[]”

Responsabilidad:

  • Extrae el año desde las keys YYYY-MM-DD.
  • Devuelve lista ordenada desc (más reciente primero).
  • Si no hay datos → devuelve [añoActual].

normalizarFechaISO no “arregla” cosas ambiguas. Si la fecha no se puede validar con seguridad, se descarta.

Ventaja: datos confiables en UI. Costo: si el usuario mete fechas en otro formato, no se contarán (pero tampoco se rompe nada).

Se evita contaminar agregados con negativos o strings raros.


  • Fechas con tiempo: 2025-12-31T10:30:00Z2025-12-31.
  • Fecha inválida: 2025-02-31null.
  • minutos = "30" o undefined → se fuerza a número y se normaliza (si queda 0, no suma).
  • Proyectos vacíos → actividad vacía.
  • Año sin actividad → yearsDesdeActividad cae al año actual (para UI).

6) Recomendaciones de pruebas (si luego metes tests)

Section titled “6) Recomendaciones de pruebas (si luego metes tests)”

Casos mínimos:

  1. Normalización:
    • "2025-12-31""2025-12-31"
    • "2025-12-31T23:59:59""2025-12-31"
    • "2025-02-31"null
  2. Agregación:
    • 2 retos mismo día → suma correcta.
    • 2 proyectos distintos mismo día → suma global correcta.
  3. onlyDone:
    • uno done y otro todo → solo suma done.

  • No duplicar agregación en la UI.
  • No meter dependencias de UI/React aquí.
  • No asumir formatos de fecha distintos a ISO sin un plan (si se decide soportar otro formato, debe ser explícito y documentado).

  • actividadGlobalPorDia(proyectos, { onlyDone: true }) como toggle de UI.
  • Escala robusta para intensidad: percentiles/log (si hay outliers).
  • Soportar fecha en formatos no ISO (solo si realmente lo necesitas; aumenta complejidad).