ERP-node/frontend/components/report/designer/SaveAsTemplateModal.tsx

158 lines
4.9 KiB
TypeScript
Raw Normal View History

2025-10-01 15:03:52 +09:00
"use client";
import { useState, useCallback, useEffect } from "react";
2025-10-01 15:03:52 +09:00
import {
Dialog,
DialogContent,
2025-11-12 18:51:20 +09:00
DialogDescription,
DialogFooter,
2025-10-01 15:03:52 +09:00
DialogHeader,
2025-11-12 18:51:20 +09:00
DialogTitle,
} from "@/components/ui/dialog";
2025-10-01 15:03:52 +09:00
import { Button } from "@/components/ui/button";
import { useUnsavedChangesGuard, UnsavedChangesDialog } from "@/components/common/UnsavedChangesGuard";
2025-10-01 15:03:52 +09:00
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Loader2 } from "lucide-react";
interface SaveAsTemplateModalProps {
isOpen: boolean;
onClose: () => void;
onSave: (data: { templateNameKor: string; templateNameEng?: string; description?: string }) => Promise<void>;
}
export function SaveAsTemplateModal({ isOpen, onClose, onSave }: SaveAsTemplateModalProps) {
const [formData, setFormData] = useState({
templateNameKor: "",
templateNameEng: "",
description: "",
});
const [isSaving, setIsSaving] = useState(false);
const hasInputData = useCallback(() => {
return formData.templateNameKor.trim() !== "" ||
formData.templateNameEng.trim() !== "" ||
formData.description.trim() !== "";
}, [formData]);
const guard = useUnsavedChangesGuard({
hasChanges: () => !isSaving && hasInputData(),
onClose: () => {
setFormData({ templateNameKor: "", templateNameEng: "", description: "" });
onClose();
},
title: "입력된 내용이 있습니다",
description: "입력된 내용이 저장되지 않습니다. 정말 닫으시겠습니까?",
});
2025-10-01 15:03:52 +09:00
const handleSave = async () => {
if (!formData.templateNameKor.trim()) {
alert("템플릿명을 입력해주세요.");
return;
}
setIsSaving(true);
try {
await onSave({
templateNameKor: formData.templateNameKor,
templateNameEng: formData.templateNameEng || undefined,
description: formData.description || undefined,
});
setFormData({ templateNameKor: "", templateNameEng: "", description: "" });
2025-10-01 15:03:52 +09:00
onClose();
} catch (error) {
console.error("템플릿 저장 실패:", error);
} finally {
setIsSaving(false);
}
};
return (
<>
<Dialog open={isOpen} onOpenChange={guard.handleOpenChange}>
<DialogContent className="sm:max-w-[500px]">
<DialogHeader>
<DialogTitle>릿 </DialogTitle>
<DialogDescription>
릿 .
</DialogDescription>
</DialogHeader>
2025-10-01 15:03:52 +09:00
<div className="space-y-4 py-4">
<div className="space-y-2">
<Label htmlFor="templateNameKor">
릿 () <span className="text-red-500">*</span>
</Label>
<Input
id="templateNameKor"
value={formData.templateNameKor}
onChange={(e) =>
setFormData({
...formData,
templateNameKor: e.target.value,
})
}
placeholder="예: 발주서 양식"
disabled={isSaving}
/>
</div>
2025-10-01 15:03:52 +09:00
<div className="space-y-2">
<Label htmlFor="templateNameEng">릿 ()</Label>
<Input
id="templateNameEng"
value={formData.templateNameEng}
onChange={(e) =>
setFormData({
...formData,
templateNameEng: e.target.value,
})
}
placeholder="예: Purchase Order Template"
disabled={isSaving}
/>
</div>
2025-10-01 15:03:52 +09:00
<div className="space-y-2">
<Label htmlFor="description"></Label>
<Textarea
id="description"
value={formData.description}
onChange={(e) =>
setFormData({
...formData,
description: e.target.value,
})
}
placeholder="템플릿에 대한 간단한 설명을 입력하세요"
rows={3}
disabled={isSaving}
/>
</div>
2025-10-01 15:03:52 +09:00
</div>
<DialogFooter>
<Button variant="outline" onClick={guard.tryClose} disabled={isSaving}>
</Button>
<Button onClick={handleSave} disabled={isSaving}>
{isSaving ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
...
</>
) : (
"저장"
)}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<UnsavedChangesDialog guard={guard} />
</>
2025-10-01 15:03:52 +09:00
);
}