126 lines
4.2 KiB
TypeScript
126 lines
4.2 KiB
TypeScript
import { useMemo, useState, type FC } from "react";
|
|
import { useParams } from "react-router-dom";
|
|
import AddNewColumn from "./components/AddNewColumn";
|
|
import Column from "./components/Column";
|
|
import HeaderWorkspace from "./components/HeaderWorkspace";
|
|
import TaskDetailModal from "./components/task-detail/TaskDetailModal";
|
|
import tasksData from "./data/tasks.json";
|
|
import type { TaskPhaseItemType } from "./task-phase/types/TaskPhaseTypes";
|
|
import type { Task, WorkspaceData } from "./types";
|
|
import { reorderColumns } from "./utils/reorderColumns";
|
|
import { reorderTasks } from "./utils/reorderTasks";
|
|
|
|
const Workspace: FC = () => {
|
|
const { slug: projectId = "" } = useParams<{ slug: string }>();
|
|
const [columns, setColumns] = useState(
|
|
(tasksData as WorkspaceData).columns,
|
|
);
|
|
const [tasks, setTasks] = useState<Task[]>(tasksData.tasks as Task[]);
|
|
const [draggedTaskId, setDraggedTaskId] = useState<string | null>(null);
|
|
const [draggedColumnId, setDraggedColumnId] = useState<string | null>(null);
|
|
const [selectedTask, setSelectedTask] = useState<Task | null>(null);
|
|
|
|
const tasksByColumn = useMemo(() => {
|
|
return columns.reduce<Record<string, Task[]>>((acc, column) => {
|
|
acc[column.id] = tasks
|
|
.filter((task) => task.columnId === column.id)
|
|
.sort((a, b) => a.order - b.order);
|
|
return acc;
|
|
}, {});
|
|
}, [columns, tasks]);
|
|
|
|
const handleDragStart = (taskId: string) => {
|
|
setDraggedTaskId(taskId);
|
|
};
|
|
|
|
const handleDragEnd = () => {
|
|
setDraggedTaskId(null);
|
|
};
|
|
|
|
const handleDrop = (columnId: string, index: number) => {
|
|
if (!draggedTaskId) return;
|
|
setTasks((prev) => reorderTasks(prev, draggedTaskId, columnId, index));
|
|
setDraggedTaskId(null);
|
|
};
|
|
|
|
const handleColumnDragStart = (columnId: string) => {
|
|
setDraggedColumnId(columnId);
|
|
};
|
|
|
|
const handleColumnDragEnd = () => {
|
|
setDraggedColumnId(null);
|
|
};
|
|
|
|
const handleColumnDrop = (overColumnId: string) => {
|
|
if (!draggedColumnId || draggedColumnId === overColumnId) return;
|
|
setColumns((prev) => reorderColumns(prev, draggedColumnId, overColumnId));
|
|
setDraggedColumnId(null);
|
|
};
|
|
|
|
const handleColumnCreated = (phase: TaskPhaseItemType) => {
|
|
setColumns((prev) => [
|
|
...prev,
|
|
{
|
|
id: phase.id,
|
|
title: phase.name,
|
|
color: phase.color,
|
|
order: phase.order,
|
|
},
|
|
]);
|
|
};
|
|
|
|
const handleColumnDeleted = (columnId: string) => {
|
|
setColumns((prev) => prev.filter((column) => column.id !== columnId));
|
|
setTasks((prev) => prev.filter((task) => task.columnId !== columnId));
|
|
if (selectedTask?.columnId === columnId) {
|
|
setSelectedTask(null);
|
|
}
|
|
};
|
|
|
|
const selectedTaskColumn = selectedTask
|
|
? columns.find((column) => column.id === selectedTask.columnId)
|
|
: null;
|
|
|
|
return (
|
|
<div className="bg-[#01347A] h-full rounded-none xl:rounded-[32px] overflow-hidden flex flex-col">
|
|
<HeaderWorkspace />
|
|
<div className="flex-1 min-h-0 overflow-x-auto overflow-y-hidden overscroll-x-contain">
|
|
<div className="flex gap-3 sm:gap-4 xl:gap-7 px-3 sm:px-4 xl:px-8 pt-4 xl:pt-6 pb-4 xl:pb-6 h-full items-start w-max min-w-full">
|
|
{columns.map((column) => (
|
|
<Column
|
|
key={column.id}
|
|
column={column}
|
|
tasks={tasksByColumn[column.id] ?? []}
|
|
draggedTaskId={draggedTaskId}
|
|
draggedColumnId={draggedColumnId}
|
|
onDragStart={handleDragStart}
|
|
onDragEnd={handleDragEnd}
|
|
onDrop={handleDrop}
|
|
onColumnDragStart={handleColumnDragStart}
|
|
onColumnDragEnd={handleColumnDragEnd}
|
|
onColumnDrop={handleColumnDrop}
|
|
onTaskClick={setSelectedTask}
|
|
onColumnDeleted={handleColumnDeleted}
|
|
/>
|
|
))}
|
|
|
|
<AddNewColumn
|
|
projectId={projectId}
|
|
nextOrder={columns.length}
|
|
onColumnCreated={handleColumnCreated}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<TaskDetailModal
|
|
open={selectedTask !== null}
|
|
task={selectedTask}
|
|
statusLabel={selectedTaskColumn?.title ?? ""}
|
|
onClose={() => setSelectedTask(null)}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Workspace;
|