Skip to content

Commit c44d07a

Browse files
committed
fix: drag and drop sprints
1 parent 3847ce4 commit c44d07a

1 file changed

Lines changed: 64 additions & 6 deletions

File tree

src/components/Projects/SprintBoardView.tsx

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ export const SprintBoardView: React.FC<SprintBoardViewProps> = ({
6161
const [tasks, setTasks] = useState<Task[]>([])
6262
const [epics, setEpics] = useState<Epic[]>([])
6363
const [sprints, setSprints] = useState<Sprint[]>([])
64+
const [colleagues, setColleagues] = useState<Colleague[]>([])
65+
const [users, setUsers] = useState<User[]>([])
6466
const [selectedSprintIds, setSelectedSprintIds] = useLocalStorage<string[]>(
6567
'sprintBoardView_selectedSprints',
6668
[],
@@ -70,10 +72,10 @@ export const SprintBoardView: React.FC<SprintBoardViewProps> = ({
7072
const [isAddSprintModalOpen, setIsAddSprintModalOpen] = useState(false)
7173
const [selectedTask, setSelectedTask] = useState<Task | null>(null)
7274
const [draggedTask, setDraggedTask] = useState<Task | null>(null)
73-
const [users, setUsers] = useState<User[]>([])
74-
const [colleagues, setColleagues] = useState<Colleague[]>([])
75-
const [heroHeight, setHeroHeight] = useState(0)
75+
const [dragOverSprintId, setDragOverSprintId] = useState<number | null>(null)
76+
const [dragOverBacklog, setDragOverBacklog] = useState(false)
7677
const [isSprintSelectorOpen, setIsSprintSelectorOpen] = useState(false)
78+
const [heroHeight, setHeroHeight] = useState(0)
7779

7880
const heroRef = useRef<HTMLDivElement>(null)
7981
const containerRef = useRef<HTMLDivElement>(null)
@@ -197,6 +199,50 @@ export const SprintBoardView: React.FC<SprintBoardViewProps> = ({
197199
setDraggedTask(task)
198200
}
199201

202+
const handleDragOverSprint = (e: React.DragEvent) => {
203+
e.preventDefault()
204+
e.dataTransfer.dropEffect = 'move'
205+
}
206+
207+
const handleDragOverBacklog = (e: React.DragEvent) => {
208+
e.preventDefault()
209+
e.dataTransfer.dropEffect = 'move'
210+
}
211+
212+
const handleDropOnSprint = (sprintId: number) => {
213+
if (!draggedTask) return
214+
215+
const currentSprint = extractId(draggedTask.sprint)
216+
if (currentSprint !== sprintId) {
217+
setTasks((prev) =>
218+
prev.map((task) =>
219+
task.id === draggedTask.id ? { ...task, sprint: sprintId } : task,
220+
),
221+
)
222+
onUpdateTask?.(draggedTask.id.toString(), { sprint: sprintId })
223+
}
224+
225+
setDraggedTask(null)
226+
setDragOverSprintId(null)
227+
}
228+
229+
const handleDropOnBacklog = () => {
230+
if (!draggedTask) return
231+
232+
const currentSprint = extractId(draggedTask.sprint)
233+
if (currentSprint) {
234+
setTasks((prev) =>
235+
prev.map((task) =>
236+
task.id === draggedTask.id ? { ...task, sprint: null } : task,
237+
),
238+
)
239+
onUpdateTask?.(draggedTask.id.toString(), { sprint: null })
240+
}
241+
242+
setDraggedTask(null)
243+
setDragOverBacklog(false)
244+
}
245+
200246
const handleAddTask = async (newTask: Omit<Task, 'id' | 'createdAt' | 'updatedAt'>) => {
201247
const temporaryTask: Task = {
202248
...newTask,
@@ -283,7 +329,7 @@ export const SprintBoardView: React.FC<SprintBoardViewProps> = ({
283329
const calculatedHeight =
284330
heroHeight > 0 ? `calc(100vh - ${heroHeight + 120}px)` : 'calc(100vh - 12rem)'
285331

286-
const selectedEpicIds = React.useMemo(
332+
const selectedEpicIds = React.useMemo<number[]>(
287333
() => [...epics.map((e) => e.id), 0], // include "no-epic" sentinel id 0
288334
[epics],
289335
)
@@ -482,8 +528,14 @@ export const SprintBoardView: React.FC<SprintBoardViewProps> = ({
482528
<div className="grid gap-6 h-full overflow-x-auto" style={{ gridTemplateColumns: `repeat(${visibleSprints.length + 1}, minmax(350px, 1fr))` }}>
483529
{/* Backlog Column */}
484530
<Card
485-
className="p-4 bg-card border-l-4 border-l-amber-500 shadow-sm hover:shadow-md transition-shadow duration-200 flex flex-col"
531+
className={`p-4 bg-card border-l-4 border-l-amber-500 shadow-sm hover:shadow-md transition-all duration-200 flex flex-col ${
532+
dragOverBacklog ? 'ring-2 ring-amber-500 bg-amber-50/50 dark:bg-amber-950/20' : ''
533+
}`}
486534
style={{ height: calculatedHeight }}
535+
onDragOver={handleDragOverBacklog}
536+
onDragEnter={() => setDragOverBacklog(true)}
537+
onDragLeave={() => setDragOverBacklog(false)}
538+
onDrop={handleDropOnBacklog}
487539
>
488540
{/* Column Header */}
489541
<div className="flex items-center justify-between mb-4 flex-shrink-0">
@@ -584,8 +636,14 @@ export const SprintBoardView: React.FC<SprintBoardViewProps> = ({
584636
return (
585637
<Card
586638
key={sprint.id}
587-
className="p-4 bg-card border-l-4 border-l-blue-500 shadow-sm hover:shadow-md transition-shadow duration-200 flex flex-col"
639+
className={`p-4 bg-card border-l-4 border-l-blue-500 shadow-sm hover:shadow-md transition-all duration-200 flex flex-col ${
640+
dragOverSprintId === sprint.id ? 'ring-2 ring-blue-500 bg-blue-50/50 dark:bg-blue-950/20' : ''
641+
}`}
588642
style={{ height: calculatedHeight }}
643+
onDragOver={handleDragOverSprint}
644+
onDragEnter={() => setDragOverSprintId(sprint.id)}
645+
onDragLeave={() => setDragOverSprintId(null)}
646+
onDrop={() => handleDropOnSprint(sprint.id)}
589647
>
590648
{/* Column Header */}
591649
<div className="flex items-center justify-between mb-4 flex-shrink-0">

0 commit comments

Comments
 (0)