1- import { useRef , useState } from "react" ;
1+ import { useEffect , useRef , useState } from "react" ;
22
33import Logo from "@/assets/logo.svg?react" ;
44import { Button } from "@/components/ui/button" ;
55import { Input } from "@/components/ui/input" ;
6+ import { CONTENT } from "@/constants/content" ;
67import { useReplaceNavigate } from "@/hooks/use-replace-navigate" ;
8+ import { invalidateQueries } from "@/lib/tanstack" ;
79import {
810 useFinishDetailSaveContent ,
911 useFinishDetailSaveYoutubeContent ,
12+ useUpdateContent ,
1013} from "@/lib/tanstack/mutation/content" ;
1114import { useGetCategories } from "@/lib/tanstack/query/category" ;
15+ import { useGetContentById } from "@/lib/tanstack/query/content" ;
1216import { contentSchema , type ContentSchemaType } from "@/schemas/content" ;
1317import { infoToast , successToast } from "@/utils/toast" ;
1418import { zodResolver } from "@hookform/resolvers/zod" ;
1519import { useOutsideClick } from "@repo/ui/hooks/use-outside-click" ;
1620
1721import { ArrowLeft , ChevronDown , Plus , Save , X } from "lucide-react" ;
1822import { useForm } from "react-hook-form" ;
19- import { Navigate , useLocation } from "react-router-dom" ;
23+ import { Navigate , useLocation , useSearchParams } from "react-router-dom" ;
2024
2125interface CreateContentState {
2226 thumbnail : string ;
@@ -29,11 +33,24 @@ interface CreateContentState {
2933 htmlFile : File ;
3034}
3135
36+ const DEFAULT_STATE : CreateContentState = {
37+ thumbnail : "" ,
38+ title : "" ,
39+ url : "" ,
40+ summary : "" ,
41+ memo : "" ,
42+ tags : [ ] ,
43+ category : "" ,
44+ htmlFile : new File ( [ ] , "" ) ,
45+ } ;
46+
3247export default function CreateContent ( ) {
3348 const [ isCategoryOpen , setIsCategoryOpen ] = useState < boolean > ( false ) ;
3449
3550 const { state } = useLocation ( ) as { state : CreateContentState } ;
36- const { htmlFile, ...restState } = state ;
51+ const [ searchParams ] = useSearchParams ( ) ;
52+ const id = searchParams . get ( "id" ) ;
53+ const { data : content , isLoading, isRefetching } = useGetContentById ( id ) ;
3754
3855 const tagInputRef = useRef < HTMLInputElement > ( null ) ;
3956
@@ -51,21 +68,47 @@ export default function CreateContent() {
5168 mutateAsync : mutateFinishDetailSaveYoutubeContent ,
5269 isPending : isPendingFinishDetailSaveYoutubeContent ,
5370 } = useFinishDetailSaveYoutubeContent ( ) ;
71+ const { mutateAsync : mutateUpdateContent , isPending : isPendingUpdateContent } =
72+ useUpdateContent ( ) ;
5473
5574 const { data : userCategories } = useGetCategories ( ) ;
5675
76+ const isBadRequest = ! id && ! state ;
77+
78+ // 기본값을 미리 계산
79+ const defaultValues = ( ( ) => {
80+ if ( isBadRequest || isLoading ) {
81+ return { ...DEFAULT_STATE , memo : "" } ;
82+ }
83+
84+ if ( id && ! isLoading && content ?. result ) {
85+ return content . result ;
86+ }
87+
88+ return { ...state , memo : "" } ;
89+ } ) ( ) ;
90+
5791 const {
5892 register,
5993 handleSubmit,
6094 watch,
6195 setValue,
96+ reset,
6297 formState : { errors } ,
6398 } = useForm < ContentSchemaType > ( {
6499 resolver : zodResolver ( contentSchema ) ,
65- defaultValues : { ... restState , memo : "" } ,
100+ defaultValues,
66101 } ) ;
67102
68- if ( ! state ) {
103+ // defaultValues가 변경될 때 폼 값 업데이트
104+ useEffect ( ( ) => {
105+ if ( ! isLoading && ! isRefetching ) {
106+ reset ( defaultValues ) ;
107+ }
108+ } , [ isLoading , isRefetching ] ) ;
109+
110+ // state가 없으면 리다이렉트
111+ if ( isBadRequest ) {
69112 return < Navigate to = "/bad-request" replace /> ;
70113 }
71114
@@ -75,14 +118,36 @@ export default function CreateContent() {
75118 const watchedCategory = watch ( "category" ) ;
76119 const watchedThumbnail = watch ( "thumbnail" ) ;
77120
78- const isYoutubeUrl = state . url . includes ( "youtube.com" ) ;
79- const isPending = isPendingFinishDetailSaveContent || isPendingFinishDetailSaveYoutubeContent ;
121+ const isYoutubeUrl = watch ( "url" ) . includes ( "youtube.com" ) ;
122+ const isPending =
123+ isPendingFinishDetailSaveContent ||
124+ isPendingFinishDetailSaveYoutubeContent ||
125+ isPendingUpdateContent ;
80126
81127 const onGoBack = ( ) => {
82128 navigate ( "/search-content" ) ;
83129 } ;
84130
85131 const onSave = handleSubmit ( async ( data ) => {
132+ if ( id ) {
133+ await mutateUpdateContent (
134+ {
135+ id : id as string ,
136+ ...data ,
137+ thumbnail : data . thumbnail || "" ,
138+ summary : data . summary || "" ,
139+ memo : data . memo || "" ,
140+ } ,
141+ {
142+ onSuccess : ( ) => {
143+ successToast ( "저장에 성공했어요." ) ;
144+ navigate ( "/search-content" ) ;
145+ invalidateQueries ( [ CONTENT . GET_CONTENT_BY_ID , id ] ) ;
146+ } ,
147+ }
148+ ) ;
149+ return ;
150+ }
86151 if ( isYoutubeUrl ) {
87152 await mutateFinishDetailSaveYoutubeContent (
88153 {
@@ -110,7 +175,7 @@ export default function CreateContent() {
110175 for ( const tag of data . tags ) {
111176 formData . append ( "tags" , tag ) ;
112177 }
113- formData . append ( "htmlFile" , htmlFile ) ;
178+ formData . append ( "htmlFile" , state . htmlFile ) ;
114179
115180 await mutateFinishDetailSaveContent ( formData , {
116181 onSuccess : ( ) => {
0 commit comments