Completely remove drag functionality of column

This commit is contained in:
sosokker 2023-11-23 13:14:24 +07:00
parent 5051f1f460
commit fd052fb613
2 changed files with 93 additions and 105 deletions

View File

@ -4,28 +4,13 @@ import { useMemo } from "react";
import { TaskCard } from "./taskCard"; import { TaskCard } from "./taskCard";
export function ColumnContainer({ column, createTask, tasks, deleteTask, updateTask }) { export function ColumnContainer({ column, createTask, tasks, deleteTask, updateTask }) {
// Memoize task IDs to prevent unnecessary recalculations
const tasksIds = useMemo(() => { const tasksIds = useMemo(() => {
return tasks.map((task) => task.id); return tasks.map((task) => task.id);
}, [tasks]); }, [tasks]);
const {
setNodeRef: columnNodeRef,
attributes: columnAttributes,
listeners: columnListeners,
} = useSortable({
id: column.id,
data: {
type: "Column",
column,
},
disabled: true, // Disable drag for the entire column
});
return ( return (
<div <div
ref={columnNodeRef}
{...columnAttributes}
{...columnListeners}
className=" className="
bg-[#f1f2f4] bg-[#f1f2f4]
w-[280px] w-[280px]
@ -49,14 +34,16 @@ export function ColumnContainer({ column, createTask, tasks, deleteTask, updateT
{/* Column task container */} {/* Column task container */}
<div className="flex flex-grow flex-col gap-2 p-1 overflow-x-hidden overflow-y-auto"> <div className="flex flex-grow flex-col gap-2 p-1 overflow-x-hidden overflow-y-auto">
{/* Provide a SortableContext for the tasks within the column */}
<SortableContext items={tasksIds}> <SortableContext items={tasksIds}>
{/* Render TaskCard for each task in the column */}
{tasks.map((task) => ( {tasks.map((task) => (
<TaskCard <TaskCard
key={task.id} key={task.id}
task={task} task={task}
deleteTask={deleteTask} deleteTask={deleteTask}
updateTask={updateTask} updateTask={updateTask}
// Adjust the useSortable hook for tasks // Adjust the useSortable hook for tasks to enable dragging
useSortable={(props) => useSortable({ ...props, disabled: false })} useSortable={(props) => useSortable({ ...props, disabled: false })}
/> />
))} ))}

View File

@ -8,14 +8,13 @@ import { axiosInstance } from "src/api/AxiosConfig";
export function KanbanBoard() { export function KanbanBoard() {
const [columns, setColumns] = useState([]); const [columns, setColumns] = useState([]);
const columnsId = useMemo(() => columns.map((col) => col.id), [columns]);
const [boardId, setBoardData] = useState(); const [boardId, setBoardData] = useState();
const [isLoading, setLoading] = useState(false); const [isLoading, setLoading] = useState(false);
const [tasks, setTasks] = useState([]); const [tasks, setTasks] = useState([]);
const [activeColumn, setActiveColumn] = useState(null);
const [activeTask, setActiveTask] = useState(null); const [activeTask, setActiveTask] = useState(null);
const columnsId = useMemo(() => columns.map((col) => col.id), [columns]);
// ---------------- END STATE INITIATE ----------------
const sensors = useSensors( const sensors = useSensors(
useSensor(PointerSensor, { useSensor(PointerSensor, {
@ -25,6 +24,76 @@ export function KanbanBoard() {
}) })
); );
// ---------------- Task Handlers ----------------
const handleTaskUpdate = (tasks, setTasks, updatedTask) => {
const updatedTasks = tasks.map((task) => (task.id === updatedTask.id ? updatedTask : task));
setTasks(updatedTasks);
};
const handleApiError = (error, action) => {
console.error(`Error ${action}:`, error);
};
const createTask = async (columnId, setTasks) => {
try {
const response = await axiosInstance.post("todo/", {
title: `Task ${tasks.length + 1}`,
importance: 1,
difficulty: 1,
challenge: false,
fromSystem: false,
is_active: false,
is_full_day_event: false,
completed: false,
priority: 1,
list_board: columnId,
});
const newTask = {
id: response.data.id,
columnId,
content: response.data.title,
};
setTasks((tasks) => [...tasks, newTask]);
} catch (error) {
handleApiError(error, "creating task");
}
};
const deleteTask = async (id, tasks, setTasks) => {
try {
await axiosInstance.delete(`todo/${id}/`);
const newTasks = tasks.filter((task) => task.id !== id);
setTasks(newTasks);
} catch (error) {
handleApiError(error, "deleting task");
}
};
const updateTask = async (id, content, tasks, setTasks) => {
try {
if (content === "") {
await deleteTask(id, tasks, setTasks);
} else {
const response = await axiosInstance.put(`todo/${id}/`, { content });
const updatedTask = {
id,
columnId: response.data.list_board,
content: response.data.title,
};
handleTaskUpdate(tasks, setTasks, updatedTask);
}
} catch (error) {
handleApiError(error, "updating task");
}
};
// ---------------- END Task Handlers ----------------
// ---------------- Fetch Data ----------------
useEffect(() => { useEffect(() => {
const fetchData = async () => { const fetchData = async () => {
try { try {
@ -88,6 +157,8 @@ export function KanbanBoard() {
fetchBoardData(); fetchBoardData();
}, []); }, []);
// ---------------- END Fetch Data ----------------
return ( return (
<div <div
className=" className="
@ -123,15 +194,6 @@ export function KanbanBoard() {
{createPortal( {createPortal(
<DragOverlay className="bg-white" dropAnimation={null} zIndex={20}> <DragOverlay className="bg-white" dropAnimation={null} zIndex={20}>
{activeColumn && (
<ColumnContainerCard
column={activeColumn}
createTask={createTask}
deleteTask={deleteTask}
updateTask={updateTask}
tasks={tasks.filter((task) => task.columnId === activeColumn.id)}
/>
)}
{activeTask && <TaskCard task={activeTask} deleteTask={deleteTask} updateTask={updateTask} />} {activeTask && <TaskCard task={activeTask} deleteTask={deleteTask} updateTask={updateTask} />}
</DragOverlay>, </DragOverlay>,
document.body document.body
@ -140,97 +202,31 @@ export function KanbanBoard() {
</div> </div>
); );
function createTask(columnId, setTasks) { // Handle the start of a drag event
const newTaskData = {
title: `Task ${tasks.length + 1}`,
importance: 1,
difficulty: 1,
challenge: false,
fromSystem: false,
is_active: false,
is_full_day_event: false,
completed: false,
priority: 1,
list_board: columnId,
};
axiosInstance
.post("todo/", newTaskData)
.then((response) => {
const newTask = {
id: response.data.id,
columnId,
content: response.data.title,
};
})
.catch((error) => {
console.error("Error creating task:", error);
});
setTasks((tasks) => [...tasks, newTask]);
}
function deleteTask(id) {
const newTasks = tasks.filter((task) => task.id !== id);
axiosInstance
.delete(`todo/${id}/`)
.then((response) => {
setTasks(newTasks);
})
.catch((error) => {
console.error("Error deleting Task:", error);
});
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 onDragStart(event) { function onDragStart(event) {
if (event.active.data.current?.type === "Column") { // Check if the dragged item is a Task
setActiveColumn(event.active.data.current.column);
return;
}
if (event.active.data.current?.type === "Task") { if (event.active.data.current?.type === "Task") {
setActiveTask(event.active.data.current.task); setActiveTask(event.active.data.current.task);
return; return;
} }
} }
// Handle the end of a drag event
function onDragEnd(event) { function onDragEnd(event) {
setActiveColumn(null); // Reset active column and task after the drag ends
setActiveTask(null); setActiveTask(null);
const { active, over } = event; const { active, over } = event;
if (!over) return; if (!over) return; // If not dropped over anything, exit
const activeId = active.id; const activeId = active.id;
const overId = over.id; const overId = over.id;
const isActiveAColumn = active.data.current?.type === "Column";
const isActiveATask = active.data.current?.type === "Task"; const isActiveATask = active.data.current?.type === "Task";
const isOverAColumn = over.data.current?.type === "Column"; const isOverAColumn = over.data.current?.type === "Column";
const isOverATask = over.data.current?.type === "Task"; const isOverATask = over.data.current?.type === "Task";
// Reorder columns if the dragged item is a column // Reorder logic for Tasks within the same column
if (isActiveAColumn && isOverAColumn) {
setColumns((columns) => {
const activeColumnIndex = columns.findIndex((col) => col.id === activeId);
const overColumnIndex = columns.findIndex((col) => col.id === overId);
const reorderedColumns = arrayMove(columns, activeColumnIndex, overColumnIndex);
return reorderedColumns;
});
}
// Reorder tasks within the same column
if (isActiveATask && isOverATask) { if (isActiveATask && isOverATask) {
setTasks((tasks) => { setTasks((tasks) => {
const activeIndex = tasks.findIndex((t) => t.id === activeId); const activeIndex = tasks.findIndex((t) => t.id === activeId);
@ -249,6 +245,7 @@ export function KanbanBoard() {
tasks[activeIndex].columnId = overId; tasks[activeIndex].columnId = overId;
// API call to update task's columnId
axiosInstance axiosInstance
.put(`todo/change_task_list_board/`, { todo_id: activeId, new_list_board_id: overId, new_index: 0 }) .put(`todo/change_task_list_board/`, { todo_id: activeId, new_list_board_id: overId, new_index: 0 })
.then((response) => {}) .then((response) => {})
@ -261,25 +258,28 @@ export function KanbanBoard() {
} }
} }
// Handle the drag-over event
function onDragOver(event) { function onDragOver(event) {
const { active, over } = event; const { active, over } = event;
if (!over) return; if (!over) return; // If not over anything, exit
const activeId = active.id; const activeId = active.id;
const overId = over.id; const overId = over.id;
if (activeId === overId) return; if (activeId === overId) return; // If over the same element, exit
const isActiveATask = active.data.current?.type === "Task"; const isActiveATask = active.data.current?.type === "Task";
const isOverATask = over.data.current?.type === "Task"; const isOverATask = over.data.current?.type === "Task";
if (!isActiveATask) return; if (!isActiveATask) return; // If not dragging a Task, exit
// Reorder logic for Tasks within the same column
if (isActiveATask && isOverATask) { if (isActiveATask && isOverATask) {
setTasks((tasks) => { setTasks((tasks) => {
const activeIndex = tasks.findIndex((t) => t.id === activeId); const activeIndex = tasks.findIndex((t) => t.id === activeId);
const overIndex = tasks.findIndex((t) => t.id === overId); const overIndex = tasks.findIndex((t) => t.id === overId);
// If moving to a different column, update columnId
if (tasks[activeIndex].columnId !== tasks[overIndex].columnId) { if (tasks[activeIndex].columnId !== tasks[overIndex].columnId) {
tasks[activeIndex].columnId = tasks[overIndex].columnId; tasks[activeIndex].columnId = tasks[overIndex].columnId;
return arrayMove(tasks, activeIndex, overIndex - 1); return arrayMove(tasks, activeIndex, overIndex - 1);
@ -291,6 +291,7 @@ export function KanbanBoard() {
const isOverAColumn = over.data.current?.type === "Column"; const isOverAColumn = over.data.current?.type === "Column";
// Move the Task to a different column and update columnId
if (isActiveATask && isOverAColumn) { if (isActiveATask && isOverAColumn) {
setTasks((tasks) => { setTasks((tasks) => {
const activeIndex = tasks.findIndex((t) => t.id === activeId); const activeIndex = tasks.findIndex((t) => t.id === activeId);