Skip to content

Commit efc7bfe

Browse files
authored
Merge pull request #112 from DMU-DebugVisual/inseong
UI 및 기능 일괄개선 1차
2 parents 089ff66 + 77de460 commit efc7bfe

20 files changed

+4307
-2307
lines changed

src/App.js

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { HashRouter, Routes, Route, useLocation, Navigate } from "react-router-dom";
1+
import { HashRouter, Routes, Route, useLocation, Navigate, useNavigate } from "react-router-dom";
22
import { useEffect, useState } from "react";
3+
import { promptLogin } from "./utils/auth";
34

45
import Header from "./components/header/Header";
56
import Footer from "./components/footer/Footer"; // Footer 컴포넌트 임포트 유지
@@ -23,6 +24,7 @@ import CodecastLive from "./components/codecast/codecastlive/CodecastLive";
2324

2425
function AppContent() {
2526
const location = useLocation();
27+
const navigate = useNavigate();
2628
const [isDark, setIsDark] = useState(false);
2729
const [isLoggedIn, setIsLoggedIn] = useState(false);
2830
const [nickname, setNickname] = useState('');
@@ -34,18 +36,36 @@ function AppContent() {
3436
const isCommunityPage = location.pathname.startsWith("/community");
3537
const isMyPage = location.pathname.startsWith("/mypage");
3638
const isCodecastPage = location.pathname.startsWith("/broadcast") || location.pathname.startsWith("/startbroadcast");
37-
const shouldShowFooter = isMainPage && !(isSignupPage || isIdePage || isCommunityPage || isMyPage || isCodecastPage);
39+
const shouldShowFooter = !(
40+
isSignupPage ||
41+
isIdePage ||
42+
isCommunityPage ||
43+
isMyPage ||
44+
isCodecastPage ||
45+
isMainPage
46+
);
3847

3948
useEffect(() => {
40-
const token = localStorage.getItem('token');
41-
const storedUsername = localStorage.getItem('username');
42-
if (token && storedUsername) {
43-
setIsLoggedIn(true);
44-
setNickname(storedUsername);
45-
} else {
46-
setIsLoggedIn(false);
47-
setNickname('');
48-
}
49+
const syncAuthState = () => {
50+
const token = localStorage.getItem('token');
51+
const storedUsername = localStorage.getItem('username');
52+
if (token && storedUsername) {
53+
setIsLoggedIn(true);
54+
setNickname(storedUsername);
55+
} else {
56+
setIsLoggedIn(false);
57+
setNickname('');
58+
}
59+
};
60+
61+
syncAuthState();
62+
window.addEventListener('storage', syncAuthState);
63+
window.addEventListener('dv:auth-updated', syncAuthState);
64+
65+
return () => {
66+
window.removeEventListener('storage', syncAuthState);
67+
window.removeEventListener('dv:auth-updated', syncAuthState);
68+
};
4969
}, []);
5070

5171
useEffect(() => {
@@ -64,6 +84,14 @@ function AppContent() {
6484
localStorage.setItem("theme", isDark ? "dark" : "light");
6585
}, [isDark]);
6686

87+
const MyPageGuard = ({ element }) => {
88+
if (!isLoggedIn) {
89+
promptLogin(undefined, { redirectTo: location.pathname });
90+
return <Navigate to="/" replace />;
91+
}
92+
return element;
93+
};
94+
6795
return (
6896
<>
6997
{!isSignupPage && (
@@ -90,7 +118,12 @@ function AppContent() {
90118
<Route path="/broadcast" element={<Codecast />} />
91119
<Route path="/startbroadcast" element={<StartCodecast />} />
92120
<Route path="/broadcast/live" element={<CodecastLive />} />
93-
<Route path="/mypage" element={<MyPageLayout nickname={nickname} />}>
121+
<Route
122+
path="/mypage"
123+
element={(
124+
<MyPageGuard element={<MyPageLayout nickname={nickname} />} />
125+
)}
126+
>
94127
<Route index element={<Mypage nickname={nickname} />} />
95128
<Route path="project" element={<MyProject />} />
96129
<Route path="community" element={<MyCommunity nickname={nickname} />} />
@@ -108,6 +141,13 @@ function AppContent() {
108141
onLoginSuccess={() => {
109142
setIsLoggedIn(true);
110143
setNickname(localStorage.getItem('username') || '');
144+
setIsLoginModalOpen(false);
145+
146+
const redirectTarget = sessionStorage.getItem('dv:postLoginRedirect');
147+
if (redirectTarget) {
148+
sessionStorage.removeItem('dv:postLoginRedirect');
149+
navigate(redirectTarget, { replace: true });
150+
}
111151
}}
112152
/>
113153
)}

src/api/globalFetch.js

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// src/api/globalFetch.js
22

3+
import { promptLogin } from "../utils/auth";
4+
35
// 1. 기존의 window.fetch 함수를 백업해둡니다.
46
const originalFetch = window.fetch;
57

@@ -9,17 +11,16 @@ window.fetch = async (...args) => {
911
const response = await originalFetch(...args);
1012

1113
// 4. 응답을 받은 후, 인증 실패(401/403)가 발생했다면
12-
if (response.status === 401 || response.status === 403) {
13-
// 이전에 localStorage에 저장된 토큰이 있을 때만 로그아웃 처리
14-
if (localStorage.getItem('token')) {
15-
localStorage.removeItem('token');
16-
localStorage.removeItem('username');
14+
if ((response.status === 401 || response.status === 403) && localStorage.getItem("token")) {
15+
localStorage.removeItem("token");
16+
localStorage.removeItem("username");
17+
localStorage.removeItem("userId");
18+
localStorage.removeItem("role");
19+
20+
window.dispatchEvent(new Event("dv:auth-updated"));
1721

18-
alert('세션이 만료되었습니다. 다시 로그인해 주세요.');
19-
// 현재 페이지를 새로고침하여 로그인 상태를 갱신합니다.
20-
// 로그인 페이지로 강제 이동시키는 것보다 사용자 경험이 더 나을 수 있습니다.
21-
window.location.reload();
22-
}
22+
const redirectTo = window.location.hash ? window.location.hash.replace(/^#/, "") || "/" : window.location.pathname || "/";
23+
promptLogin("세션이 만료되었습니다. 다시 로그인해 주세요.", { redirectTo });
2324
}
2425

2526
// 5. 원래 API를 호출했던 곳에 응답을 그대로 돌려줍니다.

0 commit comments

Comments
 (0)