Skip to content

Commit 580edc4

Browse files
authored
Merge pull request #118 from codeit-sprint-part3-6team/#116_기능_초대하기
✨ 초대하기 기능 구현
2 parents ab5a80a + 1cb8283 commit 580edc4

File tree

2 files changed

+111
-18
lines changed

2 files changed

+111
-18
lines changed

src/components/common/navbar/Navbar.tsx

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import styles from './Navbar.module.css';
2-
import { ChangeEvent, useEffect, useState } from 'react';
2+
import { useEffect, useState } from 'react';
33
import { useRouter } from 'next/router';
44
import { useSelector } from 'react-redux';
55
import { RootState } from '@/redux/store';
@@ -9,44 +9,60 @@ import InvitedMember from '../invitedmember/InvitedMember';
99
import GeneralModal from '../modal/general/GeneralModal';
1010
import Dropdown from '../dropdown/Dropdown';
1111
import { getDashboard, getMember } from '@/lib/navbar/getNavbar';
12+
import { postInvite } from '@/lib/invite/postInvite';
13+
import AuthModal from '../modal/auth/AuthModal';
14+
15+
const INITIAL_VALUES = {
16+
email: '',
17+
};
1218

1319
function Navbar() {
1420
const [dashboardData, setDashboardData] = useState(null);
1521
const [invitedMember, setInvitedMember] = useState([]);
1622
const user = useSelector((state: RootState) => state.userInfo.user);
1723
const [clientUser, setClientUser] = useState(null);
18-
const router = useRouter();
19-
// 모달
2024
const [isModalOpen, setIsModalOpen] = useState(false);
21-
const [emailValue, setEmailValue] = useState('');
22-
23-
const handleCancelClick = () => {
24-
setIsModalOpen(false);
25-
};
25+
const [emailValue, setEmailValue] = useState(INITIAL_VALUES);
26+
const [isModalVisible, setIsModalVisible] = useState(false);
27+
const [responseMessage, setResponseMessage] = useState('');
28+
const [alertMessage, setAlertMessage] = useState<string | null>(null);
29+
const router = useRouter();
30+
const {
31+
pathname,
32+
query: { id },
33+
} = router;
2634

27-
const isMyDashboard = router.pathname !== '/mydashboard';
28-
const isMyPage = router.pathname !== '/mypage';
29-
const isEdit = router.pathname !== '/edit';
35+
const isMyDashboard = pathname !== '/mydashboard';
36+
const isMyPage = pathname !== '/mypage';
37+
const isEdit = pathname !== '/edit';
3038

3139
useEffect(() => {
3240
setClientUser(user);
3341
}, [user]);
3442

3543
useEffect(() => {
36-
if (!router.query.id) {
44+
if (!id) {
3745
return;
3846
}
3947

4048
const fetchDashboardData = async () => {
41-
const memberData = await getMember(router.query.id);
49+
const memberData = await getMember(id);
4250
setInvitedMember(memberData);
4351

44-
const dashboardData = await getDashboard(router.query.id);
52+
const dashboardData = await getDashboard(id);
4553
setDashboardData(dashboardData);
4654
};
4755

4856
fetchDashboardData();
49-
}, [router.query.id]);
57+
}, [id]);
58+
59+
// 초대 요청을 보내고 alert
60+
useEffect(() => {
61+
if (!isModalOpen && alertMessage) {
62+
alert(alertMessage);
63+
setAlertMessage(null);
64+
}
65+
}, [isModalOpen, alertMessage]);
5066

5167
const renderTitle = () => {
5268
if (!isMyPage) return <h3 className={styles.title}>계정관리</h3>;
@@ -70,6 +86,29 @@ function Navbar() {
7086
}
7187
};
7288

89+
const handleCancelClick = () => {
90+
setIsModalOpen(false);
91+
setIsModalVisible(false);
92+
};
93+
94+
const submitInvite = async () => {
95+
const id = Number(router.query.id);
96+
97+
try {
98+
const response = await postInvite({ id, email: emailValue.email });
99+
setIsModalOpen(false);
100+
setEmailValue(INITIAL_VALUES);
101+
setAlertMessage(
102+
`${response.invitee.nickname}님께 초대 요청을 보냈습니다.`,
103+
);
104+
} catch (error) {
105+
setIsModalOpen(false);
106+
setResponseMessage(error.message);
107+
setIsModalVisible(true);
108+
setEmailValue(INITIAL_VALUES);
109+
}
110+
};
111+
73112
return (
74113
<div className={styles.navbar}>
75114
{renderTitle()}
@@ -99,14 +138,21 @@ function Navbar() {
99138
isOpen={isModalOpen}
100139
onClose={handleCancelClick}
101140
title="초대하기"
102-
inputValue={emailValue}
103-
onInputChange={(value) => setEmailValue(value)}
141+
inputValue={emailValue.email}
142+
onInputChange={(value) => setEmailValue({ email: value })}
104143
cancelTitle="취소"
105144
adaptTitle="초대"
106145
handleCancelClick={handleCancelClick}
107-
handleAdaptClick={() => alert('초대')}
146+
handleAdaptClick={submitInvite}
108147
/>
109148

149+
{isModalVisible && (
150+
<AuthModal
151+
message={responseMessage}
152+
handleCancelClick={handleCancelClick}
153+
/>
154+
)}
155+
110156
<InvitedMember invitedMember={invitedMember} />
111157
</div>
112158
)}

src/lib/invite/postInvite.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import instance from '../instance';
2+
3+
type inviteProps = {
4+
id: number;
5+
email: string;
6+
};
7+
8+
type inviteResponse = {
9+
createdAt: string;
10+
dashboard: {
11+
id: number;
12+
title: string;
13+
};
14+
id: number;
15+
inviteAccepted: boolean;
16+
invitee: {
17+
email: string;
18+
id: number;
19+
nickname: string;
20+
};
21+
inviter: {
22+
email: string;
23+
id: number;
24+
nickname: string;
25+
};
26+
teamId: string;
27+
updatedAt: string;
28+
};
29+
30+
export const postInvite = async ({
31+
id,
32+
email,
33+
}: inviteProps): Promise<inviteResponse> => {
34+
try {
35+
const { data } = await instance.post(`11-6/dashboards/${id}/invitations`, {
36+
email,
37+
});
38+
return data;
39+
} catch (error) {
40+
if (error.response) {
41+
return Promise.reject(error.response.data);
42+
}
43+
throw new Error(
44+
error.response?.data?.message || '정보를 불러오는데 실패했습니다.',
45+
);
46+
}
47+
};

0 commit comments

Comments
 (0)