Ir al contenido

Archivar Proyecto

Sistema completo de archivado y eliminación permanente de proyectos.

  • Componente: ProjectArchiveSystem.tsx
  • Acceso: Tab “Ajustes” en detalle del proyecto
  • Card: “Gestión del Proyecto”

Propósito: Ocultar proyecto de vista principal sin eliminar datos.

Proceso:

  1. Usuario hace click en “Archivar Proyecto”
  2. Si hay tareas activas, se muestra advertencia
  3. Dialog de confirmación con contador de tareas afectadas
  4. Al confirmar:
    • Se cancelan todas las tareas activas (pending, in_progress, on_hold)
    • Se cambia estado del proyecto a archived
    • Se registra archived_at con timestamp
    • Proyecto desaparece de lista principal
  5. Toast de confirmación

Efectos en Tareas:

// Cancelar tareas activas
await supabase
.from('tasks')
.update({ status: 'cancelled' })
.eq('project_id', project.id)
.in('status', ['pending', 'in_progress', 'on_hold']);

Advertencia Previa:

  • Si activeTasks > 0: Muestra card amarilla
  • “Este proyecto tiene N tarea(s) activa(s)”
  • “Al archivar el proyecto, estas tareas serán canceladas automáticamente”

Disponible: Solo para proyectos archivados

Proceso:

  1. Card muestra “Este proyecto está archivado”
  2. Botón “Restaurar Proyecto”
  3. Al confirmar:
    • Se cambia estado a active
    • Se limpia archived_at
    • Proyecto vuelve a lista principal
    • Las tareas NO se restauran automáticamente
  4. Toast de confirmación

Nota: Las tareas permanecen canceladas. Usuario debe reactivarlas manualmente si es necesario.

Disponible: Solo para proyectos archivados

Proceso Destructivo:

  1. Botón rojo “Eliminar Permanentemente”
  2. Dialog de confirmación con advertencia severa
  3. Lista de todo lo que se eliminará
  4. Requiere confirmación explícita
  5. Eliminación en cascada:
    1. Comentarios de tareas → task_comments
    2. Registros de tiempo de tareas → task_time_entries
    3. Adjuntos de tareas → task_attachments
    4. Tareas → tasks
    5. Hitos → project_milestones
    6. Recursos → project_resources
    7. Documentos → project_documents
    8. Actividades → project_activities
    9. Registros de tiempo → project_time_entries
    10. Items de presupuesto → project_budget_items
    11. Miembros del equipo → project_team_members
    12. Proyecto → projects
  6. Redirección a /projects

Advertencia Mostrada:

⚠️ Esta acción eliminará permanentemente el proyecto "{nombre}"
y no se puede deshacer.
Se eliminarán:
• El proyecto y toda su información
• Todas las tareas asociadas
• Comentarios y registros de tiempo
• Hitos y recursos del proyecto
• Documentos y actividades
┌─────────────────────────────┐
│ Gestión del Proyecto │
├─────────────────────────────┤
│ ⚠️ Atención │
│ Este proyecto tiene 5 │
│ tareas activas. Al │
│ archivar el proyecto, │
│ estas tareas serán │
│ canceladas automáticamente. │
│ │
│ [Archivar Proyecto] │
└─────────────────────────────┘
┌─────────────────────────────┐
│ Gestión del Proyecto │
├─────────────────────────────┤
│ 📦 Este proyecto está │
│ archivado │
│ │
│ [Restaurar Proyecto] │
│ [Eliminar Permanentemente] │
└─────────────────────────────┘

Archivado:

  • ✅ Reversible
  • ✅ Mantiene todos los datos
  • ✅ Tareas se cancelan automáticamente
  • ✅ Facturas asociadas NO se afectan
  • ✅ Historial se preserva

Eliminación:

  • ❌ Irreversible
  • ❌ Elimina TODOS los datos relacionados
  • ❌ No se pueden recuperar
  • ⚠️ Facturas se mantienen (son independientes)
  • ⚠️ Requiere que el proyecto esté archivado primero
Proyecto Activo
↓ (Finalizar trabajo)
Marcar como Completado
↓ (Después de tiempo)
Archivar Proyecto
↓ (Si ya no es necesario)
Eliminar Permanentemente
Código de eliminación en cascada
// ProjectArchiveSystem.tsx - Delete mutation
const deleteProjectMutation = useMutation({
mutationFn: async () => {
// 1. Obtener IDs de tareas
const taskIds = (await supabase
.from('tasks')
.select('id')
.eq('project_id', project.id)
).data?.map(t => t.id) || [];
// 2. Eliminar comentarios de tareas
await supabase
.from('task_comments')
.delete()
.in('task_id', taskIds);
// 3. Eliminar registros de tiempo de tareas
await supabase
.from('task_time_entries')
.delete()
.in('task_id', taskIds);
// 4. Eliminar adjuntos de tareas
await supabase
.from('task_attachments')
.delete()
.in('task_id', taskIds);
// 5. Eliminar tareas
await supabase
.from('tasks')
.delete()
.eq('project_id', project.id);
// 6-11. Eliminar datos del proyecto
await supabase.from('project_milestones').delete().eq('project_id', project.id);
await supabase.from('project_resources').delete().eq('project_id', project.id);
await supabase.from('project_documents').delete().eq('project_id', project.id);
await supabase.from('project_activities').delete().eq('project_id', project.id);
await supabase.from('project_time_entries').delete().eq('project_id', project.id);
await supabase.from('project_budget_items').delete().eq('project_id', project.id);
await supabase.from('project_team_members').delete().eq('project_id', project.id);
// 12. Eliminar proyecto
const { error } = await supabase
.from('projects')
.delete()
.eq('id', project.id);
if (error) throw error;
},
onSuccess: () => {
toast({ title: "Proyecto eliminado" });
window.location.href = '/projects';
}
});