Skip to content

Commit 78b3d9f

Browse files
authored
Merge pull request #104 from hhjin1/card-hj
[Feat, Style] Column, Card: UI 개선 및 기능 추가
2 parents 7f5597e + b90415d commit 78b3d9f

File tree

6 files changed

+79
-41
lines changed

6 files changed

+79
-41
lines changed

src/api/axiosInstance.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// axiosInstance.ts
2+
13
import axios from "axios";
24

35
console.log("🔐 BASE_URL:", process.env.NEXT_PUBLIC_BASE_URL);
@@ -7,7 +9,16 @@ const axiosInstance = axios.create({
79
baseURL: process.env.NEXT_PUBLIC_BASE_URL,
810
});
911

10-
// ✅ Authorization 헤더 자동 추가
12+
// 👉 Authorization 헤더 자동 설정, 요청 보낼때 마다 localstorage에서 토큰 가져오기
13+
axiosInstance.interceptors.request.use((config) => {
14+
const token = localStorage.getItem("accessToken"); // localStorage에서 토큰 가져오기
15+
if (token) {
16+
config.headers.Authorization = `Bearer ${token}`; // 헤더에 Authorization 추가
17+
}
18+
return config;
19+
});
20+
21+
// 👉 요청 보낼 때마다 토큰 자동 추가
1122
axiosInstance.interceptors.request.use((config) => {
1223
const token = localStorage.getItem("accessToken"); // localStorage에서 토큰 가져오기
1324
if (token) {

src/api/dashboards.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@ import axiosInstance from "./axiosInstance";
44
export const getCardsByColumn = async ({
55
teamId,
66
columnId,
7+
cursorId,
8+
size = 10,
79
}: {
810
teamId: string;
911
columnId: number;
12+
cursorId?: number;
13+
size?: number;
1014
}) => {
1115
const res = await axiosInstance.get(`/${teamId}/cards`, {
1216
params: {
1317
columnId,
18+
cursorId,
19+
size,
1420
},
1521
});
1622

src/components/columnCard/Card.tsx

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// Card.tsx
21
import { AssigneeType, CardType } from "@/types/task";
32
import Image from "next/image";
43

@@ -12,29 +11,37 @@ export default function Card({
1211
dueDate,
1312
tags,
1413
assignee,
15-
imageUrl = "/svgs/img.svg",
14+
imageUrl,
1615
}: CardProps) {
1716
return (
18-
<div className="w-[314px] border border-gray-300 rounded-md p-4">
19-
<Image
20-
className="w-full h-40 object-cover rounded-md"
21-
src={imageUrl || "svgs/img.svg"}
22-
width={300}
23-
height={160}
24-
alt="Task Image"
25-
/>
26-
<h3 className="font-medium mt-2">{title}</h3>
17+
<div className="w-[314px] border border-[0.25px] border-gray-200 rounded-md p-4">
18+
{imageUrl && (
19+
<Image
20+
className="w-full h-40 object-cover rounded-md"
21+
src={imageUrl}
22+
width={300}
23+
height={160}
24+
alt="Task Image"
25+
/>
26+
)}
27+
<h3 className="text-lg ">{title}</h3>
2728
<div className="flex items-center gap-2 mt-2">
2829
{tags.map((tag, idx) => (
2930
<span
3031
key={idx}
31-
className="bg-blue-200 text-blue-700 px-2 py-1 rounded-md text-sm"
32+
className={`px-2 py-1 rounded-md text-sm ${
33+
idx % 3 === 0
34+
? "bg-[#F9EEE3] text-[#D58D49]"
35+
: idx % 3 === 1
36+
? "bg-[#F7DBF0] text-[#D549B6]"
37+
: "bg-[#DBE6F7] text-[#4981D5]"
38+
}`}
3239
>
3340
{tag}
3441
</span>
3542
))}
3643
</div>
37-
<div className="flex items-center justify-between mt-2.5">
44+
<div className="flex items-center justify-between mt-2">
3845
<div className="flex items-center gap-2.5 text-gray-500 text-sm">
3946
<Image
4047
src="/svgs/calendar.svg"

src/components/columnCard/Column.tsx

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,10 @@ export default function Column({
2424
teamId,
2525
dashboardId,
2626
}: ColumnProps) {
27+
const [columnTitle, setColumnTitle] = useState(title);
2728
const [isColumnModalOpen, setIsColumnModalOpen] = useState(false);
2829
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
2930
const [isTodoModalOpen, setIsTodoModalOpen] = useState(false);
30-
const [columnTitle, setColmnTitle] = useState(title);
31-
3231
const [members, setMembers] = useState<
3332
{ id: number; userId: number; nickname: string }[]
3433
>([]);
@@ -65,7 +64,7 @@ export default function Column({
6564

6665
try {
6766
const updated = await updateColumn({ teamId, columnId, title: newTitle });
68-
setColmnTitle(updated.title);
67+
setColumnTitle(updated.title);
6968
setIsColumnModalOpen(false);
7069
alert("칼럼 이름이 변경되었습니다.");
7170
} catch (error) {
@@ -79,22 +78,21 @@ export default function Column({
7978
await deleteColumn({ teamId, columnId });
8079
setIsDeleteModalOpen(false);
8180
alert("칼럼이 삭제되었습니다.");
82-
// :point_right: 부모에서 상태를 관리 중이라면 삭제 후 다시 데이터를 불러오거나, 상태 업데이트 필요!
8381
} catch (error) {
8482
console.error("칼럼 삭제 실패:", error);
8583
alert("칼럼 삭제에 실패했습니다.");
8684
}
8785
};
8886

8987
return (
90-
<div className="w-[354px] h-[1010px] border-[var(--color-gray4)] flex flex-col rounded-md border border-solid bg-gray-50 p-4">
88+
<div className="w-[354px] flex flex-col rounded-md border-r border-gray-200 bg-gray-50 p-4 min-h-screen">
9189
{/* 칼럼 헤더 */}
9290
<div className="flex items-center justify-between">
9391
<div className="flex items-center gap-2">
9492
<h2 className="text-lg font-bold">
9593
<span className="text-[var(--primary)]"></span> {columnTitle}
9694
</h2>
97-
<span className="bg-gray-200 text-gray-700 px-2 py-1 rounded-full text-sm">
95+
<span className="w-5 h-5 text-sm bg-gray-200 text-gray-700 rounded-[4px] flex items-center justify-center ">
9896
{tasks.length}
9997
</span>
10098
</div>
@@ -109,20 +107,21 @@ export default function Column({
109107
/>
110108
</div>
111109

112-
{/* Todo 추가 버튼 */}
113-
<div onClick={() => setIsTodoModalOpen(true)}>
114-
<TodoButton />
115-
</div>
110+
{/* 카드 영역 */}
111+
<div className="flex-1 pb-4 flex flex-col items-center gap-3">
112+
<div onClick={() => setIsTodoModalOpen(true)}>
113+
<TodoButton />
114+
</div>
116115

117-
{/* 카드 목록 */}
118-
{tasks.map((task) => (
119-
<Card
120-
key={task.id}
121-
{...task}
122-
imageUrl={task.imageUrl}
123-
assignee={task.assignee}
124-
/>
125-
))}
116+
{tasks.map((task) => (
117+
<Card
118+
key={task.id}
119+
{...task}
120+
imageUrl={task.imageUrl}
121+
assignee={task.assignee}
122+
/>
123+
))}
124+
</div>
126125

127126
{/* Todo 모달 */}
128127
{isTodoModalOpen && (
@@ -132,7 +131,7 @@ export default function Column({
132131
teamId={teamId}
133132
dashboardId={dashboardId}
134133
columnId={columnId}
135-
members={members} // ✅ 멤버 넘겨줌
134+
members={members}
136135
/>
137136
)}
138137

src/components/columnCard/ColumnManageModal.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// components/column/ColumnManageModal.tsx
22
import { useState } from "react";
3-
import Input from "../input/Input";
43
import { Modal } from "../modal/Modal";
54
import { CustomBtn } from "../button/CustomButton";
5+
import Input from "../input/Input";
6+
import Image from "next/image";
67

78
type ColumnManageModalProps = {
89
isOpen: boolean;
@@ -23,14 +24,28 @@ export default function ColumnManageModal({
2324

2425
return (
2526
<Modal isOpen={isOpen} onClose={onClose}>
26-
<div className="flex flex-col gap-5">
27+
<div className="relative flex flex-col gap-5">
28+
<Image
29+
src="/svgs/close.svg"
30+
alt="close icon"
31+
width={24}
32+
height={24}
33+
priority
34+
className="absolute right-4 cursor-pointer hover:opacity-70"
35+
onClick={onClose}
36+
/>
2737
<h2 className="text-2xl font-bold">칼럼 관리</h2>
2838
<label className="font-medium flex flex-col gap-2">
2939
이름
3040
<Input
3141
type="text"
3242
value={newTitle}
3343
onChange={(value) => setNewTile(value)}
44+
onKeyDown={(e) => {
45+
if (e.key === "Enter") {
46+
onEditSubmit(newTitle);
47+
}
48+
}}
3449
/>
3550
</label>
3651
<div className="flex justify-between mt-1.5">

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,13 @@ export default function Dashboard() {
101101
if (!isReady) return <div>로딩 중...</div>;
102102

103103
return (
104-
<div className="flex overflow-x-auto min-w-fit">
104+
<div className="flex overflow-x-auto min-w-fit min-h-screen">
105105
<SideMenu teamId={teamId} dashboardList={dashboardList} />
106106

107107
<div className="flex-1">
108108
<HeaderDashboard variant="dashboard" dashboardId={dashboardId} />
109109

110-
<div className="flex gap-4 p-6 overflow-x-auto ">
110+
<div className="flex overflow-x-auto ">
111111
{/* 각 칼럼 렌더링 */}
112112
{columns.map((col) => (
113113
<Column
@@ -119,9 +119,9 @@ export default function Dashboard() {
119119
dashboardId={Number(dashboardId)}
120120
/>
121121
))}
122-
123-
<ColumnsButton onClick={openModal} />
124-
122+
<div className="p-5">
123+
<ColumnsButton onClick={openModal} />
124+
</div>
125125
{/* 칼럼 추가 모달 */}
126126
{isAddColumnModalOpen && (
127127
<AddColumnModal

0 commit comments

Comments
 (0)