Skip to content

Commit ae558cf

Browse files
authored
Merge pull request #87 from part3-4team-Taskify/mypage02
[Feat] 나의 대쉬보드 페이지
2 parents 97f25ed + 86643b9 commit ae558cf

File tree

3 files changed

+98
-40
lines changed

3 files changed

+98
-40
lines changed

src/components/button/CardButton.tsx

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,65 @@ import React from "react";
22
import clsx from "clsx";
33
import Image from "next/image";
44

5-
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
5+
interface CardButtonProps
6+
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
67
fullWidth?: boolean;
8+
title?: string;
9+
showCrown?: boolean;
10+
color?: string;
711
}
812

9-
const CardButton: React.FC<ButtonProps> = ({
13+
const CardButton: React.FC<CardButtonProps> = ({
1014
fullWidth,
1115
className,
12-
children = "비브리지",
16+
title = "비브리지",
17+
showCrown = true,
18+
color = "#7ac555", // 기본 색상
1319
...props
1420
}) => {
1521
return (
1622
<button
1723
className={clsx(
18-
"flex justify-center items-center gap-[10px] bg-white transition-all",
24+
"flex justify-between items-center bg-white transition-all",
1925
"rounded-lg px-4 py-3 font-semibold",
2026
"border border-gray-300 hover:border-purple-500",
21-
fullWidth ? "w-full" : "w-[260px] md:w-[247px] lg:w-[332px]", // 반응형 너비
22-
"h-[58px] md:h-[68px] lg:h-[70px]", // 반응형 높이
23-
"mt-[10px] md:mt-[16px] lg:mt-[20px]", // 여백
27+
fullWidth ? "w-full" : "w-[260px] md:w-[247px] lg:w-[332px]",
28+
"h-[58px] md:h-[68px] lg:h-[70px]",
29+
"mt-[10px] md:mt-[16px] lg:mt-[20px]",
2430
"text-lg md:text-2lg lg:text-2lg",
2531
className
2632
)}
2733
{...props}
2834
>
29-
<span className="font-semibold">{children}</span>
35+
{/* 왼쪽: 색상 도트 + 제목 + 왕관 */}
36+
<div className="flex items-center gap-[10px] overflow-hidden">
37+
{/* 색상 원 */}
38+
<svg width="8" height="8" viewBox="0 0 8 8" fill={color}>
39+
<circle cx="4" cy="4" r="4" />
40+
</svg>
41+
42+
{/* 제목 */}
43+
<span className="font-semibold truncate">{title}</span>
44+
45+
{/* 왕관 */}
46+
{showCrown && (
47+
<Image
48+
src="/svgs/icon-crown.svg"
49+
alt="crown Icon"
50+
width={20}
51+
height={20}
52+
className="w-[20px] h-[20px]"
53+
/>
54+
)}
55+
</div>
56+
57+
{/* 오른쪽: 화살표 아이콘 */}
3058
<Image
31-
src="/svgs/icon-crown.svg"
32-
alt="crown Icon"
33-
width={32}
34-
height={32}
35-
className="w-[30px] h-[30px] p-1 rounded-md"
59+
src="/svgs/arrow-forward-black.svg"
60+
alt="arrow icon"
61+
width={16}
62+
height={16}
63+
className="ml-2"
3664
/>
3765
</button>
3866
);

src/components/sideMenu/SideMenu.tsx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import clsx from "clsx";
22
import Image from "next/image";
33
import Link from "next/link";
44
import { useRouter } from "next/router";
5-
import { useEffect, useState } from "react";
6-
import { getDashboards } from "@/api/sidemenu";
75

86
interface Dashboard {
97
id: number;
@@ -17,21 +15,14 @@ interface Dashboard {
1715

1816
interface SideMenuProps {
1917
teamId: string;
18+
dashboardList: Dashboard[];
2019
}
2120

22-
export default function SideMenu({ teamId }: SideMenuProps) {
21+
export default function SideMenu({ teamId, dashboardList }: SideMenuProps) {
2322
const router = useRouter();
2423
const { boardid } = router.query;
2524
const boardId = parseInt(boardid as string);
2625

27-
const [dashboardList, setDashboardList] = useState<Dashboard[]>([]);
28-
29-
useEffect(() => {
30-
getDashboards({ teamId })
31-
.then((res) => setDashboardList(res.dashboards))
32-
.catch((err) => console.error("대시보드 로딩 실패:", err));
33-
}, [teamId]);
34-
3526
return (
3627
<aside className="h-screen overflow-y-auto border-r border-[var(--color-gray3)] px-3 py-5 lg:w-[300px] md:w-[160px] sm:w-[67px] transition-all duration-200 flex flex-col">
3728
{/* 로고 */}

src/pages/mydashboard.tsx

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,61 @@
1-
import React, { useState } from "react";
1+
import React, { useEffect, useState } from "react";
22
import SideMenu from "@/components/sideMenu/SideMenu";
33
import HeaderDashboard from "@/components/gnb/HeaderDashboard";
44
import InvitedDashBoard from "@/components/table/invited/InvitedDashBoard";
5-
import type { Dashboard } from "@/components/sideMenu/dashboard";
6-
import DashboardAddButton from "@/components/button/DashboardAddButton";
75
import CardButton from "@/components/button/CardButton";
86
import { PaginationBtn } from "@/components/button/PaginationBtn";
7+
import NewDashboard from "@/components/modal/NewDashboard";
8+
import DashboardAddButton from "@/components/button/DashboardAddButton";
9+
import { getDashboards } from "@/api/dashboard";
10+
import { useRouter } from "next/router";
11+
12+
interface Dashboard {
13+
id: number;
14+
title: string;
15+
color: string;
16+
userId: number;
17+
createdAt: string;
18+
updatedAt: string;
19+
createdByMe: boolean;
20+
}
921

1022
export default function MyDashboardPage() {
11-
const teamId = "13";
12-
const [dashCards, setDashCards] = useState<string[]>([]);
23+
const teamId = "13-4";
24+
const router = useRouter();
25+
const [dashboardList, setDashboardList] = useState<Dashboard[]>([]);
1326
const [currentPage, setCurrentPage] = useState(1);
27+
const [isModalOpen, setIsModalOpen] = useState(false);
1428
const itemsPerPage = 6;
1529

16-
const handleAddDashboard = () => {
17-
const newTitle = `대시보드 ${dashCards.length}`;
18-
setDashCards((prev) => [...prev, newTitle]);
19-
};
20-
21-
const totalPages = Math.ceil((dashCards.length + 1) / itemsPerPage);
30+
const totalPages = Math.ceil((dashboardList.length + 1) / itemsPerPage); // +1 for the add button
2231
const startIndex = (currentPage - 1) * itemsPerPage;
32+
2333
const currentItems = [
24-
<DashboardAddButton key="add" onClick={handleAddDashboard} />,
25-
...dashCards.map((title, index) => (
26-
<CardButton key={index}>{title}</CardButton>
34+
<DashboardAddButton key="add" onClick={() => setIsModalOpen(true)} />,
35+
...dashboardList.map((dashboard) => (
36+
<CardButton
37+
key={dashboard.id}
38+
title={dashboard.title}
39+
showCrown={dashboard.createdByMe}
40+
color={dashboard.color}
41+
onClick={() => router.push(`/dashboard/${dashboard.id}`)}
42+
/>
2743
)),
2844
].slice(startIndex, startIndex + itemsPerPage);
2945

46+
const fetchDashboards = async () => {
47+
try {
48+
const res = await getDashboards({ teamId });
49+
setDashboardList(res.dashboards);
50+
} catch (error) {
51+
console.error("대시보드 불러오기 실패:", error);
52+
}
53+
};
54+
55+
useEffect(() => {
56+
fetchDashboards();
57+
}, [teamId]);
58+
3059
const handlePrevPage = () => {
3160
if (currentPage > 1) setCurrentPage((prev) => prev - 1);
3261
};
@@ -37,12 +66,12 @@ export default function MyDashboardPage() {
3766

3867
return (
3968
<div className="flex h-screen overflow-hidden">
40-
<SideMenu teamId="13-4" />
69+
<SideMenu teamId={teamId} dashboardList={dashboardList} />
4170

4271
<div className="flex flex-col flex-1 overflow-hidden">
4372
<HeaderDashboard />
4473

45-
<main className="flex-1 overflow-auto px-[80px] pt-[40px] pb-10 bg-[#f9f9f9] space-y-10">
74+
<main className="flex-1 overflow-auto px-[25px] pt-[40px] pb-10 bg-[#f9f9f9] space-y-10">
4675
{/* 대시보드 카드 + 페이지네이션 */}
4776
<section className="flex flex-col items-start space-y-6">
4877
<div className="flex flex-wrap gap-x-[20px] gap-y-[16px] w-full max-w-[1100px]">
@@ -73,6 +102,16 @@ export default function MyDashboardPage() {
73102
</div>
74103
</main>
75104
</div>
105+
106+
{/* 새로운 대시보드 모달 */}
107+
{isModalOpen && (
108+
<NewDashboard
109+
onClose={() => {
110+
setIsModalOpen(false);
111+
fetchDashboards(); // 생성 후 목록 새로고침
112+
}}
113+
/>
114+
)}
76115
</div>
77116
);
78117
}

0 commit comments

Comments
 (0)