Skip to content

Commit 818ccdf

Browse files
committed
feat:: 토스트 스타일 수정
1 parent ff77be0 commit 818ccdf

File tree

2 files changed

+157
-51
lines changed

2 files changed

+157
-51
lines changed

app/components/Container.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ interface ContainerProps {
77

88
export default function Container({ children, className = "" }: ContainerProps) {
99
return (
10-
<div className="min-h-screen flex items-center justify-center bg-gray-100 p-4">
11-
<div className={`w-full max-w-sm mx-auto bg-white min-h-screen flex flex-col ${className}`}>
12-
{children}
13-
</div>
10+
<div className={`min-h-screen flex flex-col items-center justify-center px-4 pt-10 pb-0 bg-white text-black ${className}`}>
11+
{children}
1412
</div>
1513
);
1614
}

app/settings/page.tsx

Lines changed: 155 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
81167
export 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

Comments
 (0)