Skip to content

Commit 674c399

Browse files
authored
Merge pull request #125 from gyoyeon-kim/card-table
[Feat, Fix] Moal : 디자인 수정, 대시보드 삭제 확인 모달 추가 / 초대 모달 중복 문제 해결
2 parents 5bbb9a6 + ca36f2b commit 674c399

File tree

7 files changed

+129
-45
lines changed

7 files changed

+129
-45
lines changed

src/api/axiosInstance.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import axios from "axios";
22

3-
console.log("🔐 BASE_URL:", process.env.NEXT_PUBLIC_BASE_URL);
4-
console.log("🔐 API_TOKEN:", process.env.NEXT_PUBLIC_API_TOKEN);
5-
63
const axiosInstance = axios.create({
74
baseURL: process.env.NEXT_PUBLIC_BASE_URL,
85
});
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Modal } from "./Modal";
2+
import { CustomBtn } from "../button/CustomButton";
3+
import { useRouter } from "next/router";
4+
import axiosInstance from "@/api/axiosInstance";
5+
import { apiRoutes } from "@/api/apiRoutes";
6+
7+
type DeleteDashboardProps = {
8+
isOpen: boolean;
9+
onClose: () => void;
10+
dashboardid: string;
11+
};
12+
13+
export default function DeleteDashboardModal({
14+
isOpen,
15+
onClose,
16+
dashboardid,
17+
}: DeleteDashboardProps) {
18+
const router = useRouter();
19+
20+
/* 대시보드 삭제 */
21+
const handleDelete = async () => {
22+
const dashboardIdNumber = Number(dashboardid);
23+
if (!dashboardid) return;
24+
try {
25+
await axiosInstance.delete(apiRoutes.DashboardDetail(dashboardIdNumber));
26+
router.push(`/mydashboard`);
27+
} catch (error) {
28+
alert("대시보드 삭제에 실패하였습니다 .");
29+
console.error("초대 실패:", error);
30+
31+
window.location.reload();
32+
}
33+
};
34+
return (
35+
<Modal
36+
isOpen={isOpen}
37+
onClose={onClose}
38+
width="w-[327px] sm:w-[568px]"
39+
height="h-[160px] sm:h-[174px]"
40+
>
41+
<div className="flex flex-col sm:gap-10 gap-6 text-center">
42+
<p className="text-xl mt-1.5">대시보드를 삭제하시겠습니까?</p>
43+
<div className="flex justify-between gap-3">
44+
<CustomBtn variant="outlineDisabled" onClick={onClose}>
45+
취소
46+
</CustomBtn>
47+
<CustomBtn variant="primary" onClick={handleDelete}>
48+
삭제
49+
</CustomBtn>
50+
</div>
51+
</div>
52+
</Modal>
53+
);
54+
}

src/components/modal/InviteDashboard.tsx

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from "react";
1+
import { useState, useEffect } from "react";
22
import { useRouter } from "next/router";
33
import Input from "../input/Input";
44
import Image from "next/image";
@@ -13,15 +13,55 @@ export default function InviteDashboard({ onClose }: { onClose?: () => void }) {
1313
const router = useRouter();
1414
const { dashboardId } = router.query;
1515

16+
const [invitelist, setInviteList] = useState<{ email: string }[]>([]);
17+
1618
const isValidEmail = (email: string) => {
1719
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
1820
};
1921

22+
/* 초대내역 목록 api 호출*/
23+
useEffect(() => {
24+
const fetchMembers = async () => {
25+
try {
26+
const dashboardIdNumber = Number(dashboardId);
27+
const res = await axiosInstance.get(
28+
apiRoutes.DashboardInvite(dashboardIdNumber),
29+
{
30+
params: {
31+
dashboardId,
32+
},
33+
}
34+
);
35+
if (res.data && Array.isArray(res.data.invitations)) {
36+
// 초대내역 리스트
37+
const inviteData = res.data.invitations.map(
38+
(item: { invitee: { email: string } }) => ({
39+
email: item.invitee.email,
40+
})
41+
);
42+
setInviteList(inviteData);
43+
console.log("inviteData", inviteData);
44+
}
45+
} catch (error) {
46+
console.error("초대내역 불러오는데 오류 발생:", error);
47+
}
48+
};
49+
50+
if (dashboardId) {
51+
fetchMembers();
52+
}
53+
}, [dashboardId]);
54+
2055
/* 초대하기 버튼 */
2156
const handleSubmit = async () => {
2257
const dashboardIdNumber = Number(dashboardId);
2358
if (!dashboardId || !email) return;
2459

60+
if (invitelist?.some((invite) => invite.email === email)) {
61+
toast.error("이미 초대한 멤버입니다.");
62+
return;
63+
}
64+
2565
try {
2666
await axiosInstance.post(apiRoutes.DashboardInvite(dashboardIdNumber), {
2767
email,
@@ -92,7 +132,7 @@ export default function InviteDashboard({ onClose }: { onClose?: () => void }) {
92132
border border-[var(--color-gray3)] text-[var(--color-white)]
93133
${!email || !isValidEmail(email) ? "bg-gray-300 cursor-not-allowed" : "bg-[var(--primary)]"}`}
94134
>
95-
생성
135+
초대
96136
</button>
97137
</div>
98138
</div>

src/components/modal/NewDashboard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export default function NewDashboard({
4747

4848
onCreate?.(response.data);
4949
onClose?.();
50-
} catch (error) {
50+
} catch {
5151
alert("대시보드 생성에 실패했습니다.");
5252
} finally {
5353
setLoading(false);

src/components/table/invited/InvitedDashBoard.tsx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -131,18 +131,18 @@ function InvitedList({
131131
<span className="text-[#333236]">{invite.nickname}</span>
132132
</p>
133133
<div className="flex gap-2 mt-2 justify-center">
134-
<button
135-
className="cursor-pointer bg-[var(--primary)] text-white px-3 py-1 rounded-md w-[84px] h-[32px]"
136-
onClick={() => acceptInvite(invite.id)}
137-
>
138-
수락
139-
</button>
140134
<button
141135
className="cursor-pointer border px-3 py-1 rounded-md w-[84px] h-[32px] text-[var(--primary)] border-[var(--color-gray3)]"
142136
onClick={() => rejectInvite(invite.id)}
143137
>
144138
거절
145139
</button>
140+
<button
141+
className="cursor-pointer bg-[var(--primary)] text-white px-3 py-1 rounded-md w-[84px] h-[32px]"
142+
onClick={() => acceptInvite(invite.id)}
143+
>
144+
수락
145+
</button>
146146
</div>
147147
</div>
148148

@@ -154,18 +154,18 @@ function InvitedList({
154154
{invite.nickname}
155155
</p>
156156
<div className="lg:mr-5 gap-2 mt-1 mr-2 justify-between sm:justify-start hidden sm:flex">
157-
<button
158-
className="cursor-pointer bg-[var(--primary)] text-white px-3 py-1 rounded-md w-[84px] h-[32px]"
159-
onClick={() => acceptInvite(invite.id)}
160-
>
161-
수락
162-
</button>
163157
<button
164158
className="cursor-pointer border px-3 py-1 rounded-md w-[84px] h-[32px] text-[var(--primary)] border-[var(--color-gray3)]"
165159
onClick={() => rejectInvite(invite.id)}
166160
>
167161
거절
168162
</button>
163+
<button
164+
className="cursor-pointer bg-[var(--primary)] text-white px-3 py-1 rounded-md w-[84px] h-[32px]"
165+
onClick={() => acceptInvite(invite.id)}
166+
>
167+
수락
168+
</button>
169169
</div>
170170
</div>
171171
))

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

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,16 @@ import MemberList from "@/components/table/member/MemberList";
66
import SideMenu from "@/components/sideMenu/SideMenu";
77
import InviteRecords from "@/components/table/InviteRecords";
88
import Image from "next/image";
9-
import axiosInstance from "@/api/axiosInstance";
10-
import { apiRoutes } from "@/api/apiRoutes";
119
import { getDashboards } from "@/api/dashboards";
12-
13-
interface Dashboard {
14-
id: number;
15-
title: string;
16-
color: string;
17-
userId: number;
18-
createdAt: string;
19-
updatedAt: string;
20-
createdByMe: boolean;
21-
}
10+
import DeleteDashboardModal from "@/components/modal/DeleteDashboardModal";
11+
import { DashboardType } from "@/types/task";
2212

2313
export default function EditDashboard() {
2414
const teamId = "13-4";
2515
const router = useRouter();
26-
const [dashboardList, setDashboardList] = useState<Dashboard[]>([]);
16+
const [dashboardList, setDashboardList] = useState<DashboardType[]>([]);
2717
const { dashboardId } = router.query;
18+
const [isModalOpen, setIsModalOpen] = useState(false);
2819
const dashboardIdString = Array.isArray(dashboardId)
2920
? dashboardId[0]
3021
: dashboardId;
@@ -34,19 +25,13 @@ export default function EditDashboard() {
3425
router.push(`/dashboard/${dashboardId}`);
3526
};
3627

37-
/* 대시보드 삭제 */
38-
const handleDelete = async () => {
39-
const dashboardIdNumber = Number(dashboardId);
40-
if (!dashboardId) return;
41-
try {
42-
await axiosInstance.delete(apiRoutes.DashboardDetail(dashboardIdNumber));
43-
router.push(`/mydashboard`);
44-
} catch (error) {
45-
alert("대시보드 삭제에 실패하였습니다 .");
46-
console.error("초대 실패:", error);
28+
/* 대시보드 삭제 모달 */
29+
const openModal = () => {
30+
setIsModalOpen(true);
31+
};
4732

48-
window.location.reload();
49-
}
33+
const closeModal = () => {
34+
setIsModalOpen(false);
5035
};
5136

5237
/* SideMenu 값 불러오기 */
@@ -102,11 +87,19 @@ export default function EditDashboard() {
10287
</div>
10388
<div className="flex mt-15 sm:mt-0 ml-8">
10489
<button
105-
onClick={handleDelete}
90+
onClick={openModal}
10691
className="text-base sm:text-lg cursor-pointer w-[320px] h-[62px] text-black3 rounded-[8px] border-[1px] border-[var(--color-gray3)] hover:scale-105 transition-transform duration-200"
10792
>
10893
대시보드 삭제하기
10994
</button>
95+
96+
{isModalOpen && (
97+
<DeleteDashboardModal
98+
isOpen={isModalOpen}
99+
onClose={closeModal}
100+
dashboardid={String(dashboardId)}
101+
/>
102+
)}
110103
</div>
111104
</div>
112105
</div>

src/types/dashboard.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ export interface DashboardType {
22
id: number;
33
title: string;
44
color: string;
5+
userId: number;
56
createdAt: string;
67
updatedAt: string;
78
createdByMe: boolean;
8-
userId: number;
99
}

0 commit comments

Comments
 (0)