Skip to content

Commit 0c118e7

Browse files
authored
Merge pull request #108 from gyoyeon-kim/card-table
[Refactor] alret > toast 변경 / 관리 버튼 권한 추가
2 parents 33d4ac0 + d4cbdbe commit 0c118e7

File tree

11 files changed

+94
-56
lines changed

11 files changed

+94
-56
lines changed

package-lock.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"react-datetime": "^3.3.1",
2121
"react-dom": "^19.0.0",
2222
"react-hook-form": "^7.54.2",
23+
"react-toastify": "^11.0.5",
2324
"zustand": "^5.0.3"
2425
},
2526
"devDependencies": {

src/api/members.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
11
import axiosInstance from "./axiosInstance";
2-
import { MemberType } from "@/types/users";
32

4-
interface MembersResponse {
5-
members: MemberType[]; // 실제 데이터
6-
totalCount: number;
7-
}
8-
9-
export const getMembers = async (dashboardId?: string | string[]) => {
3+
export const getMembers = async ({ dashboardId }: { dashboardId: number }) => {
104
if (!dashboardId) {
115
console.error("dashboardID가 없습니다.");
126
return [];
137
}
14-
const dashboardIdNum =
15-
typeof dashboardId === "string" ? Number(dashboardId) : undefined;
168

17-
const response = await axiosInstance.get<MembersResponse>(
18-
`https://sp-taskify-api.vercel.app/13-4/members?page=1&size=20&dashboardId=${dashboardIdNum}`
19-
);
9+
const response = await axiosInstance.get(`/13-4/members`, {
10+
params: {
11+
dashboardId,
12+
},
13+
});
2014

2115
return response.data.members || [];
2216
};

src/components/gnb/HeaderDashboard.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { MemberAvatars, UserAvatars } from "@/components/gnb/Avatars";
1111
import UserMenu from "@/components/gnb/UserMenu";
1212
import MemberListMenu from "@/components/gnb/MemberListMenu";
1313
import InviteDashboard from "@/components/modal/InviteDashboard";
14+
import { ToastContainer, toast } from "react-toastify";
15+
import "react-toastify/dist/ReactToastify.css";
1416

1517
interface HeaderDashboardProps {
1618
variant?: "mydashboard" | "dashboard" | "mypage";
@@ -47,7 +49,9 @@ const HeaderDashboard: React.FC<HeaderDashboardProps> = ({
4749
useEffect(() => {
4850
const fetchMembers = async () => {
4951
try {
50-
const members = await getMembers(dashboardId);
52+
const members = await getMembers({
53+
dashboardId: Number(dashboardId),
54+
});
5155
setMembers(members);
5256
} catch (error) {
5357
console.error("멤버 불러오기 실패:", error);
@@ -110,6 +114,7 @@ const HeaderDashboard: React.FC<HeaderDashboardProps> = ({
110114

111115
return (
112116
<header className="w-full h-[60px] md:h-[70px] flex items-center justify-center bg-white border-b-[1px] border-b-[#D9D9D9]">
117+
<ToastContainer position="top-center" />
113118
<div className="w-full flex items-center justify-between pl-[4vw]">
114119
{errorMessage && (
115120
<p className="text-sm text-[var(--color-red)] px-4 py-2">
@@ -147,7 +152,11 @@ const HeaderDashboard: React.FC<HeaderDashboardProps> = ({
147152
<button
148153
onClick={() => {
149154
if (dashboardId) {
150-
router.push(`/dashboard/${dashboardId}/edit`);
155+
if (dashboard && dashboard.createdByMe === true) {
156+
router.push(`/dashboard/${dashboardId}/edit`);
157+
} else {
158+
toast.error("대시보드 수정 권한이 없습니다.");
159+
}
151160
} else {
152161
router.push("/mypage");
153162
}

src/components/modal/ChangeBebridge.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import Input from "../input/Input";
44
import Image from "next/image";
55
import axiosInstance from "@/api/axiosInstance";
66
import { apiRoutes } from "@/api/apiRoutes";
7+
import { ToastContainer, toast } from "react-toastify";
8+
import "react-toastify/dist/ReactToastify.css";
79

810
const ChangeBebridge = () => {
911
const router = useRouter();
@@ -58,16 +60,19 @@ const ChangeBebridge = () => {
5860
payload
5961
);
6062
console.log("업데이트 성공:", response.data);
61-
alert("대시보드가 업데이트되었습니다!"); // 추후에 toast로 변경
62-
window.location.reload();
63+
toast.success("대시보드가 업데이트되었습니다!");
64+
setTimeout(() => {
65+
window.location.reload();
66+
}, 100);
6367
} catch (error) {
6468
console.error("업데이트 실패:", error);
65-
alert("업데이트에 실패했습니다."); // 추후에 toast로 변경
69+
toast.error("업데이트에 실패했습니다.");
6670
}
6771
};
6872

6973
return (
7074
<div className="sm:w-[620px] sm:h-[344px] w-[327px] h-[312px] bg-white sm:rounded-[16px] rounded-[8px] p-[24px] flex flex-col">
75+
<ToastContainer position="top-center" />
7176
<h2 className="text-sm sm:text-[24px] font-bold">
7277
{dashboardDetail.title}
7378
</h2>

src/components/modal/InviteDashboard.tsx

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import Image from "next/image";
55
import axiosInstance from "@/api/axiosInstance";
66
import { apiRoutes } from "@/api/apiRoutes";
77
import { AxiosError } from "axios";
8+
import { ToastContainer, toast } from "react-toastify";
9+
import "react-toastify/dist/ReactToastify.css";
810

911
export default function InviteDashboard({ onClose }: { onClose?: () => void }) {
1012
const [email, setEmail] = useState("");
@@ -20,42 +22,41 @@ export default function InviteDashboard({ onClose }: { onClose?: () => void }) {
2022
const dashboardIdNumber = Number(dashboardId);
2123
if (!dashboardId || !email) return;
2224

23-
const payload = {
24-
email,
25-
};
26-
2725
try {
28-
const response = await axiosInstance.post(
29-
apiRoutes.DashboardInvite(dashboardIdNumber),
30-
payload
31-
);
26+
await axiosInstance.post(apiRoutes.DashboardInvite(dashboardIdNumber), {
27+
email,
28+
});
3229
onClose?.(); // 함수 있을때만 실행
3330
window.location.reload();
3431
} catch (error) {
3532
console.error("초대 실패:", error);
3633

3734
if (error instanceof AxiosError) {
3835
if (error.response?.status === 403) {
39-
alert("초대 권한이 없습니다.");
36+
toast.error("초대 권한이 없습니다.");
4037
} else if (error.response?.status === 404) {
41-
alert("대시보드 또는 유저가 존재하지 않습니다.");
38+
toast.error("대시보드 또는 유저가 존재하지 않습니다.");
4239
} else if (error.response?.status === 409) {
43-
alert("이미 대시보드에 초대된 멤버입니다.");
40+
toast.error("이미 대시보드에 초대된 멤버입니다.");
4441
} else {
45-
alert("오류가 발생했습니다.");
42+
toast.error("오류가 발생했습니다.");
4643
}
47-
// Next.js가 감지하기 전에 강제 새로고침 실행 > 추후 더 좋은 방법 있으면 변경
48-
setTimeout(() => {
49-
window.location.reload();
50-
}, 50);
44+
45+
/** Next.js가 감지하기 전에 강제 새로고침 실행
46+
* @fixme 추후 더 좋은 방법 있으면 변경
47+
* setTimeout(() => {
48+
* window.location.reload();
49+
* }, 50);
50+
*/
5151
} else {
52-
alert("네트워크 오류가 발생했습니다.");
52+
toast.error("네트워크 오류가 발생했습니다.");
5353
}
5454
}
5555
};
5656

5757
return (
5858
<div className="fixed inset-0 flex items-center justify-center bg-black/35 z-50">
59+
<ToastContainer position="top-center" autoClose={2000} />
5960
<div className="bg-white p-6 rounded-lg shadow-lg w-[327px] sm:w-[568px] sm:h-[279px]">
6061
<div className="flex justify-between items-center">
6162
<h2 className="text-sm sm:text-[24px] font-bold">초대하기</h2>

src/components/table/InviteRecords.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import InviteDashboard from "../modal/InviteDashboard";
44
import { apiRoutes } from "@/api/apiRoutes";
55
import axiosInstance from "@/api/axiosInstance";
66
import { AxiosError } from "axios";
7+
import { ToastContainer, toast } from "react-toastify";
8+
import "react-toastify/dist/ReactToastify.css";
79

810
const InviteRecords = ({ dashboardId }: { dashboardId: string }) => {
911
const [inviteList, setInviteList] = useState<
@@ -52,22 +54,22 @@ const InviteRecords = ({ dashboardId }: { dashboardId: string }) => {
5254
const dashboardIdNumber = Number(dashboardId);
5355
if (!dashboardId) return;
5456
try {
55-
const response = await axiosInstance.delete(
57+
await axiosInstance.delete(
5658
apiRoutes.DashboardInviteDelete(dashboardIdNumber, id)
5759
);
5860
window.location.reload();
5961
} catch (error) {
6062
console.error("초대 취소 실패:", error);
6163
if (error instanceof AxiosError) {
6264
if (error.response?.status === 403) {
63-
alert("대시보드 초대 취소 권한이 없습니다.");
65+
toast.error("대시보드 초대 취소 권한이 없습니다.");
6466
} else if (error.response?.status === 404) {
65-
alert("대시보드가 존재하지 않습니다.");
67+
toast.error("대시보드가 존재하지 않습니다.");
6668
} else {
67-
alert("오류가 발생했습니다.");
69+
toast.error("오류가 발생했습니다.");
6870
}
6971
} else {
70-
alert("네트워크 오류가 발생했습니다.");
72+
toast.error("네트워크 오류가 발생했습니다.");
7173
}
7274
}
7375
};
@@ -96,6 +98,7 @@ const InviteRecords = ({ dashboardId }: { dashboardId: string }) => {
9698

9799
return (
98100
<div className="relative bg-white p-4 rounded-lg lg:w-[620px] lg:h-[477px] md:w-[544px] md:h-[477px] sm:w-[284px] h-[406px] ">
101+
<ToastContainer position="top-center" autoClose={2000} />
99102
<div className="flex justify-between items-start sm:items-center">
100103
{/* 제목 */}
101104
<p className="sm:text-2xl text-xl font-bold">초대 내역</p>

src/components/table/invited/InvitedDashBoard.tsx

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { apiRoutes } from "@/api/apiRoutes";
66
import axiosInstance from "@/api/axiosInstance";
77
import { Invite } from "@/types/invite";
88
import useUserStore from "@/store/useUserStore";
9+
import { ToastContainer, toast } from "react-toastify";
10+
import "react-toastify/dist/ReactToastify.css";
911

1012
const ITEMS_PER_PAGE = 6; // 한 번에 보여줄 개수
1113

@@ -65,11 +67,13 @@ function InvitedList({
6567
payload
6668
);
6769
console.log("대시보드 수락 성공:", response.data);
68-
alert("대시보드 수락 성공"); // 추후에 toast로 변경
69-
window.location.reload();
70+
toast.success("대시보드 수락 성공");
71+
setTimeout(() => {
72+
window.location.reload();
73+
}, 100);
7074
} catch (error) {
7175
console.error("대시보드 수락 실패:", error);
72-
alert("대시보드 수락 실패"); // 추후에 toast로 변경
76+
toast.error("대시보드 수락 실패");
7377
}
7478
};
7579

@@ -85,16 +89,19 @@ function InvitedList({
8589
payload
8690
);
8791
console.log("대시보드 거절 성공:", response.data);
88-
alert("대시보드 거절 성공"); // 추후에 toast로 변경
89-
window.location.reload();
92+
toast.success("대시보드 거절 성공");
93+
setTimeout(() => {
94+
window.location.reload();
95+
}, 100);
9096
} catch (error) {
9197
console.error("대시보드 거절 실패:", error);
92-
alert("대시보드 거절 실패"); // 추후에 toast로 변경
98+
toast.error("대시보드 거절 실패");
9399
}
94100
};
95101

96102
return (
97103
<div className="relative bg-white w-[260px] sm:w-[504px] lg:w-[1022px] h-[770px] sm:h-[592px] lg:h-[620px] mx-auto mt-[40px]">
104+
<ToastContainer position="top-center" autoClose={2000} />
98105
{filteredData.length > 0 && (
99106
<div className="hidden sm:flex p-6 w-full h-[26px] justify-start items-center pl-[43px] pr-[76px] md:gap-x-[130px] lg:gap-x-[280px]">
100107
<p className="lg:ml-10 font-normal text-[var(--color-gray2)]">이름</p>
@@ -165,13 +172,11 @@ function InvitedList({
165172
: !hasMore && <NoResultDashBoard searchTitle={searchTitle} />}{" "}
166173
{/* 검색 내역이 없을 경우 */}
167174
{filteredData.length > 0 && !hasMore && (
168-
<p className="lg:mr-18 text-center text-gray-400 py-4">
175+
<p className="lg:mr-18 text-center text-gray-400 bg-transparent">
169176
더 이상 초대 목록이 없습니다.
170177
</p>
171178
)}
172-
{hasMore && (
173-
<div ref={observerRef} className="h-[50px] w-[50px] bg-red"></div>
174-
)}
179+
{hasMore && <div ref={observerRef} className="h-[50px] w-[50px]"></div>}
175180
</div>
176181
</div>
177182
);

src/components/table/member/MemberList.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import { MemberType } from "@/types/users";
55
import { getMembers } from "@/api/members";
66
import { apiRoutes } from "@/api/apiRoutes";
77
import axiosInstance from "@/api/axiosInstance";
8-
import Image from "next/image";
8+
import { ToastContainer, toast } from "react-toastify";
9+
import "react-toastify/dist/ReactToastify.css";
910

1011
interface HeaderBebridgeProps {
1112
dashboardId?: string | string[];
@@ -27,10 +28,10 @@ const MemberList: React.FC<HeaderBebridgeProps> = ({ dashboardId }) => {
2728
/*버튼(삭제, 이전, 다음)*/
2829
const handleDelete = async (id: number) => {
2930
try {
30-
const response = await axiosInstance.delete(apiRoutes.memberDetail(id));
31+
await axiosInstance.delete(apiRoutes.memberDetail(id));
3132
window.location.reload();
3233
} catch (error) {
33-
alert("구성원원 삭제에 실패하였습니다 .");
34+
toast.error("구성원원 삭제에 실패하였습니다 .");
3435
console.error("구성원 삭제 실패:", error);
3536
}
3637
};
@@ -48,7 +49,9 @@ const MemberList: React.FC<HeaderBebridgeProps> = ({ dashboardId }) => {
4849
const fetchMembers = async () => {
4950
try {
5051
if (dashboardId) {
51-
const members = await getMembers(dashboardId);
52+
const members = await getMembers({
53+
dashboardId: Number(dashboardId),
54+
});
5255
setMembers(members);
5356
console.log("member_list", members);
5457
}
@@ -62,6 +65,7 @@ const MemberList: React.FC<HeaderBebridgeProps> = ({ dashboardId }) => {
6265

6366
return (
6467
<div className="lg:h-[404px] md:h-[404px] sm:h-[337px] lg:w-[620px] md:w-[544px] sm:w-[337px] relative bg-white p-6 rounded-lg max-w-md w-full sm:max-w-lg md:max-w-xl lg:max-w-2xl">
68+
<ToastContainer position="top-center" autoClose={2000} />
6569
<div className="flex justify-between items-center">
6670
<p className="text-xl sm:text-2xl font-bold">구성원</p>
6771
<Pagination

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@ export default function EditDashboard() {
3939
const dashboardIdNumber = Number(dashboardId);
4040
if (!dashboardId) return;
4141
try {
42-
const response = await axiosInstance.delete(
43-
apiRoutes.DashboardDetail(dashboardIdNumber)
44-
);
42+
await axiosInstance.delete(apiRoutes.DashboardDetail(dashboardIdNumber));
4543
router.push(`/mydashboard`);
4644
} catch (error) {
4745
alert("대시보드 삭제에 실패하였습니다 .");

0 commit comments

Comments
 (0)