From 1b432b79b04c8e999cd3e19943f79befd631bc4c Mon Sep 17 00:00:00 2001 From: llmojoll Date: Thu, 31 Jul 2025 19:18:15 +0900 Subject: [PATCH 1/4] =?UTF-8?q?Style=20:=20=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=ED=95=98=EA=B8=B0=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Modal/ReviewModal/AddReviewModal.tsx | 6 +++--- src/components/Modal/ReviewModal/EditReviewModal.tsx | 9 +++------ src/components/common/BottomSheet/BasicBottomSheet.tsx | 4 ++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/components/Modal/ReviewModal/AddReviewModal.tsx b/src/components/Modal/ReviewModal/AddReviewModal.tsx index b76fe83..f06b271 100644 --- a/src/components/Modal/ReviewModal/AddReviewModal.tsx +++ b/src/components/Modal/ReviewModal/AddReviewModal.tsx @@ -213,14 +213,14 @@ const AddReviewModal = ({ wineId, wineName }: { wineId: number; wineName: string })} placeholder='후기를 작성해 주세요' className={cn( - 'relative h-[100px] md:h-[120px] custom-text-md-regular md:custom-text-lg-regular w-full px-[20px] py-[14px] rounded-[16px] bg-white border border-gray-300 outline-none active:border-gray-500 focus:border-gray-500 font-sans resize-none', + 'h-[100px] md:h-[120px] w-full px-[20px] py-[14px] rounded-[16px] bg-white border border-gray-300 outline-none font-sans resize-none', errors.content && 'border-red-500', )} rows={5} /> {errors.content && ( -
-

{errors.content.message}

+
+

{errors.content.message}

)}

diff --git a/src/components/Modal/ReviewModal/EditReviewModal.tsx b/src/components/Modal/ReviewModal/EditReviewModal.tsx index 7fcb47f..7e8dbb1 100644 --- a/src/components/Modal/ReviewModal/EditReviewModal.tsx +++ b/src/components/Modal/ReviewModal/EditReviewModal.tsx @@ -190,7 +190,7 @@ const EditReviewModal = ({

{errors.content && ( -
- {errors.content.message} +
+

{errors.content.message}

)} @@ -300,9 +300,6 @@ const EditReviewModal = ({ return (
- {isDesktop ? ( )} -
{children}
+
{children}
{buttons && ( - {buttons} + {buttons} )} From 3dae743ce67ca11a8010cc54e0548007b2bf5447 Mon Sep 17 00:00:00 2001 From: llmojoll Date: Thu, 31 Jul 2025 19:44:15 +0900 Subject: [PATCH 2/4] =?UTF-8?q?Refactor=20:=20=EB=AA=A8=EB=8B=AC=20?= =?UTF-8?q?=EC=9B=80=EC=B0=94=EC=9B=80=EC=B0=94=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Modal/Modal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/common/Modal/Modal.tsx b/src/components/common/Modal/Modal.tsx index 88f32d7..cfe0cdc 100644 --- a/src/components/common/Modal/Modal.tsx +++ b/src/components/common/Modal/Modal.tsx @@ -24,7 +24,7 @@ const Modal = ({ open, onOpenChange, showCloseButton = true, children, className button:last-child]:hidden focus:outline-none focus:border-none', + 'flex flex-col rounded-xl max-h-[95vh] [&>button:last-child]:hidden', className, )} > From 963c3140f561551307dfe8173842c3a686dbec47 Mon Sep 17 00:00:00 2001 From: llmojoll Date: Fri, 1 Aug 2025 16:44:35 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Feat=20:=20=EB=AA=A8=EB=8B=AC=EC=B0=BD?= =?UTF-8?q?=EC=97=90=20toast=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Modal/DeleteModal/DeleteModal.tsx | 5 +++++ src/components/Modal/ReviewModal/AddReviewModal.tsx | 7 +++++-- src/components/Modal/ReviewModal/EditReviewModal.tsx | 7 +++++-- src/components/Modal/WineModal/AddWineModal.tsx | 3 +++ src/components/Modal/WineModal/EditWineModal.tsx | 3 +++ 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/components/Modal/DeleteModal/DeleteModal.tsx b/src/components/Modal/DeleteModal/DeleteModal.tsx index b7033f9..a56ad69 100644 --- a/src/components/Modal/DeleteModal/DeleteModal.tsx +++ b/src/components/Modal/DeleteModal/DeleteModal.tsx @@ -1,5 +1,6 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { AxiosError } from 'axios'; +import { toast } from 'sonner'; import { deleteReview, deleteWine, DeleteResponse } from '@/api/delete'; import BasicBottomSheet from '@/components/common/BottomSheet/BasicBottomSheet'; @@ -32,10 +33,12 @@ const DeleteModal = ({ type, id, showDeleteModal, setShowDeleteModal }: DeleteMo deleteWineMutation.mutate(id, { onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['wines'] }); //삭제후 관련데이터 바로 갱신 + toast.success('와인이 성공적으로 삭제되었습니다.'); console.log('와인 삭제 성공'); setShowDeleteModal(false); }, onError: (error) => { + toast.error('와인 삭제가 실패하였습니다.'); console.error('와인 삭제 실패', error); }, }); @@ -44,10 +47,12 @@ const DeleteModal = ({ type, id, showDeleteModal, setShowDeleteModal }: DeleteMo onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['reviews'] }); queryClient.invalidateQueries({ queryKey: ['wineDetail'] }); + toast.success('리뷰가 성공적으로 삭제되었습니다.'); console.log('리뷰 삭제 성공'); setShowDeleteModal(false); }, onError: (error) => { + toast.error('리뷰 삭제가 실패하였습니다.'); console.error('리뷰 삭제 실패', error); }, }); diff --git a/src/components/Modal/ReviewModal/AddReviewModal.tsx b/src/components/Modal/ReviewModal/AddReviewModal.tsx index f06b271..f57917e 100644 --- a/src/components/Modal/ReviewModal/AddReviewModal.tsx +++ b/src/components/Modal/ReviewModal/AddReviewModal.tsx @@ -4,6 +4,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { AxiosError } from 'axios'; import Image from 'next/image'; import { useForm } from 'react-hook-form'; +import { toast } from 'sonner'; import { postReview } from '@/api/addreview'; import BasicBottomSheet from '@/components/common/BottomSheet/BasicBottomSheet'; @@ -114,6 +115,7 @@ const AddReviewModal = ({ wineId, wineName }: { wineId: number; wineName: string //mutation function mutationFn: postReview, //실제 서버에 리뷰를 보내는 역할 onSuccess: (data) => { + toast.success('리뷰가 성공적으로 등록되었습니다.'); console.log('리뷰 등록 성공', data); queryClient.invalidateQueries({ queryKey: ['reviews'] }); queryClient.invalidateQueries({ queryKey: ['wineDetail'] }); @@ -121,6 +123,7 @@ const AddReviewModal = ({ wineId, wineName }: { wineId: number; wineName: string setShowRegisterModal(false); }, onError: (error) => { + toast.error('리뷰 등록이 실패하였습니다.'); console.log('리뷰 등록 실패', error); }, }); @@ -279,8 +282,8 @@ const AddReviewModal = ({ wineId, wineName }: { wineId: number; wineName: string

기억에 남는 향이 있나요?

{errors.aroma && ( -
- {errors.aroma.message} +
+

{errors.aroma.message}

)}
diff --git a/src/components/Modal/ReviewModal/EditReviewModal.tsx b/src/components/Modal/ReviewModal/EditReviewModal.tsx index 7e8dbb1..4250b7c 100644 --- a/src/components/Modal/ReviewModal/EditReviewModal.tsx +++ b/src/components/Modal/ReviewModal/EditReviewModal.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import Image from 'next/image'; import { useForm } from 'react-hook-form'; +import { toast } from 'sonner'; import { updateReview } from '@/api/editreview'; import BasicBottomSheet from '@/components/common/BottomSheet/BasicBottomSheet'; @@ -98,12 +99,14 @@ const EditReviewModal = ({ mutationFn: updateReview, throwOnError: true, onSuccess: () => { + toast.success('리뷰가 성공적으로 수정되었습니다.'); console.log('리뷰 수정 완료'); queryClient.invalidateQueries({ queryKey: ['reviews'] }); queryClient.invalidateQueries({ queryKey: ['wineDetail'] }); setShowEditModal(false); }, onError: (error) => { + toast.error('리뷰 수정이 실패하였습니다.'); console.log('리뷰 수정 실패', error); }, }); @@ -276,8 +279,8 @@ const EditReviewModal = ({

기억에 남는 향이 있나요?

{errors.aroma && ( -
- {errors.aroma.message} +
+

{errors.aroma.message}

)}
diff --git a/src/components/Modal/WineModal/AddWineModal.tsx b/src/components/Modal/WineModal/AddWineModal.tsx index 9e6eb03..c080727 100644 --- a/src/components/Modal/WineModal/AddWineModal.tsx +++ b/src/components/Modal/WineModal/AddWineModal.tsx @@ -2,6 +2,7 @@ import React, { useRef, useState } from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useForm } from 'react-hook-form'; +import { toast } from 'sonner'; import { uploadImage, postWine, PostWineRequest } from '@/api/addwine'; import CameraIcon from '@/assets/camera.svg'; @@ -89,12 +90,14 @@ const AddWineModal = ({ showRegisterModal, setShowRegisterModal }: AddWineModalP const postWineMutation = useMutation({ mutationFn: handlePostWine, onSuccess: () => { + toast.success('와인이 성공적으로 등록되었습니다.'); console.log('와인 등록 성공'); resetForm(); setShowRegisterModal(false); queryClient.invalidateQueries({ queryKey: ['wines'] }); }, onError: (error) => { + toast.error('와인 등록이 실패하였습니다.'); console.log('와인 등록 실패', error); }, }); diff --git a/src/components/Modal/WineModal/EditWineModal.tsx b/src/components/Modal/WineModal/EditWineModal.tsx index 8627a81..77f9a80 100644 --- a/src/components/Modal/WineModal/EditWineModal.tsx +++ b/src/components/Modal/WineModal/EditWineModal.tsx @@ -2,6 +2,7 @@ import React, { useRef, useState } from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useForm } from 'react-hook-form'; +import { toast } from 'sonner'; import { updateWine, uploadImage } from '@/api/editwine'; import BasicBottomSheet from '@/components/common/BottomSheet/BasicBottomSheet'; @@ -84,6 +85,7 @@ const EditWineModal = ({ wine, showEditModal, setShowEditModal }: EditWineModalP const updateWineMutation = useMutation({ mutationFn: updateWine, onSuccess: () => { + toast.success('와인이 성공적으로 수정되었습니다.'); console.log('와인수정완료'); queryClient.invalidateQueries({ queryKey: ['wines'] }); reset({ @@ -96,6 +98,7 @@ const EditWineModal = ({ wine, showEditModal, setShowEditModal }: EditWineModalP setShowEditModal(false); }, onError: (error) => { + toast.error('와인 수정이 실패하였습니다.'); console.log('와인수정실패', error); }, }); From 81eaa9e0692a3dda44b99175bbb536abf8e11505 Mon Sep 17 00:00:00 2001 From: llmojoll Date: Fri, 1 Aug 2025 17:55:03 +0900 Subject: [PATCH 4/4] =?UTF-8?q?Feat=20:=20=ED=8C=8C=EC=9D=BC=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EC=A0=95=EA=B7=9C=ED=99=94=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Modal/WineModal/AddWineModal.tsx | 11 +++++++++-- src/components/Modal/WineModal/EditWineModal.tsx | 9 ++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/Modal/WineModal/AddWineModal.tsx b/src/components/Modal/WineModal/AddWineModal.tsx index c080727..dcc7969 100644 --- a/src/components/Modal/WineModal/AddWineModal.tsx +++ b/src/components/Modal/WineModal/AddWineModal.tsx @@ -9,6 +9,7 @@ import CameraIcon from '@/assets/camera.svg'; import DropdownIcon from '@/assets/dropdowntriangle.svg'; import BasicBottomSheet from '@/components/common/BottomSheet/BasicBottomSheet'; import { useMediaQuery } from '@/hooks/useMediaQuery'; +import { renameFileIfNeeded } from '@/lib/renameFile'; import SelectDropdown from '../../common/dropdown/SelectDropdown'; import Input from '../../common/Input'; @@ -42,7 +43,8 @@ const AddWineModal = ({ showRegisterModal, setShowRegisterModal }: AddWineModalP const handleImageChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { - const imageUrl = URL.createObjectURL(file); + const renamedFile = renameFileIfNeeded(file); //이미지파일 이름 정규화 + const imageUrl = URL.createObjectURL(renamedFile); setPreviewImage(imageUrl); } else { setPreviewImage(null); @@ -103,7 +105,12 @@ const AddWineModal = ({ showRegisterModal, setShowRegisterModal }: AddWineModalP }); const onSubmit = async (form: WineForm) => { - postWineMutation.mutate(form); + let file = form.wineImage[0]; + file = renameFileIfNeeded(file); //이미지파일 이름 정규화 + postWineMutation.mutate({ + ...form, + wineImage: [file] as unknown as FileList, + }); }; const categoryOptions = [ diff --git a/src/components/Modal/WineModal/EditWineModal.tsx b/src/components/Modal/WineModal/EditWineModal.tsx index 77f9a80..4101ffa 100644 --- a/src/components/Modal/WineModal/EditWineModal.tsx +++ b/src/components/Modal/WineModal/EditWineModal.tsx @@ -11,6 +11,7 @@ import Input from '@/components/common/Input'; import BasicModal from '@/components/common/Modal/BasicModal'; import { Button } from '@/components/ui/button'; import { useMediaQuery } from '@/hooks/useMediaQuery'; +import { renameFileIfNeeded } from '@/lib/renameFile'; interface WineForm { wineName: string; @@ -78,7 +79,8 @@ const EditWineModal = ({ wine, showEditModal, setShowEditModal }: EditWineModalP const handleImageChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { - setPreviewImage(URL.createObjectURL(file)); + const renamedFile = renameFileIfNeeded(file); + setPreviewImage(URL.createObjectURL(renamedFile)); } }; @@ -106,10 +108,11 @@ const EditWineModal = ({ wine, showEditModal, setShowEditModal }: EditWineModalP const onSubmit = async (form: WineForm) => { try { const file = form.wineImage?.[0]; - let imageUrl = file ? await uploadImage(file) : wine.image; + let imageUrl = wine.image; if (file) { - const uploaded = await uploadImage(file); + const renamedFile = renameFileIfNeeded(file); //이미지파일 이름 정규화 + const uploaded = await uploadImage(renamedFile); imageUrl = uploaded + `?t=${Date.now()}`; // 캐시 방지 setPreviewImage(imageUrl); // 이미지 갱신 }