Configurar Recurrencia
Exportar contenido
Configura tareas para que se generen automáticamente según un patrón de repetición.
Tipos de Recurrencia
Sección titulada «Tipos de Recurrencia»| Tipo | Descripción | Configuración |
|---|---|---|
| Diaria | Repetir cada N días | Intervalo: 1-365 días |
| Semanal | Repetir cada N semanas en días específicos | Intervalo: 1-52 semanas, Días: Lun-Dom |
| Mensual | Repetir cada N meses | Intervalo: 1-12 meses |
| Anual | Repetir cada N años | Intervalo: 1-10 años |
Configuración Avanzada
Sección titulada «Configuración Avanzada»Fecha de Finalización: Define cuándo dejar de generar nuevas instancias. Opcional.
Máximo de Ocurrencias: Limita cuántas instancias se generarán en total. Opcional.
Estado Activo/Pausado:
- Activa: Genera nuevas instancias automáticamente
- Pausada: Mantiene configuración pero no genera instancias
Generación Automática
Sección titulada «Generación Automática»Las nuevas instancias de tareas se generan automáticamente:
- Frecuencia: Diariamente a las 00:00 UTC
- Mecanismo: Edge Function
generate-recurring-tasks - Criterios: Solo tareas con recurrencia activa que cumplan condiciones
Al Crear Tarea:
- Abrir formulario de nueva tarea
- Ir a pestaña “Recurrencia”
- Activar switch “Hacer recurrente”
- Configurar parámetros
- Ver vista previa de próximas fechas
- Guardar
Al Editar Tarea:
- Abrir tarea existente
- Click en “Editar”
- Ir a pestaña “Recurrencia”
- Modificar configuración
- Guardar cambios
Desde Vista Tareas Recurrentes:
- Navegar a pestaña “Recurrentes”
- Ver todas las tareas con recurrencia
- Click en “Pausar” o “Reanudar” para cambiar estado
- Expandir para ver próximas fechas
Detalles Técnicos
Componente
Sección titulada «Componente»- Archivo:
TaskRecurrenceConfig.tsx - Ruta:
src/features/projects/sub-modules/tasks/components/TaskRecurrenceConfig.tsx
Tipo RecurrenceType
Sección titulada «Tipo RecurrenceType»type RecurrenceType = 'daily' | 'weekly' | 'monthly' | 'yearly';
interface TaskRecurrence { id: string; task_id: string; recurrence_type: RecurrenceType; recurrence_interval: number; recurrence_days: number[] | null; // 0=Domingo, 1=Lunes, etc. recurrence_end_date: string | null; max_occurrences: number | null; last_generated_date: string | null; is_active: boolean; created_at: string; updated_at: string;}Configuración por Tipo
Sección titulada «Configuración por Tipo»Diaria:
{ recurrence_type: 'daily', recurrence_interval: 1, // cada 1 día recurrence_days: null, recurrence_end_date: '2024-12-31', max_occurrences: null}Semanal:
{ recurrence_type: 'weekly', recurrence_interval: 2, // cada 2 semanas recurrence_days: [1, 3, 5], // Lunes, Miércoles, Viernes recurrence_end_date: null, max_occurrences: 20}Mensual:
{ recurrence_type: 'monthly', recurrence_interval: 1, // cada mes recurrence_days: null, recurrence_end_date: null, max_occurrences: 12}Mutación Guardar/Actualizar
Sección titulada «Mutación Guardar/Actualizar»const saveMutation = useMutation({ mutationFn: async () => { const configData = { task_id: taskId, recurrence_type: recurrenceType, recurrence_interval: interval, recurrence_days: recurrenceType === 'weekly' ? selectedDays : null, recurrence_end_date: endDate || null, max_occurrences: maxOccurrences || null, is_active: isActive, };
if (existingConfig) { // Actualizar await supabase .from('task_recurrence_config') .update(configData) .eq('id', existingConfig.id); } else { // Crear await supabase .from('task_recurrence_config') .insert(configData); } }});Edge Function: generate-recurring-tasks
Sección titulada «Edge Function: generate-recurring-tasks»// Ejecutada diariamente por Supabase Cron// Genera nuevas instancias de tareas recurrentes
const generateRecurringTasks = async () => { // 1. Obtener configuraciones activas const { data: configs } = await supabase .from('task_recurrence_config') .select('*, task:tasks(*)') .eq('is_active', true);
for (const config of configs) { // 2. Calcular próxima fecha según tipo const nextDate = calculateNextOccurrence(config);
// 3. Verificar condiciones if (shouldGenerate(config, nextDate)) { // 4. Crear nueva instancia await supabase.from('tasks').insert({ ...config.task, id: undefined, // Nuevo ID due_date: nextDate, status: 'pending', completed_at: null, progress: 0 });
// 5. Actualizar last_generated_date await supabase .from('task_recurrence_config') .update({ last_generated_date: nextDate }) .eq('id', config.id); } }};Componente RecurrencePreview
Sección titulada «Componente RecurrencePreview»Muestra vista previa de próximas fechas:
export function RecurrencePreview({ config, count = 5 }) { const nextOccurrences = calculateNextOccurrences(config, count);
return ( <div className="space-y-2"> <p className="text-sm font-medium">Próximas {count} fechas:</p> <ul className="space-y-1"> {nextOccurrences.map((date, i) => ( <li key={i} className="text-sm text-muted-foreground"> {format(date, "PPP", { locale: es })} </li> ))} </ul> </div> );}Tabla: task_recurrence_config
Sección titulada «Tabla: task_recurrence_config»CREATE TABLE task_recurrence_config ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, recurrence_type VARCHAR(20) NOT NULL, recurrence_interval INTEGER NOT NULL, recurrence_days INTEGER[], recurrence_end_date TIMESTAMPTZ, max_occurrences INTEGER, last_generated_date TIMESTAMPTZ, is_active BOOLEAN DEFAULT true, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(task_id));Días de la Semana (recurrence_days)
Sección titulada «Días de la Semana (recurrence_days)»const WEEKDAYS = [ { label: 'Lun', value: 1 }, { label: 'Mar', value: 2 }, { label: 'Mié', value: 3 }, { label: 'Jue', value: 4 }, { label: 'Vie', value: 5 }, { label: 'Sáb', value: 6 }, { label: 'Dom', value: 0 },];