react-use 의 useInterval 을 사용하여 남은 시간을 구현하겠다.
$ npm i react-use
SignupComponent.tsx 파일 상단에 import를 추가한다.
import { useInterval } from 'react-use';
useInterval을 사용한다.
useInterval(()=> {
setEmailCount(emailCount -1);
},1000)
emailSend 부분에 emailCount에 숫자를 채워준다.
추가로 email중복확인이 완료되었으므로 userState도 업데이트해준다.
const emailSend = () => {
if(userState.userInfo.email !=='' && userState.userInfo.email.indexOf('@') !== -1) { // 입력된 값이 존재하고 email 형식에 맞을경우
dispatch(userEmailDuplicate(userState.userInfo.email)).then((req : any) => {
if(!req.payload.result) { // 이메일이 이미 존재할 때
alert('해당 이메일이 이미 존재합니다.');
}else {
dispatch(userEmailSend(userState.userInfo.email)).then((req : any) => {
if(req.payload.result) { // 이메일 보내기 성공했을 때
setEmailSendOK(true);
setEmailCount(300);
dispatch({type : actionTypesUser.USER_STATE, data: ['emailDuple',true]});
}else {
alert('이메일 전송이 실패됐습니다.')
}
});
}
})
}
}
전송을 하고 웹을 확인해보면
이렇게 잘 뜨는것을 확인할 수 있다.
useEffect를 이용해서 만약 남은 시간이 0이 되면 emailSendOK state가 false가 되면서 재전송버튼은 다시 보내기버튼이 되고 남은시간과 인증번호 입력칸, 확인버튼이 사라지게 한다.
useEffect(()=> {
if(emailCount === 0)
setEmailSendOK(false)
},[emailCount])
이제 성공적으로 보냈고, 남은시간과 보여줘야 할 요소들의 정의가 끝이 났으니 인증번호를 확인하는 작업을 해보자.
- 이메일로 확인한 인증번호를 입력한다.
- 확인 버튼을 누른다. 백엔드에 쿠키에 저장된 authNum값과 입력한 enterNum 두 값이 전송된다.
- 백엔드에서 쿠키를 확인하고 두 값이 일치하면 result true를 반환한다.
- 만약 이메일 인증이 성공하면 userState.emailAuth 값이 true가 되고 남은시간과 인증번호 입력창, 확인 버튼이 사라질 것이며 보내기 버튼이 비활성화된다.
- 만약 인증에 실패하면 alert창을 띄어준다.
먼저 인증번호 입력칸 state를 작성해준다.
const [emailAuthText,setEmailAuthText] = useState<string>(''); // email auth text
이제 확인버튼을 누르면 입력한 인증번호를 bcrypt한 값이랑 쿠키에 담겨있던 암호화된 인증번호를 비교해서
두개가 일치하면 userState.emailAuth 값을 true로 바꿀 것이다.
emailCert 함수를 만들고, 입력칸과 확인버튼 쪽 코드를 수정해준다.
(...)
const emailCert = () => {
if(emailAuthText !== '') { // 인증번호 입력란이 공백이 아닐 경우에 실행
}
}
(...)
<div>
<p style={{color : 'red', fontSize: 5}}>남은 시간 : {Math.floor(emailCount / 60)} 분 {Math.floor(emailCount % 60)} 초</p>
<input
name="emailAuthText"
type="text"
placeholder="Enter number"
onChange={(event) => { setEmailAuthText(event.target.value)}}/>
<button
type="button"
onClick={emailCert}>
확인
</button>
</div>
(...)
dispatch 사용을 위해 필요한 것들을 작성해준다.
userAct.interfaces.ts
export enum actionTypesUser {
USER_INIT = "USER_INIT", // state 초기화
USER_STATE = "USER_STATE", // userState 변경
USER_INFO = "USER_INFO", // userInfo 변경
USER_ID_DUPLICATE = "USER_ID_DUPLICATE", // ID 중복 검사
USER_EMAIL_DUPLICATE = "USER_EMAIL_DUPLICATE", // Email 중복검사
USER_EMAIL_SEND = "USER_EMAIL_SEND", // Email 보내기
USER_EMAIL_CERT = "USER_EMAIL_CERT", // Email 인증번호 확인
}
export type ActionsUser = UserInit | UserState | UserInfo | UserIdDuplicate
| UserEmailDuplicate | UserEmailSend | UserEmailCert
export interface UserInit {
type : actionTypesUser.USER_INIT;
data : any;
}
export interface UserState {
type : actionTypesUser.USER_STATE;
data : any;
}
export interface UserInfo {
type : actionTypesUser.USER_INFO;
data : any;
}
export interface UserIdDuplicate {
type : actionTypesUser.USER_ID_DUPLICATE;
payload : any;
}
export interface UserEmailDuplicate {
type : actionTypesUser.USER_EMAIL_DUPLICATE;
payload : any;
}
export interface UserEmailSend {
type : actionTypesUser.USER_EMAIL_SEND;
payload : any;
}
export interface UserEmailCert {
type : actionTypesUser.USER_EMAIL_CERT;
payload : any;
}
user_reducer.ts
case actionTypesUser.USER_EMAIL_CERT:
return {
...state, data : action.payload
}
user_action.ts
export async function userEmailCert (authNum : string) {
const request = Axios.post('/api/email/cert',{authNum : authNum})
.then(response => response.data)
return {
type : actionTypesUser.USER_EMAIL_CERT,
payload: request
}
}
프론트에서 로직을 먼저 구현한다.
signComponent.tsx
const emailCert = () => {
if(emailAuthText !== '') { // 인증번호 입력란이 공백이 아닐 경우에 실행
dispatch(userEmailCert(emailAuthText)).then((req : any) => {
switch(req.payload.result) {
case "expiry" :
alert('쿠키가 존재하지 않습니다.')
break;
case "false" :
alert('인증번호가 틀립니다.')
break;
case "success" :
alert('인증번호가 일치합니다.');
setEmailSendOK(false);
setEmailCount(0);
dispatch({type : actionTypesUser.USER_STATE, data : ['emailAuth',true]});
default :
break;
}
})
}
}
- authNum 쿠키가 존재하지 않을 경우 : '쿠키가 존재하지 않습니다' 문구를 띄운다.
- 인증번호가 틀릴경우 : '인증번호가 틀립니다' 문구를 띄운다.
- 성공할 경우 : '인증번호가 일치합니다' 문구를 띄우고 emailSendOK를 false로 바꿔서 인증번호 입력칸과 전송버튼을 사라지게하고 남은 시간을 다시 0으로 바꾼다. userState의 emailAuth를 true로 바꿔서 보내기 버튼을 비활성화 시킨다.
이제 프론트쪽에서의 구현은 끝났으니 백엔드(NestJS)로 넘어가보자.
email.controller.ts
@Post('cert')
async emailCert(@Res({ passthrough: true}) res : any, @Req() req : any) {
return await this.emailService.emailCert(req);
}
service의 emailCert 함수 결과값을 리턴한다.
email.service.ts
async emailCert(req : any) {
if(req.cookies.authNum) {
const result = await bcrypt.compare(req.body.authNum,req.cookies.authNum);
if(result) {
return {result : "success"}
}
else {
return {result : "failed"}
}
}
else{
return {result : "expiry"}
}
}
쿠키가 존재하지 않으면 expiry를 반환한다.
bcrypt.compare 메소드를 사용해서 암호가 일치하면 success, 다르면 failed를 반환한다.
이제 직접 화면에서 실행해보자.
- 이메일을 보냈을 때
- 인증번호 입력해서 확인버튼 눌렀을 때
- alert 창의 확인버튼을 눌렀을 때
이렇게 이메일 인증번호를 보내고 인증번호를 확인하는것 까지 완료했다.
'Nest - Next' 카테고리의 다른 글
Nest - Next | n2server | Signup | Complete (0) | 2021.10.25 |
---|---|
Nest - Next | n2server | Signup | Address (0) | 2021.10.22 |
Nest - Next | n2server | Signup | Email Send(2) (0) | 2021.10.20 |
Nest - Next | n2server | Signup | Password, Email Send(1) (0) | 2021.10.20 |
Nest - Next | n2server | Signup | ID_Duplicate(back) (0) | 2021.10.19 |