From 31c0ddc31b352c2b46091b07873ba93713f2bc1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=9D=80?= Date: Thu, 27 Nov 2025 22:04:08 +0900 Subject: [PATCH 1/6] =?UTF-8?q?[FE]=20SISC1-214=20[FEAT]=20:=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=95=84=EC=9B=83=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/Sidebar.jsx | 86 +++++++++++++++++++---------- frontend/src/utils/auth.js | 20 +++++++ 2 files changed, 76 insertions(+), 30 deletions(-) diff --git a/frontend/src/components/Sidebar.jsx b/frontend/src/components/Sidebar.jsx index 9490daab..ed0522f5 100644 --- a/frontend/src/components/Sidebar.jsx +++ b/frontend/src/components/Sidebar.jsx @@ -1,10 +1,12 @@ import { NavLink, useNavigate, useLocation } from 'react-router-dom'; import styles from './Sidebar.module.css'; import { useState } from 'react'; +import { logout } from '../utils/auth'; const Sidebar = ({ isOpen, isRoot }) => { const navigate = useNavigate(); const location = useLocation(); + const accessToken = localStorage.getItem('accessToken'); const boardList = [ { name: '전체 게시판', path: '/board' }, @@ -124,36 +126,60 @@ const Sidebar = ({ isOpen, isRoot }) => {
계정
diff --git a/frontend/src/utils/auth.js b/frontend/src/utils/auth.js index f32fa21d..95a9ac9a 100644 --- a/frontend/src/utils/auth.js +++ b/frontend/src/utils/auth.js @@ -51,3 +51,23 @@ export const checkVerificationNumber = async ( return res.data; }; + +export const logout = async () => { + const accessToken = localStorage.getItem('accessToken'); + try { + await api.post( + '/api/auth/logout', + {}, + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + } + ); + localStorage.removeItem('accessToken'); + localStorage.removeItem('refreshToken'); + alert('로그아웃 되었습니다.'); + } catch (error) { + alert(error.message); + } +}; From 6c94d4ed1bd08ba085344ca224d64791af3e0d28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=9D=80?= Date: Thu, 27 Nov 2025 22:09:57 +0900 Subject: [PATCH 2/6] =?UTF-8?q?[FE]=20SISC1-214=20[FIX]=20:=20useState?= =?UTF-8?q?=EB=A1=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/Sidebar.jsx | 30 ++++++++++++++++++++++++++--- frontend/src/utils/auth.js | 20 ------------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/frontend/src/components/Sidebar.jsx b/frontend/src/components/Sidebar.jsx index ed0522f5..09c0db6e 100644 --- a/frontend/src/components/Sidebar.jsx +++ b/frontend/src/components/Sidebar.jsx @@ -1,12 +1,11 @@ import { NavLink, useNavigate, useLocation } from 'react-router-dom'; import styles from './Sidebar.module.css'; import { useState } from 'react'; -import { logout } from '../utils/auth'; +import { api } from '../utils/axios'; const Sidebar = ({ isOpen, isRoot }) => { const navigate = useNavigate(); const location = useLocation(); - const accessToken = localStorage.getItem('accessToken'); const boardList = [ { name: '전체 게시판', path: '/board' }, @@ -25,6 +24,31 @@ const Sidebar = ({ isOpen, isRoot }) => { const [selectedBoard, setSelectedBoard] = useState( currentBoard?.name || '전체 게시판' ); + const [isLoggedIn, setIsLoggedIn] = useState( + localStorage.getItem('accessToken') + ); + + const logout = async () => { + const accessToken = localStorage.getItem('accessToken'); + try { + await api.post( + '/api/auth/logout', + {}, + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + } + ); + localStorage.removeItem('accessToken'); + localStorage.removeItem('refreshToken'); + setIsLoggedIn(false); + navigate('/'); + alert('로그아웃 되었습니다.'); + } catch (error) { + alert(error.message); + } + }; return (
@@ -126,7 +150,7 @@ const Sidebar = ({ isOpen, isRoot }) => {
계정
    - {accessToken ? ( + {isLoggedIn ? ( <>
  • { - const accessToken = localStorage.getItem('accessToken'); - try { - await api.post( - '/api/auth/logout', - {}, - { - headers: { - Authorization: `Bearer ${accessToken}`, - }, - } - ); - localStorage.removeItem('accessToken'); - localStorage.removeItem('refreshToken'); - alert('로그아웃 되었습니다.'); - } catch (error) { - alert(error.message); - } -}; From bdbb4c1e54575ddad045fb35fae0c8213cf4e25f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=9D=80?= Date: Thu, 27 Nov 2025 22:19:40 +0900 Subject: [PATCH 3/6] =?UTF-8?q?[FE]=20SISC1-214=20[FEAT]=20:=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=A0=95=EB=B3=B4=20=EC=97=86=EC=9D=84=20?= =?UTF-8?q?=EC=8B=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A0=91=EA=B7=BC=20?= =?UTF-8?q?=EC=A0=9C=ED=95=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/Mypage.jsx | 10 ++++++++++ frontend/src/pages/StockGame.jsx | 11 ++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/Mypage.jsx b/frontend/src/pages/Mypage.jsx index 6f22bf9e..1e18a5c1 100644 --- a/frontend/src/pages/Mypage.jsx +++ b/frontend/src/pages/Mypage.jsx @@ -2,8 +2,18 @@ import styles from './Mypage.module.css'; import MyPageMenu from '../components/mypage/MyPageMenu'; import ProfileCard from '../components/mypage/ProfileCard'; import AccountSecurity from '../components/mypage/AccountSecurity'; +import { useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; const Mypage = () => { + const nav = useNavigate(); + useEffect(() => { + if (!localStorage.getItem('accessToken')) { + alert('로그인 후 이용하실 수 있습니다.'); + nav('/login'); + } + }, []); + return (

    마이페이지

    diff --git a/frontend/src/pages/StockGame.jsx b/frontend/src/pages/StockGame.jsx index 6d935496..d3cf4dad 100644 --- a/frontend/src/pages/StockGame.jsx +++ b/frontend/src/pages/StockGame.jsx @@ -1,11 +1,20 @@ import styles from './StockGame.module.css'; import Betting from '../components/stockgame/Betting'; import BettingHistory from '../components/stockgame/BettingHistory'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; const StockGame = () => { const [active, setactive] = useState('progress'); const [lastGame, setLastGame] = useState('weekly'); + const nav = useNavigate(); + + useEffect(() => { + if (!localStorage.getItem('accessToken')) { + alert('로그인 후 이용하실 수 있습니다.'); + nav('/login'); + } + }, []); return (
    From c17f727d9979104516bc58d70be5fa114d5ed075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=9D=80?= Date: Thu, 27 Nov 2025 22:53:31 +0900 Subject: [PATCH 4/6] =?UTF-8?q?[FE]=20SISC1-214=20[FIX]=20:=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=20=EB=B0=8F=20=EB=A1=9C=EA=B7=B8=EC=95=84=EC=9B=83=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/Sidebar.jsx | 7 ++++--- frontend/src/hooks/useAuthGuard.js | 13 +++++++++++++ frontend/src/pages/Mypage.jsx | 11 ++--------- frontend/src/pages/StockGame.jsx | 12 +++--------- 4 files changed, 22 insertions(+), 21 deletions(-) create mode 100644 frontend/src/hooks/useAuthGuard.js diff --git a/frontend/src/components/Sidebar.jsx b/frontend/src/components/Sidebar.jsx index 09c0db6e..8392d1da 100644 --- a/frontend/src/components/Sidebar.jsx +++ b/frontend/src/components/Sidebar.jsx @@ -25,7 +25,7 @@ const Sidebar = ({ isOpen, isRoot }) => { currentBoard?.name || '전체 게시판' ); const [isLoggedIn, setIsLoggedIn] = useState( - localStorage.getItem('accessToken') + !!localStorage.getItem('accessToken') ); const logout = async () => { @@ -40,13 +40,14 @@ const Sidebar = ({ isOpen, isRoot }) => { }, } ); + } catch { + alert('오류가 발생했습니다.'); + } finally { localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); setIsLoggedIn(false); navigate('/'); alert('로그아웃 되었습니다.'); - } catch (error) { - alert(error.message); } }; diff --git a/frontend/src/hooks/useAuthGuard.js b/frontend/src/hooks/useAuthGuard.js new file mode 100644 index 00000000..277a6089 --- /dev/null +++ b/frontend/src/hooks/useAuthGuard.js @@ -0,0 +1,13 @@ +import { useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; + +export const useAuthGuard = () => { + const nav = useNavigate(); + + useEffect(() => { + if (!localStorage.getItem('accessToken')) { + alert('로그인 후 이용하실 수 있습니다.'); + nav('/login'); + } + }, [nav]); +}; diff --git a/frontend/src/pages/Mypage.jsx b/frontend/src/pages/Mypage.jsx index 1e18a5c1..c8229c9c 100644 --- a/frontend/src/pages/Mypage.jsx +++ b/frontend/src/pages/Mypage.jsx @@ -2,17 +2,10 @@ import styles from './Mypage.module.css'; import MyPageMenu from '../components/mypage/MyPageMenu'; import ProfileCard from '../components/mypage/ProfileCard'; import AccountSecurity from '../components/mypage/AccountSecurity'; -import { useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useAuthGuard } from '../hooks/useAuthGuard'; const Mypage = () => { - const nav = useNavigate(); - useEffect(() => { - if (!localStorage.getItem('accessToken')) { - alert('로그인 후 이용하실 수 있습니다.'); - nav('/login'); - } - }, []); + useAuthGuard(); return (
    diff --git a/frontend/src/pages/StockGame.jsx b/frontend/src/pages/StockGame.jsx index d3cf4dad..b0d476e3 100644 --- a/frontend/src/pages/StockGame.jsx +++ b/frontend/src/pages/StockGame.jsx @@ -1,20 +1,14 @@ import styles from './StockGame.module.css'; import Betting from '../components/stockgame/Betting'; import BettingHistory from '../components/stockgame/BettingHistory'; -import { useState, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useState } from 'react'; +import { useAuthGuard } from '../hooks/useAuthGuard'; const StockGame = () => { const [active, setactive] = useState('progress'); const [lastGame, setLastGame] = useState('weekly'); - const nav = useNavigate(); - useEffect(() => { - if (!localStorage.getItem('accessToken')) { - alert('로그인 후 이용하실 수 있습니다.'); - nav('/login'); - } - }, []); + useAuthGuard(); return (
    From a19b0cd23abaf0ac5f56e94d0741c9d9896c04aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=9D=80?= Date: Thu, 27 Nov 2025 23:00:05 +0900 Subject: [PATCH 5/6] =?UTF-8?q?alert=20->=20toast=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.jsx | 10 ++++++++++ frontend/src/components/Sidebar.jsx | 5 +++-- frontend/src/hooks/useAuthGuard.js | 3 ++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index d95f95d1..5c56ed18 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -20,6 +20,9 @@ import Intro from './pages/external/Intro.jsx'; import Leaders from './pages/external/Leaders.jsx'; import Portfolio from './pages/external/Portfolio.jsx'; +import { ToastContainer } from 'react-toastify'; +import 'react-toastify/dist/ReactToastify.css'; + function App() { return ( <> @@ -44,6 +47,13 @@ function App() { } /> + ); } diff --git a/frontend/src/components/Sidebar.jsx b/frontend/src/components/Sidebar.jsx index 8392d1da..31fbece8 100644 --- a/frontend/src/components/Sidebar.jsx +++ b/frontend/src/components/Sidebar.jsx @@ -2,6 +2,7 @@ import { NavLink, useNavigate, useLocation } from 'react-router-dom'; import styles from './Sidebar.module.css'; import { useState } from 'react'; import { api } from '../utils/axios'; +import { toast } from 'react-toastify'; const Sidebar = ({ isOpen, isRoot }) => { const navigate = useNavigate(); @@ -41,13 +42,13 @@ const Sidebar = ({ isOpen, isRoot }) => { } ); } catch { - alert('오류가 발생했습니다.'); + toast.error('오류가 발생했습니다.'); } finally { localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); setIsLoggedIn(false); navigate('/'); - alert('로그아웃 되었습니다.'); + toast.success('로그아웃 되었습니다.'); } }; diff --git a/frontend/src/hooks/useAuthGuard.js b/frontend/src/hooks/useAuthGuard.js index 277a6089..39a9a774 100644 --- a/frontend/src/hooks/useAuthGuard.js +++ b/frontend/src/hooks/useAuthGuard.js @@ -1,12 +1,13 @@ import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; +import { toast } from 'react-toastify'; export const useAuthGuard = () => { const nav = useNavigate(); useEffect(() => { if (!localStorage.getItem('accessToken')) { - alert('로그인 후 이용하실 수 있습니다.'); + toast.error('로그인 후 이용하실 수 있습니다.'); nav('/login'); } }, [nav]); From 36c834a44c159b2b9e9e3444293581391aa25250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=9D=80?= Date: Thu, 27 Nov 2025 23:29:30 +0900 Subject: [PATCH 6/6] =?UTF-8?q?[FE]=20SISC1-214=20[FIX]=20:=20=EC=82=AC?= =?UTF-8?q?=EC=9D=B4=EB=93=9C=EB=B0=94=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/Sidebar.jsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/frontend/src/components/Sidebar.jsx b/frontend/src/components/Sidebar.jsx index 31fbece8..83605e4d 100644 --- a/frontend/src/components/Sidebar.jsx +++ b/frontend/src/components/Sidebar.jsx @@ -179,6 +179,19 @@ const Sidebar = ({ isOpen, isRoot }) => { ) : ( <> +
  • + + isActive + ? styles['active-link'] + : styles['inactive-link'] + } + > + 마이페이지 + +
  • +