-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#68] 공통 헤더 만들기 #105
The head ref may contain hidden characters: "68-68-\uACF5\uD1B5-\uD5E4\uB354-\uB9CC\uB4E4\uAE30"
[#68] 공통 헤더 만들기 #105
Changes from all commits
df57b41
1c6c091
b69c9bd
ed2c76a
6225164
6cf3886
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { createContext } from 'react'; | ||
|
||
const AuthContext = createContext({ | ||
isLoggedin: false, | ||
login: () => {}, | ||
logout: () => {}, | ||
}); | ||
|
||
export default AuthContext; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { useState } from 'react'; | ||
|
||
import AuthContext from './AuthContext'; | ||
|
||
const AuthProvider = ({ children }: { children: React.ReactNode }) => { | ||
function logout() { | ||
setIsLogined(false); | ||
} | ||
function login() { | ||
setIsLogined(true); | ||
} | ||
|
||
const [isLoggedin, setIsLogined] = useState<boolean>(false); | ||
|
||
return ( | ||
<AuthContext.Provider value={{ isLoggedin, logout, login }}>{children}</AuthContext.Provider> | ||
); | ||
}; | ||
|
||
export default AuthProvider; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
interface Props { | ||
size: string; | ||
} | ||
|
||
export default function Logo({ size }: Props) { | ||
// public이란 곳에 리소스 넣어두면 build시에 바로 밑에 생기기 때문에 ./으로 접근 가능합니다. | ||
return <img src="./algo.png" alt="logo" width={size} height={size} />; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { css } from '@style/css'; | ||
|
||
import Logo from '@/components/Common/Logo'; | ||
import useAuth from '@/hooks/login/useAuth'; | ||
|
||
export default function Header() { | ||
const { changeLoginInfo, changeLogoutInfo, isLoggedin } = useAuth(); | ||
|
||
const handleLogin = () => { | ||
changeLoginInfo(); | ||
}; | ||
|
||
const handleLogout = () => { | ||
changeLogoutInfo(); | ||
}; | ||
|
||
return ( | ||
<header className={headerStyle}> | ||
<Logo size="36px" /> | ||
{isLoggedin ? ( | ||
<button onClick={handleLogout}> 로그아웃 </button> | ||
) : ( | ||
<button onClick={handleLogin}> 로그인 </button> | ||
)} | ||
</header> | ||
); | ||
} | ||
|
||
const headerStyle = css({ | ||
width: '100%', | ||
height: '40px', | ||
display: 'flex', | ||
alignItems: 'center', | ||
justifyContent: 'space-between', | ||
}); |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. useAuth로 Provider를 참조하는 것 아주 좋습니다. 👍 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { useContext, useEffect } from 'react'; | ||
import { useLocation, useNavigate } from 'react-router-dom'; | ||
|
||
import AuthContext from '@/components/Auth/AuthContext'; | ||
|
||
import axios from 'axios'; | ||
|
||
const TOKEN_KEY = 'accessToken'; | ||
const BASE_URL = import.meta.env.VITE_API_URL; | ||
const AUTH_TEST_PATH = '/auths/tests'; | ||
|
||
const URL = `${BASE_URL}${AUTH_TEST_PATH}`; | ||
|
||
const fetchTokenValid = async (token: string) => { | ||
try { | ||
const response = await axios.get(URL, { | ||
headers: { Authorization: `Bearer ${token}` }, | ||
}); | ||
// {email: '[email protected]', nickname: '[email protected]'} | ||
// 저장할 지 말지는 나중에 결정 | ||
const data = await response.data; | ||
console.log(data, '인증 받음.'); | ||
if (response.status === 200) return true; | ||
// 올바른 유저라는 검증을 받음. | ||
} catch (e) { | ||
console.log('인증 받지 못함.', e); | ||
return false; | ||
} | ||
}; | ||
|
||
export default function useAuth() { | ||
const { isLoggedin, login, logout } = useContext(AuthContext); | ||
|
||
const location = useLocation(); | ||
const navigate = useNavigate(); | ||
|
||
useEffect(() => { | ||
if (isLoggedin) return; | ||
const queryParams = new URLSearchParams(location.search); | ||
const token = queryParams.get(TOKEN_KEY) || localStorage.getItem(TOKEN_KEY); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분이 로그인 토큰을 가져오는 코드인가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넵 맞습니다. queryParams.get(TOKEN_KEY)이 /?accessToke="여기꺼가져오는코드" 이고 이게 없다면 로컬스토리지에서 찾아라 입니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 제가 로그인 여부를 확인하는 로직이 필요한데, 그러면 이 코드를 사용하면 될까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네네넵! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넵, 감사합니다! |
||
|
||
if (!token) return; | ||
evaluateToken(token); | ||
}, []); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. isLogin에 의해 결정되는 sideeffect 같은데, 의존성에 isLogin이 있는게 좋지 않을까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
isLoggedin이 �true에서 false가 됐을 경우 => logout을 눌렀을 때임.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. api 서버가 꺼져있네요. 서버 켜지는 대로 직접 돌려보겠습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. reload가 아니라서 의존성 배열에 추가하니 위 쿼리를 읽고 tokenValid 검증을 다시 해서 로그인 버튼이 서버에서 토큰 검증 후 다시 로그아웃되네요! 2023-11-23.11.49.21.movThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 의존성 배열 뺏을 때는 정상작동합니다. 2023-11-23.11.53.29.mov |
||
|
||
const evaluateToken = async (token: string) => { | ||
const isValid = await fetchTokenValid(token); | ||
isValid ? saveAuthInfo(token) : removeAuthInfo(); | ||
}; | ||
|
||
const saveAuthInfo = (token: string) => { | ||
localStorage.setItem(TOKEN_KEY, token); | ||
login(); | ||
}; | ||
|
||
const removeAuthInfo = () => { | ||
// accessToken 없애기 | ||
// AuthContext 없애기 | ||
localStorage.removeItem(TOKEN_KEY); | ||
logout(); | ||
}; | ||
|
||
const changeLoginInfo = () => { | ||
// accessToken 없애기 | ||
// AuthContext 없애기 | ||
// 로그인 페이지로 이동 | ||
removeAuthInfo(); | ||
navigate('/login'); | ||
}; | ||
|
||
const changeLogoutInfo = () => { | ||
// accessToken 없애기 | ||
// AuthContext 없애기 | ||
removeAuthInfo(); | ||
}; | ||
return { changeLoginInfo, changeLogoutInfo, isLoggedin }; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,34 +2,41 @@ import { createBrowserRouter } from 'react-router-dom'; | |
|
||
import ContestPage from '@/pages/ContestPage'; | ||
import CreateCompetitionPage from '@/pages/CreateCompetitionPage'; | ||
import LoginPage from '@/pages/LoginPage'; | ||
import MainPage from '@/pages/MainPage'; | ||
import ProblemPage from '@/pages/ProblemPage'; | ||
|
||
import App from './App'; | ||
|
||
const router = createBrowserRouter([ | ||
const router = createBrowserRouter( | ||
[ | ||
{ | ||
path: '/', | ||
element: <App />, | ||
children: [ | ||
{ | ||
index: true, | ||
element: <MainPage />, | ||
}, | ||
{ | ||
path: '/contest/:id', | ||
element: <ContestPage />, | ||
}, | ||
{ | ||
path: '/problem/:id', | ||
element: <ProblemPage />, | ||
}, | ||
{ | ||
path: '/contest/create', | ||
element: <CreateCompetitionPage />, | ||
}, | ||
{ path: '/login', element: <LoginPage /> }, | ||
], | ||
}, | ||
], | ||
{ | ||
path: '/', | ||
element: <App />, | ||
children: [ | ||
{ | ||
index: true, | ||
element: <MainPage />, | ||
}, | ||
{ | ||
path: '/contest/:id', | ||
element: <ContestPage />, | ||
}, | ||
{ | ||
path: '/problem/:id', | ||
element: <ProblemPage />, | ||
}, | ||
{ | ||
path: '/contest/create', | ||
element: <CreateCompetitionPage />, | ||
}, | ||
], | ||
basename: process.env.NODE_ENV === 'production' ? '/web12-Algo-With-Me' : '', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기 부분이 있어야 pnpm run deploy했을 떄 제대로 경로 찾아집니다 |
||
}, | ||
]); | ||
); | ||
|
||
export default router; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런 식으로 할 수 있었네요, 배워갑니다:D