From 4fec2cfe0ebf5b7fb66309d4f0c413a1af864405 Mon Sep 17 00:00:00 2001 From: hyeseonchoi Date: Thu, 30 May 2024 18:02:53 +0900 Subject: [PATCH] =?UTF-8?q?[Feat]=20#9=20-=20=EB=93=B1=EB=A1=9D=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=A0=9C=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 사용자가 입력한 아파트를 등록 버튼을 누르게되면, 등록 폼 아래에 최신순으로 닉네임, 아파트 이름으로 이루어진 게시물이 보이도록하였습니다. 사용자의 닉네임은 아기사자+랜덤숫자"로 보이도록 하였습니다. --- src/App.jsx | 1 - src/Post.css | 2 +- src/Post.jsx | 71 ++++++++++++++++++++++++++---------------------- src/PostForm.jsx | 71 ++++++++++++++++++++++++++++++++++++++++++++---- src/PostList.css | 12 ++++++++ src/PostList.jsx | 66 +++++++++++++++++++++++++++++++++++--------- 6 files changed, 169 insertions(+), 54 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 99af48c..f5e43e7 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -14,7 +14,6 @@ function App() {

최신순

-
{/* 나중에 Post에 map()을 사용해서 등록을 한 만큼 게시물이 보이도록 할 예정 */} diff --git a/src/Post.css b/src/Post.css index a2ea9cb..5e5740c 100644 --- a/src/Post.css +++ b/src/Post.css @@ -84,7 +84,7 @@ width: 5px; background-color: black; } -#comment_list::-webkit-scrollbar-thumb{ + #comment_list::-webkit-scrollbar-thumb{ background-color: white; border-radius: 20px; } diff --git a/src/Post.jsx b/src/Post.jsx index 6eb848c..4cfd0f4 100644 --- a/src/Post.jsx +++ b/src/Post.jsx @@ -1,26 +1,32 @@ -import React, { useState,useRef } from "react"; +import React, { useState, useRef } from "react"; import "./Post.css"; import chatIcon from "./assets/chat.svg"; // chat.svg 파일을 import import heartIcon from "./assets/heart.svg"; // heart.svg 파일을 import import fillHeartIcon from "./assets/fillHeart.svg"; // fillHeart.svg 파일을 import -import postData from "./JSON/post.json"; +// import postData from "./JSON/post.json"; -function Post({nickname,aptname,heart,comment}) { //postList 컴포넌트에서 json props를 받아온다. +/** + * 좋아요 수 댓글 수를 관리합니다. + */ + +function Post({ nickname, aptname, heart, comment }) { //postList 컴포넌트에서 json props를 받아온다. // isHeartClicked 상태 변수와 setIsHeartClicked 함수: 하트 아이콘 클릭 여부를 관리 const [isHeartClicked, setIsHeartClicked] = useState(false); - // heart 상태 변수와 setHeart 함수: 하트 숫자를 관리 - const [heartNum,setHeartNum]=useState(0); //좋아요 수 개수 - + // heart 상태 변수와 setHeart 함수: 하트 숫자를 관리 + const [heartNum, setHeartNum] = useState(heart); //좋아요 수 개수 +//처음 렌더링될 때 해당 게시글의 현재 좋아요 개수를 보여주기 위해 0에서 heart로 변경 const [commentSelected, setCommentSelected] = useState(false); //댓글 이모티콘이 선택 됐는지 아닌지 + const [InputValue, setInputValue] = useState(""); + const inputCommentRef = useRef(null); + const [commentText, setCommentText] = useState(comment); + - const [InputValue, setInputValue] = useState(""); //댓글 작성 부분 input - const inputCommentRef = useRef(null) // 댓글 입력칸 초기 값 null로 설정 - const [commentText, setCommentText] = useState(postData.commentText || []); const toggleCommentSelected = () => { //댓글 버튼 선택 boolean을 바꿔주는 메소드 setCommentSelected(!commentSelected); + console.log(commentSelected); }; - + const onClickCommentAdd = () => { const newComment = inputCommentRef.current.value; //인풋칸에 새로 넣은 값 setCommentText([...commentText, newComment]); //댓글을 배열에 차곡차곡 저장 @@ -29,25 +35,24 @@ function Post({nickname,aptname,heart,comment}) { //postList 컴포넌트에 setInputValue(""); // 상태 초기화 }; -const onChangeInput=(e)=>{ //타자를 치면 변하는 값을 저장 - setInputValue(()=>e.target.value); -} - + const onChangeInput = (e) => { //타자를 치면 변하는 값을 저장 + setInputValue(() => e.target.value); + } // 하트 아이콘을 클릭했을 때 호출되는 함수 const toggleHeart = () => { - + // 하트가 이미 클릭된 상태라면 if (isHeartClicked) { // 하트 숫자를 1 감소 - setHeartNum(heartNum-1); - heart-=1; + setHeartNum(heartNum - 1); + heart -= 1; } else { // 하트 숫자를 1 증가 - setHeartNum(heartNum+1); - heart+=1; + setHeartNum(heartNum + 1); + heart += 1; } - + // 하트 클릭 상태를 반전시킴 (true -> false, false -> true) setIsHeartClicked(!isHeartClicked); }; @@ -77,24 +82,24 @@ const onChangeInput=(e)=>{ //타자를 치면 변하는 className="icon" // 인라인 스타일 대신 className 사용 /> {/* 현재 댓글 숫자를 표시 */} -

{comment.length}

-
- {commentSelected && - <> +

{commentText.length}

+ + {commentSelected && + <>
- - + +
- {comment.map((v,i)=>

익명{i+1} {v}

)} + {comment.map((comment, i) =>

익명{i + 1} {comment}

)}
- - - } - + + + } - + + ); } -export default Post; +export default Post; \ No newline at end of file diff --git a/src/PostForm.jsx b/src/PostForm.jsx index 23e606d..4ee4710 100644 --- a/src/PostForm.jsx +++ b/src/PostForm.jsx @@ -1,27 +1,83 @@ -import React, { useState } from "react"; +import React, { useState, useEffect} from "react"; import "./PostForm.css"; -function PostForm() { +/** + * 등록 폼을 관리 합니다. (입력 부분) + */ + +function PostForm({registerPost}) { const [aptName, setAptName] = useState(""); //useState를 활용한 상태관리입니다! const [password, setPassword] = useState(""); - + // 아파트 이름 자동완성 결과 상태 관리 + const [apartmentSearchResult, setApartmentSearchResult] = useState([]); + + // 폼 제출 핸들러 함수 + // 폼이 제출될 때 실행되는 함수. + // 데이터 처리, 서버 요청 작업 진행 const handleSubmit = (event) => { + event.preventDefault(); //브라우저마다 이벤트 이름부터 시작해서 이벤트 종류나 이벤트가 처리되는 방식이 달라서 이를 동일하게 처리하도록 하는 게 필요하다고 합니다. - // 폼 제출 로직 추가 예정! + + // 아파트 이름과 비밀번호를 사용하여 게시글 등록 함수 호출 + registerPost(aptName, password); + //폼 제출 후 + setAptName(""); // 입력 필드 초기화 + setPassword(""); // 입력 필드 초기화 + + //아파트 이름과 비밀번호가 잘 찍히나 확인해보기 위해 두었습니다. console.log("아파트 이름:", aptName); - console.log("비밀번호:", password); //아파트 이름과 비밀번호가 잘 찍히나 확인해보기 위해 두었습니다. + console.log("비밀번호:", password); + }; +/** + * 사용자가 아파트 이름을 입력할 때, 백엔드 서버에서 해당 이름과 일치하는 아파트 이름을 + * 자동완성 목록으로 가져와 표시, 그렇게 고른 아파트 이름은 백앤드의 id로 전달됩니다. + * + * 이부분은 아직 미완성된 부분이므로 주석처리 하였습니다. + */ + // useEffect(() => { + // if (aptName) { + // const fetchAptNames = async () => { + // try { + // const response = await fetch( + // encodeURI(`https://apt-api.blbt.app/v1/apartment/name?query=${aptName}`) + // //https://apt-api.blbt.app/v1/apartment/name?query=${aptName} + // ); + // const data = await response.json(); + // setApartmentSearchResult(data.data); // 자동완성 결과 상태 업데이트 + // } + + // catch (error) { + // console.error("Error fetching apartment names:", error); + // } + + // }; + // fetchAptNames(); + // } + + // else { + // setApartmentSearchResult([]); // 입력값이 없으면 결과 초기화 + // } + // }, [aptName]); + + return (
-
+ {/* handleSubmit 함수 호출 */} setAptName(e.target.value)} //input에 입력한 정보로 변수값을 바꿔주기 위해서는 e.target.value 를 인자로 넘겨야한다! + list="apartment-names" /> + + {apartmentSearchResult.map((apt) => ( +

등록 삭제시 필요합니다.

+ {/* 입력된 비밀번호, 아파트 이름들은 등록버튼을 눌렀을 때, 바로 아래에 렌더링되며, 최신순이 가장 위에 위치하도록 해야합니다. + 이는 PostList에 구현되어있습니다. */} +
diff --git a/src/PostList.css b/src/PostList.css index 1704245..60c23e2 100644 --- a/src/PostList.css +++ b/src/PostList.css @@ -3,3 +3,15 @@ height: 100%; } +.fixed-form-container { + position: sticky; + top: 0; + background-color: #000; /* 백그라운드 컬러를 조정하여 등록 폼을 구분되게 만듦 * + /* z-index: 1000; */ +} + + + /* .posts-container { + margin-top: 100px; 등록 폼의 높이에 맞게 여백을 추가 + } + */ \ No newline at end of file diff --git a/src/PostList.jsx b/src/PostList.jsx index 6385fcc..7cf72a8 100644 --- a/src/PostList.jsx +++ b/src/PostList.jsx @@ -1,22 +1,62 @@ import Post from './Post' -import postData from './JSON/post.json' +import PostForm from './PostForm'; import { useState } from 'react'; +import './PostList.css'; +/** + * 게시글 등록 폼, 게시글들을 관리합니다. + */ + +// 게시글 등록 함수 function PostList() { - const [postList,setPostList]=useState([]); + const [posts, setPosts] = useState([]); //게시글 리스트 상태 - 초기값을 빈 배열로 + + /** + * 등록 폼 설정 함수 아파트 이름, 비번을 받으면, + * 이름 생성 함수가 그 폼에대한 닉네임을 만든다. + */ + const registerPost = (aptName, password) => { + const generateUserName = () => { + const randomNumber = Math.floor(Math.random() * 1000); + return `아기사자${randomNumber}`; + }; + + // 새로운 게시글 데이터를 저장하기위한 객체 + // 각 게시물 구분을 위한 고유ID + // 닉네임, 아파트 이름, 공감 수, 댓글들을 관리. + const newPost = { + id: Date.now(),// 고유 ID를 사용하여 각 게시물을 구분 + nickname: generateUserName(), // 랜덤 익명 닉네임 생성 + aptname: aptName, + heart: 0, // 새로운 게시글의 초기 좋아요 개수는 0으로 설정 + comment: [], // 새로운 게시글의 초기 댓글 리스트는 빈 배열로 설정 + }; + setPosts([newPost, ...posts]); + // 새로운 게시글을 이전의 게시글 리스트 앞에 추가하는 상태 업데이트 함수이다. + }; + + // 게시물들을 렌더링 하는 하는 부분이다. return ( -
- {postData.map((v,i)=> - )} -
- - ) +
+
+ + {/* // PostForm 컴포넌트에 registerPost 함수 전달 */} +
+
+ {posts.map((post) => + 게시글의 댓글, 공감이 독립적으로 관리되도록한다. + id={post.id} // 컴포넌트에 post의 ID 값을 전달하여 게시물을 식별하고 관련 데이터를 처리 + nickname={post.nickname} //닉네임을 전달 + aptname={post.aptname} //이피트 이름을 전달 + heart={post.heart} //공감 수를 전달 + comment={post.comment} // 초기 댓글 리스트 전달 + /> + )} +
+
+ ); } export default PostList