From 47fb72704161b4b58a27c7f5c679fc44618de9a1 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Tue, 4 Nov 2025 10:03:32 +0000 Subject: (최겸) 구매 견적 내 RFQ Cancel/Delete, 연동제 적용, MRC Type 개발 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vendor/cancel-vendor-response-dialog.tsx | 208 +++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 lib/rfq-last/vendor/cancel-vendor-response-dialog.tsx (limited to 'lib/rfq-last/vendor/cancel-vendor-response-dialog.tsx') diff --git a/lib/rfq-last/vendor/cancel-vendor-response-dialog.tsx b/lib/rfq-last/vendor/cancel-vendor-response-dialog.tsx new file mode 100644 index 00000000..414cfa4b --- /dev/null +++ b/lib/rfq-last/vendor/cancel-vendor-response-dialog.tsx @@ -0,0 +1,208 @@ +"use client"; + +import * as React from "react"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { cancelVendorResponse } from "@/lib/rfq-last/cancel-vendor-response-action"; +import { Loader2, AlertTriangle } from "lucide-react"; +import { Alert, AlertDescription } from "@/components/ui/alert"; + +interface CancelVendorResponseDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + rfqId: number; + selectedVendors: Array<{ + detailId: number; + vendorId: number; + vendorName: string; + vendorCode?: string | null; + }>; + onSuccess?: () => void; +} + +export function CancelVendorResponseDialog({ + open, + onOpenChange, + rfqId, + selectedVendors, + onSuccess, +}: CancelVendorResponseDialogProps) { + const [isCancelling, setIsCancelling] = React.useState(false); + const [cancelReason, setCancelReason] = React.useState(""); + const [error, setError] = React.useState(null); + const [results, setResults] = React.useState | undefined>(); + + const handleCancel = async () => { + if (!cancelReason || cancelReason.trim() === "") { + setError("취소 사유를 입력해주세요."); + return; + } + + setIsCancelling(true); + setError(null); + setResults(undefined); + + try { + const detailIds = selectedVendors.map(v => v.detailId); + const result = await cancelVendorResponse(rfqId, detailIds, cancelReason.trim()); + + if (result.results) { + setResults(result.results); + } + + if (result.success) { + // 성공 시 다이얼로그 닫기 및 콜백 호출 + setTimeout(() => { + setCancelReason(""); + onOpenChange(false); + onSuccess?.(); + }, 1500); + } else { + setError(result.message); + } + } catch (err) { + setError(err instanceof Error ? err.message : "RFQ 취소 중 오류가 발생했습니다."); + } finally { + setIsCancelling(false); + } + }; + + const handleClose = () => { + if (!isCancelling) { + setError(null); + setResults(undefined); + setCancelReason(""); + onOpenChange(false); + } + }; + + return ( + + + + RFQ 취소 + +
+ 선택된 벤더에 대한 RFQ를 취소합니다. 취소 후 해당 벤더는 더 이상 견적을 제출할 수 없습니다. +
+ + {/* 취소 대상 벤더 목록 */} + {selectedVendors.length > 0 && ( +
+

취소 대상 벤더 ({selectedVendors.length}건):

+
+ {selectedVendors.map((vendor) => ( +
+ {vendor.vendorName} + {vendor.vendorCode && ( + + ({vendor.vendorCode}) + + )} +
+ ))} +
+
+ )} + + {/* 취소 사유 입력 */} +
+ +