Skip to content

Commit 4568620

Browse files
authored
Merge pull request #4060 from Northeastern-Electric-Racing/#4020-improved-task-dragging
#4020 improved task dragging
2 parents dcf8df3 + 6f03e1c commit 4568620

2 files changed

Lines changed: 54 additions & 19 deletions

File tree

src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/TaskList/v2/TaskColumn.tsx

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,22 @@ export const TaskColumn = ({
1313
status,
1414
tasks,
1515
project,
16+
equalizedHeight,
17+
isDragging,
1618
onEditTask,
1719
onDeleteTask,
18-
onAddTask
20+
onAddTask,
21+
onHeightChange
1922
}: {
20-
status: Task['status'];
23+
status: TaskStatus;
2124
tasks: TaskWithIndex[];
2225
project: Project;
26+
equalizedHeight: number;
27+
isDragging: boolean;
2328
onEditTask: (task: Task) => void;
2429
onDeleteTask: (taskId: string) => void;
2530
onAddTask: (task: Task) => void;
31+
onHeightChange: (status: TaskStatus, height: number) => void;
2632
}) => {
2733
const { mutateAsync: createTask } = useCreateTask();
2834
const [showCreateTaskModal, setShowCreateTaskModal] = useState(false);
@@ -62,27 +68,51 @@ export const TaskColumn = ({
6268
<Box
6369
sx={{
6470
flex: 1,
71+
display: 'flex',
72+
flexDirection: 'column',
6573
paddingTop: '8px',
6674
paddingBottom: '16px',
6775
backgroundColor: theme.palette.background.paper,
6876
marginLeft: '5px',
69-
borderRadius: '5px'
77+
borderRadius: '5px',
78+
minHeight: isDragging ? `${equalizedHeight}px` : undefined
7079
}}
7180
>
7281
<Typography align="center" variant="h5">
7382
{statusNames[status]}
7483
</Typography>
84+
<NERButton
85+
sx={{
86+
marginTop: '5px',
87+
backgroundColor: theme.palette.secondary.contrastText,
88+
width: 'calc(100% - 10px)',
89+
marginX: '5px'
90+
}}
91+
onClick={() => setShowCreateTaskModal(true)}
92+
>
93+
+ Add A Task
94+
</NERButton>
7595
<Droppable droppableId={status}>
7696
{(droppableProvided, snapshot) => (
7797
<Box
78-
ref={droppableProvided.innerRef}
98+
ref={(droppableBox: HTMLElement | null) => {
99+
droppableProvided.innerRef(droppableBox); // give dnd lib access to dom node
100+
if (!droppableBox) return;
101+
102+
const observer = new ResizeObserver(() => {
103+
onHeightChange(status, droppableBox.scrollHeight);
104+
});
105+
observer.observe(droppableBox);
106+
return () => observer.disconnect();
107+
}}
79108
{...droppableProvided.droppableProps}
80109
className={snapshot.isDraggingOver ? ' isDraggingOver' : ''}
81110
sx={{
82111
display: 'flex',
83112
flexDirection: 'column',
84113
borderRadius: 5,
85114
padding: '5px',
115+
flex: 1,
86116
'&.isDraggingOver': {
87117
bgcolor: '#dadadf'
88118
}
@@ -102,17 +132,6 @@ export const TaskColumn = ({
102132
</Box>
103133
)}
104134
</Droppable>
105-
<NERButton
106-
sx={{
107-
marginTop: '5px',
108-
backgroundColor: theme.palette.secondary.contrastText,
109-
width: 'calc(100% - 10px)',
110-
marginX: '5px'
111-
}}
112-
onClick={() => setShowCreateTaskModal(true)}
113-
>
114-
+ Add A Task
115-
</NERButton>
116135
</Box>
117136
</>
118137
);

src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/TaskList/v2/TaskListContent.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { DragDropContext, OnDragEndResponder } from '@hello-pangea/dnd';
1+
import { DragDropContext, OnDragEndResponder, OnDragStartResponder } from '@hello-pangea/dnd';
22
import { Box } from '@mui/material';
3-
import { useState } from 'react';
4-
import { Project, Task, TaskWithIndex } from 'shared';
3+
import { useCallback, useState } from 'react';
4+
import { Project, Task, TaskStatus, TaskWithIndex } from 'shared';
55
import { getTasksByStatus, statuses, TasksByStatus } from '.';
66
import { useSetTaskStatus } from '../../../../../hooks/tasks.hooks';
77
import { useToast } from '../../../../../hooks/toasts.hooks';
@@ -19,6 +19,14 @@ export const TaskListContent = ({ project }: TaskListProps) => {
1919

2020
const toast = useToast();
2121

22+
const [isDragging, setIsDragging] = useState(false);
23+
const [columnHeights, setColumnHeights] = useState<Partial<Record<TaskStatus, number>>>({});
24+
const equalizedHeight = Math.max(...(Object.values(columnHeights) as number[]));
25+
26+
const onHeightChange = useCallback((status: TaskStatus, height: number) => {
27+
setColumnHeights((prev) => ({ ...prev, [status]: height }));
28+
}, []);
29+
2230
const onDeleteTask = (taskId: string) => {
2331
setTasksByStatus((prev) => {
2432
const newTasksByStatus = { ...prev };
@@ -54,7 +62,12 @@ export const TaskListContent = ({ project }: TaskListProps) => {
5462
}));
5563
};
5664

65+
const onDragStart: OnDragStartResponder = () => {
66+
setIsDragging(true);
67+
};
68+
5769
const onDragEnd: OnDragEndResponder = async (result) => {
70+
setIsDragging(false);
5871
const { destination, source } = result;
5972

6073
if (!destination) {
@@ -110,17 +123,20 @@ export const TaskListContent = ({ project }: TaskListProps) => {
110123
};
111124

112125
return (
113-
<DragDropContext onDragEnd={onDragEnd}>
126+
<DragDropContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
114127
<Box display="flex">
115128
{statuses.map((status) => (
116129
<TaskColumn
117130
onAddTask={onAddTask}
118131
onDeleteTask={onDeleteTask}
119132
onEditTask={onEditTask}
133+
onHeightChange={onHeightChange}
120134
status={status}
121135
tasks={tasksByStatus[status]}
122136
key={status}
123137
project={project}
138+
equalizedHeight={equalizedHeight}
139+
isDragging={isDragging}
124140
/>
125141
))}
126142
</Box>

0 commit comments

Comments
 (0)