11"use client" ;
22
33import { useEffect , useState } from "react" ;
4- import { useRouter } from "next/navigation" ;
4+ import { useRouter , useSearchParams } from "next/navigation" ;
55
66import Sidebar from "@/components/sidebar" ;
77import { Button } from "@/components/ui/button" ;
88import { Input } from "@/components/ui/input" ;
99import { TOPIC } from "@/constants/topic" ;
1010import { invalidateMany , invalidateQueries } from "@/lib/tanstack" ;
11+ import {
12+ useRemoveCustomSticker ,
13+ useUpdateCustomSticker ,
14+ } from "@/lib/tanstack/mutation/custom-sticker" ;
1115import { useRemoveTopic , useUpdateTopic } from "@/lib/tanstack/mutation/topic" ;
1216import { useTopicStore } from "@/lib/zustand/topic-store" ;
1317import { containsMarkdown , markdownToHtml } from "@/utils/markdown" ;
@@ -29,16 +33,31 @@ import RemoveDialogContent from "../remove-dialog-content";
2933
3034export default function EditTopicSidebar ( ) {
3135 const router = useRouter ( ) ;
36+ const searchParams = useSearchParams ( ) ;
37+ const topicId = searchParams . get ( "id" ) ;
3238
3339 const [ title , setTitle ] = useState ( "" ) ;
3440 const [ isDeleteModalOpen , setIsDeleteModalOpen ] = useState ( false ) ;
3541
42+ // 토픽 관련 hook
3643 const { mutateAsync : updateTopic , isPending : isUpdatePending } = useUpdateTopic ( ) ;
3744 const { mutateAsync : removeTopic , isPending : isDeletePending } = useRemoveTopic ( ) ;
45+
46+ // 스티커 관련 hook
47+ const { mutateAsync : updateCustomSticker , isPending : isUpdateCustomStickerPending } =
48+ useUpdateCustomSticker ( ) ;
49+ const { mutateAsync : removeCustomSticker , isPending : isDeleteCustomStickerPending } =
50+ useRemoveCustomSticker ( ) ;
51+
3852 const { setEditingTopic, setShowEditTopicSidebar, editingTopic, showEditTopicSidebar } =
3953 useTopicStore ( ) ;
4054
41- const buttonDisabled = isUpdatePending || isDeletePending ;
55+ const buttonDisabled =
56+ isUpdatePending ||
57+ isDeletePending ||
58+ isUpdateCustomStickerPending ||
59+ isDeleteCustomStickerPending ;
60+ const currentType = editingTopic ?. type === "custom_sticker" ? "스티커" : "토픽" ;
4261
4362 const onClose = ( ) => {
4463 setEditingTopic ( null ) ;
@@ -109,28 +128,42 @@ export default function EditTopicSidebar() {
109128 } , [ editingTopic , editor ] ) ;
110129
111130 const onSave = async ( ) => {
112- if ( ! editingTopic || ! editor ) return errorToast ( "토픽 정보가 없어요." ) ;
131+ if ( ! editingTopic || ! editor ) return errorToast ( ` ${ currentType } 정보가 없어요.` ) ;
113132
114133 try {
115134 const content = editor . getHTML ( ) ;
116135 // TODO: editingTopic.type에 따라 API 요청 다르게
117- await updateTopic (
118- {
119- id : editingTopic . id ,
120- title,
121- content,
122- } ,
123- {
124- onSuccess : async ( ) => {
125- successToast ( "토픽이 성공적으로 수정되었어요." ) ;
126- await invalidateMany ( [
127- [ TOPIC . GET_ALL_TOPICS ] ,
128- [ TOPIC . GET_TOPIC_BY_ID , editingTopic ?. id . toString ( ) ] ,
129- ] ) ;
130- onClose ( ) ;
136+ if ( editingTopic . type === "topic" ) {
137+ await updateTopic (
138+ {
139+ id : editingTopic . id ,
140+ title,
141+ content,
131142 } ,
132- }
133- ) ;
143+ {
144+ onSuccess : async ( ) => {
145+ successToast ( "토픽이 성공적으로 수정되었어요." ) ;
146+ await invalidateMany ( [ [ TOPIC . GET_ALL_TOPICS ] , [ TOPIC . GET_TOPIC_BY_ID , topicId ] ] ) ;
147+ onClose ( ) ;
148+ } ,
149+ }
150+ ) ;
151+ } else if ( editingTopic . type === "custom_sticker" ) {
152+ await updateCustomSticker (
153+ {
154+ customStickerId : editingTopic . id ,
155+ title,
156+ content,
157+ } ,
158+ {
159+ onSuccess : async ( ) => {
160+ successToast ( "스티커가 성공적으로 수정되었어요." ) ;
161+ invalidateQueries ( [ TOPIC . GET_TOPIC_BY_ID , topicId ] ) ;
162+ onClose ( ) ;
163+ } ,
164+ }
165+ ) ;
166+ }
134167 } catch {
135168 errorToast ( "토픽 수정에 실패했어요." ) ;
136169 }
@@ -143,26 +176,39 @@ export default function EditTopicSidebar() {
143176 } ;
144177
145178 const onDelete = async ( id : number ) => {
146- await removeTopic ( id , {
147- onSuccess : ( ) => {
148- successToast ( "토픽이 성공적으로 삭제되었어요." ) ;
149- onCloseSidebar ( ) ;
150- invalidateQueries ( [ TOPIC . GET_ALL_TOPICS ] ) ;
151- revalidatePath ( `/topic?id=${ id } ` ) ;
152- router . back ( ) ;
153- } ,
154- onError : ( ) => {
155- errorToast ( "토픽 삭제에 실패했어요." ) ;
156- } ,
157- } ) ;
179+ if ( editingTopic ?. type === "topic" ) {
180+ await removeTopic ( id , {
181+ onSuccess : ( ) => {
182+ successToast ( "토픽이 성공적으로 삭제되었어요." ) ;
183+ onCloseSidebar ( ) ;
184+ invalidateQueries ( [ TOPIC . GET_ALL_TOPICS ] ) ;
185+ revalidatePath ( `/topic?id=${ id } ` ) ;
186+ router . back ( ) ;
187+ } ,
188+ onError : ( ) => {
189+ errorToast ( "토픽 삭제에 실패했어요." ) ;
190+ } ,
191+ } ) ;
192+ } else if ( editingTopic ?. type === "custom_sticker" ) {
193+ await removeCustomSticker ( id , {
194+ onSuccess : ( ) => {
195+ successToast ( "스티커가 성공적으로 삭제되었어요." ) ;
196+ onCloseSidebar ( ) ;
197+ invalidateQueries ( [ TOPIC . GET_ALL_TOPICS ] ) ;
198+ } ,
199+ onError : ( ) => {
200+ errorToast ( "스티커 삭제에 실패했어요." ) ;
201+ } ,
202+ } ) ;
203+ }
158204 } ;
159205
160206 return (
161207 < Sidebar isOpen = { showEditTopicSidebar } onClose = { onClickOutside } >
162208 < div className = "flex h-full flex-col" >
163209 { /* 헤더 */ }
164210 < div className = "flex items-center justify-between border-b p-6" >
165- < h2 className = "text-xl font-semibold" > 토픽 편집</ h2 >
211+ < h2 className = "text-xl font-semibold" > { currentType } 편집</ h2 >
166212 < Button variant = "ghost" size = "icon" onClick = { onCloseSidebar } aria-label = "사이드바 닫기" >
167213 < X size = { 24 } />
168214 </ Button >
@@ -176,7 +222,7 @@ export default function EditTopicSidebar() {
176222 < Input
177223 value = { title }
178224 onChange = { ( e ) => setTitle ( e . target . value ) }
179- placeholder = "토픽 제목을 입력하세요"
225+ placeholder = { ` ${ currentType } 제목을 입력하세요` }
180226 className = "text-base"
181227 />
182228 </ div >
0 commit comments