diff --git a/package-lock.json b/package-lock.json
index 495c411..3ac2ccb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,8 +11,11 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
+ "axios": "^1.4.0",
"react": "^18.2.0",
+ "react-cookie": "^4.1.1",
"react-dom": "^18.2.0",
+ "react-router-dom": "^6.11.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
@@ -3116,6 +3119,14 @@
}
}
},
+ "node_modules/@remix-run/router": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.6.1.tgz",
+ "integrity": "sha512-YUkWj+xs0oOzBe74OgErsuR3wVn+efrFhXBWrit50kOiED+pvQe2r6MWY0iJMQU/mSVKxvNzL4ZaYvjdX+G7ZA==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -3811,6 +3822,11 @@
"@types/node": "*"
}
},
+ "node_modules/@types/cookie": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz",
+ "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow=="
+ },
"node_modules/@types/eslint": {
"version": "8.37.0",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz",
@@ -3864,6 +3880,15 @@
"@types/node": "*"
}
},
+ "node_modules/@types/hoist-non-react-statics": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+ "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+ "dependencies": {
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0"
+ }
+ },
"node_modules/@types/html-minifier-terser": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
@@ -5087,6 +5112,29 @@
"node": ">=4"
}
},
+ "node_modules/axios": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
+ "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
+ "dependencies": {
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
+ "node_modules/axios/node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/axobject-query": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz",
@@ -8693,6 +8741,19 @@
"he": "bin/he"
}
},
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "node_modules/hoist-non-react-statics/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ },
"node_modules/hoopy": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
@@ -14069,6 +14130,11 @@
"node": ">= 0.10"
}
},
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
"node_modules/psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -14213,6 +14279,19 @@
"node": ">=14"
}
},
+ "node_modules/react-cookie": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-4.1.1.tgz",
+ "integrity": "sha512-ffn7Y7G4bXiFbnE+dKhHhbP+b8I34mH9jqnm8Llhj89zF4nPxPutxHT1suUqMeCEhLDBI7InYwf1tpaSoK5w8A==",
+ "dependencies": {
+ "@types/hoist-non-react-statics": "^3.0.1",
+ "hoist-non-react-statics": "^3.0.0",
+ "universal-cookie": "^4.0.0"
+ },
+ "peerDependencies": {
+ "react": ">= 16.3.0"
+ }
+ },
"node_modules/react-dev-utils": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
@@ -14360,6 +14439,36 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "6.11.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.11.1.tgz",
+ "integrity": "sha512-OZINSdjJ2WgvAi7hgNLazrEV8SGn6xrKA+MkJe9wVDMZ3zQ6fdJocUjpCUCI0cNrelWjcvon0S/QK/j0NzL3KA==",
+ "dependencies": {
+ "@remix-run/router": "1.6.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "6.11.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.11.1.tgz",
+ "integrity": "sha512-dPC2MhoPeTQ1YUOt5uIK376SMNWbwUxYRWk2ZmTT4fZfwlOvabF8uduRKKJIyfkCZvMgiF0GSCQckmkGGijIrg==",
+ "dependencies": {
+ "@remix-run/router": "1.6.1",
+ "react-router": "6.11.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
"node_modules/react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@@ -16227,6 +16336,23 @@
"node": ">=8"
}
},
+ "node_modules/universal-cookie": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz",
+ "integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==",
+ "dependencies": {
+ "@types/cookie": "^0.3.3",
+ "cookie": "^0.4.0"
+ }
+ },
+ "node_modules/universal-cookie/node_modules/cookie": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+ "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
diff --git a/package.json b/package.json
index 9ce551a..d3fe664 100644
--- a/package.json
+++ b/package.json
@@ -6,8 +6,11 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
+ "axios": "^1.4.0",
"react": "^18.2.0",
+ "react-cookie": "^4.1.1",
"react-dom": "^18.2.0",
+ "react-router-dom": "^6.11.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
diff --git a/src/App.js b/src/App.js
index 5f30328..f4334b9 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,15 +1,38 @@
import logo from "./logo.svg";
import Header from "./components/Header";
import Footer from "./components/Footer";
-import Home from "./routes/Home";
+import HomePage from "./routes/HomePage";
+import MyPage from "./routes/MyPage";
import "./App.css";
+import { BrowserRouter, Route, Routes } from "react-router-dom";
+import PostCreatePage from "./routes/PostCreatePage";
+import PostEditPage from "./routes/PostEditPage";
+import SignUpPage from "./routes/SignUpPage";
+import PostDetailPage from "./routes/PostDetailPage";
+import SignInPage from "./routes/SignInPage";
function App() {
return (
-
-
-
+
+
+
+ {/* home */}
+ } />
+ {/* craete post */}
+ } />
+ {/* edit post */}
+ } />
+ {/* post detail */}
+ } />
+ {/* sign up */}
+ } />
+ {/* sign up */}
+ } />
+ } />
+
+
+
);
}
diff --git a/src/apis/api.js b/src/apis/api.js
new file mode 100644
index 0000000..2c180f6
--- /dev/null
+++ b/src/apis/api.js
@@ -0,0 +1,185 @@
+import { instance, instanceWithToken } from "./axios";
+
+// Account 관련 API들
+export const signIn = async (data) => {
+ const response = await instance.post("/account/signin/", data);
+ if (response.status === 200) {
+ window.location.href = "/";
+ } else {
+ console.log("Error");
+ }
+ };
+
+export const signUp = async (data) => {
+ const response = await instance.post("/account/signup/", data);
+ if (response.status === 200) {
+ window.location.href = "/";
+ }
+ return response;
+ };
+
+export const getPosts = async () => {
+ const response = await instance.get("/post/");
+ return response.data;
+};
+
+export const getPost = async (id) => {
+ const response = await instance.get(`/post/${id}/`);
+ return response.data;
+ };
+
+export const createPost = async (data, navigate) => {
+ const response = await instanceWithToken.post("/post/", data);
+ if (response.status === 201) {
+ console.log("POST SUCCESS");
+ navigate("/");
+ } else {
+
+ }
+ };
+
+export const updatePost = async (id, data, navigate) => {
+ const response = await instanceWithToken.patch(`/post/${id}/`, data);
+ if (response.status === 200) {
+ console.log("POST UPDATE SUCCESS");
+ navigate(-1);
+ } else {
+
+ }
+};
+
+ // 과제!!
+export const deletePost = async (id, navigate) => {
+ const response = await instanceWithToken.delete(`/post/${id}/`);
+ if (response.status === 204) {
+ console.log("POST DELETE SUCCESS");
+ if (window.confirm("정말 글을 삭제하시겠습니까?")) {
+ navigate("/");
+ }
+ } else {
+ console.log("[ERROR] error while deleting post");
+ console.log(response.status);
+ }
+ };
+
+ // 과제!!
+export const likePost = async (postId) => {
+ const response = await instanceWithToken.post(`/post/${postId}/like/`);
+ if (response.status === 200) {
+ console.log("POST LIKE SUCCESS");
+ // window.location.reload();
+ } else {
+ console.log("[ERROR] error while liking post");
+ // console.log(response.status)
+ }
+
+
+};
+
+
+// Tag 관련 API들
+export const getTags = async () => {
+ const response = await instance.get("/tag/");
+ return response.data;
+};
+
+export const createTag = async (data) => {
+ const response = await instanceWithToken.post("/tag/", data);
+ if (response.status === 201) {
+ console.log("TAG SUCCESS");
+ } else {
+ console.log("[ERROR] error while creating tag");
+ }
+ return response; // response 받아서 그 다음 처리
+};
+
+// Comment 관련 API들
+export const getComments = async (postId) => {
+ const response = await instance.get(`/comment/?post=${postId}`);
+ return response.data;
+};
+
+export const createComment = async (data) => {
+ const response = await instanceWithToken.post("/comment/", data);
+ if (response.status === 201) {
+ console.log("COMMENT SUCCESS");
+ window.location.reload(); // 새로운 코멘트 생성시 새로고침으로 반영
+ } else {
+ console.log("[ERROR] error while creating comment");
+ }
+};
+
+export const updateComment = async (id, data) => {
+ const response = await instanceWithToken.patch(`/comment/${id}/`, data);
+ if (response.status === 200) {
+ console.log("COMMENT UPDATE SUCCESS");
+ window.location.reload();
+ } else {
+ console.log("[ERROR] error while updating comment");
+ }
+};
+
+ // 과제 !!
+export const deleteComment = async (id) => {
+ const response = await instanceWithToken.delete(`/comment/${id}/`);
+ console.log(response)
+ if (response.status === 204) {
+ console.log("COMMENT DELETE SUCCESS");
+ if (window.confirm("정말 댓글을 삭제하시겠습니까?")) {
+ window.location.reload();
+ }
+ } else {
+ console.log("[ERROR] error while deleting comment");
+ }
+};
+
+export const getUser = async () => {
+ const response = await instanceWithToken.get("/account/info/");
+ if (response.status === 200) {
+ console.log("GET USER SUCCESS");
+ } else {
+ console.log("[ERROR] error while updating comment");
+ }
+ return response.data;
+ };
+
+export const updateInfo = async (data) => {
+ const response = await instanceWithToken.patch(`/account/profile/`, data);
+ if (response.status === 200) {
+ console.log("INFO UPDATE SUCCESS");
+ window.location.reload();
+ } else {
+ console.log("[ERROR] error while updating info");
+ }
+};
+
+export const getInfo = async () => {
+ const response = await instanceWithToken.get("/account/profile/");
+ return response.data;
+};
+
+export const refreshToken = async (token) => {
+ const response = await instance.post("/account/refresh/", { refresh: token });
+ if (response.status === 200) {
+ console.log("REFRESH TOKEN SUCCESS");
+ } else {
+ console.log("[ERROR] error while refreshing token");
+ }
+ };
+
+export const logOut = async (token) => {
+ const response = await instanceWithToken.post("/account/logout/", {
+ refresh: token,
+ });
+ if (response.status === 200) {
+ console.log("REFRESH TOKEN SUCCESS");
+
+ removeCookie("refresh_token");
+ removeCookie("access_token");
+
+ window.location.reload();
+ } else {
+ console.log("[ERROR] error while refreshing token");
+ }
+ };
+
\ No newline at end of file
diff --git a/src/apis/axios.js b/src/apis/axios.js
new file mode 100644
index 0000000..1b7182c
--- /dev/null
+++ b/src/apis/axios.js
@@ -0,0 +1,60 @@
+import axios from "axios";
+import { getCookie } from "../utils/cookie";
+import { refreshToken } from "./api";
+// baseURL, credential, 헤더 세팅
+axios.defaults.baseURL = 'http://localhost:8000/api';
+axios.defaults.withCredentials = true;
+axios.defaults.headers.post['Content-Type'] = 'application/json';
+axios.defaults.headers.common['X-CSRFToken'] = getCookie('csrftoken');
+
+
+// 누구나 접근 가능한 API들
+export const instance = axios.create();
+
+// Token 있어야 접근 가능한 API들 - 얘는 토큰을 넣어줘야 해요
+export const instanceWithToken = axios.create();
+
+// instanceWithToken에는 쿠키에서 토큰을 찾고 담아줍시다!
+instanceWithToken.interceptors.request.use(
+ // 요청을 보내기전 수행할 일
+ // 사실상 이번 세미나에 사용할 부분은 이거밖에 없어요
+ (config) => {
+ const accessToken = getCookie('access_token');
+
+ if (!accessToken) {
+ // token 없으면 리턴
+ return;
+ } else {
+ // token 있으면 헤더에 담아주기 (Authorization은 장고에서 JWT 토큰을 인식하는 헤더 key)
+ config.headers["Authorization"] = `Bearer ${accessToken}`;
+ }
+ return config;
+ },
+
+ // 클라이언트 요청 오류 났을 때 처리
+ (error) => {
+ // 콘솔에 찍어주고, 요청을 보내지 않고 오류를 발생시킴
+ console.log("Request Error!!");
+ return Promise.reject(error);
+ }
+ );
+
+ instanceWithToken.interceptors.response.use(
+ (response) => {
+ // 서버 응답 데이터를 프론트에 넘겨주기 전 수행할 일
+ console.log("Interceptor Response!!");
+ return response;
+ },
+ async (error) => {
+ console.log("Response Error!!");
+
+ const originalRequest = error.config;
+ if (error.response.status === 401) { //토큰이 만료됨에 따른 에러인지 확인
+ const token = getCookie("refresh_token");
+ await refreshToken(token); //refresh token 을 활용하여 access token 을 refresh
+
+ return instanceWithToken(originalRequest); //refresh된 access token 을 활용하여 재요청 보내기
+ }
+ return Promise.reject(error);
+ }
+ );
\ No newline at end of file
diff --git a/src/components/Comment/CommentElement.jsx b/src/components/Comment/CommentElement.jsx
new file mode 100644
index 0000000..a2db3b4
--- /dev/null
+++ b/src/components/Comment/CommentElement.jsx
@@ -0,0 +1,157 @@
+import { useEffect, useState } from "react";
+import { getUser, updateComment, deleteComment } from "../../apis/api";
+import { getCookie } from "../../utils/cookie";
+
+const CommentElement = ({
+ // comment,
+ // commentList,
+ setCommentList,
+ // commentData,
+ // setCommentData,
+ // id,
+ // // content,
+ onEdit,
+ // postId
+ comment
+ // handleCommentDelete
+
+
+}) => {
+ console.log(comment);
+ // const { comment, handleCommentDelete } = props;
+ // TODO : props 받기
+ // TODO : 수정하는 input 내용 관리
+ const [content, setContent] = useState(comment.content);
+ const [isEdit, setIsEdit] = useState(false);
+ const [user, setUser] = useState(null);
+
+ // comment created_at 전처리
+ console.log("왔다");
+
+ console.log(comment);
+ const date = new Date(comment.created_at);
+ const year = date.getFullYear();
+ let month = date.getMonth() + 1;
+ month = month < 10 ? `0${month}` : month;
+ let day = date.getDate();
+ day = day < 10 ? `0${day}` : day;
+ const [isOnClickEdit, setIsOnClickEdit] = useState(false);
+ const [editedComment, setEditedComment] = useState(content);
+
+ const handleEditComment = () => {
+ updateComment(comment.id, { content: content });
+
+ };
+
+ useEffect(() => {
+ if (getCookie("access_token")) {
+ const getUserAPI = async () => {
+ const user = await getUser();
+ setUser(user);
+ };
+ getUserAPI();
+ }
+ }, []);
+
+ const handleCommentDelete = async () => {
+ // console.log(commentList);
+ // console.log(id);
+ // const newCL = commentList.filter((c) => c.id !== id);
+ // console.log(newCL);
+ // setCommentList(newCL);
+ // console.log(comment.id);
+ // deleteComment(comment.id);
+
+ deleteComment(comment.id);
+
+ };
+
+ // const onClickEdit = () => {
+ // setIsOnClickEdit(true);
+ // };
+
+ // const clickEdit = (e) => {
+ // const editCL = e.target.value;
+ // setEditedComment(editCL);
+ // };
+
+ // const onDoneClick = () => {
+ // onEdit(id, editedComment);
+ // setIsOnClickEdit(false);
+ // };
+
+ // const handleCommentDelete = async () => {
+ // // console.log(commentList);
+ // // console.log(id);
+ // // const newCL = commentList.filter((c) => c.id !== id);
+ // // console.log(newCL);
+ // // setCommentList(newCL);
+ // // console.log(comment.id);
+ // // deleteComment(comment.id);
+ // deleteComment(comment.id);
+
+ // };
+ // console.log(comment.id);
+
+ // useEffect(() => {
+ // const deleteCommentAPI = async () => {
+ // const deletecomment = await deleteComment(pos);
+
+ // }
+ // deleteCommentAPI();
+
+ // },[onClickDelete]);
+
+ // console.log(postId);
+
+ return (
+
+
+ {isEdit ? (
+
setContent(e.target.value)}
+ />
+ ) : (
+
{comment.content}
+ )}
+ {/* // 날짜 */}
+
+ {year}.{month}.{day}
+
+
+ {/* // 수정, 삭제버튼 */}
+ {user?.id === comment.author.id ? (
+
+ {isEdit ? (
+ <>
+ Done
+
+ {
+ setIsEdit(!isEdit);
+ setContent(comment.content);
+ }}
+ >
+ Back
+
+ >
+ ) : (
+ <>
+
+ Del
+
+ setIsEdit(!isEdit)}>
+ Edit
+
+ >
+ )}
+
+ ) : null}
+
+ );
+};
+
+export default CommentElement;
diff --git a/src/components/Comment/index.jsx b/src/components/Comment/index.jsx
new file mode 100644
index 0000000..555efcd
--- /dev/null
+++ b/src/components/Comment/index.jsx
@@ -0,0 +1,119 @@
+import { useState, useEffect } from "react";
+import CommentElement from "./CommentElement";
+import { getComments } from "../../apis/api";
+import { createComment, deleteComment } from "../../apis/api";
+import { getCookie } from "../../utils/cookie";
+
+const Comment = ({postId}) => {
+ // TODO 1: comments 불러와서 저장해야겟즤
+ const [commentList, setCommentList] = useState([]);
+ // TODO 2: comment추가하는 input 관리해줘야겟지
+ // TODO 3: comment Form 제출됐을때 실행되는 함수 만들어줘
+ // const [commentData, setCommentData] = useState("");
+ const [newContent, setNewContent] = useState("");
+
+ const editComment = (e) => {
+ setNewContent(e.target.value);
+ console.log("여기");
+ // setCommentData("");
+ };
+ console.log(newContent);
+
+ useEffect(() => {
+ const getCommentsAPI = async () => {
+ const comments = await getComments(postId);
+ setCommentList(comments);
+ }
+ getCommentsAPI();
+
+ },[postId]);
+ console.log(postId);
+
+ // useEffect(() => {
+ // const deleteCommentAPI = async () => {
+ // const deletecomment = await deleteComment(postId);
+ // setCommentList(deletecomment);
+ // }
+ // deleteCommentAPI();
+
+ // },[onClickDelete]);
+ // console.log(postId);
+
+ const handleCommentSubmit = (e) => {
+ e.preventDefault();
+
+ createComment({ post: postId, content: newContent });
+ setNewContent("");
+ };
+
+ const handleEditComment = (id, newContent) => {
+ setCommentList((prevCommentList) => {
+ const updatedList = prevCommentList.map((comment) => {
+ if (comment.id === id) {
+ return { ...comment, content: newContent };
+ }
+ return comment;
+ });
+ return updatedList;
+ });
+ };
+
+ const handleCommentDelete = async (e) => {
+ // console.log(commentList);
+ // console.log(id);
+ // const newCL = commentList.filter((c) => c.id !== id);
+ // console.log(newCL);
+ // setCommentList(newCL);
+ // console.log(comment.id);
+ // deleteComment(comment.id);
+
+ deleteComment(comment.id);
+
+ };
+
+ return (
+
+
Comments
+ {commentList && commentList.map((c) => (
+
+ ))}
+ {/*
+
+ );
+};
+
+export { Comment };
diff --git a/src/components/Form/index.jsx b/src/components/Form/index.jsx
new file mode 100644
index 0000000..9b97efc
--- /dev/null
+++ b/src/components/Form/index.jsx
@@ -0,0 +1,261 @@
+import { useState } from "react";
+
+export const SignUpForm = ({ formData, setFormData, handleSignUpSubmit }) => {
+ const handleFormData = (e) => {
+ const { id, value } = e.target;
+ setFormData({ ...formData, [id]: value });
+ };
+
+ return (
+
+ );
+};
+
+export const SignInForm = ({ formData, setFormData, handleSignInSubmit }) => {
+ const handleFormData = (e) => {
+ const { id, value } = e.target;
+ setFormData({ ...formData, [id]: value });
+ };
+
+ return (
+
+ );
+};
+
+export const PostForm = ({ onSubmit, tags, formData, setFormData }) => {
+ //태그 Input 안에 값
+ const [tagInputValue, setTagInputValue] = useState("");
+
+ //자동완성 태그들
+ const [autoCompletes, setAutoCompletes] = useState([]);
+
+ const handleChange = (e) => {
+ setFormData({ ...formData, [e.target.id]: e.target.value });
+ };
+
+ //태그 인풋 값 바뀌면 그에 따라서 자동 완성값들도 변경
+ const handleTag = (e) => {
+ setTagInputValue(e.target.value);
+ if (e.target.value) {
+ const autoCompleteData = tags.filter((tag) =>
+ tag.includes(e.target.value)
+ );
+ setAutoCompletes(autoCompleteData);
+ }
+ };
+
+ // 자동완성 값이 있는 버튼을 눌렀을 때 이를 태그에 등록
+ const handleAutoCompletes = (autoComplete) => {
+ const selectedTag = tags.find((tag) => tag === autoComplete);
+
+ if (formData.tags.includes(selectedTag)) return;
+
+ setFormData({
+ ...formData,
+ tags: [...formData.tags, selectedTag],
+ });
+ setTagInputValue("");
+ setAutoCompletes([]);
+ };
+
+ // 추가 버튼 혹인 엔터 누르면 태그 생성
+ const addTag = (e) => {
+ e.preventDefault();
+
+ // 입력한 내용이 이미 등록된 태그면 그냥 등록 안됨
+ if (formData.tags.find((tag) => tag === tagInputValue)) return;
+
+ setFormData({
+ ...formData,
+ tags: [...formData.tags, tagInputValue],
+ });
+
+ setTagInputValue("");
+ setAutoCompletes([]);
+ };
+
+ // X버튼 눌렀을때 태그 삭제
+ const deleteTag = (tag) => {
+ setFormData({
+ ...formData,
+ tags: formData.tags.filter((t) => t !== tag),
+ });
+ };
+ return (
+
+ );
+};
diff --git a/src/components/Header/Header.css b/src/components/Header/Header.css
deleted file mode 100644
index f80b333..0000000
--- a/src/components/Header/Header.css
+++ /dev/null
@@ -1,13 +0,0 @@
-#header-wrapper {
- width: 100%;
- height: 80px;
- padding: 10px 80px;
- display: flex;
- align-items: center;
- gap: 20px;
- background-color: rgba(0, 0, 0, 0.1);
-}
-
-#header-lion {
- max-width: 60px;
-}
diff --git a/src/components/Header/index.jsx b/src/components/Header/index.jsx
index 2110ea0..75b5999 100644
--- a/src/components/Header/index.jsx
+++ b/src/components/Header/index.jsx
@@ -1,10 +1,50 @@
+import { Link } from "react-router-dom";
import lion from "../../assets/images/lion.jpeg";
-import "./Header.css";
+import { useState, useEffect } from "react";
+import { getCookie, removeCookie } from "../../utils/cookie";
+// import "./Header.css";
const Header = () => {
+ const [isLoggedIn, setIsLoggedIn] = useState("");
+
+ useEffect(() => {
+ const loggedIn = getCookie("access_token") ? true : false;
+ setIsLoggedIn(loggedIn);
+ }, []);
+
+ const handleLogout = () => {
+ // removeCookie("access_token");
+ // removeCookie("refresh_token");
+ // window.location.href = "/"; // 새로고침 - 로그아웃 되었다는 것을 인지시켜주기 위해
+ const token = getCookie("refresh_token");
+ logOut(token);
+ };
return (
-
- {post.like_users.length > 0 && `❤️ ${post.like_users.length}`}
+ ❤️ {post.like_users.length > 0 && `${post.like_users.length}`}
+ {/* {`❤️ ${post.like_users.length}`} */}
+ {/* ❤️ {likeCount} */}
+
+
+
+ detail
+
+
+
+ );
+};
+
+
+
+export const BigPost = ({ post }) => {
+ const [likeCount, setLikeCount] = useState(post.like_users.length);
+ const onClickLike = () => {
+ console.log("나도 좋아!");
+ // add api call for liking post here
+ const liking = likePost(post.id);
+ setLikeCount(post.like_users.length);
+
+ };
+
+ return (
+
+
+
{post.title}
+
{post.author.username}
+
{post.content}
+
+ {post.tags &&
+ post.tags.map((tag) => (
+
+ #{tag.content}
+
+ ))}
+
+
+ ❤️ {post.like_users.length > 0 && `${post.like_users.length}`}
+ {/* ❤️ {post.like_users.length} */}
+ {/* ❤️ {likeCount} */}
+
);
};
+
diff --git a/src/data/comments.js b/src/data/comments.js
new file mode 100644
index 0000000..677f950
--- /dev/null
+++ b/src/data/comments.js
@@ -0,0 +1,25 @@
+//가짜 comment data 넣어주기
+const comments = [
+ {
+ "id": 1,
+ "content": "멋사 11기 화이팅!!",
+ "created_at": "2023-02-12T15:09:43Z",
+ "post": 1,
+ "author": {
+ "id": 2,
+ "username": "user2"
+ }
+ },
+ {
+ "id": 2,
+ "content": "멋사 좋아요~~",
+ "created_at": "2022-11-22T15:09:43Z",
+ "post": 1,
+ "author": {
+ "id": 2,
+ "username": "user2"
+ }
+ }
+]
+
+export default comments;
\ No newline at end of file
diff --git a/src/index.css b/src/index.css
index 5b2de4d..644d635 100644
--- a/src/index.css
+++ b/src/index.css
@@ -11,7 +11,7 @@
}
/* 모든 버튼 일괄 적용 */
.button {
- @apply bg-orange-400 text-white font-medium hover:text-black rounded-xl text-lg p-3.5;
+ @apply bg-orange-400 text-white font-medium hover:text-black rounded-xl text-lg p-2.5;
}
/* 모든 form 일괄 적용 */
.form {
@@ -25,6 +25,10 @@
@apply border-2 border-white w-full px-6 py-3 rounded-2xl text-white bg-transparent placeholder-opacity-50 focus:outline-none focus:ring-2 focus:ring-orange-400 focus:border-transparent;
}
+.textDesign{
+ @apply border-b border-gray-300 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-200 px-4 py-2 w-full;
+}
+
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
diff --git a/src/routes/Home.jsx b/src/routes/Home.jsx
deleted file mode 100644
index ce552fd..0000000
--- a/src/routes/Home.jsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import { useEffect, useState } from "react";
-import { SmallPost } from "../components/Posts";
-import posts from "../data/posts";
-
-const Home = () => {
- const [tags, setTags] = useState([]);
- const [searchTags, setSearchTags] = useState([]);
- const [searchValue, setSearchValue] = useState("");
- const [postList, setPostList] = useState(posts);
-
- useEffect(() => {
- const tagList = posts.reduce((acc, post) => {
- for (let tag of post.tags) {
- acc.add(tag.content);
- }
- return acc;
- }, new Set());
- setTags([...tagList]);
- setSearchTags([...tagList]);
- }, []);
-
- const handleChange = (e) => {
- const { value } = e.target;
- const newTags = tags.filter((tag) => tag.includes(value));
- setSearchTags(newTags);
- };
-
- const handleTagFilter = (e) => {
- let tag = e.target.innerText.slice(1);
- if (searchValue === tag) {
- const clickedtag = tags.filter((t) => {
- t !== tag;
- });
- setSearchValue(clickedtag);
- setPostList(posts);
- } else {
- // let tmp = searchValue.push(tag);
- setSearchValue(tag);
- let clickedpost = posts.filter((post) => {
- let include = false;
- post.tags.map((t) => {
- if (t.content === tag) include = true;
- // console.log(t.content);
- // console.log(tag);
- });
- return include;
- // console.log(post.tags);
- });
- // console.log(clickedpost);
- setPostList(clickedpost);
- }
- };
-
- return (
-
-
-
-
my blog
-
-
-
- {searchTags.map((tag) => {
- return (
-
- #{tag}
-
- );
- })}
-
-
-
-
- {postList.map((post) => (
-
- ))}
-
-
- );
-};
-
-export default Home;
diff --git a/src/routes/HomePage.jsx b/src/routes/HomePage.jsx
new file mode 100644
index 0000000..1103d8d
--- /dev/null
+++ b/src/routes/HomePage.jsx
@@ -0,0 +1,139 @@
+import { useEffect, useState } from "react";
+import { SmallPost } from "../components/Posts";
+import { Link } from "react-router-dom";
+import { getTags, getPosts } from "../apis/api";
+import { getCookie } from "../utils/cookie";
+// import axios from "axios";
+
+const HomePage = () => {
+ const [tags, setTags] = useState([]);
+ const [searchTags, setSearchTags] = useState([]);
+ const [searchValue, setSearchValue] = useState("");
+ const [postList, setPostList] = useState([]);
+
+ // useEffect( () => {
+ // const getPostAPI = async () => {
+ // const response = await axios.get("http://localhost:8000/api/post/");
+ // console.log(response);
+ // }
+ // getPostAPI();
+ // }, []);
+ useEffect(() => {
+ const getPostAPI = async () => {
+ const posts = await getPosts();
+ setPostList(posts);
+ }
+ getPostAPI();
+
+
+
+ //추가
+ const getTagsAPI = async () => {
+ const tags = await getTags();
+ const tagContents = tags.map((tag) => {
+ return tag.content;
+ });
+ setTags(tagContents);
+ setSearchTags(tagContents);
+ };
+ getTagsAPI();
+ // getTags() 이용해서 tag들 불러오고 tags.map을 이용해서 tagContents에
+ // tag.content만 저장한 후, tags와 searchTags에 저장
+ }, []);
+
+ const handleChange = (e) => {
+ const { value } = e.target;
+ const newTags = tags.filter((tag) => tag.includes(value));
+ setSearchTags(newTags);
+ };
+
+ const handleTagFilter = (e) => {
+ // let tag = e.target.innerText.slice(1);
+ // if (searchValue === tag) {
+ // const clickedtag = tags.filter((t) => {
+ // t !== tag;
+ // });
+ // setSearchValue(clickedtag);
+ // // setPostList(posts);
+ // } else {
+ // // let tmp = searchValue.push(tag);
+ // setSearchValue(tag);
+ // let clickedpost = posts.filter((post) => {
+ // let include = false;
+ // post.tags.map((t) => {
+ // if (t.content === tag) include = true;
+ // // console.log(t.content);
+ // // console.log(tag);
+ // });
+ // return include;
+ // // console.log(post.tags);
+ // });
+ // // console.log(clickedpost);
+ // setPostList(clickedpost);
+ // }
+ const { innerText } = e.target;
+ if (searchValue === innerText.substring(1)) {
+ setSearchValue("");
+ } else {
+ const activeTag = innerText.substring(1);
+ setSearchValue(activeTag);
+ }
+ };
+
+ return (
+
+
+
+
my blog
+
+
+
+ {searchTags.map((tag) => {
+ return (
+
+ #{tag}
+
+ );
+ })}
+
+
+
+
+ {postList
+ .filter((post) =>
+ searchValue
+ ? post.tags.find((tag) => tag.content === searchValue)
+ : post
+ )
+ .map((post) => (
+
+ ))}
+
+
+ {getCookie("access_token") ? (
+
+
+ Post
+
+
+ ) : null}
+
+ {/*
+
+ Post
+
+
*/}
+
+ );
+};
+
+export default HomePage;
diff --git a/src/routes/MyPage.jsx b/src/routes/MyPage.jsx
new file mode 100644
index 0000000..507c54b
--- /dev/null
+++ b/src/routes/MyPage.jsx
@@ -0,0 +1,256 @@
+import { useState, useEffect } from "react";
+import { getInfo, updateInfo, getPosts, getTags } from "../apis/api";
+import { SmallPost } from "../components/Posts";
+
+const MyPage = () => {
+ const [formData, setFormData] = useState({
+ email: "",
+ username: "",
+ college: "",
+ major: "",
+ });
+
+ const [originalData, setOriginalData] = useState({});
+
+ const [isEdit, setIsEdit] = useState({
+ email: false,
+ username: false,
+ college: false,
+ major: false,
+ });
+
+ const [postList, setPostList] = useState([]);
+ const [id, setId] = useState("");
+ const [tags, setTags] = useState([]);
+
+ useEffect(() => {
+ const getPostAPI = async () => {
+ const posts = await getPosts();
+ setPostList(posts);
+ };
+ getPostAPI();
+
+ //추가
+ const getTagsAPI = async () => {
+ const tags = await getTags();
+ const tagContents = tags.map((tag) => {
+ return tag.content;
+ });
+ setTags(tagContents);
+ };
+ getTagsAPI();
+ // getTags() 이용해서 tag들 불러오고 tags.map을 이용해서 tagContents에
+ // tag.content만 저장한 후, tags와 searchTags에 저장
+ }, []);
+
+ useEffect(() => {
+ const getProfileAPI = async () => {
+ const profile = await getInfo();
+ console.log(profile);
+ setFormData({
+ email: profile.user.email,
+ username: profile.user.username,
+ college: profile.college,
+ major: profile.major,
+ });
+ setOriginalData({
+ email: profile.user.email,
+ username: profile.user.username,
+ college: profile.college,
+ major: profile.major,
+ });
+ setId(profile.user.id);
+ };
+ getProfileAPI();
+ }, []);
+
+ const handleEditInfo = () => {
+ updateInfo(formData);
+ };
+
+ const handleCancelEdit = (field) => {
+ setFormData({ ...formData, [field]: originalData[field] });
+ setIsEdit({ ...isEdit, [field]: false });
+ };
+
+ console.log(postList);
+ console.log(id);
+ return (
+
+
My Info
+
+
email:
+ {isEdit.email ? (
+ <>
+
+ setFormData({ ...formData, email: e.target.value })
+ }
+ />
+
+
+ 변경하기
+
+
+ {
+ handleCancelEdit("email");
+ }}
+ >
+ 취소하기
+
+
+ >
+ ) : (
+ <>
+
+
+
{formData.email}
+
+
setIsEdit({ ...isEdit, email: true })}
+ >
+ 변경
+
+ {/*
*/}
+
+ >
+ )}
+
+ {/* */}
+ username:
+
+ {isEdit.username ? (
+ <>
+
+ setFormData({ ...formData, username: e.target.value })
+ }
+ />
+
+
+ 변경하기
+
+
+ {
+ handleCancelEdit("username");
+ }}
+ >
+ 취소하기
+
+
+ >
+ ) : (
+ <>
+
+
{formData.username}
+
setIsEdit({ ...isEdit, username: true })}
+ >
+ 변경
+
+
+ >
+ )}
+
+ college:
+ {isEdit.college ? (
+ <>
+
+ setFormData({ ...formData, college: e.target.value })
+ }
+ />
+
+
+ 변경하기
+
+
+ {
+ handleCancelEdit("college");
+ }}
+ >
+ 취소하기
+
+
+ >
+ ) : (
+ <>
+
+
{formData.college}
+
setIsEdit({ ...isEdit, college: true })}
+ >
+ 변경
+
+
+ >
+ )}
+
+ major:
+ {isEdit.major ? (
+ <>
+
+ setFormData({ ...formData, major: e.target.value })
+ }
+ />
+
+
+ 변경하기
+
+
+ {
+ handleCancelEdit("major");
+ }}
+ >
+ 취소하기
+
+
+ >
+ ) : (
+ <>
+
+
{formData.major}
+
setIsEdit({ ...isEdit, major: true })}
+ >
+ 변경
+
+
+ >
+ )}
+ {/* */}
+
+ My Posts
+
+ {postList
+ .filter((post) => post.author.id === id)
+ .map((post) => (
+
+ ))}
+
+
+ );
+};
+
+export default MyPage;
diff --git a/src/routes/PostCreatePage.jsx b/src/routes/PostCreatePage.jsx
new file mode 100644
index 0000000..fbfc812
--- /dev/null
+++ b/src/routes/PostCreatePage.jsx
@@ -0,0 +1,71 @@
+import { useEffect, useState } from "react";
+import { BigPost } from "../components/Posts";
+import posts from "../data/posts";
+import { PostForm } from "../components/Form";
+import { getTags, createPost } from "../apis/api";
+import { useNavigate } from "react-router-dom";
+
+
+const PostCreatePage = () => {
+ const [isSubmitted, setIsSubmitted] = useState(false);
+ // 화면그리기
+ const [formData, setFormData] = useState({
+ title: "",
+ content: "",
+ tags: [],
+ });
+
+ const [tags, setTags] = useState([]);
+ useEffect(() => {
+ const getTagsAPI = async () => {
+ const tags = await getTags();
+ const tagContents = tags.map((tag) => {
+ return tag.content;
+ });
+ setTags(tagContents);
+ };
+ getTagsAPI();
+ }, []);
+
+ // const navigate = useNavigate();
+
+// const onSubmit = (e) => {
+// e.preventDefault();
+// createPost(formData, navigate);
+// };
+
+// useEffect(() => {
+// const duplicatedTagList = posts.reduce((acc, post) => {
+// for (let tag of post.tags) {
+// acc.add(tag.content);
+// }
+
+// return acc;
+// }, new Set());
+
+// const tagList = [...duplicatedTagList];
+
+// setTags([...tagList]);
+// }, []);
+
+const navigate = useNavigate();
+
+const onSubmit = (e) => {
+ e.preventDefault();
+ createPost(formData, navigate);
+ };
+
+ return (
+
+ );
+ };
+
+export default PostCreatePage;
\ No newline at end of file
diff --git a/src/routes/PostDetailPage.jsx b/src/routes/PostDetailPage.jsx
new file mode 100644
index 0000000..4b4ecfc
--- /dev/null
+++ b/src/routes/PostDetailPage.jsx
@@ -0,0 +1,79 @@
+import { useEffect, useState } from "react";
+import { useNavigation, useParams } from "react-router-dom";
+import { BigPost } from "../components/Posts";
+import { Comment } from "../components/Comment/index";
+import { Link } from "react-router-dom";
+import posts from "../data/posts";
+import { deletePost, getComments } from "../apis/api";
+import { getPost, getUser } from "../apis/api";
+import { getCookie } from "../utils/cookie";
+import { useNavigate } from "react-router-dom";
+
+const PostDetailPage = () => {
+ const { postId } = useParams();
+ const [post, setPost] = useState();
+ const [comment, setComment] = useState();
+ const [user, setUser] = useState();
+
+ useEffect(() => {
+ const post = posts.find((post) => post.id === parseInt(postId));
+ setPost(post);
+ }, [postId]);
+
+ useEffect(() => {
+ const getPostAPI = async () => {
+ const post = await getPost(postId);
+ setPost(post);
+ }
+ getPostAPI();
+ },[postId]);
+ console.log(postId);
+
+ useEffect(() => {
+ // access_token이 있으면 유저 정보 가져옴
+ if (getCookie("access_token")) {
+ const getUserAPI = async () => {
+ const user = await getUser();
+ setUser(user);
+ };
+ getUserAPI();
+ }
+ }, []);
+
+ const navigate = useNavigate();
+ const onClickDelete = () => {
+ deletePost(postId, navigate);
+
+ };
+ console.log("delete");
+
+ return (
+ post && (
+
+ {/* post detail component */}
+
+
+
+ {user?.id === post?.author.id ? (
+ <>
+
+ Edit
+
+
+ Delete
+
+ >
+ ) : null}
+ {/* user와 post.author가 동일하면 버튼을 리턴, 아니면 null */}
+
+ {/* 수정 */}
+
+ )
+ );
+};
+
+export default PostDetailPage;
diff --git a/src/routes/PostEditPage.jsx b/src/routes/PostEditPage.jsx
new file mode 100644
index 0000000..f2d6eb3
--- /dev/null
+++ b/src/routes/PostEditPage.jsx
@@ -0,0 +1,61 @@
+import { getPost } from "../apis/api";
+
+const PostEditPage = () => {
+ const { postId } = useParams();
+
+ const [formData, setFormData] = useState({
+ title: "",
+ content: "",
+ tags: [],
+ });
+
+ useEffect(() => {
+ const getPostAPI = async () => {
+ const post = await getPost(postId);
+ const postFormData = {
+ ...post,
+ tags: post.tags.map((tag) => tag.content),
+ };
+ setFormData(postFormData);
+ };
+ getPostAPI();
+ }, [postId]);
+
+ const [tags, setTags] = useState([]);
+ useEffect(() => {
+ const getTagsAPI = async () => {
+ const tags = await getTags();
+ const tagContents = tags.map((tag) => {
+ return tag.content;
+ });
+ setTags(tagContents);
+ };
+ getTagsAPI();
+ }, []);
+
+ const navigate = useNavigate();
+
+const onSubmit = (e) => {
+ e.preventDefault();
+ updatePost(postId, formData, navigate);
+ };
+
+ return (
+
+
+
+ {`< Back`}
+
+
Edit Post
+
+
+
+ );
+};
+
+export default PostEditPage;
\ No newline at end of file
diff --git a/src/routes/SignInPage.jsx b/src/routes/SignInPage.jsx
new file mode 100644
index 0000000..c590108
--- /dev/null
+++ b/src/routes/SignInPage.jsx
@@ -0,0 +1,32 @@
+import { useState } from "react";
+import { SignInForm } from "../components/Form";
+import { signIn } from "../apis/api";
+const SignInPage = () => {
+ const [formData, setFormData] = useState({
+ username: "",
+ password: "",
+ });
+
+ const handleSignInSubmit = (e) => {
+ e.preventDefault();
+ signIn(formData);
+ // console.log(formData);
+ // alert("로그인 완 료!");
+ // add api call for sign in here
+ // const signinMem = await signIn(formData);
+ // console.log(signinMem);
+
+ };
+ return (
+
+
Sign In
+
+
+ );
+};
+
+export default SignInPage;
\ No newline at end of file
diff --git a/src/routes/SignUpPage.jsx b/src/routes/SignUpPage.jsx
new file mode 100644
index 0000000..43789b7
--- /dev/null
+++ b/src/routes/SignUpPage.jsx
@@ -0,0 +1,47 @@
+import { useState } from "react";
+import { SignUpForm } from "../components/Form";
+import axios from "axios";
+import { signUp } from "../apis/api";
+
+
+const SignUpPage = () => {
+ const [formData, setFormData] = useState({
+ email: "",
+ password: "",
+ confirm_password: "",
+ username: "",
+ college: "",
+ major: "",
+ });
+
+ const handleSignUpSubmit = (e) => {
+ e.preventDefault();
+ signUp(formData);
+ // const response = await axios.post("http://localhost:8000/api/account/signup/", formData, {
+ // headers: {
+ // "Content-Type": "application/json",
+ // "X-CSRFToken": getCookie("csrftoken"),
+ // },
+ // withCredentials: true
+ // });
+ // console.log(response);
+ // console.log(formData);
+ // alert(`${formData.email}로 회원가입 해 줘`);
+ // // add api call for sign up here
+ // const signupMem = await signUp(formData);
+ // console.log(signupMem);
+
+ };
+ return (
+
+
Sign Up
+
+
+ );
+};
+
+export default SignUpPage;
\ No newline at end of file
diff --git a/src/utils/cookie.js b/src/utils/cookie.js
new file mode 100644
index 0000000..aeae0dd
--- /dev/null
+++ b/src/utils/cookie.js
@@ -0,0 +1,19 @@
+import { Cookies } from 'react-cookie';
+
+const cookies = new Cookies()
+
+// 쿠키 설정하는 함수
+// 궁금하실까봐 만들긴 했는데, 우리는 안 쓸거에요!! (쿠키에 토큰 넣어주는 건 서버에서 해주니까요)
+export const setCookie = ( name, value, option) => {
+ return cookies.set( name, value, {...option})
+}
+
+// 쿠키 정보 가져오는 함수
+export const getCookie = ( name ) => {
+ return cookies.get(name)
+}
+
+// 쿠키 정보 삭제하는 함수
+export const removeCookie = ( name ) => {
+ cookies.remove(name)
+}
\ No newline at end of file