Blog
Feature
8 de marzo de 202610 min

Cómo construir una agenda colaborativa con filtros

La agenda de TAMSIV comenzó como un componente simple: una lista de eventos, un calendario, una vista de día. Y luego llegaron los grupos colaborativos. De repente, un evento ya no era personal, podía tener participantes, invitaciones, estados. Y con 15 personas en un grupo activo, la agenda se volvió ilegible sin filtros.

Tuve que repensar todo el sistema: sistema de participantes con invitaciones y notificaciones, filtros avanzados para navegar por el flujo, eventos de varios días y una superposición privada para ver los compromisos personales en el contexto del grupo. La agenda se convirtió en el componente más complejo de TAMSIV, pero también el más útil en el día a día.

Puntos clave a recordar:
- Una agenda colaborativa requiere un sistema de participantes con estados (invitado, aceptado, rechazado)
- Los filtros avanzados son indispensables tan pronto como la actividad del grupo supera los 10 eventos/semana
- Los eventos de varios días requieren un cálculo de intervalos con gestión de zonas horarias
- La superposición privada en la agenda del grupo preserva la confidencialidad y evita conflictos
- 5 vistas de calendario (día, 3 días, semana, mes, lista) cubren todos los casos de uso

¿Por qué una agenda personal no es suficiente en una aplicación colaborativa?

Mientras TAMSIV fue una aplicación estrictamente personal, la agenda era simple. Tú creas un evento, lo ves en tu calendario, punto. Pero cuando agregué los grupos jerárquicos, todo cambió.

En un grupo (familia, equipo, asociación), los eventos se comparten. Una reunión, una cena familiar, un partido deportivo, todos deben verlo. Pero no todos quieren ver todos los eventos. El gerente quiere ver las reuniones de su equipo, no las salidas del grupo de bolos. El padre quiere ver las actividades de los niños, no las reuniones profesionales de su cónyuge.

Ahí es donde los filtros y el sistema de participantes se vuelven esenciales. Sin ellos, la agenda colaborativa es un ruido inútil.

Equipo de profesionales mirando un gran calendario digital con bloques de eventos de colores y avatares de participantes
Una agenda compartida sin filtros se vuelve rápidamente inutilizable en un grupo activo.

¿Cómo funciona el sistema de participantes en TAMSIV?

Cada evento en TAMSIV puede tener participantes invitados entre los miembros del grupo. La arquitectura se basa en una tabla de unión en el esquema collaborative:

-- Tabla simplificada
calendar_event_participants (
  id UUID PRIMARY KEY,
  event_id UUID REFERENCES privat.calendar_events,
  user_id UUID REFERENCES auth.users,
  status TEXT CHECK (status IN ('invited', 'accepted', 'declined')),
  invited_at TIMESTAMPTZ,
  responded_at TIMESTAMPTZ
)

El flujo de invitación es el siguiente:

  1. El creador añade participantes durante la creación o edición del evento. Elige entre los miembros del grupo a través de un selector.
  2. Notificación push: Cada participante invitado recibe una notificación FCM con el título del evento, la fecha y un botón para aceptar o rechazar.
  3. Respuesta: El participante acepta o rechaza. Su estado se actualiza en tiempo real en la base de datos.
  4. Visibilidad: El evento aparece en la agenda de todos los participantes (invitados, aceptados). Los rechazados ya no lo ven (a menos que cambien de opinión).

Es un flujo similar al que encuentras en Google Calendar, pero adaptado al contexto de grupos jerárquicos de TAMSIV. La principal diferencia: los participantes están limitados a los miembros del grupo, no a cualquier dirección de correo electrónico.

¿Qué filtros avanzados son indispensables en una agenda de grupo?

La FilterBar de la agenda ofrece tres modos de filtrado:

  • "Todos": Muestra todos los eventos del grupo. Útil para tener una visión general, pero rápidamente ruidoso en un grupo activo.
  • "Mis creaciones": Muestra solo los eventos que tú has creado. Útil para verificar que tus propios eventos están bien planificados.
  • "Participando": Muestra solo los eventos en los que tú eres participante (invitado o aceptado). Este es el modo más utilizado, responde a la pregunta "¿A qué debo asistir?".

Estos filtros se aplican en tiempo real, sin recargar la página. El ContentCacheService almacena los eventos en caché, y los filtros operan en el lado del cliente sobre los datos en caché. El resultado: un cambio de filtro es instantáneo, incluso con cientos de eventos.

Además de los filtros por participación, la FilterBar ofrece los 3 contextos clásicos de TAMSIV:

  • Privado: Solo tus eventos personales
  • Compartido: Eventos de los grupos a los que perteneces
  • Todo: Fusión de ambas vistas

Estos filtros son coherentes con los del feed y las tareas. El usuario encuentra los mismos paradigmas de navegación en toda la aplicación.

¿Cómo gestionar los eventos de varios días en un componente de calendario?

Un evento "Conferencia lunes→miércoles" debe aparecer durante 3 días en la vista de calendario. Parece trivial, pero la implementación está llena de trampas.

El componente AgendaView calcula los intervalos, la duración en días de cada evento. Para cada día mostrado, determina qué eventos lo cubren y los posiciona visualmente:

  • Vista de día: El evento de varios días aparece como una banda en la parte superior, por encima de los eventos por hora.
  • Vista de semana: El evento se extiende horizontalmente sobre las columnas correspondientes a los días cubiertos.
  • Vista de mes: Mismo principio, con un sistema de truncamiento si demasiados eventos se superponen.
  • Vista de lista: El evento aparece una sola vez, con sus fechas de inicio y fin.

La principal trampa: las zonas horarias en los límites del día. Un evento que comienza a las 23h del lunes en UTC+1 y termina a las 2h del martes, ¿cubre 1 o 2 días? La respuesta depende de la zona horaria del usuario. Opté por una lógica simple: un evento cubre un día si tiene al menos una hora de presencia en ese día, en la zona horaria local del usuario.

Pantalla de teléfono móvil mostrando una aplicación de calendario con eventos de varios días y botones de filtro
Los eventos de varios días se extienden visualmente sobre los días correspondientes en cada vista.

¿Qué es la superposición privada y por qué es esencial?

Aquí está el escenario: estás en la agenda de tu grupo profesional. Quieres programar una reunión el martes a las 14h. Pero el martes a las 14h, tienes una cita médica personal. ¿Cómo saberlo sin salir de la agenda del grupo?

Ese es el papel de la superposición privada. En la agenda del grupo, tus eventos personales aparecen de forma transparente, en gris. No son clicables, no hay detalles visibles, solo un bloque para indicar "ya tienes algo aquí".

Las reglas de la superposición:

  • Visible solo para ti: Los otros miembros del grupo no ven tus eventos privados.
  • No interactivo: Sin clic, sin detalles, sin modificación desde la vista de grupo.
  • Visual discreto: Opacidad reducida (30%), color gris, sin título visible. Solo un indicador de "espacio ocupado".
  • Desactivable: Un interruptor en la configuración permite ocultar la superposición si no la quieres.

Esta superposición respeta la confidencialidad al tiempo que evita conflictos de horario. Es un patrón que tomé de Google Calendar (que muestra "Ocupado" para los eventos de otros), adaptado al contexto de un grupo donde la vida privada es importante.

¿Cómo cubren las 5 vistas de calendario todos los casos de uso?

TAMSIV ofrece 5 vistas de calendario, cada una adaptada a una necesidad diferente:

  1. Vista de día: Línea de tiempo hora por hora. Ideal para planificar un día ajetreado, ver los huecos libres. Se utiliza cuando buscas "¿Cuándo estoy libre hoy?".
  2. Vista de 3 días: Compromiso entre el detalle del día y la visión de la semana. Mi favorita para la planificación a corto plazo. Ves hoy + los 2 próximos días.
  3. Vista de semana: La vista clásica de negocios. 7 columnas, cada día visible. Útil para equipos que planifican semanalmente.
  4. Vista de mes: Vista general. Los eventos son puntos de colores. Útil para identificar períodos ocupados y días libres. Coherente con la visión de productividad de la aplicación.
  5. Vista de lista: Lista cronológica simple. Sin cuadrícula, sin posicionamiento. Útil en dispositivos móviles cuando la vista de semana es demasiado pequeña, o para exportar/compartir.

Cada vista conserva la fecha actual al cambiar de vista. Si estás en el miércoles 15 en la vista de día y cambias a la vista de semana, ves la semana del 15. El deslizamiento horizontal permite navegar en el tiempo (día anterior/siguiente, semana anterior/siguiente).

Vista compartida mostrando una superposición de calendario personal en transparencia sobre un calendario de equipo
La superposición privada muestra tus compromisos personales de forma transparente en la agenda del grupo.

¿Cómo interactúa la agenda con el pipeline de voz de TAMSIV?

Uno de los puntos fuertes de TAMSIV es la creación de eventos por voz. Tú dices "Añade una reunión con Marc el próximo martes a las 14h" y el dictáfono crea el evento. El backend utiliza la herramienta de función create_calendar_event para extraer la fecha, la hora, el título y los participantes mencionados.

El sistema de PendingCreation también se aplica a los eventos: la IA crea una vista previa, el usuario puede editar los detalles (añadir participantes, modificar la hora) antes de validar. Esto evita errores de transcripción: "martes" vs "miércoles" es un error STT clásico.

Una vez creado el evento, la caché en tiempo real propaga el cambio: todos los participantes ven el evento aparecer en su agenda sin necesidad de actualizar. La notificación push se envía en paralelo. Todo el flujo (voz → IA → creación → notificación → visualización) tarda aproximadamente 3 segundos.

¿Cuáles fueron las principales dificultades técnicas?

La agenda es el componente más complejo de TAMSIV. Aquí están los principales desafíos que encontré:

  • Rendimiento de renderizado: La vista semanal con más de 50 eventos y la superposición privada deben permanecer fluidas. Tuve que usar React.memo agresivamente y virtualizar las listas de eventos en la vista de lista.
  • Gestión del desplazamiento: El deslizamiento horizontal para navegar entre días/semanas entra en conflicto con el desplazamiento vertical de la línea de tiempo. Utilicé un GestureDetector de react-native-gesture-handler con umbrales de dirección para desambiguar.
  • Eventos apilados: Cuando 3 eventos se superponen en el mismo intervalo, es necesario disponerlos uno al lado del otro en la línea de tiempo. El algoritmo de diseño de eventos apilados no es trivial, es un problema de programación de intervalos.
  • RLS Supabase: Las políticas de seguridad a nivel de fila (Row Level Security) para los eventos de grupo son complejas. Un evento es visible si: tú lo creaste, O tú eres participante, O tú eres miembro del grupo y el evento es público. Tres condiciones OR en una sola política RLS.

¿Cómo se extiende esta arquitectura a futuras necesidades?

La arquitectura actual está diseñada para evolucionar. Aquí están las extensiones previstas en la hoja de ruta:

  • Recurrencia: Eventos recurrentes (todos los lunes, el 1º de cada mes). El esquema de la base de datos está listo, el frontend aún no.
  • Sincronización de calendario externo: Importación/exportación iCal para sincronizar con Google Calendar, Outlook, Apple Calendar.
  • Disponibilidad compartida: Mostrar los intervalos de disponibilidad de los miembros del grupo para facilitar la planificación.
  • Recordatorios personalizados: Cada participante puede configurar sus propios recordatorios (5 min antes, 1h antes, el día anterior).

Preguntas frecuentes

¿Se pueden invitar participantes de fuera del grupo?

Actualmente no. Los participantes están limitados a los miembros del grupo en el que se crea el evento. Es una elección deliberada para simplificar la gestión de permisos. La invitación por correo electrónico (como Google Calendar) está prevista en una versión futura.

¿Cómo funcionan las notificaciones de invitación?

Las invitaciones activan una notificación push a través de Firebase Cloud Messaging. El participante recibe el título del evento, la fecha/hora, y puede aceptar o rechazar directamente desde la notificación (botones de acción FCM). La respuesta se registra en tiempo real en Supabase.

¿La superposición privada funciona en todas las vistas?

Sí, la superposición privada está activa en las 5 vistas (día, 3 días, semana, mes, lista). En la vista de mes, los eventos privados aparecen como puntos grises discretos. En las vistas temporales (día, semana), aparecen como bloques transparentes.

¿La agenda de TAMSIV reemplaza a Google Calendar?

No, lo complementa. La agenda de TAMSIV está diseñada para la gestión de tareas y proyectos colaborativos, con la voz como modo de interacción principal. Google Calendar sigue siendo más adecuado para la gestión de calendarios puros (recurrencias complejas, sincronización multidispositivo). La sincronización entre ambos está en la hoja de ruta.

¿Se puede crear un evento por voz con participantes?

Sí. Puedes decir "Reunión con Marc y Sophie el viernes a las 10h" y la IA detectará los participantes mencionados, siempre que sean miembros del grupo activo. El sistema de PendingCreation te permite verificar y ajustar los participantes antes de la validación.