Skip to content

Commit

Permalink
[FE] Feat #133: 리뷰 디테일 페이지 버킷 디테일 컴포넌트 이용하여 UI 및 기능 구현
Browse files Browse the repository at this point in the history
Change-Id: Ica5b8fdb1474b33a0e800c561567cc32126241fd
  • Loading branch information
leewooseong committed Feb 14, 2024
1 parent c4ed507 commit 66fde03
Show file tree
Hide file tree
Showing 26 changed files with 993 additions and 80 deletions.
2 changes: 1 addition & 1 deletion frontend/src/hooks/useHasReview.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react'
import { getReviewDetail } from '../pages/Review/WriteReview/api'
import { getReviewDetail } from '../pages/Review/api'

const useHasReview = (reviewId: number | null | undefined) => {
const [hasReview, setHasReview] = useState(false)
Expand Down
7 changes: 4 additions & 3 deletions frontend/src/hooks/useInfiniteCommentList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { useInfiniteQuery } from '@tanstack/react-query'

import { getBucketCommentList } from '../pages/Bucket/BucketDetail/api'
import { ICommentItem } from '../interfaces'
import { getReviewCommentList } from '../pages/Review/api'

const useInfiniteCommentList = (id: string) => {
const useInfiniteCommentList = (id: string, type: 'bucket' | 'review') => {
const { data, isLoading, isError, hasNextPage, fetchNextPage, isFetchingNextPage } =
useInfiniteQuery({
queryKey: ['comments', id],
queryFn: getBucketCommentList,
queryKey: ['comments', id, type],
queryFn: type === 'bucket' ? getBucketCommentList : getReviewCommentList,
initialPageParam: 0,
getNextPageParam: (lastPageInfo) => {
return lastPageInfo.last ? null : lastPageInfo.number + 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const CommentList = ({ isInputFocused, setIsInputShown, id }: ICommentListProps)
const { ref: listRef, inView: listInView } = useInView()

const { commentListData, isLoading, isError, fetchNextPage, isFetchingNextPage } =
useInfiniteCommentList(id)
useInfiniteCommentList(id, 'bucket')

useEffect(() => {
if (lastElementInView) {
Expand Down Expand Up @@ -65,6 +65,11 @@ const CommentList = ({ isInputFocused, setIsInputShown, id }: ICommentListProps)
/>
</li>
))}
{commentListData.length === 0 && (
<p className="w-full py-4 text-base font-bold text-center rounded-lg bg-lightGray">
등록된 댓글이 없습니다.
</p>
)}
</ul>
)}
{isFetchingNextPage && <Skeleton />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const defaultReactionInfo: ReactionCountType = { 멋져요: 0, 응원해요: 0,

const Reaction = ({ id }: IReactionProps) => {
const [activeReaction, setActiveReaction] = useState<ReactionType | null>(null)
const [reactionInfo, setReactionInfo] = useState<ReactionCountType>()
const [reactionInfo, setReactionInfo] = useState<ReactionCountType>(defaultReactionInfo)
const activeColor = 'green' // active된 Reaction의 색상을 변수로 지정해둔 것

// id별로 cachepool을 관리하기 위해선 id가 필요하다.
Expand Down
111 changes: 110 additions & 1 deletion frontend/src/pages/Review/ReviewDetail/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,114 @@
import { useEffect, useState } from 'react'
import { useParams } from 'react-router'
import { useQuery } from '@tanstack/react-query'

import ReviewMoreButton from '../component/ReviewMoreButton'
import WithHeaderLayout from '../../../components/layout/WithHeaderLayout'
import ReviewBucket from '../component/ReviewBucket'
import UserProfile from '../../../components/UserProfile/UserProfile'
import ShareButton from '../component/ShareButton'
import Reaction from '../component/Reaction'
import CommentList from '../component/Comment/CommentList'
import CommentInput from '../component/Comment/CommentInput'
import InterestTag from '../component/InterestTag'

import { useRouter } from '../../../hooks/useRouter'
import { useDetailReviewStore } from '../../../store/detailStore'
import { getReviewDetailQuery } from '../api'
import { isMyUserType } from '../../../utils/typeFilter'

import { IReviewDetail } from '../../../types/bucket'
import { IMenu, IMenuFunc } from '../../../interfaces'
import { icons } from '../../../constants/header-icons'

const ReviewDetail = () => {
return <div>리뷰상세 페이지</div>
const { setDetailReview, resetDetailReview } = useDetailReviewStore()
const [isInputShown, setIsInputShown] = useState(false)
const [isInputFocused, setIsInputFocused] = useState(false)

const { goBack } = useRouter()
const { reviewId } = useParams()

// :: Validate reviewId
// reviewId Path variable로 Number 값이 아닌 값이 들어오면 이전 페이지로 이동
useEffect(() => {
if (isNaN(Number(reviewId))) {
goBack()
return
}
}, [])

// :: Get Review data
const { isLoading, data: reviewDetailInfo } = useQuery<IReviewDetail>({
queryKey: ['reviewDetailInfo', reviewId],
queryFn: getReviewDetailQuery,
})
useEffect(() => {
resetDetailReview()
reviewDetailInfo && setDetailReview(reviewDetailInfo)
}, [reviewDetailInfo])

// :: Header
const bucketRightMenu =
reviewDetailInfo && isMyUserType(reviewDetailInfo.writer) ? <ReviewMoreButton /> : undefined
const handleLeftFunc = () => {
goBack()
}
const headerMenu: IMenu = {
left: icons.BACK,
center: `${reviewDetailInfo ? reviewDetailInfo.writer.userNickname + '의 꿈:틀' : '꿈:틀'}`,
right: bucketRightMenu,
}
const headerFunc: IMenuFunc = { left_func: handleLeftFunc, right_func: undefined }

// :: Rendering
if (reviewId === undefined) {
goBack()
return
}
return (
<>
<WithHeaderLayout headerMenu={headerMenu} headerFunc={headerFunc}>
<p className="text-[28px] font-bold mt-6 leading-none">{reviewDetailInfo?.reviewTitle}</p>
<div className="mt-3 mb-6">
<UserProfile type="detail" isLoading={isLoading} userInfo={reviewDetailInfo?.writer} />
</div>
<section className="px-3">
<ReviewBucket
isLoading={isLoading}
title={reviewDetailInfo?.bucketTitle}
color={reviewDetailInfo?.bucketColor}
dayCount={reviewDetailInfo?.daysSinceDream}
/>
</section>

{isLoading || reviewDetailInfo === undefined ? (
<>{/* Todo: skeleton 추가 */}</>
) : (
<>
{/* 날짜 */}
<p className="mt-6 text-base text-disabled">{reviewDetailInfo.reviewCreatedDate}</p>
{/* 태그 */}
<ul className="mt-3 bg-white">
{reviewDetailInfo.categories.map((category, index) => (
<InterestTag tag={category} key={`category-${index}`} />
))}
</ul>
<div className="flex gap-3 my-8">
<ShareButton />
</div>
<Reaction id={reviewId} />
<CommentList
isInputFocused={isInputFocused}
setIsInputShown={setIsInputShown}
id={reviewId}
/>
</>
)}
</WithHeaderLayout>
{isInputShown && <CommentInput reviewId={reviewId} setIsInputFocused={setIsInputFocused} />}
</>
)
}

export default ReviewDetail
67 changes: 0 additions & 67 deletions frontend/src/pages/Review/WriteReview/api.ts

This file was deleted.

2 changes: 1 addition & 1 deletion frontend/src/pages/Review/WriteReview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import ModifyButton from '../component/ModifyButton'
import { useRouter } from '../../../hooks/useRouter'
import useFetchBucket from '../../../hooks/useFetchBucket'
import { useCurrentUserStore } from '../../../store/currentUserStore'
import { getReviewBrief } from './api'
import { getReviewBrief } from '../api'
import { IMenu, IMenuFunc } from '../../../interfaces'
import { icons } from '../../../constants/header-icons'

Expand Down
Loading

0 comments on commit 66fde03

Please sign in to comment.