diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.gitmessage.txt b/.gitmessage.txt old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/package-lock.json b/package-lock.json old mode 100644 new mode 100755 diff --git a/package.json b/package.json old mode 100644 new mode 100755 diff --git a/public/favicon.ico b/public/favicon.ico old mode 100644 new mode 100755 diff --git a/public/index.html b/public/index.html old mode 100644 new mode 100755 diff --git a/public/logo192.png b/public/logo192.png old mode 100644 new mode 100755 diff --git a/public/logo512.png b/public/logo512.png old mode 100644 new mode 100755 diff --git a/public/manifest.json b/public/manifest.json old mode 100644 new mode 100755 diff --git a/public/robots.txt b/public/robots.txt old mode 100644 new mode 100755 diff --git a/src/App.css b/src/App.css old mode 100644 new mode 100755 diff --git a/src/App.js b/src/App.js old mode 100644 new mode 100755 diff --git a/src/App.test.js b/src/App.test.js old mode 100644 new mode 100755 diff --git a/src/assets/images/lion.jpeg b/src/assets/images/lion.jpeg old mode 100644 new mode 100755 diff --git a/src/assets/images/logo.png b/src/assets/images/logo.png old mode 100644 new mode 100755 diff --git a/src/components/Footer/index.jsx b/src/components/Footer/index.jsx old mode 100644 new mode 100755 diff --git a/src/components/Header/index.jsx b/src/components/Header/index.jsx old mode 100644 new mode 100755 index 99e87e1b..94ff415d --- a/src/components/Header/index.jsx +++ b/src/components/Header/index.jsx @@ -1,8 +1,18 @@ import { Link } from "react-router-dom"; +import { useEffect, useState } from "react"; import lion from "../../assets/images/lion.jpeg"; const Header = () => { + const [isUserLoggedIn, setIsUserLoggedIn] = useState(false); // 로그인 여부 상태, 우선 false로 초기화 + + useEffect(() => { + // TODO: 이후 api 연결 시 유효한 token이 있다면 setIsUserLoggedIn(true)로 상태 변경하는 코드 작성 + }, []); + + const handleSignOut = () => { + // TODO: 이후 api 연결 시 token 제거 + }; return (
@@ -10,12 +20,18 @@ const Header = () => {
SNULION BLOG
- - sign in - - - sign up - + {isUserLoggedIn ? + sign out + : + <> + + sign in + + + sign up + + + }
); diff --git a/src/components/Posts/index.jsx b/src/components/Posts/index.jsx old mode 100644 new mode 100755 index 07686dcc..594053a7 --- a/src/components/Posts/index.jsx +++ b/src/components/Posts/index.jsx @@ -1,6 +1,12 @@ import { Link } from "react-router-dom"; export const SmallPost = ({ post }) => { + const onClickLike = (e) => { + e.preventDefault(); + alert("나도 좋아!"); + // add api call for liking post here + }; + return ( { ))} - + {post.like_users.length > 0 && `❤️ ${post.like_users.length}`} @@ -23,6 +29,11 @@ export const SmallPost = ({ post }) => { }; export const BigPost = ({ post }) => { + const onClickLike = (e) => { + e.preventDefault(); + alert("나도 좋아!"); + // add api call for liking post here + }; return (
@@ -44,7 +55,7 @@ export const BigPost = ({ post }) => { ))}
- + ❤️ {post.like_users.length > 0 ? post.like_users.length : "0"}
diff --git a/src/data/posts.js b/src/data/posts.js old mode 100644 new mode 100755 diff --git a/src/index.css b/src/index.css old mode 100644 new mode 100755 diff --git a/src/index.js b/src/index.js old mode 100644 new mode 100755 diff --git a/src/logo.svg b/src/logo.svg old mode 100644 new mode 100755 diff --git a/src/reportWebVitals.js b/src/reportWebVitals.js old mode 100644 new mode 100755 diff --git a/src/routes/HomePage.jsx b/src/routes/HomePage.jsx old mode 100644 new mode 100755 index 027eae34..43566c34 --- a/src/routes/HomePage.jsx +++ b/src/routes/HomePage.jsx @@ -1,11 +1,46 @@ import { SmallPost } from "../components/Posts"; import { Link } from "react-router-dom"; import posts from "../data/posts"; +import { useEffect, useState } from "react"; const HomePage = () => { - const postList = posts; + const [postList, setPostList] = useState(posts); - const handleChange = (e) => {}; + const [tags, setTags] = useState([]); + const [searchTags, setSearchTags] = useState([]); + const [searchValue, setSearchValue] = useState(""); + + 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) => { + const { innerText } = e.target; + if (searchValue === innerText.substring(1)) { + setSearchValue(""); + setPostList(posts); + } else { + const activeTag = innerText.substring(1); + setSearchValue(activeTag); + const newPosts = posts.filter((post) => + post.tags.find((tag) => tag.content === activeTag) + ); + setPostList(newPosts); + } + }; return (
@@ -20,6 +55,19 @@ const HomePage = () => { className="border border-orange-400 outline-none rounded-2xl text-center py-2 px-20 text-orange-400 bg-transparent" />
+
+ {searchTags.map((tag) => { + return ( + + ); + })} +
{postList.map((post) => ( diff --git a/src/routes/PostCreatePage.jsx b/src/routes/PostCreatePage.jsx old mode 100644 new mode 100755 index a33c7af4..e98b4387 --- a/src/routes/PostCreatePage.jsx +++ b/src/routes/PostCreatePage.jsx @@ -1,7 +1,13 @@ +import { useEffect, useState } from "react"; import posts from "../data/posts"; +import { BigPost } from "../components/Posts"; const PostCreatePage = () => { - const post = { + const [isSubmitted, setIsSubmitted] = useState(false); + const [tags, setTags] = useState([]); + const [tagInputValue, setTagInputValue] = useState(""); + const [autoCompletes, setAutoCompletes] = useState([]); + const [post, setPost] = useState({ id: posts.length, title: "", content: "", @@ -9,14 +15,85 @@ const PostCreatePage = () => { tags: [], like_users: [], created_at: "2024-02-04T07:42:50.658501Z", + }); + + const addTag = (e) => { + e.preventDefault(); + if (post.tags.find((tag) => tag === tagInputValue)) return; + setPost({ + ...post, + tags: [...post.tags, tagInputValue], + }); + setTagInputValue(""); + setAutoCompletes([]); + }; + + const deleteTag = (tag) => { + setPost({ + ...post, + tags: post.tags.filter((t) => t !== tag), + }); + }; + + const handleChange = (e) => { + setPost({ ...post, [e.target.id]: e.target.value }); }; const onSubmit = (e) => { + e.preventDefault(); + const createdPost = { + ...post, + like_users: [], + tags: post.tags.map((tag, idx) => { + return { id: idx + 1, content: tag }; + }), + }; + setPost(createdPost); + setIsSubmitted(true); + alert("게시글을 등록합니다."); //TODO : api connect(create post) }; - return ( + 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 handleAutoCompletes = (autoComplete) => { + const selectedTag = tags.find((tag) => tag === autoComplete); + if (post.tags.includes(selectedTag)) return; // 입력한 내용이 이미 등록된 태그면 그냥 등록 안됨 + setPost({ + ...post, + tags: [...post.tags, selectedTag], + }); + setTagInputValue(""); + setAutoCompletes([]); + }; + + const handleTag = (e) => { + setTagInputValue(e.target.value); + if (e.target.value) { + const autoCompleteData = tags.filter((tag) => + tag.includes(e.target.value) + ); + setAutoCompletes(autoCompleteData); + } else { + setAutoCompletes([]); + } + }; + + return isSubmitted ? ( +
+ +
+ ) : (

게시글 작성

@@ -26,10 +103,11 @@ const PostCreatePage = () => {
+
+ {autoCompletes && + autoCompletes.map((autoComplete) => ( + + ))} +
{post.tags && (
{post.tags.map((tag) => ( @@ -66,7 +163,10 @@ const PostCreatePage = () => {

#{tag}

-
))} @@ -77,6 +177,6 @@ const PostCreatePage = () => { ); -}; + }; export default PostCreatePage; diff --git a/src/routes/PostDetailPage.jsx b/src/routes/PostDetailPage.jsx old mode 100644 new mode 100755 index 079fd151..66721a1a --- a/src/routes/PostDetailPage.jsx +++ b/src/routes/PostDetailPage.jsx @@ -1,5 +1,5 @@ import { useState, useEffect } from "react"; -import { useParams, Link } from "react-router-dom"; +import { useParams, Link, useNavigate } from "react-router-dom"; import { BigPost } from "../components/Posts"; import posts from "../data/posts"; @@ -11,9 +11,11 @@ const PostDetailPage = () => { setPost(post); }, [postId]); + const navigate = useNavigate(); const onClickDelete = () => { - alert("삭제"); - //TODO : api connect(delete post) + alert("게시물을 삭제합니다."); + navigate("/"); + // add api call for deleting post }; return ( diff --git a/src/routes/PostEditPage.jsx b/src/routes/PostEditPage.jsx old mode 100644 new mode 100755 index ff86e811..1df3065b --- a/src/routes/PostEditPage.jsx +++ b/src/routes/PostEditPage.jsx @@ -1,10 +1,23 @@ import { useEffect, useState } from "react"; import { useParams } from "react-router-dom"; import posts from "../data/posts"; +import { BigPost } from "../components/Posts"; const PostEditPage = () => { const { postId } = useParams(); - const [post, setPost] = useState({}); + const [isSubmitted, setIsSubmitted] = useState(false); + const [tagInputValue, setTagInputValue] = useState(""); + const [autoCompletes, setAutoCompletes] = useState([]); + const [tags, setTags] = useState([]); + const [post, setPost] = useState({ + id: posts.length, + title: "", + content: "", + author: { id: posts.length, username: "아기사자" }, + tags: [], + like_users: [], + created_at: "2024-02-04T07:42:50.658501Z", + }); // 기존 게시글 불러오기 useEffect(() => { @@ -13,12 +26,33 @@ const PostEditPage = () => { setPost(originalPost); }, [postId]); + useEffect(() => { + const post = posts.find((post) => post.id === parseInt(postId)); + const originalPost = { ...post, tags: post.tags.map((tag) => tag.content) }; + setPost(originalPost); + }, [postId]); + const onSubmit = (e) => { + e.preventDefault(); + const editedPost = { + ...post, + like_users: [], + tags: post.tags.map((tag, idx) => { + return { id: idx + 1, content: tag }; + }), + }; + setPost(editedPost); + setIsSubmitted(true); alert("게시글을 수정합니다."); // TODO : api connect(edit post) }; - return ( + + return isSubmitted ? ( +
+ +
+ ) : (

게시글 수정

diff --git a/src/routes/SignInPage.jsx b/src/routes/SignInPage.jsx old mode 100644 new mode 100755 index 537272d3..1a17be90 --- a/src/routes/SignInPage.jsx +++ b/src/routes/SignInPage.jsx @@ -1,25 +1,61 @@ +import { useState } from "react"; + const SignInPage = () => { - const handleSignInSubmit = () => { - alert("로그인 하기"); // TODO: add api call for sign in - }; + const [signInData, setSignInData] = useState({ + username: "", + password: "", + }); + + const handleSignInData = (e) => { + const { id, value } = e.target; + setSignInData({ ...signInData, [id]: value }); + }; + + const handleSignInSubmit = (e) => { + e.preventDefault(); // to prevent reloading the page + console.log(signInData); + alert("로그인 하기"); // TODO: add api call for sign in + }; + + return ( +
+

로그인

+ + + + + + - return ( -
-

로그인

- - - - - - - -
- - -
- -
- ); +
+ + +
+ +
+ ); }; export default SignInPage; diff --git a/src/routes/SignUpPage.jsx b/src/routes/SignUpPage.jsx old mode 100644 new mode 100755 index 9b87106b..c0461a96 --- a/src/routes/SignUpPage.jsx +++ b/src/routes/SignUpPage.jsx @@ -1,5 +1,23 @@ +import { useState } from "react"; + const SignUpPage = () => { - const handleSignUpSubmit = () => { + const [signUpData, setSignUpData] = useState({ + email: "", + password: "", + confirm_password: "", + username: "", + college: "", + major: "", + }); + + const handleSignUpData = (e) => { + const { id, value } = e.target; + setSignUpData({ ...signUpData, [id]: value }); + }; + + const handleSignUpSubmit = (e) => { + e.preventDefault(); + console.log("email: ", signUpData.email); alert("회원가입 하기"); // TODO: add api call for sign up }; @@ -10,17 +28,38 @@ const SignUpPage = () => { - + - + - +