Skip to content

Commit 1cf6d59

Browse files
author
ozen0718
committed
ColumnDD 적용
1 parent 373ec96 commit 1cf6d59

File tree

2 files changed

+79
-16
lines changed

2 files changed

+79
-16
lines changed

src/components/columnCard/CardList.tsx

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
import { useEffect, useRef, useState, useCallback } from "react";
2+
import {
3+
DndContext,
4+
closestCenter,
5+
PointerSensor,
6+
useSensor,
7+
useSensors,
8+
} from "@dnd-kit/core";
9+
import {
10+
SortableContext,
11+
verticalListSortingStrategy,
12+
arrayMove,
13+
} from "@dnd-kit/sortable";
214
import { CardType } from "@/types/task";
3-
import Card from "./Card";
15+
import SortableCard from "@/components/columnCard/SortableCard";
416
import { getCardsByColumn } from "@/api/card";
517

618
type CardListProps = {
@@ -25,7 +37,14 @@ export default function CardList({
2537
const observerRef = useRef<HTMLDivElement | null>(null);
2638
const isFetchingRef = useRef(false);
2739

28-
/* cursorId 업데이트 방식 변경 */
40+
const sensors = useSensors(
41+
useSensor(PointerSensor, {
42+
activationConstraint: {
43+
distance: 5,
44+
},
45+
})
46+
);
47+
2948
const fetchMoreCards = useCallback(async () => {
3049
if (isFetchingRef.current || !hasMore) return;
3150

@@ -35,7 +54,7 @@ export default function CardList({
3554
const res = await getCardsByColumn({
3655
columnId,
3756
size: ITEMS_PER_PAGE,
38-
cursorId: cursorId ?? undefined, // 최신 cursorId 사용
57+
cursorId: cursorId ?? undefined,
3958
});
4059

4160
const newCards = res.cards as CardType[];
@@ -49,7 +68,6 @@ export default function CardList({
4968
return [...prev, ...uniqueCards];
5069
});
5170

52-
// cursorId 안전하게 업데이트
5371
setCursorId((prevCursorId) => {
5472
const newCursor = newCards[newCards.length - 1]?.id ?? prevCursorId;
5573
return newCursor;
@@ -66,7 +84,6 @@ export default function CardList({
6684
}
6785
}, [columnId, cursorId, hasMore]);
6886

69-
/* 무한 스크롤 */
7087
useEffect(() => {
7188
if (!observerRef.current) return;
7289

@@ -84,17 +101,35 @@ export default function CardList({
84101
return () => observer.disconnect();
85102
}, [fetchMoreCards, hasMore]);
86103

104+
const handleDragEnd = (event: any) => {
105+
const { active, over } = event;
106+
107+
if (!over || active.id === over.id) return;
108+
109+
const oldIndex = cards.findIndex((card) => card.id === active.id);
110+
const newIndex = cards.findIndex((card) => card.id === over.id);
111+
112+
const newOrder = arrayMove(cards, oldIndex, newIndex);
113+
setCards(newOrder);
114+
};
115+
87116
return (
88-
<div className="grid gap-3 w-full grid-cols-1">
89-
{cards.map((task) => (
90-
<Card
91-
key={task.id}
92-
{...task}
93-
assignee={task.assignee}
94-
onClick={() => onCardClick(task)}
95-
/>
96-
))}
97-
{hasMore && <div ref={observerRef} className="h-20" />}
98-
</div>
117+
<DndContext
118+
sensors={sensors}
119+
collisionDetection={closestCenter}
120+
onDragEnd={handleDragEnd}
121+
>
122+
<SortableContext
123+
items={cards.map((card) => card.id)}
124+
strategy={verticalListSortingStrategy}
125+
>
126+
<div className="grid gap-3 w-full grid-cols-1">
127+
{cards.map((card) => (
128+
<SortableCard key={card.id} card={card} onClick={onCardClick} />
129+
))}
130+
{hasMore && <div ref={observerRef} className="h-20" />}
131+
</div>
132+
</SortableContext>
133+
</DndContext>
99134
);
100135
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useSortable } from "@dnd-kit/sortable";
2+
import { CSS } from "@dnd-kit/utilities";
3+
import Card from "@/components/columnCard/Card";
4+
import { CardType } from "@/types/task";
5+
6+
interface SortableCardProps {
7+
card: CardType;
8+
onClick: (card: CardType) => void;
9+
}
10+
11+
export default function SortableCard({ card, onClick }: SortableCardProps) {
12+
const { attributes, listeners, setNodeRef, transform, transition } =
13+
useSortable({
14+
id: card.id,
15+
});
16+
17+
const style = {
18+
transform: CSS.Transform.toString(transform),
19+
transition,
20+
zIndex: 5,
21+
};
22+
23+
return (
24+
<div ref={setNodeRef} style={style} {...attributes} {...listeners}>
25+
<Card {...card} onClick={() => onClick(card)} assignee={card.assignee} />
26+
</div>
27+
);
28+
}

0 commit comments

Comments
 (0)