Skip to content

Commit 9dafd2c

Browse files
authored
Merge pull request #195 from part3-4team-Taskify/minji
[Refactor] Column, Card: 칼럼 삭제, 카드 생성, 삭제, 수정 즉시 반영 / 마감일 빠른 순 정렬
2 parents f4ef1c1 + e6114b7 commit 9dafd2c

File tree

8 files changed

+65
-54
lines changed

8 files changed

+65
-54
lines changed

src/components/columnCard/CardList.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ export default function CardList({
102102
return () => observer.disconnect();
103103
}, [fetchMoreCards, hasMore]);
104104

105+
useEffect(() => {
106+
setCards(initialTasks);
107+
}, [initialTasks]);
108+
105109
const handleDragEnd = (event: DragEndEvent) => {
106110
const { active, over } = event;
107111

@@ -114,18 +118,25 @@ export default function CardList({
114118
setCards(newOrder);
115119
};
116120

121+
// 마감일 빠른 순 정렬
122+
const sortedCards = [...cards].sort((a, b) => {
123+
const dateA = a.dueDate ? new Date(a.dueDate).getTime() : Infinity;
124+
const dateB = b.dueDate ? new Date(b.dueDate).getTime() : Infinity;
125+
return dateA - dateB;
126+
});
127+
117128
return (
118129
<DndContext
119130
sensors={sensors}
120131
collisionDetection={closestCenter}
121132
onDragEnd={handleDragEnd}
122133
>
123134
<SortableContext
124-
items={cards.map((card) => card.id)}
135+
items={sortedCards.map((card) => card.id)}
125136
strategy={verticalListSortingStrategy}
126137
>
127138
<div className="grid gap-3 w-full grid-cols-1">
128-
{cards.map((card) => (
139+
{sortedCards.map((card) => (
129140
<SortableCard key={card.id} card={card} onClick={onCardClick} />
130141
))}
131142
{hasMore && <div ref={observerRef} className="h-20" />}

src/components/columnCard/Column.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,17 @@ type ColumnProps = {
2020
title?: string;
2121
tasks?: CardType[];
2222
dashboardId: number;
23+
columnDelete: (columnId: number) => void;
24+
fetchColumnsAndCards: () => void;
2325
};
2426

2527
export default function Column({
2628
columnId,
2729
title = "new Task",
2830
tasks = [],
2931
dashboardId,
32+
columnDelete,
33+
fetchColumnsAndCards,
3034
}: ColumnProps) {
3135
const [columnTitle, setColumnTitle] = useState(title);
3236
const [isColumnModalOpen, setIsColumnModalOpen] = useState(false);
@@ -61,25 +65,26 @@ export default function Column({
6165

6266
const handleEditColumn = async (newTitle: string) => {
6367
if (!newTitle.trim()) {
64-
toast.error("칼럼 이름을 입력해주세요.");
68+
toast.error("칼럼 제목을 입력해주세요.");
6569
return;
6670
}
6771

6872
try {
6973
const updated = await updateColumn({ columnId, title: newTitle });
7074
setColumnTitle(updated.title);
7175
setIsColumnModalOpen(false);
72-
toast.success("칼럼이 변경되었습니다.");
76+
toast.success("칼럼 제목이 변경되었습니다.");
7377
} catch (error) {
74-
console.error("칼럼 이름 수정 실패:", error);
75-
toast.error("칼럼 변경에 실패했습니다.");
78+
console.error("칼럼 제목 수정 실패:", error);
79+
toast.error("칼럼 제목 변경에 실패했습니다.");
7680
}
7781
};
7882

7983
const handleDeleteColumn = async () => {
8084
try {
8185
await deleteColumn({ columnId });
8286
setIsDeleteModalOpen(false);
87+
if (columnDelete) columnDelete(columnId);
8388
toast.success("칼럼이 삭제되었습니다.");
8489
} catch (error) {
8590
console.error("칼럼 삭제 실패:", error);
@@ -158,6 +163,7 @@ export default function Column({
158163
dashboardId={dashboardId}
159164
columnId={columnId}
160165
members={members}
166+
updateCard={fetchColumnsAndCards}
161167
/>
162168
)}
163169

@@ -190,6 +196,7 @@ export default function Column({
190196
setIsCardDetailModalOpen(false);
191197
setSelectedCard(null);
192198
}}
199+
updateCard={fetchColumnsAndCards}
193200
/>
194201
)}
195202
</div>

src/components/modalDashboard/CardDetail.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export default function CardDetail({ card, columnName }: CardDetailProps) {
7070
{/* 설명 */}
7171
<p
7272
className="
73-
text-gray-700 p-2 break-words overflow-auto
73+
text-gray-700 p-2 overflow-auto
7474
w-full max-w-[470px] md:max-w-[349px]
7575
whitespace-pre-wrap word-break break-words
7676
h-[70px]

src/components/modalDashboard/CardDetailModal.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ import type { CardDetailType } from "@/types/cards";
1010
import TaskModal from "@/components/modalInput/TaskModal";
1111
import { useClosePopup } from "@/hooks/useClosePopup";
1212
import { getColumn } from "@/api/columns";
13-
import { useRouter } from "next/router";
1413
import { toast } from "react-toastify";
1514

1615
interface CardDetailModalProps {
1716
card: CardDetailType;
1817
currentUserId: number;
1918
dashboardId: number;
2019
onClose: () => void;
20+
updateCard: () => void;
2121
}
2222

2323
interface ColumnType {
@@ -31,14 +31,14 @@ export default function CardDetailPage({
3131
currentUserId,
3232
dashboardId,
3333
onClose,
34+
updateCard,
3435
}: CardDetailModalProps) {
3536
const [cardData, setCardData] = useState<CardDetailType>(card);
3637
const [commentText, setCommentText] = useState("");
3738
const [showMenu, setShowMenu] = useState(false);
3839
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
3940
const queryClient = useQueryClient();
4041
const popupRef = useRef(null);
41-
const router = useRouter();
4242
useClosePopup(popupRef, () => setShowMenu(false));
4343

4444
const { data: columns = [] } = useQuery<ColumnType[]>({
@@ -67,9 +67,7 @@ export default function CardDetailPage({
6767
queryClient.invalidateQueries({ queryKey: ["cards"] });
6868
toast.success("카드가 삭제되었습니다.");
6969
onClose();
70-
setTimeout(() => {
71-
router.reload();
72-
}, 1500);
70+
if (updateCard) updateCard();
7371
},
7472
});
7573

@@ -194,7 +192,7 @@ export default function CardDetailPage({
194192
imageUrl: data.image || undefined,
195193
});
196194
setIsEditModalOpen(false);
197-
router.reload();
195+
if (updateCard) updateCard();
198196
}}
199197
initialData={{
200198
status: columnName,

src/components/modalInput/CardInput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export default function CardInput({
3535
onChange={handleChange}
3636
placeholder={placeholder}
3737
className={clsx(
38-
"p-4 w-full resize-none rounded-md border border-[var(--color-gray3)] focus:border-[var(--primary)] p-1 outline-none bg-white",
38+
"p-4 w-full resize-none rounded-md border border-[var(--color-gray3)] focus:border-[var(--primary)] outline-none bg-white",
3939
small ? "text-sm" : "text-base",
4040
className
4141
)}

src/components/modalInput/ToDoModal.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import ModalInput from "@/components/modalInput/ModalInput";
55
import ModalTextarea from "@/components/modalInput/ModalTextarea";
66
import ModalImage from "@/components/modalInput/ModalImage";
77
import TextButton from "@/components/modalInput/TextButton";
8-
import { useRouter } from "next/router";
98
import { toast } from "react-toastify";
109

1110
interface TaskModalProps {
1211
isOpen: boolean;
1312
onClose: () => void;
13+
updateCard: () => void;
1414
teamId: string;
1515
dashboardId: number;
1616
columnId: number;
@@ -31,6 +31,7 @@ interface TaskData {
3131

3232
export default function TaskModal({
3333
onClose,
34+
updateCard,
3435
dashboardId,
3536
columnId,
3637
members,
@@ -44,8 +45,6 @@ export default function TaskModal({
4445
image: "",
4546
});
4647

47-
const router = useRouter();
48-
4948
const handleChange = (field: keyof TaskData, value: string | string[]) => {
5049
setFormData((prev) => ({
5150
...prev,
@@ -81,9 +80,9 @@ export default function TaskModal({
8180
tags: formData.tags,
8281
imageUrl: formData.image || undefined,
8382
});
84-
85-
router.reload(); // 카드 생성 후 새로고침
8683
onClose();
84+
if (updateCard) updateCard();
85+
toast.success("카드가 생성되었습니다.");
8786
} catch (err) {
8887
console.error("카드 생성 실패:", err);
8988
toast.error("카드 생성에 실패했습니다.");

src/components/table/member/MemberList.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ const MemberList: React.FC<HeaderBebridgeProps> = ({ dashboardId }) => {
2525
currentPage * itemsPerPage
2626
);
2727

28-
/* 멤버 삭제 모달 */
29-
const openModal = () => {
30-
setIsModalOpen(true);
31-
};
32-
3328
const closeModal = () => {
3429
setIsModalOpen(false);
3530
};

src/pages/dashboard/[dashboardId]/index.tsx

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -60,40 +60,39 @@ export default function Dashboard() {
6060
}
6161
};
6262

63-
// 대시보드 및 칼럼/카드 데이터 패칭
63+
// 칼럼/카드 데이터 패칭
64+
const fetchColumnsAndCards = async () => {
65+
try {
66+
const numericDashboardId = Number(dashboardId);
67+
68+
// 칼럼 목록 조회
69+
const columnRes = await getColumns({
70+
dashboardId: numericDashboardId,
71+
});
72+
setColumns(columnRes.data);
73+
74+
// 각 칼럼에 대한 카드 목록 조회
75+
const columnTasks: { [columnId: number]: CardType[] } = {};
76+
77+
await Promise.all(
78+
columnRes.data.map(async (column: ColumnType) => {
79+
const cardRes = await getCardsByColumn({
80+
columnId: column.id,
81+
});
82+
columnTasks[column.id] = cardRes.cards;
83+
})
84+
);
85+
86+
setTasksByColumn(columnTasks);
87+
} catch (err) {
88+
console.error("❌ 칼럼 또는 카드 로딩 에러:", err);
89+
}
90+
};
91+
6492
useEffect(() => {
6593
if (!isReady || !dashboardId || !isInitialized || !user) return;
6694

6795
fetchDashboards();
68-
69-
const fetchColumnsAndCards = async () => {
70-
try {
71-
const numericDashboardId = Number(dashboardId);
72-
73-
// 칼럼 목록 조회
74-
const columnRes = await getColumns({
75-
dashboardId: numericDashboardId,
76-
});
77-
setColumns(columnRes.data);
78-
79-
// 각 칼럼에 대한 카드 목록 조회
80-
const columnTasks: { [columnId: number]: CardType[] } = {};
81-
82-
await Promise.all(
83-
columnRes.data.map(async (column: ColumnType) => {
84-
const cardRes = await getCardsByColumn({
85-
columnId: column.id,
86-
});
87-
columnTasks[column.id] = cardRes.cards;
88-
})
89-
);
90-
91-
setTasksByColumn(columnTasks);
92-
} catch (err) {
93-
console.error("❌ 칼럼 또는 카드 로딩 에러:", err);
94-
}
95-
};
96-
9796
fetchColumnsAndCards();
9897
}, [isReady, dashboardId, isInitialized, user]);
9998

@@ -130,6 +129,8 @@ export default function Dashboard() {
130129
title={col.title}
131130
tasks={tasksByColumn[col.id] || []}
132131
dashboardId={Number(dashboardId)}
132+
columnDelete={fetchColumnsAndCards}
133+
fetchColumnsAndCards={fetchColumnsAndCards}
133134
/>
134135
))}
135136
{/* ColumnsButton: 모바일/태블릿에서는 하단 고정, 데스크탑에서는 원래 위치 */}

0 commit comments

Comments
 (0)