ERP-node/frontend/components/dataflow/node-editor/dialogs/SaveConfirmDialog.tsx

202 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
/**
* 저장 확인 다이얼로그
*
* 경고가 있을 때 저장 전 확인을 받습니다
*/
import { memo } from "react";
import { AlertTriangle, AlertCircle, Info } from "lucide-react";
import type { FlowValidation } from "@/lib/utils/flowValidation";
import { summarizeValidations } from "@/lib/utils/flowValidation";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { ScrollArea } from "@/components/ui/scroll-area";
interface SaveConfirmDialogProps {
open: boolean;
validations: FlowValidation[];
onConfirm: () => void;
onCancel: () => void;
}
export const SaveConfirmDialog = memo(
({ open, validations, onConfirm, onCancel }: SaveConfirmDialogProps) => {
const summary = summarizeValidations(validations);
// 오류가 있으면 저장 불가
if (summary.hasBlockingIssues) {
return (
<Dialog open={open} onOpenChange={onCancel}>
<DialogContent className="max-w-[95vw] sm:max-w-[500px]">
<DialogHeader>
<DialogTitle className="flex items-center gap-2 text-base sm:text-lg">
<AlertCircle className="h-5 w-5 text-red-500" />
</DialogTitle>
<DialogDescription className="text-xs sm:text-sm">
</DialogDescription>
</DialogHeader>
<div className="space-y-3">
<div className="flex items-center gap-2">
<Badge variant="destructive" className="gap-1">
<AlertCircle className="h-3 w-3" />
{summary.errorCount}
</Badge>
{summary.warningCount > 0 && (
<Badge className="gap-1 bg-yellow-500 hover:bg-yellow-600">
<AlertTriangle className="h-3 w-3" />
{summary.warningCount}
</Badge>
)}
</div>
<ScrollArea className="max-h-[300px]">
<div className="space-y-2">
{validations
.filter((v) => v.severity === "error")
.map((validation, index) => (
<div
key={index}
className="rounded-lg border-2 border-red-200 bg-red-50 p-3"
>
<div className="mb-1 text-xs font-medium text-red-600">
{validation.type}
</div>
<div className="text-sm text-red-800">
{validation.message}
</div>
</div>
))}
</div>
</ScrollArea>
<p className="text-xs text-gray-500">
.
.
</p>
</div>
<DialogFooter className="gap-2 sm:gap-0">
<Button
onClick={onCancel}
className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
// 경고만 있는 경우 - 저장 가능하지만 확인 필요
return (
<Dialog open={open} onOpenChange={onCancel}>
<DialogContent className="max-w-[95vw] sm:max-w-[500px]">
<DialogHeader>
<DialogTitle className="flex items-center gap-2 text-base sm:text-lg">
<AlertTriangle className="h-5 w-5 text-yellow-500" />
</DialogTitle>
<DialogDescription className="text-xs sm:text-sm">
{summary.warningCount + summary.infoCount}
</DialogDescription>
</DialogHeader>
<div className="space-y-3">
<div className="flex items-center gap-2">
{summary.warningCount > 0 && (
<Badge className="gap-1 bg-yellow-500 hover:bg-yellow-600">
<AlertTriangle className="h-3 w-3" />
{summary.warningCount}
</Badge>
)}
{summary.infoCount > 0 && (
<Badge variant="secondary" className="gap-1">
<Info className="h-3 w-3" />
{summary.infoCount}
</Badge>
)}
</div>
<ScrollArea className="max-h-[300px]">
<div className="space-y-2">
{validations
.filter((v) => v.severity === "warning")
.map((validation, index) => (
<div
key={index}
className="rounded-lg border-2 border-yellow-200 bg-yellow-50 p-3"
>
<div className="mb-1 text-xs font-medium text-yellow-600">
{validation.type}
</div>
<div className="text-sm text-yellow-800">
{validation.message}
</div>
</div>
))}
{validations
.filter((v) => v.severity === "info")
.map((validation, index) => (
<div
key={index}
className="rounded-lg border-2 border-blue-200 bg-blue-50 p-3"
>
<div className="mb-1 text-xs font-medium text-blue-600">
{validation.type}
</div>
<div className="text-sm text-blue-800">
{validation.message}
</div>
</div>
))}
</div>
</ScrollArea>
<div className="rounded-lg bg-gray-50 p-3">
<p className="text-xs text-gray-600">
.
<br />
?
</p>
</div>
</div>
<DialogFooter className="gap-2 sm:gap-0">
<Button
variant="outline"
onClick={onCancel}
className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
>
</Button>
<Button
onClick={onConfirm}
className="h-8 flex-1 bg-yellow-500 text-xs hover:bg-yellow-600 sm:h-10 sm:flex-none sm:text-sm"
>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
);
SaveConfirmDialog.displayName = "SaveConfirmDialog";