103 lines
3.5 KiB
TypeScript
103 lines
3.5 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useCallback, useRef } from "react";
|
|
import { ReportMaster } from "@/types/report";
|
|
import { reportApi } from "@/lib/api/reportApi";
|
|
import { useToast } from "@/hooks/use-toast";
|
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
|
|
import { Button } from "@/components/ui/button";
|
|
import { useUnsavedChangesGuard, UnsavedChangesDialog } from "@/components/common/UnsavedChangesGuard";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Loader2 } from "lucide-react";
|
|
|
|
interface ReportCopyModalProps {
|
|
report: ReportMaster;
|
|
onClose: () => void;
|
|
onSuccess: () => void;
|
|
}
|
|
|
|
export function ReportCopyModal({ report, onClose, onSuccess }: ReportCopyModalProps) {
|
|
const [newName, setNewName] = useState(`${report.report_name_kor} (복사)`);
|
|
const [isCopying, setIsCopying] = useState(false);
|
|
const initialNameRef = useRef(`${report.report_name_kor} (복사)`);
|
|
const { toast } = useToast();
|
|
|
|
const guard = useUnsavedChangesGuard({
|
|
hasChanges: () => !isCopying && newName !== initialNameRef.current,
|
|
onClose,
|
|
title: "입력된 내용이 있습니다",
|
|
description: "입력된 내용이 저장되지 않습니다. 정말 닫으시겠습니까?",
|
|
});
|
|
|
|
const handleCopy = async () => {
|
|
const trimmed = newName.trim();
|
|
if (!trimmed) {
|
|
toast({ title: "오류", description: "리포트 이름을 입력해주세요.", variant: "destructive" });
|
|
return;
|
|
}
|
|
|
|
setIsCopying(true);
|
|
try {
|
|
const response = await reportApi.copyReport(report.report_id, trimmed);
|
|
if (response.success) {
|
|
toast({ title: "성공", description: "리포트가 복사되었습니다." });
|
|
onSuccess();
|
|
}
|
|
} catch (error: any) {
|
|
toast({
|
|
title: "오류",
|
|
description: error.message || "리포트 복사에 실패했습니다.",
|
|
variant: "destructive",
|
|
});
|
|
} finally {
|
|
setIsCopying(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Dialog open onOpenChange={guard.handleOpenChange}>
|
|
<DialogContent className="sm:max-w-lg">
|
|
<DialogHeader>
|
|
<DialogTitle className="text-lg">리포트 복사</DialogTitle>
|
|
</DialogHeader>
|
|
<div className="space-y-5 py-3">
|
|
<div className="space-y-2.5">
|
|
<Label htmlFor="copy-name" className="text-base">
|
|
새 리포트 이름
|
|
</Label>
|
|
<Input
|
|
id="copy-name"
|
|
value={newName}
|
|
onChange={(e) => setNewName(e.target.value)}
|
|
onKeyDown={(e) => e.key === "Enter" && !isCopying && handleCopy()}
|
|
placeholder="리포트 이름 입력"
|
|
className="h-11 text-base"
|
|
autoFocus
|
|
/>
|
|
</div>
|
|
</div>
|
|
<DialogFooter>
|
|
<Button variant="outline" onClick={guard.tryClose} disabled={isCopying} className="text-base">
|
|
취소
|
|
</Button>
|
|
<Button onClick={handleCopy} disabled={isCopying} className="text-base">
|
|
{isCopying ? (
|
|
<>
|
|
<Loader2 className="mr-2 h-5 w-5 animate-spin" />
|
|
복사 중...
|
|
</>
|
|
) : (
|
|
"복사"
|
|
)}
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
|
|
<UnsavedChangesDialog guard={guard} />
|
|
</>
|
|
);
|
|
}
|