diff --git a/frontend/components/report/designer/ReportDesignerToolbar.tsx b/frontend/components/report/designer/ReportDesignerToolbar.tsx index dba01fbb..484dae80 100644 --- a/frontend/components/report/designer/ReportDesignerToolbar.tsx +++ b/frontend/components/report/designer/ReportDesignerToolbar.tsx @@ -42,6 +42,16 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog"; import { SaveAsTemplateModal } from "./SaveAsTemplateModal"; import { reportApi } from "@/lib/api/reportApi"; @@ -93,6 +103,8 @@ export function ReportDesignerToolbar() { } = useReportDesigner(); const [showPreview, setShowPreview] = useState(false); const [showSaveAsTemplate, setShowSaveAsTemplate] = useState(false); + const [showBackConfirm, setShowBackConfirm] = useState(false); + const [showResetConfirm, setShowResetConfirm] = useState(false); const { toast } = useToast(); // 버튼 활성화 조건 @@ -120,16 +132,14 @@ export function ReportDesignerToolbar() { router.push("/admin/report"); }; - const handleReset = async () => { - if (confirm("현재 변경사항을 모두 취소하고 마지막 저장 상태로 되돌리시겠습니까?")) { - await loadLayout(); - } + const handleResetConfirm = async () => { + setShowResetConfirm(false); + await loadLayout(); }; - const handleBack = () => { - if (confirm("저장하지 않은 변경사항이 있을 수 있습니다. 목록으로 돌아가시겠습니까?")) { - router.push("/admin/report"); - } + const handleBackConfirm = () => { + setShowBackConfirm(false); + router.push("/admin/report"); }; const handleSaveAsTemplate = async (data: { @@ -193,7 +203,7 @@ export function ReportDesignerToolbar() { <>
- @@ -437,7 +447,7 @@ export function ReportDesignerToolbar() { - @@ -491,6 +501,40 @@ export function ReportDesignerToolbar() { onClose={() => setShowSaveAsTemplate(false)} onSave={handleSaveAsTemplate} /> + + {/* 목록으로 돌아가기 확인 모달 */} + + + + 목록으로 돌아가기 + + 저장하지 않은 변경사항이 있을 수 있습니다. +
+ 목록으로 돌아가시겠습니까? +
+
+ + 취소 + 확인 + +
+
+ + {/* 초기화 확인 모달 */} + + + + 초기화 + + 현재 변경사항을 모두 취소하고 마지막 저장 상태로 되돌리시겠습니까? + + + + 취소 + 확인 + + + ); } diff --git a/frontend/components/report/designer/TemplatePalette.tsx b/frontend/components/report/designer/TemplatePalette.tsx index 268b2dcc..27a062ad 100644 --- a/frontend/components/report/designer/TemplatePalette.tsx +++ b/frontend/components/report/designer/TemplatePalette.tsx @@ -3,6 +3,16 @@ import { useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import { Trash2, Loader2, RefreshCw } from "lucide-react"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog"; import { useReportDesigner } from "@/contexts/ReportDesignerContext"; import { reportApi } from "@/lib/api/reportApi"; import { useToast } from "@/hooks/use-toast"; @@ -19,6 +29,7 @@ export function TemplatePalette() { const [customTemplates, setCustomTemplates] = useState([]); const [isLoading, setIsLoading] = useState(false); const [deletingId, setDeletingId] = useState(null); + const [deleteTarget, setDeleteTarget] = useState<{ id: string; name: string } | null>(null); const { toast } = useToast(); const fetchTemplates = async () => { @@ -49,14 +60,18 @@ export function TemplatePalette() { await applyTemplate(templateId); }; - const handleDeleteTemplate = async (templateId: string, templateName: string) => { - if (!confirm(`"${templateName}" 템플릿을 삭제하시겠습니까?`)) { - return; - } + const handleDeleteClick = (templateId: string, templateName: string) => { + setDeleteTarget({ id: templateId, name: templateName }); + }; + + const handleDeleteConfirm = async () => { + if (!deleteTarget) return; + + setDeletingId(deleteTarget.id); + setDeleteTarget(null); - setDeletingId(templateId); try { - const response = await reportApi.deleteTemplate(templateId); + const response = await reportApi.deleteTemplate(deleteTarget.id); if (response.success) { toast({ title: "성공", @@ -108,7 +123,7 @@ export function TemplatePalette() { size="sm" onClick={(e) => { e.stopPropagation(); - handleDeleteTemplate(template.template_id, template.template_name_kor); + handleDeleteClick(template.template_id, template.template_name_kor); }} disabled={deletingId === template.template_id} className="absolute top-1/2 right-1 h-6 w-6 -translate-y-1/2 p-0 opacity-0 transition-opacity group-hover:opacity-100" @@ -123,6 +138,29 @@ export function TemplatePalette() { )) )}
+ + {/* 삭제 확인 모달 */} + !open && setDeleteTarget(null)}> + + + 템플릿 삭제 + + "{deleteTarget?.name}" 템플릿을 삭제하시겠습니까? +
+ 삭제된 템플릿은 복구할 수 없습니다. +
+
+ + 취소 + + 삭제 + + +
+
); }