Skip to content

Commit 220e4bf

Browse files
committed
Merge branch 'dev'
2 parents 6bd517a + a91c6b0 commit 220e4bf

File tree

12 files changed

+160
-90
lines changed

12 files changed

+160
-90
lines changed

.pnp.cjs

Lines changed: 30 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.yarn/cache/@team-aliens-design-system-npm-1.5.5-58c6352e2b-146e0834ec.zip renamed to .yarn/cache/@team-aliens-design-system-npm-1.6.3-ddd07ad2a4-b575be76b4.zip

192 KB
Binary file not shown.
11.2 KB
Binary file not shown.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"postpublish": "pinst --enable"
2525
},
2626
"dependencies": {
27-
"@team-aliens/design-system": "^1.5.5",
27+
"@team-aliens/design-system": "^1.6.3",
2828
"react-slick": "^0.30.2"
2929
}
3030
}

services/admin/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,14 @@
6161
"dependencies": {
6262
"@tanstack/react-query": "^4.29.12",
6363
"@tanstack/react-query-devtools": "^4.29.12",
64-
"@team-aliens/design-system": "^1.5.5",
64+
"@team-aliens/design-system": "^1.6.1",
6565
"@types/styled-components": "^5.1.26",
6666
"axios": "^1.1.3",
6767
"core-js": "^3.24.1",
6868
"date-fns": "^4.1.0",
6969
"exceljs": "^4.3.0",
7070
"file-saver": "^2.0.5",
71+
"mitt": "^3.0.1",
7172
"react": "^18.2.0",
7273
"react-color": "^2.19.3",
7374
"react-cookie": "^4.1.1",

services/admin/src/App.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,27 @@ import { ToastContainer, ToastProvider } from '@team-aliens/design-system';
22
import { Router } from './router';
33
import { useModal } from './hooks/useModal';
44
import { useEffect } from 'react';
5-
import { getCookie } from './utils/cookies';
65
import { pagePath } from './utils/pagePath';
76
import { Outlet, RouterProvider } from 'react-router-dom';
87
import { PointListProvider } from './context/pointHistoryList';
98
import { GlobalStyle } from './style/globalStyle';
9+
import { eventBus } from './utils/eventBus';
1010

1111
export function App() {
1212
const { modalState } = useModal();
13-
const accessToken = getCookie('access_token');
14-
const refreshToken = getCookie('refresh_token');
15-
if (!accessToken && !refreshToken && window.location.pathname !== '/login') {
16-
window.location.href = pagePath.login;
17-
}
13+
14+
useEffect(() => {
15+
const handleSessionExpired = () => {
16+
if (window.location.pathname !== pagePath.login) {
17+
window.location.href = pagePath.login;
18+
}
19+
};
20+
eventBus.on('sessionExpired', handleSessionExpired);
21+
return () => {
22+
eventBus.off('sessionExpired', handleSessionExpired);
23+
};
24+
}, []);
25+
1826
useEffect(() => {
1927
if (modalState.selectedModal) {
2028
document.body.style.overflow = 'hidden';
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { reIssueToken } from '@/apis/auth';
2+
import { getCookie, setCookie } from '@/utils/cookies';
3+
import { eventBus } from '@/utils/eventBus';
4+
5+
let isRefreshing = false;
6+
let subscribers: Array<(token: string) => void> = [];
7+
8+
const onRefreshed = (token: string) => {
9+
subscribers.forEach((callback) => callback(token));
10+
subscribers = [];
11+
};
12+
13+
export const refreshToken = (): Promise<string> => {
14+
const refreshToken = getCookie('refresh_token');
15+
if (!refreshToken) {
16+
eventBus.emit('sessionExpired');
17+
return Promise.reject(new Error('No refresh token available'));
18+
}
19+
20+
if (isRefreshing) {
21+
return new Promise((resolve) => {
22+
subscribers.push((token: string) => resolve(token));
23+
});
24+
}
25+
26+
isRefreshing = true;
27+
28+
return new Promise((resolve, reject) => {
29+
reIssueToken(refreshToken)
30+
.then((res) => {
31+
const newAccessToken = res.access_token;
32+
33+
setCookie('access_token', newAccessToken, {
34+
expires: new Date(res.access_token_expired_at),
35+
});
36+
37+
setCookie('refresh_token', res.refresh_token, {
38+
expires: new Date(res.refresh_token_expired_at),
39+
});
40+
41+
isRefreshing = false;
42+
onRefreshed(newAccessToken);
43+
resolve(newAccessToken);
44+
})
45+
.catch((err) => {
46+
isRefreshing = false;
47+
subscribers = [];
48+
eventBus.emit('sessionExpired');
49+
reject(err);
50+
});
51+
});
52+
};

services/admin/src/apis/index.ts

Lines changed: 8 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,15 @@ import axios, {
33
AxiosHeaders,
44
InternalAxiosRequestConfig,
55
} from 'axios';
6-
import { reIssueToken } from '@/apis/auth';
7-
import { getCookie, setCookie } from '@/utils/cookies';
6+
import { refreshToken } from '@/apis/TokenRefresher';
7+
import { getCookie } from '@/utils/cookies';
8+
import { handleApiError } from '@/utils/apiErrorHandler';
89

910
export const instance = axios.create({
1011
baseURL: `${process.env.APP_PUBLIC_URL}`,
1112
timeout: 10000,
1213
});
1314

14-
let isRefreshing = false;
15-
let refreshSubscribers: ((token: string) => void)[] = [];
16-
17-
const hasMessage = (data: any): data is { message: string } => {
18-
return typeof data === 'object' && data !== null && 'message' in data;
19-
};
20-
21-
const onRefreshed = (token: string) => {
22-
refreshSubscribers.forEach((callback) => callback(token));
23-
refreshSubscribers = [];
24-
};
25-
2615
instance.interceptors.request.use(
2716
(config) => {
2817
const accessToken = getCookie('access_token');
@@ -44,60 +33,23 @@ instance.interceptors.response.use(
4433
_retry?: boolean;
4534
};
4635

47-
if (error.response.status === 401 || error.response.status === 403) {
48-
const refreshToken = getCookie('refresh_token');
49-
50-
if (!refreshToken) {
51-
window.location.href = '/login';
52-
return Promise.reject(error);
53-
}
54-
36+
if (error.response?.status === 401 || error.response?.status === 403) {
5537
if (originalRequest._retry) {
5638
return Promise.reject(error);
5739
}
5840
originalRequest._retry = true;
59-
60-
if (isRefreshing) {
61-
return new Promise((resolve) => {
62-
refreshSubscribers.push((token: string) => {
63-
originalRequest.headers = new AxiosHeaders({
64-
...originalRequest.headers,
65-
Authorization: `Bearer ${token}`,
66-
});
67-
resolve(instance(originalRequest));
68-
});
69-
});
70-
}
71-
72-
isRefreshing = true;
73-
7441
try {
75-
const res = await reIssueToken(refreshToken);
76-
const newAccessToken = res.access_token;
77-
78-
setCookie('access_token', newAccessToken, {
79-
expires: new Date(res.access_token_expired_at),
80-
});
81-
82-
setCookie('refresh_token', res.refresh_token, {
83-
expires: new Date(res.refresh_token_expired_at),
84-
});
85-
86-
isRefreshing = false;
87-
onRefreshed(newAccessToken);
88-
42+
const newAccessToken = await refreshToken();
8943
originalRequest.headers = new AxiosHeaders({
9044
...originalRequest.headers,
9145
Authorization: `Bearer ${newAccessToken}`,
9246
});
9347
return instance(originalRequest);
94-
} catch (err) {
95-
isRefreshing = false;
96-
window.location.href = '/login';
97-
return Promise.reject(err);
48+
} catch (refreshError) {
49+
return Promise.reject(refreshError);
9850
}
9951
}
10052

101-
return Promise.reject(error);
53+
return handleApiError(error);
10254
},
10355
);
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { AxiosError } from 'axios';
2+
3+
const hasMessage = (data: any): data is { message: string } => {
4+
return typeof data === 'object' && data !== null && 'message' in data;
5+
};
6+
7+
export const handleApiError = (error: AxiosError) => {
8+
if (error.response) {
9+
const { status, data } = error.response;
10+
const message = hasMessage(data)
11+
? data.message
12+
: '알 수 없는 오류가 발생했습니다.';
13+
14+
switch (status) {
15+
case 400:
16+
console.log(`[${status}] 잘못된 요청입니다.\n${message}`);
17+
break;
18+
case 404:
19+
console.log('요청하신 자원을 찾을 수 없습니다.');
20+
break;
21+
case 500:
22+
console.log('서버에 문제가 발생했습니다. 잠시 후 다시 시도해주세요.');
23+
break;
24+
default:
25+
console.log(`[${status}] 오류가 발생했습니다.\n${message}`);
26+
break;
27+
}
28+
} else {
29+
console.log('네트워크 오류가 발생했습니다. 인터넷 연결을 확인해주세요.');
30+
}
31+
return Promise.reject(error);
32+
};

0 commit comments

Comments
 (0)