Feat: 리뷰 디테일 구현, test 못함

This commit is contained in:
정현조 2024-09-20 07:12:37 +09:00
parent 745a1198d8
commit ea344dca19

View File

@ -1,86 +1,152 @@
import useReviewDetailQuery from '@/queries/reviews/useReviewDetailQuery'; import { useState } from 'react';
import useUpdateReviewQuery from '@/queries/reviews/useUpdateReviewQuery';
import useDeleteReviewQuery from '@/queries/reviews/useDeleteReviewQuery';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import Slider from 'react-slick';
import useReviewDetailQuery from '@/queries/reviews/useReviewDetailQuery';
import useUpdateReviewStatusQuery from '@/queries/reviews/useUpdateReviewStatusQuery';
import useProjectMembersQuery from '@/queries/projects/useProjectMembersQuery';
import useAuthStore from '@/stores/useAuthStore';
import { Button } from '@/components/ui/button';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
export default function ReviewDetail() { export default function ReviewDetail(): JSX.Element {
const { projectId, reviewId } = useParams<{ projectId: string; reviewId: string }>(); const { projectId, reviewId } = useParams<{ projectId: string; reviewId: string }>();
const memberId = 1; const profile = useAuthStore((state) => state.profile);
const memberId = profile?.id || 0;
const { data: reviewDetail } = useReviewDetailQuery(Number(projectId), Number(reviewId), memberId); const { data: reviewDetail } = useReviewDetailQuery(Number(projectId), Number(reviewId), memberId);
const updateReview = useUpdateReviewQuery(); const { data: projectMembers } = useProjectMembersQuery(Number(projectId), memberId);
const deleteReview = useDeleteReviewQuery();
const handleUpdate = () => { const updateReviewStatus = useUpdateReviewStatusQuery();
updateReview.mutate({ const [activeTab, setActiveTab] = useState<'content' | 'images'>('content');
const handleApprove = () => {
updateReviewStatus.mutate({
projectId: Number(projectId), projectId: Number(projectId),
reviewId: Number(reviewId), reviewId: Number(reviewId),
memberId, memberId,
reviewData: { reviewStatus: 'APPROVED',
title: reviewDetail.title,
content: reviewDetail.content,
imageIds: reviewDetail.images.map((image) => image.id),
},
}); });
}; };
const handleDelete = () => { const handleReject = () => {
deleteReview.mutate({ updateReviewStatus.mutate({
projectId: Number(projectId), projectId: Number(projectId),
reviewId: Number(reviewId), reviewId: Number(reviewId),
memberId, memberId,
reviewStatus: 'REJECTED',
}); });
}; };
if (!reviewDetail) return <p>Loading...</p>; const settings = {
dots: true,
const { title, content, reviewStatus, images } = reviewDetail; infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
};
return ( return (
<div className="flex flex-col gap-4 bg-white p-6"> <div className="review-detail-container p-4">
<header className="flex items-center justify-between"> <div className="header mb-4">
<h1 className="text-2xl font-bold text-[#333238]">{title}</h1> <h1 className="text-2xl font-bold">{reviewDetail.title}</h1>
<div className="rounded-full bg-[#cbe2f9] px-3 py-0.5 text-xs text-[#0b5cad]">{reviewStatus}</div> <p className="text-sm text-gray-500">
</header> : {reviewDetail.nickname} ({reviewDetail.email})
</p>
<div className="flex items-center gap-2"> <p className="text-sm text-gray-500">: {new Date(reviewDetail.createAt).toLocaleDateString()}</p>
<p className="text-sm text-[#737278]">by </p> <p className="text-sm text-gray-500">: {new Date(reviewDetail.updateAt).toLocaleDateString()}</p>
<p className="text-sm text-[#737278]">|</p>
<p className="text-sm text-[#737278]">8 hours ago</p>
</div> </div>
<div className="border-b pb-4"> <div className="relative w-full px-4">
<h2 className="text-xl font-semibold"></h2> <div className="flex w-full items-center border-b-[0.67px] border-solid border-[#dcdcde]">
<p className="mt-2 text-sm text-[#333238]">{content}</p> {['content', 'images'].map((tab) => (
</div> <button
key={tab}
<div className="flex flex-col"> className={`flex h-12 w-[100px] items-center justify-center px-3 ${
<h2 className="text-xl font-semibold"> </h2> activeTab === tab ? 'shadow-[inset_0px_-2px_0px_#1f75cb]' : ''
<ul className="mt-2 list-inside list-disc"> }`}
{images.map((image) => ( onClick={() => setActiveTab(tab as 'content' | 'images')}
<li
key={image.id}
className="text-sm text-[#737278]"
> >
{image.imageTitle} (status: {image.status}) <span className={`text-sm ${activeTab === tab ? 'font-semibold' : 'font-normal'} text-[#333238]`}>
{tab === 'content' ? '내용' : '이미지'}
</span>
</button>
))}
</div>
</div>
<div className="content mt-4">
{activeTab === 'content' ? (
<p className="text-gray-700">{reviewDetail.content}</p>
) : (
<div className="images mt-4">
{reviewDetail.images.length > 0 ? (
<Slider {...settings}>
{reviewDetail.images.map((image) => (
<div key={image.id}>
<img
src={image.imagePath}
alt="리뷰 이미지"
className="h-auto w-full rounded"
/>
</div>
))}
</Slider>
) : (
<p className="text-gray-500"> .</p>
)}
</div>
)}
</div>
{reviewDetail.reviewStatus === 'APPROVED' && (
<div className="reviewer-info mt-6">
<h2 className="text-lg font-semibold"></h2>
<div className="flex items-center">
<img
src={reviewDetail.reviewerProfileImage}
alt="리뷰어 프로필"
className="h-10 w-10 rounded-full"
/>
<div className="ml-4">
<p className="font-bold">{reviewDetail.reviewerNickname}</p>
<p className="text-gray-500">{reviewDetail.reviewerEmail}</p>
</div>
</div>
</div>
)}
<div className="meta-info mt-6">
<h2 className="text-lg font-semibold"> </h2>
<ul className="list-disc pl-6">
{projectMembers.map((member) => (
<li
key={member.memberId}
className="text-gray-700"
>
{member.nickname} - {member.privilegeType}
</li> </li>
))} ))}
</ul> </ul>
</div> </div>
<div className="flex gap-2"> <div className="actions mt-6 flex justify-end space-x-2">
<button {reviewDetail.reviewStatus !== 'APPROVED' && (
onClick={handleUpdate} <Button
className="rounded-lg bg-blue-500 px-4 py-2 text-white hover:bg-blue-600" variant="default"
onClick={handleApprove}
> >
</button> </Button>
<button )}
onClick={handleDelete} {reviewDetail.reviewStatus !== 'REJECTED' && (
className="rounded-lg bg-red-500 px-4 py-2 text-white hover:bg-red-600" <Button
variant="destructive"
onClick={handleReject}
> >
</button> </Button>
)}
</div> </div>
</div> </div>
); );