UX 개선 - 입력값 검증 및 confirm을 모달로 변경
This commit is contained in:
parent
7875d8ab86
commit
da195200a8
|
|
@ -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() {
|
|||
<>
|
||||
<div className="flex items-center justify-between border-b bg-white px-4 py-3 shadow-sm">
|
||||
<div className="flex items-center gap-4">
|
||||
<Button variant="ghost" size="sm" onClick={handleBack} className="gap-2">
|
||||
<Button variant="ghost" size="sm" onClick={() => setShowBackConfirm(true)} className="gap-2">
|
||||
<ArrowLeft className="h-4 w-4" />
|
||||
목록으로
|
||||
</Button>
|
||||
|
|
@ -437,7 +447,7 @@ export function ReportDesignerToolbar() {
|
|||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<Button variant="outline" size="sm" onClick={handleReset} className="gap-2">
|
||||
<Button variant="outline" size="sm" onClick={() => setShowResetConfirm(true)} className="gap-2">
|
||||
<RotateCcw className="h-4 w-4" />
|
||||
초기화
|
||||
</Button>
|
||||
|
|
@ -491,6 +501,40 @@ export function ReportDesignerToolbar() {
|
|||
onClose={() => setShowSaveAsTemplate(false)}
|
||||
onSave={handleSaveAsTemplate}
|
||||
/>
|
||||
|
||||
{/* 목록으로 돌아가기 확인 모달 */}
|
||||
<AlertDialog open={showBackConfirm} onOpenChange={setShowBackConfirm}>
|
||||
<AlertDialogContent className="max-w-[400px]">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>목록으로 돌아가기</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
저장하지 않은 변경사항이 있을 수 있습니다.
|
||||
<br />
|
||||
목록으로 돌아가시겠습니까?
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>취소</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={handleBackConfirm}>확인</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
|
||||
{/* 초기화 확인 모달 */}
|
||||
<AlertDialog open={showResetConfirm} onOpenChange={setShowResetConfirm}>
|
||||
<AlertDialogContent className="max-w-[400px]">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>초기화</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
현재 변경사항을 모두 취소하고 마지막 저장 상태로 되돌리시겠습니까?
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>취소</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={handleResetConfirm}>확인</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Template[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [deletingId, setDeletingId] = useState<string | null>(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() {
|
|||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 삭제 확인 모달 */}
|
||||
<AlertDialog open={!!deleteTarget} onOpenChange={(open) => !open && setDeleteTarget(null)}>
|
||||
<AlertDialogContent className="max-w-[400px]">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>템플릿 삭제</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
"{deleteTarget?.name}" 템플릿을 삭제하시겠습니까?
|
||||
<br />
|
||||
삭제된 템플릿은 복구할 수 없습니다.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>취소</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={handleDeleteConfirm}
|
||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
삭제
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue