import axios from 'axios';
import Link from 'next/link'
import React from 'react'
import { useAuthDispatch, useAuthState } from '../context/auth'
const NavBar: React.FC = () => {
const { loading, authenticated } = useAuthState();
const dispatch = useAuthDispatch();
const handleLogout = () => {
axios.post("/auth/logout")
.then(() => {
dispatch("LOGOUT");
window.location.reload();
})
.catch((error) => {
console.log(error);
})
}
return (
<div className='fixed inset-x-0 top-0 z-10 flex items-center justify-between h-16 px-5 bg-white'>
<span className='text-2xl font-semibold text-gray-400'>
<Link href="/">Community</Link>
</span>
<div className='max-w-full px-4'>
<div className='relative flex items-center bg-gray-100 border rounded hover:border-gray-700 hover:bg-white'>
<input
type="text"
placeholder="Search..."
className='px-3 py-1 bg-transparent rounded focus:outline-none'
/>
</div>
</div>
<div className='flex'>
{!loading && (
authenticated ? (
<button className='w-20 p-2 mr-2 text-center text-white bg-gray-400 rounded'
onClick={handleLogout}>
로그아웃
</button>
) : (<>
<Link href="/login">
<a className='w-20 p-2 mr-2 text-center text-blue-500 border border-blue-500 rounded'>
로그인
</a>
</Link>
<Link href="/register">
<a className='w-20 p-2 text-center text-white bg-gray-400 rounded'>
회원가입
</a>
</Link>
</>)
)}
</div>
</div>
)
}
export default NavBar
이후 상단바 UI를 reddit-clone-app\client\src\pages\_app.tsx
파일에 추가한다.
import '../styles/globals.css'
import type { AppProps } from 'next/app'
import Axios from 'axios'
import { AuthProvider } from '../context/auth';
import NavBar from '../components/NavBar';
function MyApp({ Component, pageProps }: AppProps) {
Axios.defaults.baseURL = process.env.NEXT_PUBLIC_SERVER_BASE_URL + "/api";
Axios.defaults.withCredentials = true;
return <AuthProvider>
// 추가 부분
<NavBar />
<div className="pt-12">
<Component {...pageProps} />
</div>
</AuthProvider>
}
export default MyApp
reddit-clone-app\server\src\routes\auth.ts
파일에 아래 내용을 추가한다.
/api/auth/logout
요청이 서버로 들어왔을 때 동작을 정의한다.
...생략
// 추가 부분
const logout = async (_ : Request, res: Response) => {
res.set(
"Set-Cookie",
cookie.serialize("token", "", {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
expires: new Date(0),
path: "/"
})
);
res.status(200).json({ success: true });
}
const router = Router();
router.get("/me", userMiddleware, authMiddleware, me);
router.post("/register", register);
router.post("/login", login);
// 추가 부분
router.post("/logout", userMiddleware, authMiddleware, logout);
...생략
reddit-clone-app\client\src\components\NavBar.tsx
파일에 아래 내용을 추가한다.
... 생략
import { useAuthDispatch, useAuthState } from '../context/auth'
const NavBar: React.FC = () => {
const { loading, authenticated } = useAuthState();
const dispatch = useAuthDispatch();
// 로그아웃 버튼 클릭 시 동작
const handleLogout = () => {
axios.post("/auth/logout")
.then(() => {
dispatch("LOGOUT");
window.location.reload();
})
.catch((error) => {
console.log(error);
})
}
... 생략
<div className='flex'>
{!loading && (
authenticated ? (
<button className='w-20 p-2 mr-2 text-center text-white bg-gray-400 rounded'
// 추가 부분
onClick={handleLogout}>
로그아웃
</button>
) : (<>
<Link href="/login">
<a className='w-20 p-2 mr-2 text-center text-blue-500 border border-blue-500 rounded'>
로그인
</a>
</Link>
<Link href="/register">
<a className='w-20 p-2 text-center text-white bg-gray-400 rounded'>
회원가입
</a>
</Link>
</>)
)}
</div>
</div>
)
}
로그인된 상태로 localhost:3000
진입한다.
로그아웃 버튼을 클릭하면 로그인, 회원가입 버튼이 나타나며 로그아웃 버튼이 사라지게 된다.