import PlusIcon from "../icons/plusIcon"; import { useMemo, useState } from "react"; import ColumnContainer from "./columnContainer"; import { DndContext, DragOverlay, PointerSensor, useSensor, useSensors, } from "@dnd-kit/core"; import { SortableContext, arrayMove } from "@dnd-kit/sortable"; import { createPortal } from "react-dom"; import TaskCard from "./taskCard"; const defaultCols = [ { id: "todo", title: "Todo", }, { id: "doing", title: "Work in progress", }, { id: "done", title: "Done", }, ]; const defaultTasks = [ { id: "1", columnId: "todo", content: "List admin APIs for dashboard", }, { id: "2", columnId: "todo", content: "Develop user registration functionality with OTP delivered on SMS after email confirmation and phone number confirmation", }, { id: "3", columnId: "doing", content: "Conduct security testing", }, { id: "4", columnId: "doing", content: "Analyze competitors", }, { id: "5", columnId: "done", content: "Create UI kit documentation", }, { id: "6", columnId: "done", content: "Dev meeting", }, { id: "7", columnId: "done", content: "Deliver dashboard prototype", }, { id: "8", columnId: "todo", content: "Optimize application performance", }, { id: "9", columnId: "todo", content: "Implement data validation", }, { id: "10", columnId: "todo", content: "Design database schema", }, { id: "11", columnId: "todo", content: "Integrate SSL web certificates into workflow", }, { id: "12", columnId: "doing", content: "Implement error logging and monitoring", }, { id: "13", columnId: "doing", content: "Design and implement responsive UI", }, ]; function KanbanBoard() { const [columns, setColumns] = useState(defaultCols); const columnsId = useMemo(() => columns.map((col) => col.id), [columns]); const [tasks, setTasks] = useState(defaultTasks); const [activeColumn, setActiveColumn] = useState(null); const [activeTask, setActiveTask] = useState(null); const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 10, }, }) ); return (
{columns.map((col) => ( task.columnId === col.id)} /> ))}
{/* create new column */}
{createPortal( {activeColumn && ( task.columnId === activeColumn.id )} /> )} {activeTask && ( )} , document.body )}
); function createTask(columnId) { const newTask = { id: generateId(), columnId, content: `Task ${tasks.length + 1}`, }; setTasks([...tasks, newTask]); } function deleteTask(id) { const newTasks = tasks.filter((task) => task.id !== id); setTasks(newTasks); } function updateTask(id, content) { const newTasks = tasks.map((task) => { if (task.id !== id) return task; return { ...task, content }; }); if (content === "") return deleteTask(id); setTasks(newTasks); } function createNewColumn() { const columnToAdd = { id: generateId(), title: `Column ${columns.length + 1}`, }; setColumns([...columns, columnToAdd]); } function deleteColumn(id) { const filteredColumns = columns.filter((col) => col.id !== id); setColumns(filteredColumns); const newTasks = tasks.filter((t) => t.columnId !== id); setTasks(newTasks); } function updateColumn(id, title) { const newColumns = columns.map((col) => { if (col.id !== id) return col; return { ...col, title }; }); setColumns(newColumns); } function onDragStart(event) { if (event.active.data.current?.type === "Column") { setActiveColumn(event.active.data.current.column); return; } if (event.active.data.current?.type === "Task") { setActiveTask(event.active.data.current.task); return; } } function onDragEnd(event) { setActiveColumn(null); setActiveTask(null); const { active, over } = event; if (!over) return; const activeId = active.id; const overId = over.id; if (activeId === overId) return; const isActiveAColumn = active.data.current?.type === "Column"; if (!isActiveAColumn) return; setColumns((columns) => { const activeColumnIndex = columns.findIndex((col) => col.id === activeId); const overColumnIndex = columns.findIndex((col) => col.id === overId); return arrayMove(columns, activeColumnIndex, overColumnIndex); }); } function onDragOver(event) { const { active, over } = event; if (!over) return; const activeId = active.id; const overId = over.id; if (activeId === overId) return; const isActiveATask = active.data.current?.type === "Task"; const isOverATask = over.data.current?.type === "Task"; if (!isActiveATask) return; if (isActiveATask && isOverATask) { setTasks((tasks) => { const activeIndex = tasks.findIndex((t) => t.id === activeId); const overIndex = tasks.findIndex((t) => t.id === overId); if (tasks[activeIndex].columnId !== tasks[overIndex].columnId) { tasks[activeIndex].columnId = tasks[overIndex].columnId; return arrayMove(tasks, activeIndex, overIndex - 1); } return arrayMove(tasks, activeIndex, overIndex); }); } const isOverAColumn = over.data.current?.type === "Column"; if (isActiveATask && isOverAColumn) { setTasks((tasks) => { const activeIndex = tasks.findIndex((t) => t.id === activeId); tasks[activeIndex].columnId = overId; return arrayMove(tasks, activeIndex, activeIndex); }); } } function generateId() { return Math.floor(Math.random() * 10001); } } export default KanbanBoard;