/** * @file app/(app)/dashboard/Board.tsx * @description Client component wrapping the columns grid, tracking individual task update/deletion states, and handling asynchronous mutations via API with cache revalidation. */ "use client"; import { useState, useTransition } from "react"; import { useRouter } from "next/navigation"; import Column from "./column/Column"; import { COLUMNS, Task, TaskStatus } from "@/lib/types/task"; import Header from "./header/Header"; import { mutate } from "swr"; import TaskDetailModal from "./modal/TaskModal"; /** * Renders the responsive grid container of columns, coordinating state tracking * for active task updates/deletions, and triggering mutation API requests. * * @param {Object} props - The component props. * @param {Task[]} props.tasks - The array of task items displayed across the board. * @returns {JSX.Element} The rendered board component. */ export default function Board({ tasks }: { tasks: Task[] }) { const router = useRouter(); const [, startTransition] = useTransition(); const [selectedTask, setSelectedTask] = useState(null); const [updatingTaskIds, setUpdatingTaskIds] = useState>( new Set(), ); /** * Updates the status of a specific task by sending a PATCH request to the API, * managing loading states, triggering SWR cache mutations for the trash count, and refreshing the router upon success. * * @param {string} taskId - The unique identifier of the task to update. * @param {TaskStatus} targetStatus - The new target status for the task. */ const updateTaskStatus = (taskId: string, targetStatus: TaskStatus) => { setUpdatingTaskIds((prev) => new Set(prev).add(taskId)); startTransition(async () => { try { const response = await fetch(`/api/tasks/${taskId}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ status: targetStatus }), }); if (!response.ok) { throw new Error("Failed to update task status"); } mutate("/api/trash/count"); await router.refresh(); } catch (error) { console.error("Error during task status update:", error); } finally { setUpdatingTaskIds((prev) => { const next = new Set(prev); next.delete(taskId); return next; }); } }); }; /** * Deletes a specific task by sending a DELETE request to the API, * managing loading states, triggering SWR cache mutations for the trash count, and refreshing the router upon success. * * @param {string} taskId - The unique identifier of the task to delete. */ const deleteTask = (taskId: string) => { setUpdatingTaskIds((prev) => new Set(prev).add(taskId)); startTransition(async () => { try { const response = await fetch(`/api/tasks/${taskId}`, { method: "DELETE", }); if (!response.ok) throw new Error("Failed to delete task"); mutate("/api/trash/count"); await router.refresh(); } catch (error) { console.error("Error during task deletion:", error); } finally { setUpdatingTaskIds((prev) => { const next = new Set(prev); next.delete(taskId); return next; }); } }); }; return (
{/* Workspace Header */}
{/* Columns Grid */}
{COLUMNS.map((col) => { const columnTasks = tasks.filter((t) => t.status === col.id); return ( setSelectedTask(task)} /> ); })}
{/* Detail Modal */} setSelectedTask(null)} onDelete={(taskId) => { deleteTask(taskId); setSelectedTask(null); }} />
); }