Skip to content

Commit c821635

Browse files
committed
feat: 회원가입 약관동의 팝업 구현
1 parent c66475c commit c821635

File tree

8 files changed

+112
-66
lines changed

8 files changed

+112
-66
lines changed

src/components/Join/TermsCheckInput.tsx

Lines changed: 69 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,79 @@
11
import { useJoinState } from '@/stores/joinStore';
2-
import { useEffect } from 'react';
3-
import { useLocation } from 'react-router-dom';
2+
import { useEffect, useRef, useState } from 'react';
3+
import Dialog from '../common/Dialog';
4+
import { PersonalInfoPage, UseConditionPage } from '@/pages/Policy';
45

56
const TermsCheckInput = () => {
6-
const { useTermsCheck, privacyTermsCheck, useTermsCheckHandler, privacyTermsCheckHandler } = useJoinState();
7-
const { privacyTerms, useTerms } = useLocation().state || {};
7+
interface DialogElement {
8+
openModal: () => void;
9+
closeModal: () => void;
10+
}
11+
12+
const [dialogMessage, setDialogMessage] = useState('');
13+
const { useTermsCheck, privacyTermsCheck } = useJoinState();
14+
const dialogRef = useRef<DialogElement | null>(null);
15+
16+
const useTermsClick = () => {
17+
setDialogMessage('이용약관 동의');
18+
dialogRef.current?.openModal();
19+
};
20+
21+
const privacyTermsClick = () => {
22+
setDialogMessage('개인정보 수집, 이용 동의');
23+
dialogRef.current?.openModal();
24+
};
825

926
useEffect(() => {
10-
if (privacyTerms) privacyTermsCheckHandler;
11-
if (useTerms) useTermsCheckHandler;
12-
}, [privacyTerms, privacyTermsCheckHandler, useTerms, useTermsCheckHandler]);
27+
dialogRef.current?.closeModal();
28+
}, [useTermsCheck, privacyTermsCheck]);
1329

1430
return (
15-
<label className="form-control mb-9 mt-5 w-full">
16-
<div className="flex flex-col">
17-
<label className="font-bold">약관 동의</label>
18-
</div>
19-
<div className="mt-2 flex items-center justify-between">
20-
<label className="hover:underline" htmlFor="termsOne">
21-
<a href="/policy/usecondition">이용약관 동의 (필수)</a>
22-
</label>
23-
<input
24-
type="radio"
25-
className="radio-primary radio"
26-
checked={useTermsCheck}
27-
aria-label={'join-useTermsCheck-input'}
28-
readOnly
29-
/>
30-
</div>
31-
{!useTermsCheck ? <span className="text-red-500">이용약관에 동의해 주세요.</span> : <span className="h-6"></span>}
32-
<div className="mt-2 flex items-center justify-between">
33-
<label className="hover:underline" htmlFor="termsTwo">
34-
<a href="/policy/personalInfo">개인정보 수집, 이용 동의 (필수)</a>
35-
</label>
36-
<input
37-
type="radio"
38-
className="radio-primary radio"
39-
checked={privacyTermsCheck}
40-
aria-label={'join-privacyTermsCheck-input'}
41-
readOnly
42-
/>
43-
</div>
44-
{!privacyTermsCheck ? (
45-
<span className="text-red-500">개인정보 수집, 이용에 동의해 주세요.</span>
46-
) : (
47-
<span className="h-6"></span>
48-
)}
49-
</label>
31+
<>
32+
<label className="form-control mb-9 mt-5 w-full">
33+
<div className="flex flex-col">
34+
<label className="font-bold">약관 동의</label>
35+
</div>
36+
<div className="mt-2 flex items-center justify-between">
37+
<label className="hover:underline" htmlFor="termsOne" onClick={useTermsClick}>
38+
이용약관 동의 (필수)
39+
</label>
40+
<input
41+
type="radio"
42+
className="radio-primary radio"
43+
checked={useTermsCheck}
44+
onClick={useTermsClick}
45+
aria-label={'join-useTermsCheck-input'}
46+
readOnly
47+
/>
48+
</div>
49+
{!useTermsCheck ? (
50+
<span className="text-red-500">이용약관에 동의해 주세요.</span>
51+
) : (
52+
<span className="h-6"></span>
53+
)}
54+
<div className="mt-2 flex items-center justify-between">
55+
<label className="hover:underline" htmlFor="termsTwo" onClick={privacyTermsClick}>
56+
개인정보 수집, 이용 동의 (필수)
57+
</label>
58+
<input
59+
type="radio"
60+
className="radio-primary radio"
61+
checked={privacyTermsCheck}
62+
onClick={privacyTermsClick}
63+
aria-label={'join-privacyTermsCheck-input'}
64+
readOnly
65+
/>
66+
</div>
67+
{!privacyTermsCheck ? (
68+
<span className="text-red-500">개인정보 수집, 이용에 동의해 주세요.</span>
69+
) : (
70+
<span className="h-6"></span>
71+
)}
72+
</label>
73+
<Dialog ref={dialogRef} desc={dialogMessage}>
74+
{dialogMessage === '이용약관 동의' ? <UseConditionPage /> : <PersonalInfoPage />}
75+
</Dialog>
76+
</>
5077
);
5178
};
5279

src/components/Policy/PolicyPersonalButton.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import { useNavigate } from 'react-router-dom';
1+
import { useJoinState } from '@/stores/joinStore';
22

33
const PolicyPersonalButton = () => {
4-
const navigate = useNavigate();
5-
6-
const onClick = () => {
7-
navigate('/join', { replace: true, state: { privacyTerms: true } });
8-
};
4+
const { privacyTermsCheckHandler } = useJoinState();
95

106
return (
117
<div className="absolute bottom-12 w-10/12 md:w-11/12">
12-
<button type={'submit'} onClick={onClick} className="btn btn-outline btn-primary m-auto block w-full max-w-md">
8+
<button
9+
type={'button'}
10+
onClick={privacyTermsCheckHandler}
11+
className="btn btn-outline btn-primary m-auto block w-full max-w-md"
12+
>
1313
동의하기
1414
</button>
1515
</div>

src/components/Policy/PolicyUseConditionButton.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import { useNavigate } from 'react-router-dom';
1+
import { useJoinState } from '@/stores/joinStore';
22

33
const PolicyUseConditionButton = () => {
4-
const navigate = useNavigate();
5-
6-
const onClick = () => {
7-
navigate('/join', { replace: true, state: { useTerms: true } });
8-
};
4+
const { useTermsCheckHandler } = useJoinState();
95

106
return (
117
<div className="absolute bottom-12 w-10/12 md:w-11/12">
12-
<button type={'submit'} onClick={onClick} className="btn btn-outline btn-primary m-auto block w-full max-w-md">
8+
<button
9+
type={'button'}
10+
onClick={useTermsCheckHandler}
11+
className="btn btn-outline btn-primary m-auto block w-full max-w-md"
12+
>
1313
동의하기
1414
</button>
1515
</div>

src/layouts/PolicyPageLayout.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { FC, ReactNode } from 'react';
22
import PolicyPersonalButton from '../components/Policy/PolicyPersonalButton';
3-
import HistoryBackButton from '../components/common/HistoryBackButton';
43

54
interface Props {
65
children: ReactNode;
@@ -10,7 +9,6 @@ interface Props {
109
const PolicyPageLayout: FC<Props> = ({ children, title }) => {
1110
return (
1211
<main className={'relative m-auto h-screen w-fit p-8'}>
13-
<HistoryBackButton />
1412
<h2 className="my-5 text-xl font-semibold">{title}</h2>
1513
{/* <div className="card h-5/6 max-w-5xl bg-white">{children}</div> */}
1614
<div className="card h-3/4 max-w-5xl bg-white">{children}</div>

src/layouts/UseTermsPageLayout.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { FC, ReactNode } from 'react';
2+
import PolicyUseConditionButton from '@/components/Policy/PolicyUseConditionButton';
3+
4+
interface Props {
5+
children: ReactNode;
6+
title: string;
7+
}
8+
9+
const UseTermsPageLayout: FC<Props> = ({ children, title }) => {
10+
return (
11+
<main className={'relative m-auto h-screen w-fit p-8'}>
12+
<h2 className="my-5 text-xl font-semibold">{title}</h2>
13+
{/* <div className="card h-5/6 max-w-5xl bg-white">{children}</div> */}
14+
<div className="card h-3/4 max-w-5xl bg-white">{children}</div>
15+
<PolicyUseConditionButton />
16+
</main>
17+
);
18+
};
19+
20+
export default UseTermsPageLayout;

src/pages/Policy/UseConditionPage.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { FC } from 'react';
2-
import PolicyPageLayout from '../../layouts/PolicyPageLayout';
32
import PolicyUseCondition from '../../components/Policy/PolicyUseCondition';
3+
import UseTermsPageLayout from '@/layouts/UseTermsPageLayout';
44

55
const UseConditionPage: FC = () => {
66
return (
7-
<PolicyPageLayout title="전자상거래 표준약관">
7+
<UseTermsPageLayout title="전자상거래 표준약관">
88
<PolicyUseCondition />
9-
</PolicyPageLayout>
9+
</UseTermsPageLayout>
1010
);
1111
};
1212

src/pages/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import Loading from './Loading';
44
import LoginPage from './LoginPage';
55
import { NotFound } from './Notfound';
66

7-
import * as Policy from './Policy/index';
7+
import * as Policy from './Policy';
88

99
export { ResetPwPage as ResetPwPage, JoinPage, Loading, LoginPage, NotFound, Policy };

src/tests/join.test.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ describe('Join test', () => {
107107
it('이용약관 및 개인정보 관련 체크를 하지 않으면 에러 텍스트를 보여줄 수 있어야 한다.', async () => {
108108
const useTermsCheckInput = screen.getByLabelText(/useTermsCheck/i) as HTMLInputElement;
109109
const privacyTermsCheckInput = screen.getByLabelText(/privacyTermsCheck/i) as HTMLInputElement;
110+
110111
fireEvent.change(useTermsCheckInput, {
111112
target: {
112113
checked: false,
@@ -219,14 +220,14 @@ describe('Join test', () => {
219220
value: '123456',
220221
},
221222
});
222-
fireEvent.change(useTermsCheckInput, {
223+
fireEvent.click(useTermsCheckInput, {
223224
target: {
224-
checked: true,
225+
checked: false,
225226
},
226227
});
227-
fireEvent.change(privacyTermsCheckInput, {
228+
fireEvent.click(privacyTermsCheckInput, {
228229
target: {
229-
checked: true,
230+
checked: false,
230231
},
231232
});
232233
await waitFor(() => {});

0 commit comments

Comments
 (0)