@@ -78,6 +78,92 @@ function Toast({ message, type, isVisible, onClose }: ToastProps) {
7878 ) ;
7979}
8080
81+ interface DeleteModalProps {
82+ isOpen : boolean
83+ childId : number
84+ childName : string
85+ onClose : ( ) => void
86+ onDeleteRelation : ( childId : number ) => void
87+ onDeleteChild : ( childId : number ) => void
88+ }
89+
90+ function DeleteModal ( { isOpen, childId, childName, onClose, onDeleteRelation, onDeleteChild } : DeleteModalProps ) {
91+ const [ isDeleting , setIsDeleting ] = useState ( false )
92+ const [ deleteType , setDeleteType ] = useState < 'relation' | 'child' | null > ( null )
93+
94+ const handleDelete = async ( type : 'relation' | 'child' ) => {
95+ setIsDeleting ( true )
96+ setDeleteType ( type )
97+
98+ try {
99+ if ( type === 'relation' ) {
100+ await onDeleteRelation ( childId )
101+ } else {
102+ await onDeleteChild ( childId )
103+ }
104+ } finally {
105+ setIsDeleting ( false )
106+ setDeleteType ( null )
107+ onClose ( )
108+ }
109+ }
110+
111+ if ( ! isOpen ) return null
112+
113+ return (
114+ < div className = "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50" >
115+ < div className = "bg-white rounded-2xl p-6 mx-4 max-w-sm w-full" >
116+ < h3 className = "text-lg font-semibold mb-4" > 삭제 옵션 선택</ h3 >
117+ < p className = "text-sm text-gray-600 mb-6" >
118+ < strong > { childName } </ strong > 에 대한 삭제 옵션을 선택해주세요.
119+ </ p >
120+
121+ < div className = "space-y-3 mb-6" >
122+ < button
123+ onClick = { ( ) => handleDelete ( 'relation' ) }
124+ disabled = { isDeleting }
125+ className = "w-full p-4 border border-gray-200 rounded-lg text-left hover:bg-gray-50 disabled:opacity-50"
126+ >
127+ < div className = "flex items-center justify-between" >
128+ < div >
129+ < h4 className = "font-medium text-gray-900" > 돌봄관계 삭제</ h4 >
130+ < p className = "text-sm text-gray-500" > 아이 정보는 유지하고 돌봄관계만 삭제합니다</ p >
131+ </ div >
132+ { isDeleting && deleteType === 'relation' && (
133+ < div className = "animate-spin rounded-full h-4 w-4 border-b-2 border-[#FF6F71]" > </ div >
134+ ) }
135+ </ div >
136+ </ button >
137+
138+ < button
139+ onClick = { ( ) => handleDelete ( 'child' ) }
140+ disabled = { isDeleting }
141+ className = "w-full p-4 border border-red-200 rounded-lg text-left hover:bg-red-50 disabled:opacity-50"
142+ >
143+ < div className = "flex items-center justify-between" >
144+ < div >
145+ < h4 className = "font-medium text-red-600" > 아이 완전 삭제</ h4 >
146+ < p className = "text-sm text-red-500" > 아이 정보와 모든 관련 데이터를 완전히 삭제합니다</ p >
147+ </ div >
148+ { isDeleting && deleteType === 'child' && (
149+ < div className = "animate-spin rounded-full h-4 w-4 border-b-2 border-red-500" > </ div >
150+ ) }
151+ </ div >
152+ </ button >
153+ </ div >
154+
155+ < button
156+ onClick = { onClose }
157+ disabled = { isDeleting }
158+ className = "w-full py-3 text-gray-600 hover:text-gray-800 disabled:opacity-50"
159+ >
160+ 취소
161+ </ button >
162+ </ div >
163+ </ div >
164+ )
165+ }
166+
81167export default function ChildrenListPage ( ) {
82168 const router = useRouter ( )
83169 const [ activeTab , setActiveTab ] = useState ( '설정' )
@@ -94,6 +180,15 @@ export default function ChildrenListPage() {
94180 type : 'success' ,
95181 isVisible : false
96182 } )
183+ const [ deleteModal , setDeleteModal ] = useState < {
184+ isOpen : boolean
185+ childId : number
186+ childName : string
187+ } > ( {
188+ isOpen : false ,
189+ childId : 0 ,
190+ childName : ''
191+ } )
97192
98193 useEffect ( ( ) => {
99194 const fetchChildRelations = async ( ) => {
@@ -170,61 +265,57 @@ export default function ChildrenListPage() {
170265 router . push ( `/settings/edit-child?id=${ childId } ` )
171266 }
172267
173- const handleDelete = async ( childId : number , childName : string ) => {
268+ const handleDelete = ( childId : number , childName : string ) => {
269+ console . log ( 'Delete child:' , childId , childName )
174270 setOpenMenuId ( null )
175-
176- // 삭제 옵션 선택을 위한 confirm
177- const deleteType = confirm (
178- `${ childName } 을(를) 삭제하시겠습니까?\n\n` +
179- `• 돌봄관계 삭제: 아이 정보는 유지하고 돌봄관계만 삭제\n` +
180- `• 아이 완전 삭제: 아이 정보와 모든 관련 데이터를 완전히 삭제\n\n` +
181- `확인을 누르면 돌봄관계 삭제, 취소를 누르면 아이 완전 삭제가 실행됩니다.`
182- ) ;
271+ setDeleteModal ( {
272+ isOpen : true ,
273+ childId,
274+ childName
275+ } )
276+ }
183277
278+ const handleDeleteRelation = async ( childId : number ) => {
184279 try {
185- if ( deleteType ) {
186- // 돌봄관계 삭제
187- const response = await fetch ( `${ apiBaseUrl } /api/childRelations/${ childId } ` , {
188- method : 'DELETE' ,
189- credentials : 'include' ,
190- headers : {
191- 'Content-Type' : 'application/json'
192- }
193- } ) ;
194-
195- if ( ! response . ok ) {
196- throw new Error ( `관계 삭제 실패: ${ response . status } ` ) ;
280+ const response = await fetch ( `${ apiBaseUrl } /api/childRelations/${ childId } ` , {
281+ method : 'DELETE' ,
282+ credentials : 'include' ,
283+ headers : {
284+ 'Content-Type' : 'application/json'
197285 }
286+ } )
198287
199- setChildrenData ( prev => prev . filter ( child => child . id !== childId ) ) ;
200- showToast ( '돌봄관계가 삭제되었습니다.' , 'success' ) ;
201- } else {
202- // 아이 완전 삭제
203- const finalConfirm = confirm (
204- `정말로 ${ childName } 의 모든 정보를 완전히 삭제하시겠습니까?\n\n` +
205- `이 작업은 되돌릴 수 없습니다.`
206- ) ;
207-
208- if ( finalConfirm ) {
209- const response = await fetch ( `${ apiBaseUrl } /api/children/${ childId } ` , {
210- method : 'DELETE' ,
211- credentials : 'include' ,
212- headers : {
213- 'Content-Type' : 'application/json'
214- }
215- } ) ;
216-
217- if ( ! response . ok ) {
218- throw new Error ( `아이 삭제 실패: ${ response . status } ` ) ;
219- }
288+ if ( ! response . ok ) {
289+ throw new Error ( `관계 삭제 실패: ${ response . status } ` )
290+ }
220291
221- setChildrenData ( prev => prev . filter ( child => child . id !== childId ) ) ;
222- showToast ( '아이가 완전히 삭제되었습니다.' , 'success' ) ;
292+ setChildrenData ( prev => prev . filter ( child => child . id !== childId ) )
293+ showToast ( '돌봄관계가 삭제되었습니다.' , 'success' )
294+ } catch ( error ) {
295+ console . error ( '관계 삭제 실패:' , error )
296+ showToast ( '돌봄관계 삭제에 실패했습니다.' , 'error' )
297+ }
298+ }
299+
300+ const handleDeleteChild = async ( childId : number ) => {
301+ try {
302+ const response = await fetch ( `${ apiBaseUrl } /api/children/${ childId } ` , {
303+ method : 'DELETE' ,
304+ credentials : 'include' ,
305+ headers : {
306+ 'Content-Type' : 'application/json'
223307 }
308+ } )
309+
310+ if ( ! response . ok ) {
311+ throw new Error ( `아이 삭제 실패: ${ response . status } ` )
224312 }
313+
314+ setChildrenData ( prev => prev . filter ( child => child . id !== childId ) )
315+ showToast ( '아이가 완전히 삭제되었습니다.' , 'success' )
225316 } catch ( error ) {
226- console . error ( '삭제 실패:' , error ) ;
227- showToast ( '삭제에 실패했습니다. 다시 시도해주세요. ' , 'error' ) ;
317+ console . error ( '아이 삭제 실패:' , error )
318+ showToast ( '아이 삭제에 실패했습니다.' , 'error' )
228319 }
229320 }
230321
@@ -237,6 +328,14 @@ export default function ChildrenListPage() {
237328 setOpenMenuId ( openMenuId === childId ? null : childId )
238329 }
239330
331+ const closeDeleteModal = ( ) => {
332+ setDeleteModal ( {
333+ isOpen : false ,
334+ childId : 0 ,
335+ childName : ''
336+ } )
337+ }
338+
240339 // 로딩 상태 렌더링
241340 if ( isLoading ) {
242341 return (
@@ -322,7 +421,7 @@ export default function ChildrenListPage() {
322421 { childrenData . map ( ( child ) => (
323422 < div
324423 key = { child . id }
325- className = "bg-white rounded-2xl p-5 border border-gray-100 relative"
424+ className = "bg-white rounded-2xl p-5 border border-gray-100 relative shadow-sm "
326425 >
327426 < div className = "flex items-center justify-between" >
328427 < div className = "flex-1 min-w-0" >
@@ -392,6 +491,15 @@ export default function ChildrenListPage() {
392491 </ div >
393492
394493 < NavigationBar activeTab = { activeTab } onTabChange = { setActiveTab } />
494+
495+ < DeleteModal
496+ isOpen = { deleteModal . isOpen }
497+ childId = { deleteModal . childId }
498+ childName = { deleteModal . childName }
499+ onClose = { closeDeleteModal }
500+ onDeleteRelation = { handleDeleteRelation }
501+ onDeleteChild = { handleDeleteChild }
502+ />
395503 </ Container >
396504 )
397505}
0 commit comments