화면
배경
유저들이 룸메이트를 찾기 위해 신청을 할 수 있는 게시글을 읽을 수 있고, 작성, 수정, 삭제를 할 수 있습니다. 원하는 게시글에 룸메이트 신청을 하고, 신청 받은 사람은 승인
구현한 기능
•
BE
게시글(CRUD)
방갑고 서비스에서 사용자는 모집 상태의 글을 5개까지 작성할 수 있기 때문에 게시글 작성시 countByUserAndIsDeletedFalseAndIsRecruitingTrue(user) 로 모집 상태 글 개수를 검증했습니다. 게시글 삭제는 Soft Delete 방식을 사용했기 때문에 작성한 글 개수를 가져올 때 isDeleted 값이 False인 조건도 추가했습니다.
게시글 최신순으로 조회하는 기능은 모집 중인 글만 불러오기, 마감된 글까지 전체 글 가져오기를 isRecruiting 값을 받아서 원하는 요청에 따른 응답을 보내도록 했습니다. 또한 페이지에 대한 정보도 받아서 페이징 처리를 했습니다. 각 게시글 정보에 작성자의 이메일 정보를 함께 보내서 프론트엔드에서 자신이 작성한 게시글인지 확인할 수 있도록 했습니다.
게시글 찜하기, 찜 해제
게시글 Id, 요청을 보내는 사용자 정보를 받습니다. 찜하기 DB는 삭제시 Hard Delete를 사용해서 찜하기 요청을 받았을 때 사용자가 해당 글에 찜한 내역이 있으면 삭제시키고, 없으면 추가하는 방식으로 기능을 구현했습니다.
1:1 룸메이트 매칭(CRUD)
방갑고 서비스에서 신청 목록을 통해 작성자는 게시글의 룸메이트를 대기 상태에서 승인, 거절로 변경할수 있고 승인, 거절상태에서 더이상 안보이게끔 삭제할수 있습니다. 이과정에서 hard delete를 사용하게되면 상대편의 룸메이트 또한 본인이 삭제되지 않았음에도 불구하고 삭제하게 됩니다. 따라서 soft delete를 통해 각각 작성자, 신청자가 삭제여부를 등록하여 삭제 과정의 문제가 없도록 하였습니다.
신청자 목록을 불러오는 과정은 가장 최근에 신청 상태(승인, 거절, 대기)가 변경된 신청목록이 가장 먼저 나오게 설정하기 위해 JPA Auditing 으로 구현된 modifiedDateTime을 기준으로 정렬하였습니다.
단 삭제가 soft delete로 구현된이상 한쪽에서 삭제하면 jpa auditing 으로 인해 신청 상태가 변경되지 않았음에도 modifiedDateTime이 변경되는 문제가 있습니다. 이부분은 Query dsl의 벌크연산은 jpa auditing의 이벤트가 실행되지 않는다는 점을 이용하여 문제를 해결하였습니다.
•
FE
게시글 생성
유저가 작성한 글을 백엔드에 POST를 하는 방식으로 api 명세서에 body에 적힌 값을 보내지 않으면 오류처리가 되게 하였습니다.
{
“title” : “글 제목”,
“region” : “지역”,
“period” : 기간,
“price” : 1000,
“gender” : “남성”,
“content” : “추가 소개글”
}
여기서 gender는 프로필에 입력된 값을 보내게 하였고, 만약 프로필을 입력하지 않았다면 게시글을 작성하지 못하게 하였습니다.
const goToWritePage = () => {
if (isLogged === true) {
if (profileData?.gender !== "null") {
navigate("/WritePage")
} else {
messageApi.info("내 정보를 입력 후 사용해주세요.")
}
} else {
messageApi.error("로그인이 필요합니다.")
}
}
TypeScript
복사
게시글 Modal
게시글이 생성되면 게시글이 postcard로 나오게 되고 그 게시글을 클릭하게 되면 modal창이 열려 게시글을 상세하게 읽을 수 있습니다.
메인페이지에 게시글 정보를 Fetch 하여 그 값들을 각각 postcard 컴포먼트와 postmodal 컴포먼트에 보내게 하여 이중으로 Fetch문을 작성하지 않게 하였습니다.
또한 본인이 작성한 글은 찜하기 버튼, 신청하기 버튼이 없는 대신 수정, 삭제 버튼이 추가로 보이게 하였습니다. 구분하는 방법은 고유한 값은 email을 이용하여 백엔드에서 게시글에 보내준 email 값과 Local Stroage에 있는 email값을 비교하여 일치한다면 수정, 삭제 버튼을 추가로 보이게 하였습니다.
const userEmail = useSelector((state: RootState) => state.user.email)
{userEmail === post.email ? (
<div className={styles.buttonContainer}>
<Button className={styles.editButton} onClick={handleEditClick}>
수정
</Button>
<Button
className={styles.deleteButton}
onClick={handleDeleteClick}
>
삭제
</Button>
</div>
) : (
<button
className={applySave}
style={{ float: "right" }}
onClick={handleApplyClick}
>
신청하기
</button>
)}
TypeScript
복사
게시글 수정
기존 게시물에 있던 내용들을 react-router-dom에 있는 useLocation을 사용하여 post값을 가져왔다. method PUT으로 백엔드에 보냅니다.
const location = useLocation()
const editPost = location.state.post
useEffect(() => {
if (editPost) {
form.setFieldsValue({
title: editPost.title,
content: editPost.content,
region: editPost.region,
period: editPost.period,
price: editPost.price,
gender: editPost.gender,
})
setUserContent(editPost.content)
}
}, [editPost])
TypeScript
복사
게시물 삭제
모달에 삭제버튼을 누르면 ‘게시글이 삭제하겠습니다’ 라는 문구와 함께 ‘네’ 버튼을 누르면 게시글이 삭제가 된다. method delete로 백엔드에 보냅니다.
삭제가 되는 동시에 새로고침이 되면서 게시글이 삭제가 된 것이 보이게 만들었습니다.
게시글 찜하기, 찜 해제
Redux toolkit을 사용하여 찜하기 상태 관리를 수행하기 위한 action과 reducer를 정의하였습니다.
게시글의 id 값을 key로 하여 해당 값이 찜한 상태인지 여부 확인
사용자가 특정 게시글에 대해 찜 또는 찜 해제를 할 경우
상태값 toggle 후, 서버에 반영
성공적으로 반영 될 경우, 서버로부터 사용자가 찜한 게시글의 목록을 가져오도록 비동기 작업 처리
1:1 룸메이트 매칭(CRUD)
1:1 매칭 기능을 위해 Redux toolkit을 활용하여 다양한 action과 reducer를 정의하였습니다.
게시글의 신청, 취소, 승인, 거절, 삭제와 관련된 상태를 관리합니다.
게시글의 id를 key로 하여 redux 상태에 저장
action을 통해 업데이트
비동기적으로 서버로부터 신청 관련 정보를 가져와 상태를 갱신하며, 페이징 처리를 위해 전체 데이터와 함께 저장
신청, 취소, 승인, 거절, 삭제와 같은 작업을 수행하는 각각의 API 요청을 서버에 보내고 결과 반영
해당 action 각각의 비동기 작업을 통해 처리
해당 결과를 Redux 상태에 저장
즉, 사용자가 특정 게시글에 대한 신청, 취소, 승인, 거절, 삭제를 할 때마다 해당 상태를 업데이트하고, 이를 서버에 반영하도록 비동기 작업을 처리합니다. 성공적으로 반영된 후에는 백엔드 서버로부터 신청 정보를 가져와 상태를 갱신합니다.