import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd' import type { DropResult } from '@hello-pangea/dnd' import { AlertCircle, CheckCircle2, Clock, List, MoreVertical, Plus, XCircle, } from 'lucide-react' import { useEffect, useRef, useState } from 'react' import { Link, useNavigate } from 'react-router-dom' import { taskService } from '../services/taskService' import { projectService } from '../services/projectService' import type { Project } from '../services/projectService' import { categoryService } from '../services/categoryService' import type { Category } from '../types/category' import { cn } from '../lib/utils' import type { TaskResponse, TaskStatus } from '../types/task' import { TaskTimer } from '../components/TaskTimer' import { TaskFilterBar } from '../components/TaskFilterBar' import { DEFAULT_TASK_FILTERS, type TaskFilters } from '../components/taskFilters' import { CategoryBadge } from '../components/CategoryBadge' import { useAuth } from '../contexts/AuthContext' const COLUMNS: { id: TaskStatus; label: string; icon: any; color: string }[] = [ { id: 'NOT_STARTED', label: 'Pendente', icon: AlertCircle, color: 'text-text-muted' }, { id: 'IN_PROGRESS', label: 'Em Andamento', icon: Clock, color: 'text-warning' }, { id: 'COMPLETED', label: 'ConcluĂ­da', icon: CheckCircle2, color: 'text-success' }, { id: 'CANCELED', label: 'Cancelada', icon: XCircle, color: 'text-danger' }, ] export function TaskBoardPage() { const [tasks, setTasks] = useState([]) const [isLoading, setIsLoading] = useState(true) const [projects, setProjects] = useState([]) const [categories, setCategories] = useState([]) const [filters, setFilters] = useState(DEFAULT_TASK_FILTERS) const navigate = useNavigate() const { activeOrg } = useAuth() const debounceRef = useRef | null>(null) const loadTasks = async (currentFilters: TaskFilters, silent = false) => { if (!silent) setIsLoading(true) try { const response = await taskService.getMyTasks({ text: currentFilters.searchQuery || undefined, projectIds: currentFilters.projectIds.length > 0 ? currentFilters.projectIds : undefined, statuses: currentFilters.statuses.length > 0 ? currentFilters.statuses : undefined, categoryIds: currentFilters.categoryIds.length > 0 ? currentFilters.categoryIds : undefined, }) setTasks(response) } catch (error) { console.error('Erro ao carregar tarefas', error) } finally { setIsLoading(false) } } useEffect(() => { void loadTasks(filters) if (activeOrg) { projectService.listByOrganization(activeOrg.id).then(setProjects).catch(() => {}) categoryService.listByOrganization(activeOrg.id).then(setCategories).catch(() => {}) } }, []) const handleFiltersChange = (newFilters: TaskFilters) => { setFilters(newFilters) if (debounceRef.current) clearTimeout(debounceRef.current) debounceRef.current = setTimeout(() => { void loadTasks(newFilters) }, 300) } const onDragEnd = async (result: DropResult) => { const { destination, source, draggableId } = result if (!destination) return if ( destination.droppableId === source.droppableId && destination.index === source.index ) { return } const taskId = Number.parseInt(draggableId) const newStatus = destination.droppableId as TaskStatus const updatedTasks = tasks.map((t) => t.id === taskId ? { ...t, status: newStatus } : t, ) setTasks(updatedTasks) try { await taskService.updateTaskStatus(taskId, newStatus) } catch (error) { console.error('Erro ao atualizar status da tarefa', error) void loadTasks(filters, true) } } const tasksByStatus = (status: TaskStatus) => tasks.filter((t) => t.status === status) return (

Quadro Kanban

Arraste e solte as tarefas para atualizar o progresso.

Lista Quadro
Nova Tarefa
void loadTasks(filters)} />
{COLUMNS.map((column) => (

{column.label}

{tasksByStatus(column.id).length}
{(provided, snapshot) => (
{tasksByStatus(column.id).map((task, index) => ( {(provided, snapshot) => (
navigate(`/edit/${task.id}`)} className={cn( 'group cursor-pointer rounded-2xl border border-border-soft bg-surface p-4 shadow-sm transition-all', snapshot.isDragging ? 'shadow-2xl ring-2 ring-brand/20' : 'hover:border-brand/30', )} >

{task.title}

{task.description && (

{task.description}

)}
loadTasks(filters, true)} />
{task.project?.name || 'Geral'}
#{task.id}
)}
))} {provided.placeholder}
)}
))}
) }