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 useUpdateReviewQuery from '@/queries/reviews/useUpdateReviewQuery';
import useDeleteReviewQuery from '@/queries/reviews/useDeleteReviewQuery';
import { useState } from 'react';
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 memberId = 1;
const profile = useAuthStore((state) => state.profile);
const memberId = profile?.id || 0;
const { data: reviewDetail } = useReviewDetailQuery(Number(projectId), Number(reviewId), memberId);
const updateReview = useUpdateReviewQuery();
const deleteReview = useDeleteReviewQuery();
const { data: projectMembers } = useProjectMembersQuery(Number(projectId), memberId);
const handleUpdate = () => {
updateReview.mutate({
const updateReviewStatus = useUpdateReviewStatusQuery();
const [activeTab, setActiveTab] = useState<'content' | 'images'>('content');
const handleApprove = () => {
updateReviewStatus.mutate({
projectId: Number(projectId),
reviewId: Number(reviewId),
memberId,
reviewData: {
title: reviewDetail.title,
content: reviewDetail.content,
imageIds: reviewDetail.images.map((image) => image.id),
},
reviewStatus: 'APPROVED',
});
};
const handleDelete = () => {
deleteReview.mutate({
const handleReject = () => {
updateReviewStatus.mutate({
projectId: Number(projectId),
reviewId: Number(reviewId),
memberId,
reviewStatus: 'REJECTED',
});
};
if (!reviewDetail) return <p>Loading...</p>;
const { title, content, reviewStatus, images } = reviewDetail;
const settings = {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
};
return (
<div className="flex flex-col gap-4 bg-white p-6">
<header className="flex items-center justify-between">
<h1 className="text-2xl font-bold text-[#333238]">{title}</h1>
<div className="rounded-full bg-[#cbe2f9] px-3 py-0.5 text-xs text-[#0b5cad]">{reviewStatus}</div>
</header>
<div className="flex items-center gap-2">
<p className="text-sm text-[#737278]">by </p>
<p className="text-sm text-[#737278]">|</p>
<p className="text-sm text-[#737278]">8 hours ago</p>
<div className="review-detail-container p-4">
<div className="header mb-4">
<h1 className="text-2xl font-bold">{reviewDetail.title}</h1>
<p className="text-sm text-gray-500">
: {reviewDetail.nickname} ({reviewDetail.email})
</p>
<p className="text-sm text-gray-500">: {new Date(reviewDetail.createAt).toLocaleDateString()}</p>
<p className="text-sm text-gray-500">: {new Date(reviewDetail.updateAt).toLocaleDateString()}</p>
</div>
<div className="border-b pb-4">
<h2 className="text-xl font-semibold"></h2>
<p className="mt-2 text-sm text-[#333238]">{content}</p>
</div>
<div className="flex flex-col">
<h2 className="text-xl font-semibold"> </h2>
<ul className="mt-2 list-inside list-disc">
{images.map((image) => (
<li
key={image.id}
className="text-sm text-[#737278]"
<div className="relative w-full px-4">
<div className="flex w-full items-center border-b-[0.67px] border-solid border-[#dcdcde]">
{['content', 'images'].map((tab) => (
<button
key={tab}
className={`flex h-12 w-[100px] items-center justify-center px-3 ${
activeTab === tab ? 'shadow-[inset_0px_-2px_0px_#1f75cb]' : ''
}`}
onClick={() => setActiveTab(tab as 'content' | 'images')}
>
{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>
))}
</ul>
</div>
<div className="flex gap-2">
<button
onClick={handleUpdate}
className="rounded-lg bg-blue-500 px-4 py-2 text-white hover:bg-blue-600"
>
</button>
<button
onClick={handleDelete}
className="rounded-lg bg-red-500 px-4 py-2 text-white hover:bg-red-600"
>
</button>
<div className="actions mt-6 flex justify-end space-x-2">
{reviewDetail.reviewStatus !== 'APPROVED' && (
<Button
variant="default"
onClick={handleApprove}
>
</Button>
)}
{reviewDetail.reviewStatus !== 'REJECTED' && (
<Button
variant="destructive"
onClick={handleReject}
>
</Button>
)}
</div>
</div>
);