https://moneyfulpublicpolicy.co.kr
기존과 동일, axios 추가
yarn add axios
or
npm install axios
import React, { createContext, useState, useEffect } from "react";
export const AuthContext = createContext();
const token = localStorage.getItem("accessToken");
export const AuthProvider = ({ children }) => {
const [isAuthenticated, setIsAuthenticated] = useState(!!token);
const login = (token) => {
localStorage.setItem("accessToken", token);
setIsAuthenticated(true);
};
const logout = () => {
localStorage.removeItem("accessToken");
setIsAuthenticated(false);
};
return (
<AuthContext.Provider value={{ isAuthenticated, login, logout }}>
{children}
</AuthContext.Provider>
);
};
import React, { useState, useContext } from "react";
import {
BrowserRouter as Router,
Route,
Routes,
Navigate,
} from "react-router-dom";
import Home from "../pages/Home.jsx";
import Record from "../pages/Record.jsx";
import Login from "../pages/Login.jsx";
import SignUp from "../pages/SignUp.jsx";
import MyPage from "../pages/MyPage.jsx";
import { AuthContext } from "../context/AuthContext";
// PrivateRoute : 로그인이 필요한 페이지에 접근할 수 있도록 하는 컴포넌트
// 로그인이 되어있지 않은 사용자는 login 페이지로 리다이렉트
const PrivateRoute = ({ element: Element, ...rest }) => {
const { isAuthenticated } = useContext(AuthContext);
return isAuthenticated ? <Element {...rest} /> : <Navigate to="/login" />;
};
// PublicRoute : 로그인이 필요없는 페이지에 접근할 수 있도록 하는 컴포넌트
// 로그인이 되어있는 사용자는 mypage로 리다이렉트
const PublicRoute = ({ element: Element, ...rest }) => {
const { isAuthenticated } = useContext(AuthContext);
return !isAuthenticated ? <Element {...rest} /> : <Navigate to="/mypage" />;
};
const SharedRouter = () => {
const [selectedMonth, setSelectedMonth] = useState("");
return (
<>
<Router>
<Header />
<Routes>
<Route
path="/"
element={
<Home
selectedMonth={selectedMonth}
setSelectedMonth={setSelectedMonth}
/>
}
/>
<Route path="/login" element={<PublicRoute element={Login} />} />
<Route path="/signup" element={<PublicRoute element={SignUp} />} />
<Route path="/mypage" element={<PrivateRoute element={MyPage} />} />
<Route path="/record/:id" element={<Record />} />
</Routes>
</Router>
</>
);
};
export default SharedRouter;
import React from "react";
import GlobalStyle from "./styles/GlobalStyle.jsx";
import Router from "./shared/Router.jsx";
import Layout from "./components/layout/Layout.jsx";
import { RecordProvider } from "./contexts/RecordContext.jsx";
import { AuthProvider } from "./contexts/AuthContext.jsx";
const App = () => {
return (
<>
<AuthProvider>
<RecordProvider>
<GlobalStyle />
<Layout>
<Router />
</Layout>
</RecordProvider>
</AuthProvider>
</>
);
};
export default App;
import React, { useContext } from "react";
import { Link, useNavigate } from "react-router-dom";
import { AuthContext } from "../context/AuthContext";
import styled from "styled-components";
import Button from "../atoms/Button";
const Layout = ({ children }) => {
const { isAuthenticated, logout } = useContext(AuthContext);
const navigate = useNavigate();
const handleLogout = () => {
const confirmLogout = window.confirm("정말로 로그아웃 하시겠습니까?");
if (confirmLogout) {
logout();
navigate("/");
}
};
return (
<>
<Header>
<HeaderLeft>
{" "}
<Link to="/">HOME</Link>
<span>내 프로필</span>
</HeaderLeft>
<HeaderRight>
<div>사진</div>
<span>아이디</span>
{isAuthenticated ? (
<Button
backgroundColor="#ff4d4d"
color="white"
contents="로그아웃"
onClick={handleLogout}
/>
) : (
<>
<Link to="/login">
<Button
backgroundColor="#8cbaff"
color="white"
contents="로그인"
/>
</Link>
<Link to="/signup">
<Button
backgroundColor="#8cbaff"
color="white"
contents="회원가입"
/>
</Link>
</>
)}
</HeaderRight>
</Header>
<LayoutDiv>{children}</LayoutDiv>
</>
);
};
// styled 코드 생략
export default Layout;
import React, { useState, useContext } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";
import { AuthContext } from "../context/AuthContext";
import styled from "styled-components";
import StyledContainer from "../styles/StyledContainer";
import Button from "../components/atoms/Button";
const Login = () => {
const [id, setId] = useState("");
const [password, setPassword] = useState("");
const { login } = useContext(AuthContext);
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await axios.post(
"https://moneyfulpublicpolicy.co.kr/login",
{
id,
password,
}
);
const data = response.data;
if (data.success) {
login(data.accessToken);
navigate("/mypage");
} else {
alert("Login failed");
}
} catch (error) {
console.error("Login error:", error);
alert("Login failed");
}
};
return (
<>
<LoginPage>
<LoginForm onSubmit={handleSubmit}>
<InputDiv>
<span>로그인 아이디</span>
<Input
type="text"
value={id}
onChange={(e) => setId(e.target.value)}
placeholder="ID"
/>
</InputDiv>
<InputDiv>
<span>비밀번호</span>
<Input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
</InputDiv>
<Button
width="100%"
backgroundColor="#999"
color="white"
margin="0 0 1.6rem 0"
contents="로그인"
type="submit"
/>
<Link to="/signup">
<Button
width="100%"
backgroundColor="#6c757d"
color="white"
contents="회원가입"
type="button"
/>
</Link>
</LoginForm>
</LoginPage>
</>
);
};
export default Login;
// styled 코드 생략
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";
import styled from "styled-components";
import StyledContainer from "../styles/StyledContainer";
import Button from "../components/atoms/Button";
const SignUp = () => {
const [id, setId] = useState("");
const [password, setPassword] = useState("");
const [nickname, setNickname] = useState("");
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await axios.post(
"https://moneyfulpublicpolicy.co.kr/register",
{
id,
password,
nickname,
}
);
const data = response.data;
if (data.success) {
navigate("/login");
} else {
alert("Signup failed");
}
} catch (error) {
console.error("Signup error:", error);
alert("Signup failed");
}
};
return (
<>
<SignUpPage>
<SignUpForm onSubmit={handleSubmit}>
<InputDiv>
<span>회원가입 아이디</span>
<Input
type="text"
value={id}
onChange={(e) => setId(e.target.value)}
placeholder="ID"
/>
</InputDiv>
<InputDiv>
<span>비밀번호</span>
<Input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
</InputDiv>
<InputDiv>
<span>닉네임</span>
<Input
type="text"
value={nickname}
onChange={(e) => setNickname(e.target.value)}
placeholder="Nickname"
/>
</InputDiv>
<Button
width="100%"
backgroundColor="#999"
color="white"
margin="0 0 1.6rem 0"
contents="회원가입"
type="submit"
/>
<Link to="/login">
<Button
width="100%"
backgroundColor="#6c757d"
color="white"
contents="로그인"
type="button"
/>
</Link>
</SignUpForm>
</SignUpPage>
</>
);
};
export default SignUp;
// styled 코드 생략
import React, { useEffect, useState, useContext } from "react";
import axios from "axios";
import { AuthContext } from "../context/AuthContext";
import { useNavigate } from "react-router-dom";
const MyPage = () => {
const [userInfo, setUserInfo] = useState(null);
const [newNickname, setNewNickname] = useState("");
const { isAuthenticated } = useContext(AuthContext);
const navigate = useNavigate();
useEffect(() => {
if (!isAuthenticated) {
alert("로그인이 필요합니다.");
navigate("/login");
} else {
const fetchUserInfo = async () => {
try {
const token = localStorage.getItem("accessToken");
const response = await axios.get(
"https://moneyfulpublicpolicy.co.kr/user",
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
setUserInfo(response.data);
} catch (error) {
console.error("Failed to fetch user info:", error);
}
};
fetchUserInfo();
}
}, [isAuthenticated, navigate]);
const handleNicknameChange = async (e) => {
e.preventDefault();
try {
const token = localStorage.getItem("accessToken");
const formData = new FormData();
formData.append("nickname", newNickname);
const response = await axios.patch(
"https://moneyfulpublicpolicy.co.kr/profile",
formData,
{
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "multipart/form-data",
},
}
);
if (response.data.success) {
setUserInfo((prevState) => ({
...prevState,
nickname: response.data.nickname,
}));
alert("닉네임이 변경되었습니다.");
setNewNickname("");
} else {
alert("닉네임 변경에 실패했습니다.");
}
} catch (error) {
console.error("Failed to update nickname:", error);
alert("닉네임 변경에 실패했습니다.");
}
};
if (!userInfo) {
return <div>Loading...</div>;
}
return (
<div>
<h2>My Page</h2>
<p>ID: {userInfo.id}</p>
<p>Nickname: {userInfo.nickname}</p>
<form onSubmit={handleNicknameChange}>
<input
type="text"
value={newNickname}
onChange={(e) => setNewNickname(e.target.value)}
placeholder="새 닉네임"
/>
<button type="submit">닉네임 변경</button>
</form>
</div>
);
};
export default MyPage;