From 50adedf48ee4674ebe00f1ee72d93485183cdc51 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Fri, 5 Sep 2025 11:44:32 +0000 Subject: (대표님, 최겸, 임수민) EDP 입력 진행률, 견적목록관리, EDP excel import 오류수정, GTC-Contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/rfq-last/vendor/add-vendor-dialog.tsx | 307 ++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 lib/rfq-last/vendor/add-vendor-dialog.tsx (limited to 'lib/rfq-last/vendor/add-vendor-dialog.tsx') diff --git a/lib/rfq-last/vendor/add-vendor-dialog.tsx b/lib/rfq-last/vendor/add-vendor-dialog.tsx new file mode 100644 index 00000000..d8745298 --- /dev/null +++ b/lib/rfq-last/vendor/add-vendor-dialog.tsx @@ -0,0 +1,307 @@ +"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 } 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"; + +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 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([]); + } + }, [open]); + + // 벤더 추가 + const handleAddVendor = (vendor: any) => { + if (!selectedVendors.find(v => v.id === vendor.id)) { + setSelectedVendors([...selectedVendors, vendor]); + } + setVendorOpen(false); + }; + + // 벤더 제거 + const handleRemoveVendor = (vendorId: number) => { + setSelectedVendors(selectedVendors.filter(v => v.id !== vendorId)); + }; + + // 제출 처리 - 벤더만 추가 + const handleSubmit = async () => { + if (selectedVendors.length === 0) { + toast.error("최소 1개 이상의 벤더를 선택해주세요."); + return; + } + + setIsLoading(true); + + try { + const vendorIds = selectedVendors.map(v => v.id); + const result = await addVendorsToRfq({ + rfqId, + vendorIds, + // 기본값으로 벤더만 추가 (상세 조건은 나중에 일괄 입력) + conditions: null, + }); + + if (result.success) { + toast.success( +
+

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

+

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

+
+ ); + onSuccess(); + onOpenChange(false); + } else { + toast.error(result.error || "벤더 추가에 실패했습니다."); + } + } catch (error) { + console.error("Submit error:", error); + toast.error("오류가 발생했습니다."); + } finally { + setIsLoading(false); + } + }; + + // 이미 선택된 벤더인지 확인 + const isVendorSelected = (vendorId: number) => { + return selectedVendors.some(v => v.id === vendorId); + }; + + return ( + + + {/* 헤더 */} + + 벤더 추가 + + 견적 요청을 보낼 벤더를 선택하세요. 조건 설정은 추가 후 일괄로 진행할 수 있습니다. + + + + {/* 컨텐츠 영역 */} +
+
+ {/* 안내 메시지 */} + + + + 여기서는 벤더만 선택합니다. 납기일, 결제조건 등의 상세 정보는 벤더 추가 후 + '정보 일괄 입력' 기능으로 한 번에 설정할 수 있습니다. + + + + {/* 벤더 선택 카드 */} + + +
+ 벤더 선택 + + {selectedVendors.length}개 선택됨 + +
+ + 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} + +
+ +
+ ))} +
+
+
+ )} + + {/* 벤더가 없는 경우 메시지 */} + {selectedVendors.length === 0 && ( +
+

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

+

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

+
+ )} +
+
+
+
+
+ + {/* 푸터 */} + + + + +
+
+ ); +} \ No newline at end of file -- cgit v1.2.3