Skip to content

Commit

Permalink
Feat: 로그아웃 서버 api 연동 (#195)
Browse files Browse the repository at this point in the history
  • Loading branch information
yangjaehyuk authored Jan 24, 2024
1 parent b9cd203 commit ea0df01
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 158 deletions.
97 changes: 36 additions & 61 deletions src/api/index.tsx
Original file line number Diff line number Diff line change
@@ -1,96 +1,71 @@
import axios from 'axios';
import { HTTP_STATUS_CODE } from '../constants/api';
import { getCookie, removeCookie, setCookie } from '@hooks/sign-in/useSignIn';
import { REFRESH_API } from './refresh';
import { message } from 'antd';
import { TextBox } from '@components/text-box';
import { ROUTES } from '@/constants/routes';
import { REFRESH_API } from './refresh';
import { isAccessTokenExpired } from '@/utils/refresh';

export const instance = axios.create({
// baseURL: '',
baseURL: process.env.REACT_APP_SERVER_URL,
timeout: 5000,
headers: {
'Content-Type': 'application/json',
timeout: 5000,
},
});

const handleUnauthorized = () => {
removeCookie('accessToken');
removeCookie('refreshToken');
localStorage.clear();
message.error('로그인 만료 입니다.');
window.location.replace('/signin');
};

instance.interceptors.request.use(
(config) => {
async (config) => {
const accessToken = getCookie('accessToken');
if (accessToken) {
config.headers['Authorization'] = `Bearer ${accessToken}`;
const isTokenExpired = isAccessTokenExpired(accessToken);
if (isTokenExpired) {
try {
const res = await REFRESH_API.postRefresh({
accessToken: accessToken,
refreshToken: getCookie('refreshToken') as string,
});
config.headers['Authorization'] = `Bearer ${res.data.accessToken}`;
setCookie('accessToken', res.data.accessToken);
setCookie('refreshToken', res.data.refreshToken);
} catch (refreshError) {
console.log('재발급 실패');
}
} else {
config.headers['Authorization'] = `Bearer ${accessToken}`;
}
}
return config;
},
(error) => {
// 여기 뺐습니다.
return Promise.reject(error);
},
);

instance.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
const accessToken = getCookie('accessToken');
const refreshToken = getCookie('refreshToken');
if (error.response.status === HTTP_STATUS_CODE.NOTFOUND) {
console.log('404페이지로 이동');
} else if (
(response) => response,
(error) => {
if (
error.response?.status === HTTP_STATUS_CODE.UNAUTHORIZED &&
window.location.pathname !== ROUTES.SIGNIN &&
window.location.pathname !== ROUTES.SIGNUP &&
window.location.pathname !== ROUTES.SIGNIN_AGREEMENT &&
window.location.pathname !== ROUTES.SIGNUP_SUCCESS &&
error.response.status === HTTP_STATUS_CODE.UNAUTHORIZED &&
accessToken
) {
try {
const response = await REFRESH_API.postRefresh({
accessToken: accessToken,
refreshToken: refreshToken as string,
});
removeCookie('accessToken');
removeCookie('refreshToken');
removeCookie('accommodationId');
const newAccessToken = response.data.data.accessToken;
const newRefreshToken = response.data.data.refreshToken;
setCookie('accessToken', newAccessToken);
setCookie('refreshToken', newRefreshToken);
} catch (error) {
removeCookie('accessToken');
removeCookie('refreshToken');
removeCookie('accommodationId');
message.error({
content: (
<TextBox typography="body3" fontWeight={'400'}>
로그인 만료입니다.
</TextBox>
),
duration: 2,
});
setTimeout(() => {
window.location.href = ROUTES.SIGNIN;
}, 1000);
}
return axios(error.config);
} else if (
!accessToken &&
window.location.pathname !== ROUTES.SIGNIN &&
window.location.pathname !== ROUTES.SIGNUP &&
window.location.pathname !== ROUTES.SIGNIN_AGREEMENT &&
window.location.pathname !== ROUTES.SIGNUP_SUCCESS
) {
removeCookie('accessToken');
removeCookie('refreshToken');
removeCookie('accommodationId');
localStorage.clear();
setTimeout(() => {
window.location.href = ROUTES.SIGNIN;
}, 1000);
handleUnauthorized();
} else if (error.response?.status === HTTP_STATUS_CODE.NOTFOUND) {
console.log('여기 404에러 핸들링 필요해요~');
}
return Promise.reject(error);
},
);

export default instance;
3 changes: 1 addition & 2 deletions src/api/refresh/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { instance } from '..';
import { PostRefreshData, RefreshData } from './type';
import { Response } from '@/types/api';

export const REFRESH_API = {
postRefresh: (data: RefreshData) =>
instance.post<Response<PostRefreshData>>('/api/auth/refresh', data),
instance.post<PostRefreshData>('/api/auth/refresh', data),
};
7 changes: 3 additions & 4 deletions src/api/sign-up/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@ import {
VerificationData,
} from './type';
import { instance } from '..';
import { Response } from '@/types/api';

export const SIGN_UP_API = {
postSignUp: (data: SignUpData) =>
instance.post<Response<PostSignUpResData>>('/api/auth/owners/signup', data),
instance.post<PostSignUpResData>('/api/auth/owners/signup', data),
postAuthentication: (data: AuthenticationData) =>
instance.post<Response<PostAuthenticationData>>(
instance.post<PostAuthenticationData>(
'/api/auth/owners/request-email',
data,
),
getVerify: (data: VerificationData) =>
instance.get<Response<GetVerificationData>>('/api/auth/owners/verify', {
instance.get<GetVerificationData>('/api/auth/owners/verify', {
params: {
email: data.email,
'verification-code': data.verificationCode,
Expand Down
15 changes: 6 additions & 9 deletions src/assets/data/signInData.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
{
"message": "성공적으로 로그인 했습니다.",
"data": {
"accessToken": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0MTIzNDVAbmF2ZXIuY29tIiwiaWF0IjoxNzAxMzMwOTE0LCJleHAiOjE3MDE0MTczMTR9._G-tEQZpJdCgT_Uo4ipDByBwjP-0HclSq35G3MLvNvIiPILbT0Y9MZR19gTWDbzLuU0Gp1phFMbSGNYuAD1cSg",
"refreshToken": "eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE3MDEzMzA5MTQsImV4cCI6MTcwMTkzNTcxNH0.8BZt06CkTEWx7FyT4OH4c7ZNNplz9un2TCmyxf-nM5aCJe-MXJVdJAYnHW00j3ZytR_aYWp-R78tBSSF3pfAkw",
"memberResponse": {
"id": 1,
"email": "[email protected]",
"name": "홍길동"
}
"accessToken": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0MTIzNDVAbmF2ZXIuY29tIiwiaWF0IjoxNzAxMzMwOTE0LCJleHAiOjE3MDE0MTczMTR9._G-tEQZpJdCgT_Uo4ipDByBwjP-0HclSq35G3MLvNvIiPILbT0Y9MZR19gTWDbzLuU0Gp1phFMbSGNYuAD1cSg",
"refreshToken": "eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE3MDEzMzA5MTQsImV4cCI6MTcwMTkzNTcxNH0.8BZt06CkTEWx7FyT4OH4c7ZNNplz9un2TCmyxf-nM5aCJe-MXJVdJAYnHW00j3ZytR_aYWp-R78tBSSF3pfAkw",
"memberResponse": {
"id": 1,
"email": "[email protected]",
"name": "홍길동"
}
}
13 changes: 12 additions & 1 deletion src/components/layout/side-bar/signout-btn/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import { ROUTES } from '@/constants/routes';
import { LogoutOutlined } from '@ant-design/icons';
import { TextBox } from '@components/text-box';
import { removeCookie } from '@hooks/sign-in/useSignIn';
import styled from 'styled-components';

export const SignOutBtn = () => {
const handleSignOut = () => {
// 여기에 로그아웃 api 연결할 예정
// 밑에는 onSuccess 시 할 일
removeCookie('accessToken');
removeCookie('refreshToken');
localStorage.clear();
window.location.href = ROUTES.SIGNIN;
// 여기 밑에는 onError 시 할 일 추가할 예정
};
return (
<StyledContainer>
<StyledLogoutOutlined />
<TextBox typography="body2" color="black700">
<TextBox typography="body2" color="black700" onClick={handleSignOut}>
로그아웃
</TextBox>
</StyledContainer>
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/sign-in/useSignIn.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const setCookie = (name: string, value: string | number) => {
try {
if (name === 'accessToken') {
document.cookie = `${name}=${value};max-age=7200;path=/;`;
document.cookie = `${name}=${value};max-age=3600;path=/;`;
} else if (name === 'refreshToken') {
const expirationDate = new Date();
expirationDate.setDate(expirationDate.getDate() + 7);
Expand Down
134 changes: 65 additions & 69 deletions src/pages/sign-in/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export const SignIn = () => {
setCookie('accessToken', response.data.accessToken);
setCookie('refreshToken', response.data.refreshToken);
const memberResponse = response.data.memberResponse;
setCookie('accessToken', response.data.accessToken);
setCookie('refreshToken', response.data.refreshToken);
const memberData = JSON.stringify(memberResponse);
localStorage.setItem('member', memberData);
if (accommodationListData?.accommodations[0]?.id) {
Expand All @@ -32,74 +34,35 @@ export const SignIn = () => {
accommodationListData?.accommodations[0]?.id,
);
}
try {
const res = isAccomodationList();
if (res === true) {
const accomodationId = getCookie('accomodationId');
setTimeout(() => {
handleChangeUrl(`/${accomodationId}/main`);
}, 1000);
} else {
setTimeout(() => {
handleChangeUrl('/init');
}, 1000);
}
} catch (e) {
message.error({
content: (
<TextBox typography="body3" fontWeight={'400'}>
요청에 실패했습니다. 잠시 후 다시 시도해 주세요.
</TextBox>
),
duration: 2,
style: {
width: '346px',
height: '41px',
},
});
const res = isAccommodationList();
if (res === true) {
const accommodationId = getCookie('accommodationId');
setTimeout(() => {
handleChangeUrl(`/${accommodationId}/main`);
}, 1000);
} else {
setTimeout(() => {
handleChangeUrl('/init');
}, 1000);
}
},
onError(error) {
if (error instanceof AxiosError && error.response) {
if (error.response.status === HTTP_STATUS_CODE.BAD_GATEWAY) {
message.error({
content: (
<TextBox typography="body3" fontWeight={'400'}>
요청에 실패했습니다. 잠시 후 다시 시도해 주세요.
</TextBox>
),
duration: 2,
style: {
width: '346px',
height: '41px',
},
});
} else {
message.error({
content: (
<TextBox typography="body3" fontWeight={'400'}>
이메일과 비밀번호를 확인해 주세요.
</TextBox>
),
duration: 2,
style: {
width: '346px',
height: '41px',
},
});
}
}
onError() {
message.error({
content: (
<TextBox typography="body3" fontWeight={'400'}>
이메일과 비밀번호를 확인해 주세요.
</TextBox>
),
duration: 2,
});
},
});
const isAccomodationList = () => {
if (

const isAccommodationList = () => {
return (
accommodationListData?.accommodations &&
accommodationListData.accommodations.length > 0
) {
return true;
} else {
return false;
}
);
};

const handleOnclick = () => {
Expand All @@ -123,18 +86,51 @@ export const SignIn = () => {
});
}
};

const formik = useFormik({
initialValues: {
email: '',
password: '',
},
validationSchema: ValidateSchema,
onSubmit: async (values) => {
const signInData: SignInData = {
email: values.email,
password: values.password,
};
mutate(signInData);
try {
const signInData: SignInData = {
email: values.email,
password: values.password,
};
await mutate(signInData);
} catch (e) {
if (e instanceof AxiosError && e.response) {
if (e.response.status === HTTP_STATUS_CODE.BAD_GATEWAY) {
message.error({
content: (
<TextBox typography="body3" fontWeight={'400'}>
요청에 실패했습니다. 잠시 후 다시 시도해 주세요.
</TextBox>
),
duration: 2,
style: {
width: '346px',
height: '41px',
},
});
} else {
message.error({
content: (
<TextBox typography="body3" fontWeight={'400'}>
이메일과 비밀번호를 확인해 주세요.
</TextBox>
),
duration: 2,
style: {
width: '346px',
height: '41px',
},
});
}
}
}
},
});

Expand All @@ -155,7 +151,7 @@ export const SignIn = () => {
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
></StyledInput>
/>
{touched.email && errors.email && (
<TextBox typography="body4" color="error">
{errors.email}
Expand All @@ -171,7 +167,7 @@ export const SignIn = () => {
value={values.password}
onChange={handleChange}
onBlur={handleBlur}
></StyledPassword>
/>
{touched.password && errors.password && (
<TextBox typography="body4" color="error">
{errors.password}
Expand Down
Loading

0 comments on commit ea0df01

Please sign in to comment.