diff --git a/package-lock.json b/package-lock.json
index cc88270..3ac2ccb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,7 +11,9 @@
"@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",
@@ -3820,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",
@@ -3873,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",
@@ -5096,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",
@@ -8702,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",
@@ -14078,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",
@@ -14222,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",
@@ -16266,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 ac7db0d..d3fe664 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,9 @@
"@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",
diff --git a/src/App.js b/src/App.js
index c1f77e7..785bd66 100644
--- a/src/App.js
+++ b/src/App.js
@@ -9,6 +9,7 @@ import PostEditPage from "./routes/PostEditPage";
import SignUpPage from "./routes/SignUpPage";
import PostDetailPage from "./routes/PostDetailPage";
import SignInPage from "./routes/SignInPage";
+import MyInfoPage from "./routes/MyInfoPage"
function App() {
@@ -29,6 +30,8 @@ function App() {
} />
{/* sign up */}
} />
+ {/* my info */}
+ } />
diff --git a/src/apis/api.js b/src/apis/api.js
new file mode 100644
index 0000000..69c30f1
--- /dev/null
+++ b/src/apis/api.js
@@ -0,0 +1,188 @@
+import { instance, instanceWithToken } from "./axios";
+import { removeCookie } from "../utils/cookie";
+
+// src/api/api.js
+// 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 getUser = async () => {
+ const response = await instanceWithToken.get("/account/info/");
+ if (response.status == 200) {
+ console.log("success");
+ } else {
+ console.log("fail");
+ }
+ return response;
+};
+
+export const getUserProfile = async () => {
+ const response = await instanceWithToken.get("/account/profile/");
+ if (response.status == 200) {
+ console.log("success");
+ } else {
+ console.log("fail");
+ }
+ return response;
+};
+
+export const updateUserProfile = async () => {
+ const response = await instanceWithToken.patch("/account/profile/");
+ if (response.status == 200) {
+ console.log("success");
+ } else {
+ console.log("fail");
+ }
+ 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(-1); // 새로고침 X
+ navigate("/post");
+ } else {
+ console.log("[ERROR] error while creating post");
+ }
+};
+
+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 {
+ console.log("[ERROR] error while updating post");
+ }
+};
+
+// 과제!!
+export const deletePost = async (id, navigate) => {
+ const response = await instanceWithToken.delete(`/post/${id}/`);
+ window.confirm("정말 삭제하실건가요...? U._.U");
+ if (response.status === 204) {
+ console.log("POST DELETE SUCCESS");
+ window.location.reload();
+ navigate(-1);
+ } else {
+ console.log("[ERROR] error while deleting post");
+ }
+};
+
+// 과제!!
+export const likePost = async (postId) => {
+ const response = await instanceWithToken.post(`/post/${postId}/like/`);
+ if (response.status == 200) {
+ console.log("I like it!");
+ window.location.reload();
+ } else {
+ console.log("[Error] error while liking post");
+ }
+};
+
+// src/apis/api.js
+// ...
+// 추가
+
+// 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}/`);
+ if (response.status === 204) {
+ console.log("COMMENT DELETE SUCCESS");
+ window.location.reload();
+ } else {
+ console.log("[ERROR] error while deleting comment");
+ }
+};
+
+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 === 204) {
+ console.log("REFRESH TOKEN SUCCESS");
+
+ removeCookie("refresh_token");
+ removeCookie("access_token");
+
+ window.location.reload();
+ } else {
+ console.log("[ERROR] error while refreshing token");
+ }
+};
diff --git a/src/apis/axios.js b/src/apis/axios.js
new file mode 100644
index 0000000..0d2f8e7
--- /dev/null
+++ b/src/apis/axios.js
@@ -0,0 +1,65 @@
+// src/apis/axios.js
+
+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();
+
+// src/apis/axios.js
+// ⬇️ 추가
+// 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);
+ }
+);
+
diff --git a/src/components/Comments/CommentElement.jsx b/src/components/Comments/CommentElement.jsx
index 1057c66..90d8305 100644
--- a/src/components/Comments/CommentElement.jsx
+++ b/src/components/Comments/CommentElement.jsx
@@ -1,10 +1,14 @@
import { useEffect, useState } from "react";
+import { getUser, updateComment, deleteComment } from "../../apis/api";
+import { getCookie } from "../../utils/cookie";
-const CommentElement = ({ comment, deleteComment, editComment}) => {
- // TODO : props 받기
- // TODO : 수정하는 input 내용 관리`
+const CommentElement = (props) => {
+ const { comment, handleCommentDelete } = props;
+ const [content, setContent] = useState(comment.content);
+ const [isEdit, setIsEdit] = useState(false);
+
+ const [user, setUser] = useState(null);
- // comment created_at 전처리
const date = new Date(comment.created_at);
const year = date.getFullYear();
let month = date.getMonth() + 1;
@@ -12,78 +16,73 @@ const CommentElement = ({ comment, deleteComment, editComment}) => {
let day = date.getDate();
day = day < 10 ? `0${day}` : day;
- const [isClickEdit, setIsClickEdit] = useState(false);
-
- const onClickDelete = () => {
- console.log("delete");
- deleteComment(comment);
- };
-
- const onClickEdit = () => {
- setIsClickEdit(true);
+ const handleEditComment = () => {
+ console.log("content: ", content);
+ updateComment(comment.id, { content: content });
};
- const doneClickEdit = () => {
- // setFormData((nowFormData) => ({
- // ...nowFormData,
- // content: input.value
- // }))
- editComment(comment);
- setIsClickEdit(false);
+ const handleDeleteComment = () => {
+ console.log("comment.id: ", comment.id);
+ deleteComment(comment.id);
};
- // useEffect(()=>{
- // if(handleCommentDelete){
-
- // }
- // })
+ useEffect(() => {
+ // access_token이 있으면 유저 정보 가져옴
+ if (getCookie("access_token")) {
+ const getUserAPI = async () => {
+ const user = await getUser();
+ setUser(user);
+ };
+ getUserAPI();
+ }
+ }, []);
return (
-
-
- {isClickEdit ? (
-
-
-
-
- {year}.{month}.{day}
-
-
-
-
-
-
+
+
+ {isEdit ? (
+
setContent(e.target.value)}
+ />
) : (
-
-
-
{comment.content}
-
- {year}.{month}.{day}
-
-
-
-
-
-
-
+
{comment.content}
)}
+
+ {year}.{month}.{day}
+
-
// 1
- //
- //
- //
{comment.content}
- //
- // {year}.{month}.{day}
- //
- //
- //
- //
- //
- //
- // )};
+ {user?.data.id === comment.author.id ? (
+
+ {isEdit ? (
+ <>
+
+
+ >
+ ) : (
+ <>
+
+
+ >
+ )}
+
+ ) : null}
+
);
};
-
export default CommentElement;
diff --git a/src/components/Comments/index.jsx b/src/components/Comments/index.jsx
index aca7515..68cc298 100644
--- a/src/components/Comments/index.jsx
+++ b/src/components/Comments/index.jsx
@@ -2,108 +2,98 @@ import { createElement, useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import comment from "../../data/comment";
import CommentElement from "./CommentElement";
+import { getComments } from "../../apis/api";
+import { createComment } from "../../apis/api";
-const Comment = ({ commentt }) => {
- // TODO 1: 가짜 comments 불러와서 관리해야겟즤
- const { postId } = useParams();
-
- const [comments, setComments] = useState();
+const Comment = ({ postId }) => {
+ // TODO 1: 가짜 comments 불러와서 관리해야겟즤
+ // const { postId } = useParams();
+ const [commentList, setCommentList] = useState([]); // 처음에는 빈 리스트로 설정
+ const [newContent, setNewContent] = useState("");
+
+ //추가
useEffect(() => {
- const comments = comment.filter((comment)=> comment.post == postId);
- setComments(comments);
- }, [postId]);
+ const getCommentsAPI = async () => {
+ const comments = await getComments(postId);
+ setCommentList(comments);
+ };
+ getCommentsAPI();
+ }, [postId]);
+;
- // TODO 2: comment추가하는 input 관리해줘야겟지
- const [isSubmitted, setIsSubmitted] = useState(false);
- const [commentInputValue, setCommentInputValue] = useState("");
-
- useEffect(() =>{
- const commentInputValue = formData.content;
- setCommentInputValue(commentInputValue);
- // commentelement로 만들어줘야겠지? -> 이게 아닌가벼?
- // 그럼 이걸 그냥 밑에 올리는. 그런...
- },[commentInputValue]);
+ // TODO 2: comment추가하는 input 관리해줘야겟지
+ const [isSubmitted, setIsSubmitted] = useState(false);
+ const [commentInputValue, setCommentInputValue] = useState("");
+
+ useEffect(() => {
+ const commentInputValue = formData.content;
+ setCommentInputValue(commentInputValue);
+ }, [commentInputValue]);
- // TODO 3: comment Form 제출됐을때 실행되는 함수 만들어줘
+ // TODO 3: comment Form 제출됐을때 실행되는 함수 만들어줘
- const time = new Date();
- const [created_at, setCreated_at] = useState(time.toJSON());
- // ✅ submit 될 때의 시간을 넣고 싶은데 어떻게 하지??!?
+ const time = new Date();
+ const [created_at, setCreated_at] = useState(time.toJSON());
- const [formData, setFormData] = useState({
- id: comment.length + 1, // 이건 data/comment에 접근을 못해서 제대로 된 index가 나올 수 없을 듯...
- content: "",
- created_at: created_at,
- post: postId, // 사실 여기에는 postId가 들어가는 명세로 되어있어요
- author: {id: 2, username: "user2"}
- });
+ const [formData, setFormData] = useState({
+ id: comment.length + 1, // 이건 data/comment에 접근을 못해서 제대로 된 index가 나올 수 없을 듯...
+ content: "",
+ created_at: created_at,
+ post: postId, // 사실 여기에는 postId가 들어가는 명세로 되어있어요
+ author: { id: 2, username: "user2" },
+ });
- const handleFormData = (e) => {
+ const handleFormData = (e) => {
const { id, value } = e.target;
setFormData({ ...formData, [id]: value });
- console.log(formData);
+ console.log(formData);
};
- const handleCommentSubmit = (e) => {
- e.preventDefault();
- comments.push(formData);
- console.log(formData.content);
- setFormData((nowFormData) => ({
- ...nowFormData,
- content: ""
- }))
- // console.log("input", commentInputValue);
- console.log(comments);
- // alert(`"${formData.content}" 댓글이 작성 완료되었습니다잉`);
- // comments.push(formData);
+ const handleCommentSubmit = (e) => {
+ e.preventDefault();
+ createComment({ post: postId, content: newContent });
+ setNewContent("");
};
-// TODO 4: commet Delete 하는 함수 만들어죠
- const deleteComment = (comment) => {
- console.log(comment.content);
- const deletedComments = comments.filter((c) => c.content !== comment.content)
- setComments(deletedComments);
- console.log(deletedComments);
- };
+ // TODO 4: commet Delete 하는 함수 만들어죠
+ // const handleCommentDelete = () => {
+ // // deleteComment(comment.id);
+ // console.log("delete");
+ // };
- const editComment = (comment) => {
- // console.log("comment:", comment);
- // console.log("comment.id:", comment.id);
- // console.log("감히 제가.. comments에 접근해봅니다", comments[comment.id-1]);
- console.log(comment.value);
- const editedComment = comments[comment.id-1].content = comment.value;
- // console.log(editedComment);
- };
-
- return (
-
+ return (
+
Comments
- {/* // commentElement */}
- {/* //
가 comment마다 반복시켜야즤 */}
-
- {comments && comments.map((comment)=> (
-
- ))}
-
-
- );
+
+
+ );
};
-export default Comment;
\ No newline at end of file
+export default Comment;
diff --git a/src/components/Form/index.jsx b/src/components/Form/index.jsx
index 9743d2c..a6b485d 100644
--- a/src/components/Form/index.jsx
+++ b/src/components/Form/index.jsx
@@ -181,6 +181,7 @@ export const PostForm = ({ onSubmit, tags, formData, setFormData }) => {
tags: formData.tags.filter((t) => t !== tag),
});
};
+
return (
);
};
diff --git a/src/components/Posts/index.jsx b/src/components/Posts/index.jsx
index f8449b6..a0fccfa 100644
--- a/src/components/Posts/index.jsx
+++ b/src/components/Posts/index.jsx
@@ -1,9 +1,11 @@
import { Link } from "react-router-dom";
+import { likePost } from "../../apis/api";
export const SmallPost = ({ post }) => {
const onClickLike = () => {
console.log("나도 좋아!");
// add api call for liking post here
+ likePost(post.id);
};
return (
@@ -32,13 +34,14 @@ export const SmallPost = ({ post }) => {
export const BigPost = ({ post }) => {
const onClickLike = () => {
console.log("나도 좋아!");
+ likePost(post.id);
// add api call for liking post here
};
return (
-
{post.title}
+
{post.title}
{post.author.username}
{post.content}
@@ -55,4 +58,4 @@ export const BigPost = ({ post }) => {
);
-};
\ No newline at end of file
+};
diff --git a/src/index.css b/src/index.css
index 5b2de4d..bffa0ef 100644
--- a/src/index.css
+++ b/src/index.css
@@ -25,6 +25,14 @@
@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;
}
+.infoinput {
+ @apply w-4/5 px-6 py-3 bg-transparent focus:outline-none;
+}
+
+.infobutton {
+ @apply border-none p-2 border-r-4 font-semibold rounded-xl h-10 bg-[#FAC454] hover:bg-orange-400 hover:text-gray-900 text-gray-100;
+ /* transition duration-150 ease-out hover:ease-in */
+}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
diff --git a/src/routes/HomePage.jsx b/src/routes/HomePage.jsx
index aa78d04..0896e1c 100644
--- a/src/routes/HomePage.jsx
+++ b/src/routes/HomePage.jsx
@@ -2,12 +2,34 @@ import { useEffect, useState } from "react";
import { SmallPost } from "../components/Posts";
import posts from "../data/posts";
import { Link } from "react-router-dom";
+import { getPosts, getUser } from "../apis/api";
+import { getTags } from "../apis/api";
+import { getCookie } from "../utils/cookie";
const HomePage = () => {
const [tags, setTags] = useState([]);
const [searchTags, setSearchTags] = useState([]);
const [searchValue, setSearchValue] = useState("");
- const [postList, setPostList] = useState(posts);
+ const [postList, setPostList] = useState([]);
+
+ useEffect(() => {
+ const getPostsAPI = async () => {
+ const posts = await getPosts();
+ setPostList(posts);
+ };
+ getPostsAPI();
+
+ const getTagsAPI = async () => {
+ const tags = await getTags();
+ const tagContents = tags.map((tag) => {
+ return tag.content;
+ });
+ setTags(tagContents);
+ setSearchTags(tagContents);
+ };
+ getTagsAPI();
+ }, []);
+
useEffect(() => {
const tagList = posts.reduce((acc, post) => {
@@ -27,25 +49,13 @@ const HomePage = () => {
};
const handleTagFilter = (e) => {
- const tagText = e.target.innerText;
- console.log(tagText);
- const filteredTagText = tagText.replace("#", "");
- console.log(filteredTagText);
- setSearchValue(filteredTagText);
-
- if (filteredTagText === searchValue) {
- console.log("다시");
+ const { innerText } = e.target;
+ if (searchValue === innerText.substring(1)) {
setSearchValue("");
- setPostList(posts);
- return;
+ } else {
+ const activeTag = innerText.substring(1);
+ setSearchValue(activeTag);
}
-
- console.log("postList", postList);
- console.log("posts", posts);
- const filteredPosts = posts.filter((post) =>
- post.tags.some((tag) => tag.content === filteredTagText)
- );
- setPostList(filteredPosts);
};
return (
@@ -76,15 +86,23 @@ const HomePage = () => {
- {postList.map((post) => (
-
- ))}
-
-
-
- Post
-
+ {postList
+ .filter((post) =>
+ searchValue
+ ? post.tags.find((tag) => tag.content === searchValue)
+ : post
+ )
+ .map((post) => (
+
+ ))}
+ {getCookie("access_token") ? (
+
+
+ Post
+
+
+ ) : null}
);
};
diff --git a/src/routes/MyInfoPage.jsx b/src/routes/MyInfoPage.jsx
new file mode 100644
index 0000000..227eead
--- /dev/null
+++ b/src/routes/MyInfoPage.jsx
@@ -0,0 +1,275 @@
+import { useState, useEffect } from "react";
+import { SmallPost } from "../components/Posts";
+import { getUserProfile } from "../apis/api";
+import { updateUserProfile } from "../apis/api";
+import { getPosts } from "../apis/api";
+import { useParams } from "react-router-dom";
+
+const MyInfo = () => {
+ const [formData, setFormData] = useState({
+ email: "",
+ username: "",
+ college: "",
+ major: "",
+ });
+
+ const [postList, setPostList] = useState([]);
+ const [id, setId] = useState();
+
+ useEffect(() => {
+ const getPostsAPI = async () => {
+ const posts = await getPosts();
+ setPostList(posts);
+ };
+ getPostsAPI();
+ }, []);
+
+ console.log("postlist", postList);
+
+ useEffect(() => {
+ const getUserAPI = async () => {
+ const info = await getUserProfile();
+ console.log("info", info);
+ setId(info.data.user.id);
+ setFormData({
+ email: info.data.user.email,
+ username: info.data.user.username,
+ college: info.data.college,
+ major: info.data.major,
+ });
+ };
+ getUserAPI();
+ }, []);
+
+ const [tempFormData, setTempFormData] = useState({
+ email: "",
+ username: "",
+ college: "",
+ major: "",
+ });
+
+ useEffect(() => {
+ setTempFormData({ ...formData });
+ console.log("tempdata", tempFormData);
+ }, [formData]);
+
+ const [isChange, setIsChange] = useState({
+ email: false,
+ username: false,
+ college: false,
+ major: false,
+ });
+
+ const onSubmit = (e) => {
+ e.preventDefault();
+ setFormData({ ...tempFormData });
+ updateUserProfile();
+ setIsChange(false);
+ };
+
+ const handleFormData = (e) => {
+ const { id, value } = e.target;
+ setTempFormData({ ...tempFormData, [id]: value });
+ };
+
+ const onClickChange = (e) => {
+ e.preventDefault();
+ const { id, value } = e.target;
+ setIsChange((info) => ({ ...info, [id]: true }));
+ };
+
+ const onClickCancle = (e) => {
+ e.preventDefault();
+ const { id } = e.target;
+ setTempFormData({ ...formData });
+ setIsChange((info) => ({ ...info, [id]: false }));
+ };
+
+ const [user, setUser] = useState();
+
+ return (
+
+
My Page
+
+
+
+
+
+ {isChange.email ? (
+ <>
+
+
+
+ >
+ ) : (
+ <>
+
{formData.email}
+
+ >
+ )}
+
+
+
+
+
+
+ {isChange.username ? (
+ <>
+
+
+
+ >
+ ) : (
+ <>
+
{formData.username}
+
+ >
+ )}
+
+
+
+
+
+
+ {isChange.college ? (
+ <>
+
+
+
+ >
+ ) : (
+ <>
+
{formData.college}
+
+ >
+ )}
+
+
+
+
+
+
+
+
+ {isChange.major ? (
+ <>
+
+
+
+ >
+ ) : (
+ <>
+
{formData.major}
+
+ >
+ )}
+
+
+
+
+
+
My Post
+
+ {postList
+ .filter((post) => post.author.id == id)
+ .map((post) => (
+
+ ))}
+
+
+ );
+};
+
+export default MyInfo;
diff --git a/src/routes/PostCreatePage.jsx b/src/routes/PostCreatePage.jsx
index b92e1f9..52e05bd 100644
--- a/src/routes/PostCreatePage.jsx
+++ b/src/routes/PostCreatePage.jsx
@@ -1,66 +1,46 @@
import { useEffect, useState } from "react";
-import { BigPost } from "../components/Posts";
-import posts from "../data/posts";
import { PostForm } from "../components/Form";
+import { useNavigate } from "react-router-dom";
+import { createPost, getTags } from "../apis/api";
const PostCreatePage = () => {
- const [isSubmitted, setIsSubmitted] = useState(false);
const [formData, setFormData] = useState({
- id: posts.length,
title: "",
content: "",
- author: { id: posts.length, username: "와기" },
tags: [],
});
const [tags, setTags] = useState([]);
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 getTagsAPI = async () => {
+ const tags = await getTags();
+ const tagContents = tags.map((tag) => {
+ return tag.content;
+ });
+ setTags(tagContents);
+ };
+ getTagsAPI();
}, []);
+ const navigate = useNavigate();
+
const onSubmit = (e) => {
- //TODO : api connect
e.preventDefault();
- const createdPost = {
- ...formData,
- like_users: [],
- tags: formData.tags.map((tag, idx) => {
- return { id: idx + 1, content: tag };
- }),
- };
- setFormData(createdPost);
- setIsSubmitted(true);
+ createPost(formData, navigate);
+ window.location.href="/";
};
return (
- <>
- {isSubmitted ? (
-
-
-
- ) : (
-
- )}
- >
+
);
};
-export default PostCreatePage;
+export default PostCreatePage;
\ No newline at end of file
diff --git a/src/routes/PostDetailPage.jsx b/src/routes/PostDetailPage.jsx
index 5813914..f170352 100644
--- a/src/routes/PostDetailPage.jsx
+++ b/src/routes/PostDetailPage.jsx
@@ -1,50 +1,71 @@
import { useEffect, useState } from "react";
-import { useParams } from "react-router-dom";
+import { useNavigate, useParams } from "react-router-dom";
+import Comment from "../components/Comments";
import { BigPost } from "../components/Posts";
-import Comment from "../components/Comments"
import { Link } from "react-router-dom";
-import posts from "../data/posts";
-import comments from "../data/comment";
+import { deletePost, getPost, getUser } from "../apis/api";
+import { getCookie } from "../utils/cookie";
const PostDetailPage = () => {
-// parameter로 받은 id에 해당하는 post를 찾아서 넣자
-// TODO : api call(get post by id)
const { postId } = useParams();
const [post, setPost] = useState();
+ const [user, setUser] = useState();
+
+ console.log(user);
+
useEffect(() => {
- const post = posts.find((post) => post.id === parseInt(postId));
- setPost(post);
+ const getPostAPI = async () => {
+ const post = await getPost(postId);
+ setPost(post);
+ };
+ getPostAPI();
}, [postId]);
+ useEffect(() => {
+ // access_token이 있으면 유저 정보 가져옴
+ if (getCookie("access_token")) {
+ const getUserAPI = async () => {
+ const user = await getUser();
+ setUser(user);
+ };
+ getUserAPI();
+ }
+ }, []);
-const onClickDelete = () => {
- console.log("delete");
- // add api call for deleting post here
- // add redirect to home page
- };
-const [comment, setComment] = useState();
-useEffect(() => {
- const comment = comments.find((comment) => comment.post === parseInt(postId));
- setComment(comment);
-}, [postId]);
+ const navigate = useNavigate();
+
+ const onClickDelete = () => {
+ deletePost(post.id, navigate);
+ };
return (
post && (
{/* post detail component */}
-
-
-
-
-
-
-
+ {/* comments component */}
+
+
+
+ {user?.data.id === post?.author.id ? (
+ <>
+
+
+
+
+ >
+ ) : null}
+
)
);
};
-export default PostDetailPage;
\ No newline at end of file
+export default PostDetailPage;
diff --git a/src/routes/PostEditPage.jsx b/src/routes/PostEditPage.jsx
index aec8ded..8c214b9 100644
--- a/src/routes/PostEditPage.jsx
+++ b/src/routes/PostEditPage.jsx
@@ -1,74 +1,65 @@
import { useEffect, useState } from "react";
-import { BigPost } from "../components/Posts";
-import posts from "../data/posts";
+import { useNavigate, useParams } from "react-router-dom";
import { PostForm } from "../components/Form";
-import { useParams } from "react-router-dom";
+import posts from "../data/posts";
import { Link } from "react-router-dom";
+import { BigPost } from "../components/Posts";
+import { getPost, getTags, updatePost } from "../apis/api";
const PostEditPage = () => {
- const [isSubmitted, setIsSubmitted] = useState(false);
- const { postId } = useParams();
- const [formData, setFormData] = useState({});
- useEffect(() => {
- const post = posts.find((post) => post.id === parseInt(postId));
- const postFormData = { ...post, tags: post.tags.map((tag) => tag.content) };
- setFormData(postFormData);
- }, [postId]);
+ const { postId } = useParams();
+ const [formData, setFormData] = useState({
+ title: "",
+ content: "",
+ tags: [],
+ });
+ const navigate = useNavigate();
+ 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 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 getTagsAPI = async () => {
+ const tags = await getTags();
+ const tagContents = tags.map((tag) => {
+ return tag.content;
+ });
+ setTags(tagContents);
+ };
+ getTagsAPI();
}, []);
const onSubmit = (e) => {
- //TODO : api connect
e.preventDefault();
- const createdPost = {
- ...formData,
- like_users: [],
- tags: formData.tags.map((tag, idx) => {
- return { id: idx + 1, content: tag };
- }),
- };
- setFormData(createdPost);
- setIsSubmitted(true);
+ updatePost(postId, formData, navigate);
};
return (
- <>
- {isSubmitted ? (
-
-
-
- ) : (
-
-
-
-
-
-
Edit Post
-
-
-
- )}
- >
+
+
+
+
+
+
Edit Post
+
+
+
);
};
-export default PostEditPage;
+export default PostEditPage;
\ No newline at end of file
diff --git a/src/routes/SignInPage.jsx b/src/routes/SignInPage.jsx
index 3cd17c3..9632b35 100644
--- a/src/routes/SignInPage.jsx
+++ b/src/routes/SignInPage.jsx
@@ -1,5 +1,6 @@
import { useState } from "react";
import { SignInForm } from "../components/Form";
+import { signIn } from "../apis/api";
const SignInPage = () => {
const [formData, setFormData] = useState({
@@ -7,10 +8,9 @@ const SignInPage = () => {
password: "",
});
- const handleSignInSubmit = () => {
- console.log(formData);
- alert("로그인 완-료!");
- // add api call for sign in here
+ const handleSignInSubmit = (e) => {
+ e.preventDefault();
+ signIn(formData);
};
return (
diff --git a/src/routes/SignUpPage.jsx b/src/routes/SignUpPage.jsx
index 92b990b..5303e52 100644
--- a/src/routes/SignUpPage.jsx
+++ b/src/routes/SignUpPage.jsx
@@ -1,5 +1,8 @@
import { useState } from "react";
import { SignUpForm } from "../components/Form";
+import axios from "axios";
+import { getCookie } from "../utils/cookie";
+import { signUp } from "../apis/api";
const SignUpPage = () => {
const [formData, setFormData] = useState({
@@ -11,20 +14,20 @@ const SignUpPage = () => {
major: "",
});
- const handleSignUpSubmit = () => { // API 호출하는 함수
- console.log(formData);
- alert(`${formData.email}로 회원가입 해 줘`);
- // add api call for sign up here
+ const handleSignUpSubmit = async (e) => {
+ // API 호출하는 함수
+ e.preventDefault(); // form 보낼 때 새로고침 안 되도록 해주세용
+ signUp(formData);
};
return (
Sign Up
-
+
);
};
diff --git a/src/utils/cookie.js b/src/utils/cookie.js
new file mode 100644
index 0000000..9be8dea
--- /dev/null
+++ b/src/utils/cookie.js
@@ -0,0 +1,22 @@
+// src/utils/cookie.js
+
+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) => {
+ const cookieValue = cookies.get(name);
+ return cookies.get(name);
+};
+
+// 쿠키 정보 삭제하는 함수
+export const removeCookie = (name) => {
+ cookies.remove(name);
+};