Skip to content

Commit

Permalink
[Feat] #9 - 등록 컴포넌트 제작
Browse files Browse the repository at this point in the history
사용자가 입력한 아파트를 등록 버튼을 누르게되면, 등록 폼 아래에 최신순으로 닉네임, 아파트 이름으로 이루어진 게시물이 보이도록하였습니다.
사용자의 닉네임은 아기사자+랜덤숫자"로 보이도록 하였습니다.
  • Loading branch information
hyeseon-cpu committed May 30, 2024
1 parent d24f6e8 commit 4fec2cf
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 54 deletions.
1 change: 0 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ function App() {
<p id='sortBy_latest'>최신순</p>
</div>
</div>
<PostForm/>
<div id='mid'>
<PostList/>
{/* 나중에 Post에 map()을 사용해서 등록을 한 만큼 게시물이 보이도록 할 예정 */}
Expand Down
2 changes: 1 addition & 1 deletion src/Post.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
71 changes: 38 additions & 33 deletions src/Post.jsx
Original file line number Diff line number Diff line change
@@ -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]); //댓글을 배열에 차곡차곡 저장
Expand All @@ -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);
};
Expand Down Expand Up @@ -77,24 +82,24 @@ const onChangeInput=(e)=>{ //타자를 치면 변하는
className="icon" // 인라인 스타일 대신 className 사용
/>
{/* 현재 댓글 숫자를 표시 */}
<p id='countComment'>{comment.length}</p>
</div>
{commentSelected &&
<>
<p id='countComment'>{commentText.length}</p>
</div>
{commentSelected &&
<>
<div id='input_comment_div'>
<input ref={inputCommentRef} value={InputValue} onChange={onChangeInput} type='text' placeholder='댓글을 입력하세요.' id='input_comment'></input>
<button onClick={onClickCommentAdd} >댓글 추가</button>
<input ref={inputCommentRef} value={InputValue} onChange={onChangeInput} type='text' placeholder='댓글을 입력하세요.' id='input_comment'/>
<button onClick={onClickCommentAdd} >댓글 추가</button>
</div>
<div id='comment_list'>
{comment.map((v,i)=><p><b>익명{i+1} </b>{v}</p>)}
{comment.map((comment, i) => <p key={i} ><b>익명{i + 1} </b>{comment}</p>)}
</div>
</>

}
</div>
</>

}
</div>

</div>

);
}

export default Post;
export default Post;
71 changes: 65 additions & 6 deletions src/PostForm.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<div id="postForm">
<form onSubmit={handleSubmit}>
<form onSubmit={handleSubmit}> {/* handleSubmit 함수 호출 */}
<input
id="apt_name"
type="text"
placeholder="당신이 살고 있는 쌈@@뽕한 아파트의 이름은 무엇인가요?"
value={aptName}
onChange={(e) => setAptName(e.target.value)} //input에 입력한 정보로 변수값을 바꿔주기 위해서는 e.target.value 를 인자로 넘겨야한다!
list="apartment-names"
/>
<datalist id="apartment-names">
{apartmentSearchResult.map((apt) => (
<option key={apt.id} value={apt.name} />
))}
</datalist>
<div id="password_div">
<p>등록 삭제시 필요합니다.</p>
<input
Expand All @@ -33,6 +89,9 @@ function PostForm() {
required //비밀번호를 입력하지 않으면, 폼이 제출되지 않고 입력하라는 경고란이 뜬다!
/>
<input id="submit" type="submit" value="등록" />
{/* 입력된 비밀번호, 아파트 이름들은 등록버튼을 눌렀을 때, 바로 아래에 렌더링되며, 최신순이 가장 위에 위치하도록 해야합니다.
이는 PostList에 구현되어있습니다. */}

</div>
</form>
</div>
Expand Down
12 changes: 12 additions & 0 deletions src/PostList.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,15 @@
height: 100%;
}

.fixed-form-container {
position: sticky;
top: 0;
background-color: #000; /* 백그라운드 컬러를 조정하여 등록 폼을 구분되게 만듦 *
/* z-index: 1000; */
}


/* .posts-container {
margin-top: 100px; 등록 폼의 높이에 맞게 여백을 추가
}
*/
66 changes: 53 additions & 13 deletions src/PostList.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<div id='PostList_div'>
{postData.map((v,i)=>
<Post
nickname={v.nickname}
aptname={v.aptname}
heart={v.heart}
comment={v.comment}
/>)}
</div>

)
<div id='PostList_div'>
<div className="fixed-form-container">
<PostForm registerPost={registerPost} />
{/* // PostForm 컴포넌트에 registerPost 함수 전달 */}
</div>
<div className="posts-container">
{posts.map((post) =>
<Post
key={post.id} // React에서 리스트 항목을 고유하게 식별하기 위해 사용 --> 게시글의 댓글, 공감이 독립적으로 관리되도록한다.
id={post.id} // 컴포넌트에 post의 ID 값을 전달하여 게시물을 식별하고 관련 데이터를 처리
nickname={post.nickname} //닉네임을 전달
aptname={post.aptname} //이피트 이름을 전달
heart={post.heart} //공감 수를 전달
comment={post.comment} // 초기 댓글 리스트 전달
/>
)}
</div>
</div>
);
}

export default PostList

0 comments on commit 4fec2cf

Please sign in to comment.