AI컴퓨터공학부
From 6569d6b1b889a7b955c28dacf9f8cf0a77fec12d Mon Sep 17 00:00:00 2001
From: JaeguJaegu <118053865+SunwooJaeho@users.noreply.github.com>
Date: Tue, 11 Mar 2025 23:47:16 +0900
Subject: [PATCH 06/11] =?UTF-8?q?refactor(admin):=20use-auth=EC=97=90?=
=?UTF-8?q?=EC=84=9C=20=EC=9C=A0=ED=8B=B8=ED=95=A8=EC=88=98=EB=A1=9C=20?=
=?UTF-8?q?=EB=B6=84=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
apps/admin/src/utils/auth.ts | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 apps/admin/src/utils/auth.ts
diff --git a/apps/admin/src/utils/auth.ts b/apps/admin/src/utils/auth.ts
new file mode 100644
index 0000000..5071635
--- /dev/null
+++ b/apps/admin/src/utils/auth.ts
@@ -0,0 +1,36 @@
+import { useNavigate } from '@tanstack/react-router';
+
+import { ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY } from '~/constants/api';
+import { removeTokens } from '~/utils/api';
+import { decodeJwt } from '~/utils/jwt';
+
+import type { Tokens } from '~/hooks/use-sign-in';
+
+const authServices = () => {
+ const navigate = useNavigate();
+ const setTokens = (tokens: Tokens) => {
+ if (!tokens.accessToken || !tokens.refreshToken) {
+ console.log('토큰이 존재하지 않습니다');
+ return;
+ }
+
+ localStorage.setItem(ACCESS_TOKEN_KEY, tokens.accessToken);
+ localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken);
+
+ const decoded = decodeJwt(tokens.accessToken);
+
+ if (!decoded || !decoded.exp) {
+ console.log('잘못된 토큰입니다.');
+ return;
+ }
+ };
+
+ const logout = () => {
+ removeTokens();
+ navigate({ to: '/' });
+ };
+
+ return { setTokens, logout };
+};
+
+export { authServices };
From 8810ba401132d4af9017e5cf0baced9e3b757578 Mon Sep 17 00:00:00 2001
From: JaeguJaegu <118053865+SunwooJaeho@users.noreply.github.com>
Date: Tue, 11 Mar 2025 23:48:15 +0900
Subject: [PATCH 07/11] feat: add mainpage
---
apps/admin/src/routes/main/index.tsx | 9 +++++++++
1 file changed, 9 insertions(+)
create mode 100644 apps/admin/src/routes/main/index.tsx
diff --git a/apps/admin/src/routes/main/index.tsx b/apps/admin/src/routes/main/index.tsx
new file mode 100644
index 0000000..1e11775
--- /dev/null
+++ b/apps/admin/src/routes/main/index.tsx
@@ -0,0 +1,9 @@
+import { createFileRoute } from '@tanstack/react-router';
+
+export const Route = createFileRoute('/main/')({
+ component: MainPage,
+});
+
+function MainPage() {
+ return
main
;
+}
From e90b6f3eb40c9e08a74763f82b6ca0c58580533e Mon Sep 17 00:00:00 2001
From: JaeguJaegu <118053865+SunwooJaeho@users.noreply.github.com>
Date: Tue, 11 Mar 2025 23:49:28 +0900
Subject: [PATCH 08/11] =?UTF-8?q?refactor:=20use-auth=EC=97=90=EC=84=9C=20?=
=?UTF-8?q?refreshTokens=20=EB=B6=84=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
apps/admin/src/hooks/use-auth.ts | 67 --------------------
apps/admin/src/hooks/use-refresh-token.ts | 40 ++++++++++++
apps/admin/src/hooks/use-token-experation.ts | 33 ++++++++++
3 files changed, 73 insertions(+), 67 deletions(-)
delete mode 100644 apps/admin/src/hooks/use-auth.ts
create mode 100644 apps/admin/src/hooks/use-refresh-token.ts
create mode 100644 apps/admin/src/hooks/use-token-experation.ts
diff --git a/apps/admin/src/hooks/use-auth.ts b/apps/admin/src/hooks/use-auth.ts
deleted file mode 100644
index fd8690a..0000000
--- a/apps/admin/src/hooks/use-auth.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import {
- ACCESS_TOKEN_KEY,
- END_POINT,
- REFRESH_TOKEN_KEY,
-} from '~/constants/api';
-
-import type { Tokens } from '~/hooks/use-sign-in';
-import { getToken, removeTokens } from '~/utils/api';
-import { http } from '~/utils/http';
-import { decodeJwt } from '~/utils/jwt';
-
-const useAuth = () => {
- const setTokens = (tokens: Tokens) => {
- if (!tokens.accessToken || !tokens.refreshToken) {
- console.log('토큰이 존재하지 않음');
- return;
- }
-
- localStorage.setItem(ACCESS_TOKEN_KEY, tokens.accessToken);
- localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken);
-
- const decoded = decodeJwt(tokens.accessToken);
-
- if (!decoded || !decoded.exp) {
- console.log('잘못된 jwt 토큰');
- return;
- }
-
- const expiresIn = decoded.exp * 1000 - Date.now();
-
- if (expiresIn <= 0) {
- logout();
- return;
- }
-
- setTimeout(() => {
- logout();
- }, expiresIn);
- };
-
- const refreshTokens = async () => {
- const [accessToken, refreshToken] = getToken();
-
- if (!accessToken || !refreshToken) {
- logout();
- return;
- }
-
- try {
- const newTokens = await http
- .post(END_POINT.REISSUE, { json: { accessToken, refreshToken } })
- .json
();
- setTokens(newTokens);
- } catch (error) {
- console.log(error);
- logout();
- }
- };
-
- const logout = () => {
- removeTokens();
- };
-
- return { setTokens, logout, refreshTokens };
-};
-
-export { useAuth };
diff --git a/apps/admin/src/hooks/use-refresh-token.ts b/apps/admin/src/hooks/use-refresh-token.ts
new file mode 100644
index 0000000..d01fa40
--- /dev/null
+++ b/apps/admin/src/hooks/use-refresh-token.ts
@@ -0,0 +1,40 @@
+import { useMutation } from '@tanstack/react-query';
+import { END_POINT } from '~/constants/api';
+import { getToken } from '~/utils/api';
+import { authServices } from '~/utils/auth';
+import { authHttp } from '~/utils/http';
+import type { Tokens } from './use-sign-in';
+
+interface RefreshToken {
+ refreshToken: string;
+}
+
+const useRefreshTokens = () => {
+ const { setTokens, logout } = authServices();
+
+ const refreshMutation = useMutation({
+ mutationFn: () => {
+ const [accessToken, refreshToken] = getToken();
+
+ if (!accessToken || !refreshToken) {
+ throw new Error('토큰이 존재하지 않습니다');
+ }
+
+ const response = authHttp.post(END_POINT.REISSUE, {
+ json: { refreshToken },
+ });
+ return response.json();
+ },
+ onSuccess: (newTokens) => {
+ setTokens(newTokens);
+ },
+ onError: () => {
+ alert('오류가 발생하여 로그아웃합니다.');
+ logout();
+ },
+ });
+
+ return refreshMutation;
+};
+
+export { type RefreshToken, useRefreshTokens };
diff --git a/apps/admin/src/hooks/use-token-experation.ts b/apps/admin/src/hooks/use-token-experation.ts
new file mode 100644
index 0000000..039f94b
--- /dev/null
+++ b/apps/admin/src/hooks/use-token-experation.ts
@@ -0,0 +1,33 @@
+import { useEffect, useState } from 'react';
+import { getAccessToken } from '~/utils/api';
+import { authServices } from '~/utils/auth';
+import { decodeJwt } from '~/utils/jwt';
+
+export const useTokenExpiration = () => {
+ const { logout } = authServices();
+ const [expireTime, setExpireTime] = useState(null);
+ const accessToken = getAccessToken();
+
+ useEffect(() => {
+ if (accessToken) {
+ const decoded = decodeJwt(accessToken);
+ if (decoded?.exp) {
+ const expiresIn = decoded.exp * 1000 - Date.now();
+ setExpireTime(expiresIn);
+ }
+ }
+ }, [accessToken]);
+
+ useEffect(() => {
+ if (expireTime !== null && expireTime <= 0) {
+ logout();
+ } else if (expireTime !== null && expireTime > 0) {
+ const timerId = setTimeout(() => {
+ setExpireTime(expireTime - 1000);
+ }, 1000);
+ return () => clearTimeout(timerId);
+ }
+ }, [expireTime, logout]);
+
+ return { expireTime };
+};
From 0b3b019544bf31c0e1ead1cabbab60a3d817796a Mon Sep 17 00:00:00 2001
From: JaeguJaegu <118053865+SunwooJaeho@users.noreply.github.com>
Date: Tue, 11 Mar 2025 23:50:01 +0900
Subject: [PATCH 09/11] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?=
=?UTF-8?q?=ED=9B=84=20=EB=A9=94=EC=9D=B8=ED=8E=98=EC=9D=B4=EC=A7=80?=
=?UTF-8?q?=EB=A1=9C=20=EB=A6=AC=EB=8B=A4=EC=9D=B4=EB=9E=99=EC=85=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
apps/admin/src/hooks/use-sign-in.ts | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/apps/admin/src/hooks/use-sign-in.ts b/apps/admin/src/hooks/use-sign-in.ts
index b220a87..e3c843e 100644
--- a/apps/admin/src/hooks/use-sign-in.ts
+++ b/apps/admin/src/hooks/use-sign-in.ts
@@ -1,6 +1,7 @@
import { useMutation } from '@tanstack/react-query';
+import { useNavigate } from '@tanstack/react-router';
import { END_POINT } from '~/constants/api';
-import { useAuth } from '~/hooks/use-auth';
+import { authServices } from '~/utils/auth';
import { authHttp } from '~/utils/http';
interface SignInData {
@@ -14,15 +15,16 @@ interface Tokens {
}
const useSignIn = () => {
- const { setTokens } = useAuth();
+ const { setTokens } = authServices();
+ const navigate = useNavigate();
return useMutation({
mutationFn: (data: SignInData) => {
return authHttp.post(END_POINT.SIGN_IN, { json: data }).json();
},
onSuccess: (token) => {
- console.log('success : ', token);
setTokens(token);
+ navigate({ to: '/main' });
},
});
};
From ca9a0ebf640244e19e8fffae02d218e81df90103 Mon Sep 17 00:00:00 2001
From: JaeguJaegu <118053865+SunwooJaeho@users.noreply.github.com>
Date: Tue, 11 Mar 2025 23:50:35 +0900
Subject: [PATCH 10/11] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?=
=?UTF-8?q?=EC=97=B0=EC=9E=A5=20=EB=B0=8F=20=EB=A1=9C=EA=B7=B8=EC=95=84?=
=?UTF-8?q?=EC=9B=83=20=EA=B8=B0=EB=8A=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/components/aside-navigation-menu.tsx | 42 +++++++++++++++----
apps/admin/src/utils/.gitkeep | 0
apps/admin/src/utils/utils.ts | 9 ++++
3 files changed, 43 insertions(+), 8 deletions(-)
delete mode 100644 apps/admin/src/utils/.gitkeep
create mode 100644 apps/admin/src/utils/utils.ts
diff --git a/apps/admin/src/components/aside-navigation-menu.tsx b/apps/admin/src/components/aside-navigation-menu.tsx
index 5f1ab83..bd42e4b 100644
--- a/apps/admin/src/components/aside-navigation-menu.tsx
+++ b/apps/admin/src/components/aside-navigation-menu.tsx
@@ -2,6 +2,7 @@ import { Link } from '@tanstack/react-router';
import { Menu, type MenuProps } from 'antd';
import {
Clipboard,
+ Clock,
FlaskConical,
GraduationCap,
Speech,
@@ -9,6 +10,10 @@ import {
} from 'lucide-react';
import LOGO from '~/assets/logo.svg';
+import { useRefreshTokens } from '~/hooks/use-refresh-token';
+import { useTokenExpiration } from '~/hooks/use-token-experation';
+import { authServices } from '~/utils/auth';
+import { formatExpireTime } from '~/utils/utils';
type MenuItem = Required['items'][number];
@@ -63,15 +68,36 @@ function AsideHeader() {
}
function AsideFooter() {
- //TODO: 로그아웃 기능 적용
+ const { expireTime } = useTokenExpiration();
+ const refreshMutation = useRefreshTokens();
+ const { logout } = authServices();
+
+ const handleRefreshToken = () => {
+ refreshMutation.mutate();
+ };
+
return (
-
-
+
+
+
+ {formatExpireTime(expireTime)}
+
+
+
+
+
);
}
diff --git a/apps/admin/src/utils/.gitkeep b/apps/admin/src/utils/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/apps/admin/src/utils/utils.ts b/apps/admin/src/utils/utils.ts
new file mode 100644
index 0000000..3d68bc8
--- /dev/null
+++ b/apps/admin/src/utils/utils.ts
@@ -0,0 +1,9 @@
+export const formatExpireTime = (times: number | null) => {
+ if (times === null || times <= 0) return null;
+
+ const totalSeconds = Math.floor(times / 1000);
+ const minutes = Math.floor(totalSeconds / 60);
+ const seconds = totalSeconds % 60;
+
+ return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
+};
From 46079be4e4010982b97a22fc3246286b3d24dd97 Mon Sep 17 00:00:00 2001
From: JaeguJaegu <118053865+SunwooJaeho@users.noreply.github.com>
Date: Wed, 12 Mar 2025 14:59:17 +0900
Subject: [PATCH 11/11] chore: change file name
---
apps/admin/src/components/aside-navigation-menu.tsx | 2 +-
.../hooks/{use-token-experation.ts => use-token-expiration.ts} | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename apps/admin/src/hooks/{use-token-experation.ts => use-token-expiration.ts} (100%)
diff --git a/apps/admin/src/components/aside-navigation-menu.tsx b/apps/admin/src/components/aside-navigation-menu.tsx
index bd42e4b..0699756 100644
--- a/apps/admin/src/components/aside-navigation-menu.tsx
+++ b/apps/admin/src/components/aside-navigation-menu.tsx
@@ -11,7 +11,7 @@ import {
import LOGO from '~/assets/logo.svg';
import { useRefreshTokens } from '~/hooks/use-refresh-token';
-import { useTokenExpiration } from '~/hooks/use-token-experation';
+import { useTokenExpiration } from '~/hooks/use-token-expiration';
import { authServices } from '~/utils/auth';
import { formatExpireTime } from '~/utils/utils';
diff --git a/apps/admin/src/hooks/use-token-experation.ts b/apps/admin/src/hooks/use-token-expiration.ts
similarity index 100%
rename from apps/admin/src/hooks/use-token-experation.ts
rename to apps/admin/src/hooks/use-token-expiration.ts