diff --git a/src/routes/tasks.index.tsx b/src/routes/tasks.index.tsx index c826086..cbb6e39 100644 --- a/src/routes/tasks.index.tsx +++ b/src/routes/tasks.index.tsx @@ -24,6 +24,7 @@ import { NewTaskDialog } from "@/components/tasks/new-task-dialog"; import { ApplyWorkflowPickerDialog } from "@/components/tasks/apply-workflow-picker-dialog"; import { cn } from "@/lib/utils"; import { spawnNextWorkflowTask } from "@/lib/workflow-chain"; +import { toast } from "sonner"; import { parseDateOnly } from "@/lib/format"; export const Route = createFileRoute("/tasks/")({ @@ -179,7 +180,20 @@ function TasksPage() { const toggleComplete = async (t: TaskRow, checked: boolean) => { if (!user) return; - await supabase + // Optimistic update so the row moves between lists immediately. + setTasks((prev) => + prev.map((row) => + row.id === t.id + ? { + ...row, + status: checked ? "complete" : "incomplete", + completed_by: checked ? user.id : null, + completed_at: checked ? (new Date().toISOString() as any) : null, + } + : row, + ), + ); + const { error } = await supabase .from("tasks") .update({ status: checked ? "complete" : "incomplete", @@ -187,6 +201,11 @@ function TasksPage() { completed_at: checked ? (new Date().toISOString() as any) : null, }) .eq("id", t.id); + if (error) { + toast.error(error.message); + load(); + return; + } await supabase.from("task_history").insert({ task_id: t.id, actor_id: user.id, @@ -196,6 +215,7 @@ function TasksPage() { if (checked) { await spawnNextWorkflowTask(t.id); } + load(); }; const overdueCount = grouped.Overdue.length;