Skip to content

Commit

Permalink
feat: 인증번호 확인 버튼 추가 및 인증번호 전송 시 토스트 메시지
Browse files Browse the repository at this point in the history
  • Loading branch information
chaeseungyun committed Jul 9, 2024
1 parent 90f836b commit a1019f6
Showing 1 changed file with 78 additions and 77 deletions.
155 changes: 78 additions & 77 deletions src/page/Auth/FindPassword/Verify/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { isKoinError, sendClientError } from '@bcsdlab/koin';
import { sendVerifyCode, verifyCode } from 'api/auth';
import { ChangeEvent, useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import {
UseFormClearErrors,
useFormContext, UseFormGetValues, UseFormSetError,
} from 'react-hook-form';
import { useOutletContext } from 'react-router-dom';
Expand All @@ -11,6 +10,7 @@ import { ReactComponent as Warning } from 'assets/svg/auth/warning.svg';
import styles from 'page/Auth/FindPassword/index.module.scss';
import { OutletProps } from 'page/Auth/FindPassword/entity';
import { useDebounce } from 'utils/hooks/useDebounce';
import showToast from 'utils/ts/showToast';

interface SendCode {
getValues: UseFormGetValues<Verify>;
Expand All @@ -27,59 +27,17 @@ const code = (
}: SendCode,
) => {
sendVerifyCode(getValues('phone_number'))
.then(() => setIsSent(true))
.then(() => {
setIsSent(true);
showToast('success', '인증번호를 발송했습니다');
})
.catch((e) => {
if (isKoinError(e)) {
setError('phone_number', { type: 'custom', message: e.message });
}
});
};

const useCheckCode = (
setIsStepComplete: React.Dispatch<React.SetStateAction<boolean>>,
getValues: UseFormGetValues<Verify>,
setError: UseFormSetError<Verify>,
clearErrors: UseFormClearErrors<Verify>,
) => {
const [certificationCode, setCertificationCode] = useState<string>('');
const [isCertified, setIsCertified] = useState<boolean>(false);

const setCode = (e: ChangeEvent<HTMLInputElement>) => {
setCertificationCode(e.target.value);
if (e.target.value.length < 6) {
setError('certification_code', { message: '필수 입력 항목입니다.' });
setIsCertified(false);
setIsStepComplete(false);
return;
}
clearErrors();
};

useEffect(() => {
if (certificationCode.length === 6) {
verifyCode({
certification_code: certificationCode,
phone_number: getValues('phone_number'),
}).then((data) => {
setIsStepComplete(true);
setIsCertified(true);
clearErrors();
sessionStorage.setItem('accessToken', data.data.token);
})
.catch((e) => {
if (isKoinError(e)) {
setError('certification_code', { type: 'error', message: e.message });
} else {
sendClientError(e);
}
setIsStepComplete(false);
});
}
}, [certificationCode, setIsStepComplete, getValues, setError, clearErrors]);

return { certificationCode, setCode, isCertified };
};

interface Verify {
phone_number: string;
certification_code: string;
Expand All @@ -91,43 +49,78 @@ export default function Verify() {
} = useFormContext<Verify>();

const [isSent, setIsSent] = useState(false);
const [isCertified, setIsCertified] = useState(false);
const debounce = useDebounce<SendCode>(code, { getValues, setError, setIsSent });
const steps = useOutletContext<OutletProps>();

const { setCode, isCertified } = useCheckCode(
steps.setIsStepComplete,
getValues,
setError,
clearErrors,
);

const sendCode = () => {
if (getValues('phone_number').length === 0) {
setError('phone_number', { type: 'custom', message: '필수 입력 항목입니다.' });
return;
}
debounce();
clearErrors();
};

const verify = () => verifyCode({
certification_code: getValues('certification_code'),
phone_number: getValues('phone_number'),
}).then((data) => {
steps.setIsStepComplete(true);
setIsCertified(true);
clearErrors();
sessionStorage.setItem('accessToken', data.data.token);
})
.catch((e) => {
if (isKoinError(e)) {
setError('certification_code', { type: 'error', message: e.message });
} else {
sendClientError(e);
}
setIsCertified(false);
steps.setIsStepComplete(false);
});

useEffect(() => {
if (errors.certification_code || errors.phone_number) {
steps.setIsStepComplete(false);
setIsCertified(false);
}
}, [errors, steps]);

return (
<form className={styles.container}>
<section className={styles.section}>
<div className={styles.title}>휴대폰 번호</div>
<input
className={styles.input}
{...register('phone_number', {
required: {
value: true,
message: '필수 입력 항목입니다.',
},
maxLength: {
value: 11,
message: '11자리의 숫자로 입력해주세요',
},
})}
type="text"
placeholder="-없이 번호를 입력해주세요."
/>
<div className={styles.verify}>
<input
className={styles.input}
{...register('phone_number', {
required: {
value: true,
message: '필수 입력 항목입니다.',
},
minLength: {
value: 11,
message: '11자리의 숫자로 입력해주세요',
},
})}
maxLength={11}
type="text"
placeholder="-없이 번호를 입력해주세요."
/>
<button
className={cn({
[styles.button]: true,
[styles['button--active']]: watch('phone_number') && watch('phone_number').length === 11,
[styles['button--error']]: !!errors.certification_code,
})}
type="button"
onClick={sendCode}
>
{isSent ? '인증번호 재발송' : '인증번호 발송'}
</button>
</div>
{errors.phone_number
&& (
<div className={styles.error}>
Expand All @@ -140,23 +133,31 @@ export default function Verify() {
<div className={styles.title}>인증번호</div>
<div className={styles.verify}>
<input
className={styles['input--verify']}
{...register('certification_code')}
className={styles.input}
{...register('certification_code', {
required: {
value: true,
message: '인증번호를 입력해주세요',
},
minLength: {
value: 6,
message: '6자리의 인증번호를 입력해주세요',
},
})}
type="text"
placeholder="인증번호를 입력해주세요."
maxLength={6}
onChange={setCode}
/>
<button
className={cn({
[styles.button]: true || isCertified,
[styles.button]: true,
[styles['button--active']]: watch('phone_number') && watch('phone_number').length === 11,
[styles['button--error']]: !!errors.certification_code,
})}
type="button"
onClick={sendCode}
onClick={verify}
>
{isSent ? '인증번호 재발송' : '인증번호 발송'}
인증번호 확인
</button>
</div>
{
Expand All @@ -168,7 +169,7 @@ export default function Verify() {
)
}
{
isCertified && (
isCertified && watch('certification_code').length === 6 && (
<div className={styles.error}>
인증되었습니다
</div>
Expand Down

0 comments on commit a1019f6

Please sign in to comment.