From 72d465c3cfa86ce801a7555b0c954e8e3dd756e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=ED=98=84=EC=A1=B0?= Date: Mon, 30 Sep 2024 12:58:48 +0900 Subject: [PATCH 1/2] =?UTF-8?q?Fix:=20=EB=A6=AC=EB=B7=B0=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=97=90=EB=9F=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EA=B3=A0?= =?UTF-8?q?=EC=B9=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/ImageSelection/index.tsx | 45 +++++++---- frontend/src/components/ReviewForm/index.tsx | 79 ++++++++++++++----- frontend/src/pages/ReviewRequest.tsx | 51 ++---------- 3 files changed, 100 insertions(+), 75 deletions(-) diff --git a/frontend/src/components/ImageSelection/index.tsx b/frontend/src/components/ImageSelection/index.tsx index 4653cab..062e38c 100644 --- a/frontend/src/components/ImageSelection/index.tsx +++ b/frontend/src/components/ImageSelection/index.tsx @@ -1,4 +1,3 @@ -// ImageSelection.tsx import { Label } from '@/components/ui/label'; import useRecursiveSavedImages from '@/hooks/useRecursiveSavedImages'; import { Button } from '@/components/ui/button'; @@ -7,27 +6,44 @@ import { ScrollArea } from '@/components/ui/scroll-area'; interface ImageSelectionProps { projectId: string; selectedImages: number[]; - setSelectedImages: React.Dispatch>; + setSelectedImages: (images: number[]) => void; } export default function ImageSelection({ projectId, selectedImages, setSelectedImages }: ImageSelectionProps) { const { allSavedImages } = useRecursiveSavedImages(projectId, 0); const handleImageSelect = (imageId: number) => { - // 상태 업데이트 안전하게 관리 - setSelectedImages((prevSelectedImages) => { - // 이미 선택된 이미지가 있는 경우 필터링하여 제거 - if (prevSelectedImages.includes(imageId)) { - return prevSelectedImages.filter((id) => id !== imageId); + const updatedImages = selectedImages.includes(imageId) + ? selectedImages.filter((id) => id !== imageId) + : [...selectedImages, imageId]; + + setSelectedImages(updatedImages); + }; + + const handleSelectAll = () => { + if (allSavedImages) { + if (selectedImages.length === allSavedImages.length) { + setSelectedImages([]); + } else { + setSelectedImages(allSavedImages.map((image) => image.id)); } - // 선택되지 않은 이미지를 배열에 추가 - return [...prevSelectedImages, imageId]; - }); + } }; return (
- +
+ + +
    {allSavedImages && allSavedImages.length > 0 ? ( @@ -42,11 +58,12 @@ export default function ImageSelection({ projectId, selectedImages, setSelectedI
    diff --git a/frontend/src/components/ReviewForm/index.tsx b/frontend/src/components/ReviewForm/index.tsx index f8a8a74..ee733ef 100644 --- a/frontend/src/components/ReviewForm/index.tsx +++ b/frontend/src/components/ReviewForm/index.tsx @@ -1,38 +1,63 @@ +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { z } from 'zod'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import ImageSelection from '@/components/ImageSelection'; -import { useForm } from 'react-hook-form'; +import { Button } from '@/components/ui/button'; +import { useNavigate } from 'react-router-dom'; interface ReviewFormProps { projects: { id: string; title: string }[]; - selectedProjectId: string | null; - setSelectedProjectId: (id: string) => void; - selectedImages: number[]; - setSelectedImages: React.Dispatch>; - onSubmit: (data: { title: string; content: string }) => void; + onSubmit: (data: ReviewFormData) => void; } -export default function ReviewForm({ - projects, - selectedProjectId, - setSelectedProjectId, - selectedImages, - setSelectedImages, - onSubmit, -}: ReviewFormProps): JSX.Element { +const reviewFormSchema = z.object({ + projectId: z.string().min(1, '프로젝트를 선택해주세요.'), + title: z.string().min(1, '제목을 입력해주세요.'), + content: z.string().min(1, '내용을 입력해주세요.'), + imageIds: z.array(z.number()), +}); + +type ReviewFormData = z.infer; + +export default function ReviewForm({ projects, onSubmit }: ReviewFormProps): JSX.Element { + const navigate = useNavigate(); const { register, handleSubmit, formState: { errors }, - } = useForm<{ title: string; content: string }>(); + setValue, + watch, + } = useForm({ + resolver: zodResolver(reviewFormSchema), + defaultValues: { + projectId: '', + title: '', + content: '', + imageIds: [], + }, + }); + + const selectedProjectId = watch('projectId'); + const selectedImages = watch('imageIds'); + + const setSelectedProjectId = (value: string) => { + setValue('projectId', value); + setValue('imageIds', []); // 프로젝트 변경 시 이미지 초기화 + }; + + const setSelectedImages = (images: number[]) => { + setValue('imageIds', images); + }; return (
    - @@ -56,6 +81,7 @@ export default function ReviewForm({ )} + {errors.projectId &&

    {errors.projectId.message}

    }
    @@ -63,7 +89,7 @@ export default function ReviewForm({ {errors.title &&

    {errors.title.message}

    }
    @@ -73,7 +99,7 @@ export default function ReviewForm({