diff --git a/src/components/diary/write/DiaryEditor.tsx b/src/components/diary/write/DiaryEditor.tsx index 83242d33..12be5477 100644 --- a/src/components/diary/write/DiaryEditor.tsx +++ b/src/components/diary/write/DiaryEditor.tsx @@ -128,7 +128,7 @@ const DiaryEditor = ({ {formContext.formState.errors.address && (

- 주소를 입력해 주세요. + 모든 날짜의 주소를 입력해 주세요.

)} diff --git a/src/containers/diary/write/AddressModalContainer.tsx b/src/containers/diary/write/AddressModalContainer.tsx index 3c566893..49e69a20 100644 --- a/src/containers/diary/write/AddressModalContainer.tsx +++ b/src/containers/diary/write/AddressModalContainer.tsx @@ -39,7 +39,7 @@ const AddressModalContainer = ({ closeModal }: Props) => { const addressList: string[] = formContext.getValues("address"); addressList[index] = ""; formContext.setValue("address", addressList); - formContext.trigger(); + formContext.trigger("address"); closeModal(); }; @@ -48,7 +48,7 @@ const AddressModalContainer = ({ closeModal }: Props) => { const addressList: string[] = formContext.getValues("address"); addressList[index] = placeInfo.address_name; formContext.setValue("address", addressList); - formContext.trigger(); + formContext.trigger("address"); closeModal(); }; diff --git a/src/containers/diary/write/DiaryEditorContainer.tsx b/src/containers/diary/write/DiaryEditorContainer.tsx index 0d5f855c..098d7022 100644 --- a/src/containers/diary/write/DiaryEditorContainer.tsx +++ b/src/containers/diary/write/DiaryEditorContainer.tsx @@ -22,13 +22,22 @@ const DiaryEditorContainer = () => { const [addressModal, setAddressModal] = useState(false); const [loading, setLoading] = useState(false); - const methods = useForm({ + const methods = useForm<{ + userId: number; + title: string; + startDate: Date | null; + endDate: Date | null; + address: string[]; + image: string; + moodLevels: number[]; + contents: string[]; + }>({ resolver: zodResolver(DiaryCreateFormSchema), defaultValues: { userId: authStore.id, title: "", - startDate: new Date(), - endDate: new Date(), + startDate: null, + endDate: null, address: [""], image: "", moodLevels: [], @@ -61,8 +70,8 @@ const DiaryEditorContainer = () => { const data: CreateDiaryRequestDto = { title: title, titleImage: image, - startDatetime: startDate, - endDatetime: endDate, + startDatetime: startDate!, + endDatetime: endDate!, diaryDayRequests: Array.from( { length: diaryEditorStore.days }, (_, index) => ({ diff --git a/src/containers/diary/write/QuillEditorContainer.tsx b/src/containers/diary/write/QuillEditorContainer.tsx index 2ee2e9e0..6ffb1a92 100644 --- a/src/containers/diary/write/QuillEditorContainer.tsx +++ b/src/containers/diary/write/QuillEditorContainer.tsx @@ -95,7 +95,7 @@ const QuillEditorContainer = () => { const contents: string[] = formContext.getValues("contents"); contents[diaryEditorStore.currentDay - 1] = value; formContext.setValue("contents", contents); - formContext.trigger(); + formContext.trigger("contents"); }} /> ); diff --git a/src/containers/informations/edit/InformationEditorContainer.tsx b/src/containers/informations/edit/InformationEditorContainer.tsx index 0a33bf22..2e02f4d9 100644 --- a/src/containers/informations/edit/InformationEditorContainer.tsx +++ b/src/containers/informations/edit/InformationEditorContainer.tsx @@ -33,7 +33,28 @@ const InformationEditorContainer = ({ informationId, data }: Props) => { const [originalThumbnailUrl, setOriginalThumbnailUrl] = useState(""); const [originalContentUrl, setOriginalContentUrl] = useState([]); - const methods = useForm({ + const methods = useForm<{ + userId: number; + informationTitle: string; + informationAddress: string; + province: string; + city: string; + placeId: string; + placeXAxis: string; + placeYAxis: string; + placeName: string; + categoryId: number; + categoryName: string; + newThumbNailUrl: string | null; + newThumbNailFromContent: string | null; + moveThumbNailToContent: string | null; + newContentImagesUrl: string[]; + deleteImagesUrl: string[]; + informationContent: string; + contentLength: number; + hashtags: string[]; + tips: string[]; + }>({ resolver: zodResolver(InformationUpdateFormSchema), defaultValues: { userId: id, @@ -47,9 +68,9 @@ const InformationEditorContainer = ({ informationId, data }: Props) => { placeName: "", categoryId: 0, categoryName: "", - newThumbNailUrl: "", - newThumbNailFromContent: "", - moveThumbNailToContent: "", + newThumbNailUrl: null, + newThumbNailFromContent: null, + moveThumbNailToContent: null, newContentImagesUrl: Array(0), deleteImagesUrl: Array(0), informationContent: "", @@ -121,19 +142,19 @@ const InformationEditorContainer = ({ informationId, data }: Props) => { // 썸네일 이미지가 변경되지 않은 경우 if (originalThumbnailUrl === thumbnailUrl) { - methods.setValue("newThumbNailUrl", ""); - methods.setValue("newThumbNailFromContent", ""); - methods.setValue("moveThumbNailToContent", ""); + methods.setValue("newThumbNailUrl", null); + methods.setValue("newThumbNailFromContent", null); + methods.setValue("moveThumbNailToContent", null); } else { // 기존 본문 이미지가 썸네일 이미지로 변경되는 경우 if (originalContentUrl.includes(thumbnailUrl)) { - methods.setValue("newThumbNailUrl", ""); + methods.setValue("newThumbNailUrl", null); methods.setValue("newThumbNailFromContent", thumbnailUrl); } // 새로운 썸네일 이미지를 사용하는 경우 else { methods.setValue("newThumbNailUrl", thumbnailUrl); - methods.setValue("newThumbNailFromContent", ""); + methods.setValue("newThumbNailFromContent", null); } // 기존 썸네일 이미지가 본문으로 이동하는 경우 @@ -142,7 +163,7 @@ const InformationEditorContainer = ({ informationId, data }: Props) => { } // 기존 썸네일 이미지를 삭제하는 경우 else { - methods.setValue("moveThumbNailToContent", ""); + methods.setValue("moveThumbNailToContent", null); } } @@ -169,51 +190,78 @@ const InformationEditorContainer = ({ informationId, data }: Props) => { return; } - alert("정보 수정 API 연동 예정"); - - // const data: UpdateInformationRequestDto = { - // title: validatedFields.data.informationTitle, - // address: validatedFields.data.informationAddress, - // content: validatedFields.data.informationContent, - // tips: validatedFields.data.tips.join(";"), - // placeModifyRequest: { - // searchId: validatedFields.data.placeId, - // name: validatedFields.data.placeName, - // xAxis: validatedFields.data.placeXAxis, - // yAxis: validatedFields.data.placeYAxis, - // address: validatedFields.data.informationAddress, - // }, - // categoryId: validatedFields.data.categoryId, - // zoneCategoryNameParent: validatedFields.data.province, - // zoneCategoryNameChild: validatedFields.data.city, - // deleteImages: deletedImages, - // thumbNailUrl: validatedFields.data.thumbnailImageUrl, - // contentImagesUrl: validatedFields.data.contentImagesUrl, - // tagRegisterRequests: validatedFields.data.hashtags.map((tag) => ({ - // name: tag, - // })), - // }; - - // setLoading(true); - - // const response = await fetch(`/api/informations/${informationId}`, { - // method: "PUT", - // headers: { - // "Content-Type": "application/json", - // }, - // body: JSON.stringify(data), - // cache: "no-store", - // }); - - // if (!response.ok) { - // alert("정보 수정에 실패하였습니다."); - // setLoading(false); - // throw new Error(response.statusText); - // } - - // const result: InformationRegisterResponseDto = await response.json(); - // router.push(`/informations/${result.id}`); - // router.refresh(); + const { + informationTitle, + informationAddress, + informationContent, + tips, + placeId, + placeName, + placeXAxis, + placeYAxis, + categoryId, + province, + city, + newThumbNailUrl, + newThumbNailFromContent, + moveThumbNailToContent, + newContentImagesUrl, + deleteImagesUrl, + hashtags, + } = methods.getValues(); + + const data: UpdateInformationRequestDto = { + title: informationTitle, + address: informationAddress, + content: informationContent, + tips: tips.join(";"), + placeModifyRequest: { + searchId: placeId, + name: placeName, + xAxis: placeXAxis, + yAxis: placeYAxis, + address: informationAddress, + }, + categoryId: categoryId, + zoneCategoryNameParent: province, + zoneCategoryNameChild: city, + newThumbNailUrl: + newThumbNailUrl === null ? null : { address: newThumbNailUrl }, + newThumbNailFromContent: + newThumbNailFromContent === null + ? null + : { address: newThumbNailFromContent }, + moveThumbNailToContent: + moveThumbNailToContent === null + ? null + : { address: moveThumbNailToContent }, + newContentImagesUrl: newContentImagesUrl.map((url) => ({ address: url })), + deleteImagesUrl: deleteImagesUrl.map((url) => ({ address: url })), + tagRegisterRequests: hashtags.map((tag) => ({ + name: tag, + })), + }; + + setLoading(true); + + const response = await fetch(`/api/informations/${informationId}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + cache: "no-store", + }); + + if (!response.ok) { + alert("정보 수정에 실패하였습니다."); + setLoading(false); + throw new Error(response.statusText); + } + + const result: InformationRegisterResponseDto = await response.json(); + router.push(`/informations/${result.id}`); + router.refresh(); }; // 로그인을 하지 않은 사용자의 경우 로그인 페이지로 리다이렉트. diff --git a/src/lib/zod/schema/InformationCreateFormSchema.ts b/src/lib/zod/schema/InformationCreateFormSchema.ts index 29377d05..422cfd28 100644 --- a/src/lib/zod/schema/InformationCreateFormSchema.ts +++ b/src/lib/zod/schema/InformationCreateFormSchema.ts @@ -21,7 +21,7 @@ export const InformationCreateFormSchema = z.object({ invalid_type_error: "Address must be a string.", }) .min(1, { message: "장소를 입력해 주세요." }) - .max(20, { message: "장소 길이는 20자 이하여야 합니다." }), + .max(50, { message: "장소 길이는 50자 이하여야 합니다." }), province: z .string({ required_error: "Province is required.", diff --git a/src/lib/zod/schema/InformationUpdateFormSchema.ts b/src/lib/zod/schema/InformationUpdateFormSchema.ts index 99319422..deded731 100644 --- a/src/lib/zod/schema/InformationUpdateFormSchema.ts +++ b/src/lib/zod/schema/InformationUpdateFormSchema.ts @@ -21,7 +21,7 @@ export const InformationUpdateFormSchema = z.object({ invalid_type_error: "Address must be a string.", }) .min(1, { message: "장소를 입력해 주세요." }) - .max(20, { message: "장소 길이는 20자 이하여야 합니다." }), + .max(50, { message: "장소 길이는 50자 이하여야 합니다." }), province: z .string({ required_error: "Province is required.", @@ -65,18 +65,24 @@ export const InformationUpdateFormSchema = z.object({ }) .int() .positive({ message: "카테고리를 선택해 주세요." }), - newThumbNailUrl: z.string({ - required_error: "newThumbNailUrl is required.", - invalid_type_error: "newThumbNailUrl must be a string.", - }), - newThumbNailFromContent: z.string({ - required_error: "newThumbNailFromContent is required.", - invalid_type_error: "newThumbNailFromContent must be a string.", - }), - moveThumbNailToContent: z.string({ - required_error: "moveThumbNailToContent is required.", - invalid_type_error: "moveThumbNailToContent must be a string.", - }), + newThumbNailUrl: z + .string({ + required_error: "newThumbNailUrl is required.", + invalid_type_error: "newThumbNailUrl must be a string.", + }) + .nullable(), + newThumbNailFromContent: z + .string({ + required_error: "newThumbNailFromContent is required.", + invalid_type_error: "newThumbNailFromContent must be a string.", + }) + .nullable(), + moveThumbNailToContent: z + .string({ + required_error: "moveThumbNailToContent is required.", + invalid_type_error: "moveThumbNailToContent must be a string.", + }) + .nullable(), newContentImagesUrl: z .string({ required_error: "newContentImagesUrl is required.", diff --git a/src/types/InformationDto.ts b/src/types/InformationDto.ts index 6f18887f..cf4ab8b5 100644 --- a/src/types/InformationDto.ts +++ b/src/types/InformationDto.ts @@ -39,9 +39,11 @@ export interface UpdateInformationRequestDto { categoryId: number; zoneCategoryNameParent: string; zoneCategoryNameChild: string; - deleteImages: { address: string }[]; - thumbNailUrl: string; - contentImagesUrl: string[]; + newThumbNailUrl: { address: string } | null; + newThumbNailFromContent: { address: string } | null; + moveThumbNailToContent: { address: string } | null; + newContentImagesUrl: { address: string }[]; + deleteImagesUrl: { address: string }[]; tagRegisterRequests: { name: string }[]; }