"use client"; import * as React from "react"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Check, ChevronsUpDown, Loader2, X, Plus, FileText, Shield, Globe, Settings } from "lucide-react"; import { cn } from "@/lib/utils"; import { toast } from "sonner"; import { addVendorsToRfq } from "../service"; import { getVendorsForSelection } from "@/lib/b-rfq/service"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Info } from "lucide-react"; import { Checkbox } from "@/components/ui/checkbox"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Separator } from "@/components/ui/separator"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; interface VendorContract { vendorId: number; agreementYn: boolean; ndaYn: boolean; gtcType: "general" | "project" | "none"; } interface AddVendorDialogProps { open: boolean; onOpenChange: (open: boolean) => void; rfqId: number; onSuccess: () => void; } export function AddVendorDialog({ open, onOpenChange, rfqId, onSuccess, }: AddVendorDialogProps) { const [isLoading, setIsLoading] = React.useState(false); const [vendorOpen, setVendorOpen] = React.useState(false); const [vendorList, setVendorList] = React.useState([]); const [selectedVendors, setSelectedVendors] = React.useState([]); const [activeTab, setActiveTab] = React.useState<"vendors" | "contracts">("vendors"); // 각 벤더별 기본계약 요구사항 상태 const [vendorContracts, setVendorContracts] = React.useState([]); // 일괄 적용용 기본값 const [defaultContract, setDefaultContract] = React.useState({ agreementYn: true, ndaYn: true, gtcType: "none" as "general" | "project" | "none" }); // 벤더 로드 const loadVendors = React.useCallback(async () => { try { const result = await getVendorsForSelection(); if (result) { setVendorList(result); } } catch (error) { console.error("Failed to load vendors:", error); toast.error("벤더 목록을 불러오는데 실패했습니다."); } }, []); React.useEffect(() => { if (open) { loadVendors(); } }, [open, loadVendors]); // 초기화 React.useEffect(() => { if (!open) { setSelectedVendors([]); setVendorContracts([]); setActiveTab("vendors"); setDefaultContract({ agreementYn: true, ndaYn: true, gtcType: "none" }); } }, [open]); // 벤더 추가 const handleAddVendor = (vendor: any) => { if (!selectedVendors.find(v => v.id === vendor.id)) { const updatedVendors = [...selectedVendors, vendor]; setSelectedVendors(updatedVendors); // 해당 벤더의 기본계약 설정 추가 const isInternational = vendor.country && vendor.country !== "KR" && vendor.country !== "한국"; setVendorContracts([ ...vendorContracts, { vendorId: vendor.id, agreementYn: defaultContract.agreementYn, ndaYn: defaultContract.ndaYn, gtcType: isInternational ? defaultContract.gtcType : "none" } ]); } setVendorOpen(false); }; // 벤더 제거 const handleRemoveVendor = (vendorId: number) => { setSelectedVendors(selectedVendors.filter(v => v.id !== vendorId)); setVendorContracts(vendorContracts.filter(c => c.vendorId !== vendorId)); }; // 개별 벤더의 계약 설정 업데이트 const updateVendorContract = (vendorId: number, field: string, value: any) => { setVendorContracts(contracts => contracts.map(c => c.vendorId === vendorId ? { ...c, [field]: value } : c ) ); }; // 모든 벤더에 일괄 적용 const applyToAll = () => { setVendorContracts(contracts => contracts.map(c => { const vendor = selectedVendors.find(v => v.id === c.vendorId); const isInternational = vendor?.country && vendor.country !== "KR" && vendor.country !== "한국"; return { ...c, agreementYn: defaultContract.agreementYn, ndaYn: defaultContract.ndaYn, gtcType: isInternational ? defaultContract.gtcType : "none" }; }) ); toast.success("모든 벤더에 기본계약 설정이 적용되었습니다."); }; // 제출 처리 const handleSubmit = async () => { if (selectedVendors.length === 0) { toast.error("최소 1개 이상의 벤더를 선택해주세요."); return; } setIsLoading(true); try { // 각 벤더별로 개별 추가 const results = await Promise.all( selectedVendors.map(async (vendor) => { const contract = vendorContracts.find(c => c.vendorId === vendor.id); return addVendorsToRfq({ rfqId, vendorIds: [vendor.id], conditions: null, contractRequirements: contract || defaultContract }); }) ); // 결과 확인 const successCount = results.filter(r => r.success).length; const failedCount = results.length - successCount; if (successCount > 0) { toast.success(

{successCount}개 벤더가 추가되었습니다.

{failedCount > 0 && (

{failedCount}개 벤더 추가 실패

)}

벤더 목록에서 '정보 일괄 입력' 버튼으로 조건을 설정하세요.

); onSuccess(); onOpenChange(false); } else { toast.error("벤더 추가에 실패했습니다."); } } catch (error) { console.error("Submit error:", error); toast.error("오류가 발생했습니다."); } finally { setIsLoading(false); } }; // 이미 선택된 벤더인지 확인 const isVendorSelected = (vendorId: number) => { return selectedVendors.some(v => v.id === vendorId); }; // 선택된 벤더가 있고 계약 탭으로 이동 가능한지 const canProceedToContracts = selectedVendors.length > 0; return ( {/* 헤더 */} 벤더 추가 견적 요청을 보낼 벤더를 선택하고 각 벤더별 기본계약 요구사항을 설정하세요. {/* 탭 */} setActiveTab(v as any)} className="flex-1 flex flex-col min-h-0"> 1. 벤더 선택 {selectedVendors.length > 0 && ( {selectedVendors.length} )} 2. 기본계약 설정 {/* 벤더 선택 탭 */} 벤더 선택 RFQ를 발송할 벤더를 선택하세요. 여러 개 선택 가능합니다.
{/* 벤더 추가 버튼 */} { e.stopPropagation(); const target = e.currentTarget; target.scrollTop += e.deltaY; }} > 검색 결과가 없습니다. {vendorList .filter(vendor => !isVendorSelected(vendor.id)) .map((vendor) => ( handleAddVendor(vendor)} >
{vendor.vendorCode} {vendor.vendorName} {vendor.country && ( {vendor.country} )}
))}
{/* 선택된 벤더 목록 */} {selectedVendors.length > 0 && (
{selectedVendors.map((vendor, index) => (
{index + 1}. {vendor.vendorCode} {vendor.vendorName} {vendor.country && ( {vendor.country} )}
))}
)} {selectedVendors.length === 0 && (

아직 선택된 벤더가 없습니다.

위 버튼을 클릭하여 벤더를 추가하세요.

)}
{/* 기본계약 설정 탭 */}
{/* 일괄 적용 카드 */} 일괄 적용 설정 모든 벤더에 동일한 설정을 적용할 수 있습니다.
setDefaultContract({ ...defaultContract, agreementYn: !!checked }) } />
setDefaultContract({ ...defaultContract, ndaYn: !!checked }) } />
setDefaultContract({ ...defaultContract, gtcType: value }) } >
{/* 개별 벤더 설정 */} 개별 벤더 기본계약 설정 각 벤더별로 다른 기본계약을 요구할 수 있습니다.
{selectedVendors.map((vendor) => { const contract = vendorContracts.find(c => c.vendorId === vendor.id); const isInternational = vendor.country && vendor.country !== "KR" && vendor.country !== "한국"; return (
{vendor.vendorCode} {vendor.vendorName} {vendor.country || "미지정"}
updateVendorContract(vendor.id, "agreementYn", !!checked) } />
updateVendorContract(vendor.id, "ndaYn", !!checked) } />
{isInternational && (
updateVendorContract(vendor.id, "gtcType", value) } >
)} {!isInternational && (
국내 업체 - GTC 불필요
)}
); })}
{/* 푸터 */} {activeTab === "vendors" && canProceedToContracts && ( )} {activeTab === "contracts" && ( )}
); }