Skip to content

Commit

Permalink
Merge pull request #105 from CoolPeace-yanolza/feature/#95
Browse files Browse the repository at this point in the history
[#95] 회원가입 관련 API 연결 및 로그인 관련 추가 API 로직 수정
  • Loading branch information
dabin-Hailey authored Jan 25, 2024
2 parents d356c15 + 3ab8703 commit 8e6f257
Show file tree
Hide file tree
Showing 16 changed files with 301 additions and 45 deletions.
2 changes: 2 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ export { default as getDailyReport } from './lib/getDailyReport';
export { default as getCouponRanking } from './lib/getCouponRanking';
export { default as getLocalCouponUsage } from './lib/getLocalCouponUsage';
export { default as getMonthStatus } from './lib/getMonthStatus';
export { default as getEmailValid } from './lib/getEmailValid';
export { default as postSignUp } from './lib/postSignUp';
18 changes: 18 additions & 0 deletions src/api/lib/getEmailValid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { AxiosError } from 'axios';

import { instance } from '..';

const getEmailValid = async (email: string) => {
try {
const response = await instance.get(
`/v1/member/register/check/email?email=${email}`
);
return response;
} catch (error) {
if (error instanceof AxiosError) {
return error.response;
}
}
};

export default getEmailValid;
18 changes: 9 additions & 9 deletions src/api/lib/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import axios, {
InternalAxiosRequestConfig
} from 'axios';

import { getCookies, setCookies } from '@utils/lib/cookies';
import { postRefreshToken } from '..';
import { deleteAllCookies, getCookies, setCookies } from '@utils/lib/cookies';
import { postLogout, postRefreshToken } from '..';
import { AxiosResponseError } from '@/types/axios';

const instance = axios.create({
Expand Down Expand Up @@ -60,14 +60,14 @@ const onErrorResponse = async (error: AxiosResponseError<string>) => {
originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`;
return instance(originalRequest);

// 리프레시 토큰도 만료되었을 때 = 재로그인 안내
// 리프레시 토큰도 만료되었을 때 (재로그인 안내)
} else if (tokenResponse.status === 404) {
console.log(tokenResponse.data.message);
// await postLogout();
// deleteAllCookies();
// navigate('/login');

return Promise.reject(error);
alert(
'안전한 서비스 이용을 위해 자동 로그아웃되었습니다.\n다시 로그인해주세요.'
);
await postLogout();
deleteAllCookies();
window.location.replace('/login');
}
}
console.log(error.response.data.code, error.response);
Expand Down
17 changes: 17 additions & 0 deletions src/api/lib/postSignUp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { AxiosError } from 'axios';

import { instance } from '..';
import { SignUpData } from '@/types/signUp';

const postSignUp = async (signUpData: SignUpData) => {
try {
const response = await instance.post('/v1/member/register', signUpData);
return response;
} catch (error) {
if (error instanceof AxiosError) {
return error.response;
}
}
};

export default postSignUp;
9 changes: 9 additions & 0 deletions src/assets/icons/ic-signup-firecracker.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/Login/LoginForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const LoginForm = ({ handleModalOpen }: LoginFormProps) => {
);

if (state) {
navigate(state);
navigate(state.from);
} else {
navigate('/');
}
Expand Down
102 changes: 83 additions & 19 deletions src/components/SignUp/SignUpForm/index.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,88 @@
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import styled from '@emotion/styled';
import { FormProvider, useForm } from 'react-hook-form';
import {
FieldValues,
FormProvider,
SubmitHandler,
useForm
} from 'react-hook-form';

import { SignUpInputValidation } from '@/types/signUp';
import {
SignUpData,
SignUpFormProps,
SignUpInputValidation
} from '@/types/signUp';
import {
AuthButton,
AuthInputNormal,
AuthInputPassword
} from '@components/Auth';
import { getEmailValid, postSignUp } from 'src/api';

const SignUpForm = ({ handleModalOpen }: SignUpFormProps) => {
const navigate = useNavigate();

const SignUpForm = () => {
const methods = useForm({
mode: 'all'
});
const { getFieldState, formState } = methods;
const { watch, getValues, getFieldState, formState, handleSubmit } = methods;
const { errors, isValid } = formState;

const emailValue: string = getValues('user_email');
const isEmailTouched = getFieldState('user_email', formState).isTouched;
const isEmailValid = isEmailTouched ? !errors?.user_email : false;
const isEmailValueValid = isEmailTouched ? !errors?.user_email : false;

const emailValidInitialValue = {
message: '',
type: ''
};

const [emailValidMessage, setEmailValidMessage] = useState(
emailValidInitialValue
);

const checkEmailValid = async (event: React.FormEvent<HTMLButtonElement>) => {
event.preventDefault();

const response = await getEmailValid(emailValue);

if (response?.status === 200) {
setEmailValidMessage({
message: '사용 가능한 아이디입니다.',
type: 'success'
});
} else if (response?.status === 400) {
setEmailValidMessage({
message: '이미 사용 중인 아이디입니다.',
type: 'failure'
});
}
};

const onSubmit: SubmitHandler<FieldValues> = async data => {
const formData: SignUpData = {
email: data.user_email,
password: data.user_password,
name: data.user_name
};

const response = await postSignUp(formData);

if (response?.status === 201) {
navigate('/signup/complete', { replace: true });
} else {
handleModalOpen();
}
};

useEffect(() => {
setEmailValidMessage(emailValidInitialValue);
}, [watch('user_email')]);

return (
<FormProvider {...methods}>
<Form>
<Form onSubmit={handleSubmit(onSubmit)}>
<InputLabelWrapper>
<Label htmlFor="user_name">이름</Label>
<AuthInputNormal
Expand Down Expand Up @@ -48,22 +110,22 @@ const SignUpForm = () => {
/>
<AuthButton
size="small"
variant={isEmailValid ? 'navy' : 'disabled'}
variant={isEmailValueValid ? 'navy' : 'disabled'}
text="중복확인"
disabled={!isEmailValid}
buttonFunc={() => {
// TODO : 이메일 중복확인 API 요청 로직
}}
disabled={!isEmailValueValid}
buttonFunc={checkEmailValid}
/>
</EmailInputWrapper>
{/* 입력항목 자체 유효성 검사에 따라 나타날 유효성 메세지 */}
{errors.user_email && (
<ValidationText>
{errors?.user_email?.message?.toString()}
</ValidationText>
)}
{!errors.user_email && isEmailValid && (
<ValidationText $isValid={isEmailValid}>
백엔드 응답에 따라 나타날 유효성 메세지
{/* API 응답에 따라 나타날 유효성 메세지 */}
{!errors.user_email && isEmailValueValid && !!emailValue && (
<ValidationText $isValid={emailValidMessage.type === 'success'}>
{emailValidMessage.message}
</ValidationText>
)}
</InputLabelWrapper>
Expand Down Expand Up @@ -97,12 +159,14 @@ const SignUpForm = () => {
</InputLabelWrapper>
<AuthButton
size="large"
variant={isValid ? 'navy' : 'disabled'}
variant={
isValid && emailValidMessage.type === 'success'
? 'navy'
: 'disabled'
}
text="회원가입"
disabled={!isValid}
buttonFunc={() => {
// TODO : 회원가입 API 요청 로직
}}
disabled={!isValid || emailValidMessage.type === 'failure'}
buttonFunc={handleSubmit(onSubmit)}
/>
</Form>
</FormProvider>
Expand Down
4 changes: 2 additions & 2 deletions src/components/common/Layout/Header/User/UserModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ErrorModal } from '@components/common';
import { postLogout } from 'src/api';
import { getCookies, deleteAllCookies } from '@utils/lib/cookies';
import { UserModal, UserModalStyleProps } from '@/types/layout';
import ERROR_MODAL_MESSAGE from 'src/constants/lib/ERROR_MODAL_MESSAGE';
import { ERROR_MODAL_MESSAGE } from 'src/constants';
import theme from '@styles/theme';

const UserModal = ({ isOpen }: UserModal) => {
Expand All @@ -21,7 +21,7 @@ const UserModal = ({ isOpen }: UserModal) => {
const handleLogout = async () => {
await postLogout();
deleteAllCookies();
navigate('/login');
navigate('/login'), { replace: true };
/* HACK: 로그아웃 에러 response 가 있을 경우 사용
[ 대안 1 ]
Expand Down
1 change: 1 addition & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as STATUS_CODES } from './lib/STATUS_CODES';
export { default as ERROR_MODAL_MESSAGE } from './lib/ERROR_MODAL_MESSAGE';
4 changes: 4 additions & 0 deletions src/constants/lib/ERROR_MODAL_MESSAGE.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ const ERROR_MODAL_MESSAGE = {
text: '이메일 또는 비밀번호를 잘못 입력했습니다.',
errorText: '입력하신 내용을 다시 확인해주세요.'
},
SIGNUP: {
text: '회원가입에 실패했습니다.',
errorText: '다시 시도해주세요.'
},
USER_MODAL: {
text: '로그아웃에 실패하였습니다.',
errorText: '잠시후 재시도 해주세요.'
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Login/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import styled from '@emotion/styled';

import { ErrorModal, Footer } from '@components/common';
import { LoginForm, LoginTitle } from '@components/Login';
import ERROR_MODAL_MESSAGE from 'src/constants/lib/ERROR_MODAL_MESSAGE';
import { ERROR_MODAL_MESSAGE } from 'src/constants';

const Login = () => {
const [modalContent, setModalContent] = useState(ERROR_MODAL_MESSAGE.LOGIN);
Expand Down
16 changes: 14 additions & 2 deletions src/pages/SignUp/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { useState } from 'react';
import styled from '@emotion/styled';

import logo from '@assets/icons/ic-logo.svg';
import { Footer } from '@components/common';
import { ErrorModal, Footer } from '@components/common';
import { SignUpForm, SignUpTitle } from '@components/SignUp';
import { ERROR_MODAL_MESSAGE } from 'src/constants';

const SignUp = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const handleModalClose = () => setIsModalOpen(false);
const handleModalOpen = () => setIsModalOpen(true);

return (
<WhiteBackground>
<WithoutFooterSection>
Expand All @@ -17,11 +23,17 @@ const SignUp = () => {
<Container>
<Content>
<SignUpTitle />
<SignUpForm />
<SignUpForm handleModalOpen={handleModalOpen} />
</Content>
</Container>
</WithoutFooterSection>
<Footer />
{isModalOpen && (
<ErrorModal
modalContent={ERROR_MODAL_MESSAGE.SIGNUP}
ButtonFunc={handleModalClose}
/>
)}
</WhiteBackground>
);
};
Expand Down
Loading

0 comments on commit 8e6f257

Please sign in to comment.