Skip to content

Commit 5446351

Browse files
authored
Merge pull request #116 from hyeonjiroh/feat/#112/mydashboard-page
feat: #112/나의 대시보드 페이지 초대 부분 완료 및 대시보드 수정 페이지 구성원 부분 수정
2 parents 84b83a6 + d1be1f6 commit 5446351

File tree

13 files changed

+312
-43
lines changed

13 files changed

+312
-43
lines changed

public/icon/search_icon.svg

Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading

src/app/(after-login)/dashboard/[dashboardid]/_components/Column.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import { useCallback, useEffect, useState, useRef } from "react";
3+
import { useEffect, useState, useRef } from "react";
44
import { useIntersection } from "@/lib/hooks/useIntersection";
55
import { DashboardColumn, TaskCardList } from "@/lib/types";
66
import { fetchTaskCardList } from "@/lib/apis/cardsApi";
@@ -19,7 +19,7 @@ export default function Column({ id, title }: DashboardColumn) {
1919
const observerRef = useRef<HTMLDivElement | null>(null);
2020
const accessToken = localStorage.getItem("accessToken") ?? "";
2121

22-
const handleLoad = useCallback(async () => {
22+
const handleLoad = async () => {
2323
if (isLoading || isLast) return;
2424
setIsLoading(true);
2525

@@ -45,11 +45,11 @@ export default function Column({ id, title }: DashboardColumn) {
4545
} finally {
4646
setIsLoading(false);
4747
}
48-
}, [accessToken, isLoading, isLast, cursorId, id]);
48+
};
4949

5050
useEffect(() => {
5151
handleLoad();
52-
}, [handleLoad]);
52+
}, []);
5353

5454
useIntersection({
5555
target: observerRef,

src/app/(after-login)/dashboard/[dashboardid]/edit/_components/DeleteButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export default function DeleteButton({
2929
<button
3030
type="button"
3131
onClick={handleDeleteClick}
32-
className="max-w-[320px] rounded-lg border border-gray-400 bg-gray-200 font-medium text-lg text-gray-800 tablet:h-[62px] tablet:text-2lg hover:bg-gray-300"
32+
className="max-w-[320px] h-[52px] rounded-lg border border-gray-400 bg-gray-200 font-medium text-lg text-gray-800 tablet:h-[62px] tablet:text-2lg hover:bg-gray-300"
3333
>
3434
대시보드 삭제하기
3535
</button>

src/app/(after-login)/dashboard/[dashboardid]/edit/_components/InvitationSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { useEffect, useState } from "react";
44
import { Invitation } from "@/lib/types";
55
import { fetchInvitationList } from "@/lib/apis/dashboardsApi";
6-
import Pagination from "@/components/common/pagenation-button/PagenationButton";
6+
import Pagination from "@/components/common/pagination-button/PaginationButton";
77
import InvitationCard from "./InvitationCard";
88
import InviteModalButton from "./InviteModalButton";
99

src/app/(after-login)/dashboard/[dashboardid]/edit/_components/MemberSection.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use client";
22

33
import { useEffect, useState } from "react";
4-
import Pagination from "@/components/common/pagenation-button/PagenationButton";
4+
import Pagination from "@/components/common/pagination-button/PaginationButton";
55
import { DashboardMember } from "@/lib/types";
66
import Button from "@/components/common/button/Button";
77
import UserIcon from "@/components/common/user-icon/UserIcon";
@@ -64,7 +64,6 @@ export default function MemberSection({
6464
setIsLoading(true);
6565
await deleteDashboardMember({
6666
token,
67-
dashboardId: id,
6867
memberId,
6968
});
7069

@@ -126,7 +125,7 @@ export default function MemberSection({
126125
img={item.profileImageUrl}
127126
size="md"
128127
/>
129-
<span>{item.email}</span>
128+
<span>{item.nickname}</span>
130129
</div>
131130
<Button
132131
variant="whiteViolet"

src/app/(after-login)/mydashboard/_components/DashboardListSection.tsx

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,50 +3,50 @@
33
import { useEffect, useState } from "react";
44
import { fetchDashboardList } from "@/lib/apis/dashboardsApi";
55
import { DashboardList } from "@/lib/types";
6+
import Pagination from "@/components/common/pagination-button/PaginationButton";
67

78
const PAGE_SIZE = 6;
89

910
export default function DashboardListSection({ token }: { token: string }) {
1011
const [myDashboards, setMyDashboards] = useState<DashboardList[]>([]);
1112
const [page, setPage] = useState(1);
12-
13-
setPage(1); // vercel 배포 때문에 임시로 넣은 코드라 삭제하시면 됩니다.
14-
15-
const [loading, setLoading] = useState(true);
13+
const [totalPages, setTotalPages] = useState(1);
14+
const [loading, setLoading] = useState(false);
1615

1716
useEffect(() => {
1817
async function loadDashboards() {
18+
setLoading(true);
1919
try {
20-
const { dashboards }: { dashboards: DashboardList[] } =
20+
const {
21+
dashboards,
22+
total,
23+
}: { dashboards: DashboardList[]; total: number } =
2124
await fetchDashboardList({
22-
token: token,
23-
page: page,
25+
token,
26+
page,
2427
size: PAGE_SIZE,
2528
});
2629

27-
setMyDashboards(
28-
dashboards.filter((dashboard) => dashboard.createdByMe)
29-
);
30+
setMyDashboards(dashboards.filter((d) => d.createdByMe));
31+
setTotalPages(Math.ceil(total / PAGE_SIZE));
3032
} catch (error) {
3133
console.error("대시보드를 불러오는 중 오류 발생:", error);
3234
} finally {
3335
setLoading(false);
3436
}
3537
}
3638
loadDashboards();
37-
}, []);
39+
}, [page, token]);
3840

3941
return (
40-
<>
42+
<div className="max-w-[1022px]">
4143
<button className="px-4 py-2 bg-blue-500 text-white rounded-lg flex items-center">
4244
새로운 대시보드 +
4345
</button>
4446

4547
<div>
4648
<h2 className="text-lg font-semibold">내 대시보드</h2>
47-
{loading ? (
48-
<p>로딩 중...</p>
49-
) : myDashboards.length > 0 ? (
49+
{myDashboards.length > 0 ? (
5050
<ul className="mt-4 space-y-2">
5151
{myDashboards.map((dashboard) => (
5252
<li key={dashboard.id} className="p-4 bg-white shadow rounded-lg">
@@ -55,11 +55,30 @@ export default function DashboardListSection({ token }: { token: string }) {
5555
))}
5656
</ul>
5757
) : (
58-
<div className="p-6 bg-gray-100 text-center rounded-lg">
59-
<p className="text-gray-500">아직 생성한 대시보드가 없어요.</p>
58+
!loading && (
59+
<div className="p-6 bg-gray-100 text-center rounded-lg">
60+
<p className="text-gray-500">아직 생성한 대시보드가 없어요.</p>
61+
</div>
62+
)
63+
)}
64+
65+
{loading && (
66+
<div className="flex justify-center mt-4">
67+
<div className="w-6 h-6 border-4 border-blue-500 border-t-transparent rounded-full animate-spin"></div>
6068
</div>
6169
)}
70+
71+
<div className="flex justify-center mt-4">
72+
<Pagination
73+
currentPage={page}
74+
totalPages={totalPages}
75+
onPrevClick={() => setPage((prev) => Math.max(prev - 1, 1))}
76+
onNextClick={() =>
77+
setPage((prev) => Math.min(prev + 1, totalPages))
78+
}
79+
/>
80+
</div>
6281
</div>
63-
</>
82+
</div>
6483
);
6584
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { useRouter } from "next/navigation";
2+
import { useDashboardStore } from "@/lib/store/useDashboardStore";
3+
import { Invitation } from "@/lib/types";
4+
import { putInvitation } from "@/lib/apis/invitationsApi";
5+
import Button from "@/components/common/button/Button";
6+
7+
type InvitationCardProps = Invitation & {
8+
token: string;
9+
};
10+
11+
export default function InvitationCard({
12+
id,
13+
inviter,
14+
dashboard,
15+
token,
16+
}: InvitationCardProps) {
17+
const newDashboardId = String(dashboard.id);
18+
const router = useRouter();
19+
const setDashboardId = useDashboardStore((state) => state.setDashboardId);
20+
21+
const handleApproveInvite = async () => {
22+
await putInvitation({
23+
token,
24+
invitationId: id,
25+
inviteAccepted: true,
26+
});
27+
28+
router.push(`/dashboard/${newDashboardId}`);
29+
setDashboardId(newDashboardId);
30+
};
31+
32+
const handleRejectInvite = async () => {
33+
await putInvitation({
34+
token,
35+
invitationId: id,
36+
inviteAccepted: false,
37+
});
38+
39+
window.location.reload();
40+
};
41+
42+
return (
43+
<div className="flex flex-col gap-[14px] border-b border-gray-400 py-[14px] tablet:flex-row tablet:gap-0 tablet:justify-between tablet:py-5 pc:pl-12 ">
44+
<div className="flex flex-col tablet:flex-row tablet:justify-between tablet:flex-grow">
45+
<div className="flex gap-6 tablet:w-1/2">
46+
<div className="w-[38px] font-normal text-md text-gray-500 tablet:hidden">
47+
이름
48+
</div>
49+
<div className="font-normal text-md text-gray-800 tablet:text-lg">
50+
{dashboard.title}
51+
</div>
52+
</div>
53+
<div className="flex gap-6 tablet:w-1/2">
54+
<div className="w-[38px] font-normal text-md text-gray-500 tablet:hidden">
55+
초대자
56+
</div>
57+
<div className="font-normal text-md text-gray-800 tablet:text-lg">
58+
{inviter.nickname}
59+
</div>
60+
</div>
61+
</div>
62+
<div className="flex justify-between gap-[10px] tablet:justify-start tablet:tablet:w-1/3 tablet:relative tablet:left-[-44px] pc:left-[-56px]">
63+
<Button
64+
variant="purple"
65+
onClick={handleApproveInvite}
66+
radius="sm"
67+
className="flex-1 max-h-[32px] tablet:max-w-[72px] pc:max-w-[84px]"
68+
>
69+
<div className="font-medium text-xs tablet:text-md">수락</div>
70+
</Button>
71+
<Button
72+
variant="whiteViolet"
73+
onClick={handleRejectInvite}
74+
radius="sm"
75+
className="flex-1 max-h-[32px] tablet:max-w-[72px] pc:max-w-[84px]"
76+
>
77+
<div className="font-medium text-xs tablet:text-md">거절</div>
78+
</Button>
79+
</div>
80+
</div>
81+
);
82+
}

0 commit comments

Comments
 (0)