Skip to content

Commit c8c3779

Browse files
authored
[FRONTEND] 배포용 의존성 설치 (#68)
의존성 vite 설치
1 parent f7ae046 commit c8c3779

File tree

6 files changed

+167
-10
lines changed

6 files changed

+167
-10
lines changed

frontend/package-lock.json

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

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@
3434
"globals": "^16.3.0",
3535
"typescript": "~5.8.3",
3636
"typescript-eslint": "^8.39.1",
37-
"vite": "^7.1.2"
37+
"vite": "^7.1.12"
3838
}
3939
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { useEffect } from "react";
2+
import { useNavigate } from "react-router-dom";
3+
import { useAuthStore } from "../../stores/useAuthStore";
4+
5+
interface HomeProtectedRouteProps {
6+
children: React.ReactNode;
7+
}
8+
9+
/**
10+
* 홈 페이지 보호 컴포넌트
11+
* 초기화되지 않은 사용자는 설정 페이지로 리다이렉트
12+
*/
13+
export default function HomeProtectedRoute({
14+
children,
15+
}: HomeProtectedRouteProps) {
16+
const { user, isAuthenticated } = useAuthStore();
17+
const navigate = useNavigate();
18+
19+
useEffect(() => {
20+
// 인증되지 않은 사용자는 로그인 페이지로
21+
if (!isAuthenticated) {
22+
console.log("🔒 인증되지 않은 사용자 → 로그인 페이지로 이동");
23+
navigate("/signIn");
24+
return;
25+
}
26+
27+
// 초기화되지 않은 사용자는 설정 페이지로 리다이렉트
28+
if (user && !user.initialized) {
29+
console.log("⚙️ 초기화되지 않은 사용자 → 설정 페이지로 이동");
30+
navigate("/setting");
31+
return;
32+
}
33+
34+
// 초기화된 사용자만 홈 페이지 접근 허용
35+
console.log("🏠 초기화된 사용자 → 홈 페이지 접근 허용");
36+
}, [user, isAuthenticated, navigate]);
37+
38+
// 로딩 중이거나 리다이렉트 중일 때는 아무것도 렌더링하지 않음
39+
if (!isAuthenticated || (user && !user.initialized)) {
40+
return null;
41+
}
42+
43+
// 초기화된 인증된 사용자만 홈 페이지 렌더링
44+
return <>{children}</>;
45+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { Navigate } from "react-router-dom";
2+
import { useAuthStore } from "../../stores/useAuthStore";
3+
import { useTokenStore } from "../../stores/useTokenStore";
4+
import { useEffect } from "react";
5+
6+
interface ProtectedRouteProps {
7+
children: React.ReactNode;
8+
}
9+
10+
export const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
11+
const { isAuthenticated, clearUser, setAuthenticated } = useAuthStore();
12+
const { getAccessToken, getRefreshToken, isTokenExpired } = useTokenStore();
13+
14+
// 토큰 상태와 인증 상태 동기화
15+
useEffect(() => {
16+
const accessToken = getAccessToken();
17+
const refreshToken = getRefreshToken();
18+
19+
// 토큰이 없으면 인증 상태를 false로 설정
20+
if (!accessToken || !refreshToken) {
21+
if (isAuthenticated) {
22+
setAuthenticated(false);
23+
clearUser();
24+
}
25+
return;
26+
}
27+
28+
// access token이 만료되었는지 확인
29+
if (isTokenExpired(accessToken)) {
30+
// refresh token도 확인
31+
if (isTokenExpired(refreshToken)) {
32+
// 둘 다 만료되었으면 로그아웃
33+
setAuthenticated(false);
34+
clearUser();
35+
return;
36+
}
37+
// refresh token이 유효하면 토큰 갱신 필요 (여기서는 일단 통과)
38+
}
39+
40+
// 토큰은 있지만 인증 상태가 false인 경우 true로 설정
41+
if (!isAuthenticated) {
42+
setAuthenticated(true);
43+
}
44+
}, [
45+
isAuthenticated,
46+
getAccessToken,
47+
getRefreshToken,
48+
isTokenExpired,
49+
setAuthenticated,
50+
clearUser,
51+
]);
52+
53+
const accessToken = getAccessToken();
54+
const refreshToken = getRefreshToken();
55+
56+
// 토큰이 없거나 인증되지 않았으면 로그인 페이지로
57+
if (!isAuthenticated || !accessToken || !refreshToken) {
58+
return <Navigate to="/signIn" replace />;
59+
}
60+
61+
// access token이 만료되었고 refresh token도 만료되었으면 로그인 페이지로
62+
if (isTokenExpired(accessToken) && isTokenExpired(refreshToken)) {
63+
return <Navigate to="/signIn" replace />;
64+
}
65+
66+
return <>{children}</>;
67+
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { useEffect } from "react";
2+
import { useNavigate } from "react-router-dom";
3+
import { useAuthStore } from "../../stores/useAuthStore";
4+
5+
interface SettingProtectedRouteProps {
6+
children: React.ReactNode;
7+
}
8+
9+
/**
10+
* 설정 페이지 보호 컴포넌트
11+
* 이미 초기화가 완료된 사용자는 설정 페이지에 접근할 수 없도록 보호
12+
*/
13+
export default function SettingProtectedRoute({
14+
children,
15+
}: SettingProtectedRouteProps) {
16+
const { user, isAuthenticated } = useAuthStore();
17+
const navigate = useNavigate();
18+
19+
useEffect(() => {
20+
// 인증되지 않은 사용자는 로그인 페이지로
21+
if (!isAuthenticated) {
22+
console.log("🔒 인증되지 않은 사용자 → 로그인 페이지로 이동");
23+
navigate("/signIn");
24+
return;
25+
}
26+
27+
// 이미 초기화가 완료된 사용자는 홈으로 리다이렉트
28+
if (user && user.initialized) {
29+
console.log("✅ 이미 초기화된 사용자 → 홈으로 이동");
30+
navigate("/home");
31+
return;
32+
}
33+
34+
// 초기화되지 않은 사용자만 설정 페이지 접근 허용
35+
console.log("⚙️ 초기화되지 않은 사용자 → 설정 페이지 접근 허용");
36+
}, [user, isAuthenticated, navigate]);
37+
38+
// 로딩 중이거나 리다이렉트 중일 때는 아무것도 렌더링하지 않음
39+
if (!isAuthenticated || (user && user.initialized)) {
40+
return null;
41+
}
42+
43+
// 초기화되지 않은 인증된 사용자만 설정 페이지 렌더링
44+
return <>{children}</>;
45+
}

frontend/src/main.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { StrictMode } from "react";
1+
import React from "react";
22
import { createRoot } from "react-dom/client";
33
import "./index.css";
44
import App from "./App.tsx";
@@ -7,9 +7,9 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
77
const queryClient = new QueryClient();
88

99
createRoot(document.getElementById("root")!).render(
10-
<QueryClientProvider client={queryClient}>
11-
<StrictMode>
10+
<React.StrictMode>
11+
<QueryClientProvider client={queryClient}>
1212
<App />
13-
</StrictMode>
14-
</QueryClientProvider>
13+
</QueryClientProvider>
14+
</React.StrictMode>
1515
);

0 commit comments

Comments
 (0)