33import { useState } from "react" ;
44
55import { useMutation , useQuery , useQueryClient } from "@tanstack/react-query" ;
6- import Image from "next/image" ;
76import { useParams , useRouter } from "next/navigation" ;
87
98import DatePicker from "@/components/archive-form/DayPicker" ;
109import Dropdown from "@/components/archive-form/Dropdown" ;
10+ import EditableImageUploader , {
11+ type EditableArchiveImage ,
12+ } from "@/components/archive-form/EditableImageUploader" ;
1113import Input from "@/components/archive-form/Input" ;
1214import Label from "@/components/archive-form/Label" ;
1315import RegionSelect from "@/components/archive-form/RegionSelect" ;
@@ -16,6 +18,7 @@ import Textarea from "@/components/archive-form/Textarea";
1618import ToggleButton from "@/components/archive-form/ToggleButton" ;
1719import Header from "@/components/common/Header" ;
1820import { ART_TYPES } from "@/constants/art" ;
21+ import { useUploadImage } from "@/hooks/useImageUploader" ;
1922import { useRequireAuth } from "@/hooks/useRequireAuth" ;
2023import { getMyArtworkDetail , updateArtwork } from "@/services/artworks" ;
2124import type { ArtworkDetail } from "@/types/archiveDetail" ;
@@ -46,9 +49,30 @@ function getErrorMessage(error: unknown) {
4649 return error instanceof Error ? error . message : "작품 수정에 실패했습니다." ;
4750}
4851
52+ function toEditableImages ( artwork : ArtworkDetail ) : EditableArchiveImage [ ] {
53+ return artwork . imageIds . map ( ( id , index ) => ( {
54+ kind : "existing" ,
55+ id,
56+ url : normalizeImageUrl ( artwork . imageUrls [ index ] ) ,
57+ } ) ) ;
58+ }
59+
60+ function resolveThumbnailIndex (
61+ images : EditableArchiveImage [ ] ,
62+ originalImageIds : number [ ] ,
63+ originalThumbnailIndex : number | null
64+ ) {
65+ const thumbnailImageId = originalImageIds [ originalThumbnailIndex ?? 0 ] ;
66+ const currentThumbnailIndex = images . findIndex (
67+ image => image . kind === "existing" && image . id === thumbnailImageId
68+ ) ;
69+ return currentThumbnailIndex >= 0 ? currentThumbnailIndex : 0 ;
70+ }
71+
4972function ArtEditForm ( { artwork, artworkId } : { artwork : ArtworkDetail ; artworkId : string } ) {
5073 const router = useRouter ( ) ;
5174 const queryClient = useQueryClient ( ) ;
75+ const { mutateAsync : uploadImage } = useUploadImage ( ) ;
5276 const [ artType , setArtType ] = useState ( artwork . artworkType ?? "" ) ;
5377 const [ title , setTitle ] = useState ( artwork . title ?? "" ) ;
5478 const [ description , setDescription ] = useState ( artwork . description ?? "" ) ;
@@ -59,11 +83,23 @@ function ArtEditForm({ artwork, artworkId }: { artwork: ArtworkDetail; artworkId
5983 const [ height , setHeight ] = useState ( artwork . heightCm ? String ( artwork . heightCm ) : "" ) ;
6084 const [ notes , setNotes ] = useState ( artwork . caution ?? "" ) ;
6185 const [ isPublic , setIsPublic ] = useState ( artwork . status === "PUBLISHED" ) ;
86+ const [ images , setImages ] = useState < EditableArchiveImage [ ] > ( ( ) => toEditableImages ( artwork ) ) ;
6287 const [ submitErrorMessage , setSubmitErrorMessage ] = useState < string | null > ( null ) ;
6388
6489 const updateMutation = useMutation ( {
65- mutationFn : ( ) =>
66- updateArtwork ( artworkId , {
90+ mutationFn : async ( ) => {
91+ const uploadedImages = await Promise . all (
92+ images . filter ( image => image . kind === "new" ) . map ( image => uploadImage ( image . file ) )
93+ ) ;
94+ let uploadedImageIndex = 0 ;
95+ const imageIds = images . map ( image => {
96+ if ( image . kind === "existing" ) {
97+ return image . id ;
98+ }
99+ return uploadedImages [ uploadedImageIndex ++ ] . imageId ;
100+ } ) ;
101+
102+ return updateArtwork ( artworkId , {
67103 title : title . trim ( ) ,
68104 artworkType : artType ,
69105 description : description . trim ( ) ,
@@ -74,10 +110,11 @@ function ArtEditForm({ artwork, artworkId }: { artwork: ArtworkDetail; artworkId
74110 depthCm : toNullableNumber ( depth ) ,
75111 createdDate : toDateString ( date ) ,
76112 isPublic,
77- imageIds : artwork . imageIds ,
78- thumbnailIndex : artwork . thumbnailIndex ?? 0 ,
113+ imageIds,
114+ thumbnailIndex : resolveThumbnailIndex ( images , artwork . imageIds , artwork . thumbnailIndex ) ,
79115 availableRegions : selectedRegions ,
80- } ) ,
116+ } ) ;
117+ } ,
81118 onSuccess : ( ) => {
82119 void queryClient . invalidateQueries ( { queryKey : [ "mypage" , "feed" ] } ) ;
83120 void queryClient . invalidateQueries ( { queryKey : [ "artwork-detail" , artworkId ] } ) ;
@@ -90,6 +127,7 @@ function ArtEditForm({ artwork, artworkId }: { artwork: ArtworkDetail; artworkId
90127 } ) ;
91128
92129 const isFormValid =
130+ images . length > 0 &&
93131 title . trim ( ) !== "" &&
94132 artType !== "" &&
95133 description . trim ( ) !== "" &&
@@ -101,27 +139,7 @@ function ArtEditForm({ artwork, artworkId }: { artwork: ArtworkDetail; artworkId
101139 < section className = "flex flex-col gap-6 px-5 py-6 pb-32" >
102140 < FieldWrapper >
103141 < Label required > 사진</ Label >
104- < div className = "flex flex-wrap gap-3" >
105- { artwork . imageUrls . map ( ( url , index ) => {
106- const imageUrl = normalizeImageUrl ( url ) ;
107- if ( ! imageUrl ) return null ;
108- return (
109- < div
110- key = { `${ imageUrl } -${ index } ` }
111- className = "border-border-primary relative h-18 w-18 overflow-hidden rounded-sm border"
112- >
113- < Image
114- src = { imageUrl }
115- alt = { `작품 이미지 ${ index + 1 } ` }
116- fill
117- sizes = "72px"
118- unoptimized
119- className = "object-cover"
120- />
121- </ div >
122- ) ;
123- } ) }
124- </ div >
142+ < EditableImageUploader images = { images } onChange = { setImages } />
125143 </ FieldWrapper >
126144
127145 < FieldWrapper >
0 commit comments