summaryrefslogtreecommitdiff
path: root/lib/rfq-last/vendor/add-vendor-dialog.tsx
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-11-10 15:46:15 +0900
committerjoonhoekim <26rote@gmail.com>2025-11-10 15:46:15 +0900
commit012504b8b01dc4d8de65e049f578ba133e18f62b (patch)
tree51ed6581063386f07c78b3f61e34379a2780d23d /lib/rfq-last/vendor/add-vendor-dialog.tsx
parent1197e176493c88e301f9bb02321d815ffc717d10 (diff)
(김준회) 구매 견적: 벤더 선택기를 공용 벤더 선택기 사용하도록 변경, 벤더선택기에 국가정보 보여줄 수 있도록 확장
Diffstat (limited to 'lib/rfq-last/vendor/add-vendor-dialog.tsx')
-rw-r--r--lib/rfq-last/vendor/add-vendor-dialog.tsx231
1 files changed, 56 insertions, 175 deletions
diff --git a/lib/rfq-last/vendor/add-vendor-dialog.tsx b/lib/rfq-last/vendor/add-vendor-dialog.tsx
index bcf882a1..eddd09b0 100644
--- a/lib/rfq-last/vendor/add-vendor-dialog.tsx
+++ b/lib/rfq-last/vendor/add-vendor-dialog.tsx
@@ -11,34 +11,18 @@ import {
} 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 { Loader2, X } from "lucide-react";
import { toast } from "sonner";
import { addVendorsToRfq, getRfqItemsAction } from "../service";
-import { getVendorsForSelection } from "@/lib/b-rfq/service";
import { Badge } from "@/components/ui/badge";
import { getMrcTypeByMatnr } from "@/lib/mdg/actions/material-service";
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";
+import { VendorSelector } from "@/components/common/vendor/vendor-selector";
+import { VendorSearchItem } from "@/components/common/vendor/vendor-service";
interface VendorContract {
vendorId: number;
@@ -63,9 +47,7 @@ export function AddVendorDialog({
onSuccess,
}: AddVendorDialogProps) {
const [isLoading, setIsLoading] = React.useState(false);
- const [vendorOpen, setVendorOpen] = React.useState(false);
- const [vendorList, setVendorList] = React.useState<any[]>([]);
- const [selectedVendors, setSelectedVendors] = React.useState<any[]>([]);
+ const [selectedVendors, setSelectedVendors] = React.useState<VendorSearchItem[]>([]);
const [activeTab, setActiveTab] = React.useState<"vendors" | "contracts">("vendors");
// 각 벤더별 기본계약 요구사항 상태
@@ -148,25 +130,11 @@ export function AddVendorDialog({
}
}, [rfqId]);
- // 벤더 로드
- 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();
checkMrcType();
}
- }, [open, loadVendors, checkMrcType]);
+ }, [open, checkMrcType]);
// 초기화
React.useEffect(() => {
@@ -184,17 +152,28 @@ export function AddVendorDialog({
}, [open]);
// 외자업체 여부 확인
- const isInternationalVendor = (vendor: any) => {
+ const isInternationalVendor = (vendor: VendorSearchItem) => {
return vendor.country && vendor.country !== "KR" && vendor.country !== "한국";
};
- // 벤더 추가
- const handleAddVendor = (vendor: any) => {
- if (!selectedVendors.find(v => v.id === vendor.id)) {
- const updatedVendors = [...selectedVendors, vendor];
- setSelectedVendors(updatedVendors);
-
- // 해당 벤더의 기본계약 설정 추가
+ // 벤더 선택 변경 핸들러
+ const handleVendorsChange = (vendors: VendorSearchItem[]) => {
+ const prevVendorIds = selectedVendors.map(v => v.id);
+ const newVendorIds = vendors.map(v => v.id);
+
+ // 새로 추가된 벤더들 찾기
+ const addedVendors = vendors.filter(v => !prevVendorIds.includes(v.id));
+
+ // 제거된 벤더들 찾기
+ const removedVendorIds = prevVendorIds.filter(id => !newVendorIds.includes(id));
+
+ // 제거된 벤더의 계약 정보 삭제
+ if (removedVendorIds.length > 0) {
+ setVendorContracts(vendorContracts.filter(c => !removedVendorIds.includes(c.vendorId)));
+ }
+
+ // 새로 추가된 벤더의 계약 정보 추가
+ const newContracts = addedVendors.map(vendor => {
const isInternational = isInternationalVendor(vendor);
let shouldCheckAgreement = false;
@@ -207,23 +186,19 @@ export function AddVendorDialog({
shouldCheckAgreement = hasMrcTypeP && !isInternational;
}
- setVendorContracts([
- ...vendorContracts,
- {
- vendorId: vendor.id,
- agreementYn: shouldCheckAgreement,
- ndaYn: shouldCheckAgreement,
- gtcType: isInternational ? defaultContract.gtcType : "none"
- }
- ]);
+ return {
+ vendorId: vendor.id,
+ agreementYn: shouldCheckAgreement,
+ ndaYn: shouldCheckAgreement,
+ gtcType: isInternational ? defaultContract.gtcType : "none"
+ };
+ });
+
+ if (newContracts.length > 0) {
+ setVendorContracts([...vendorContracts, ...newContracts]);
}
- setVendorOpen(false);
- };
-
- // 벤더 제거
- const handleRemoveVendor = (vendorId: number) => {
- setSelectedVendors(selectedVendors.filter(v => v.id !== vendorId));
- setVendorContracts(vendorContracts.filter(c => c.vendorId !== vendorId));
+
+ setSelectedVendors(vendors);
};
// 개별 벤더의 계약 설정 업데이트
@@ -308,11 +283,6 @@ export function AddVendorDialog({
}
};
- // 이미 선택된 벤더인지 확인
- const isVendorSelected = (vendorId: number) => {
- return selectedVendors.some(v => v.id === vendorId);
- };
-
// 선택된 벤더가 있고 계약 탭으로 이동 가능한지
const canProceedToContracts = selectedVendors.length > 0;
@@ -354,112 +324,21 @@ export function AddVendorDialog({
</CardHeader>
<CardContent>
<div className="space-y-4">
- {/* 벤더 추가 버튼 */}
- <Popover open={vendorOpen} onOpenChange={setVendorOpen}>
- <PopoverTrigger asChild>
- <Button
- variant="outline"
- role="combobox"
- aria-expanded={vendorOpen}
- className="w-full justify-between"
- disabled={vendorList.length === 0}
- >
- <span className="flex items-center gap-2">
- <Plus className="h-4 w-4" />
- 벤더 선택하기
- </span>
- <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
- </Button>
- </PopoverTrigger>
- <PopoverContent className="w-[500px] p-0" align="start">
- <Command>
- <CommandInput placeholder="벤더명 또는 코드로 검색..." />
- <CommandList
- onWheel={(e) => {
- e.stopPropagation();
- const target = e.currentTarget;
- target.scrollTop += e.deltaY;
- }}
- >
- <CommandEmpty>검색 결과가 없습니다.</CommandEmpty>
- <CommandGroup>
- {vendorList
- .filter(vendor => !isVendorSelected(vendor.id))
- .map((vendor) => (
- <CommandItem
- key={vendor.id}
- value={`${vendor.vendorCode} ${vendor.vendorName}`}
- onSelect={() => handleAddVendor(vendor)}
- >
- <div className="flex items-center gap-2 w-full">
- <Badge variant="outline" className="shrink-0">
- {vendor.vendorCode}
- </Badge>
- <span className="truncate">{vendor.vendorName}</span>
- {vendor.country && (
- <Badge
- variant={vendor.country === "KR" || vendor.country === "한국" ? "default" : "secondary"}
- className="ml-auto"
- >
- {vendor.country}
- </Badge>
- )}
- </div>
- </CommandItem>
- ))}
- </CommandGroup>
- </CommandList>
- </Command>
- </PopoverContent>
- </Popover>
-
- {/* 선택된 벤더 목록 */}
- {selectedVendors.length > 0 && (
- <div className="space-y-2">
-
- <div className="space-y-2">
- {selectedVendors.map((vendor, index) => (
- <div
- key={vendor.id}
- className="flex items-center justify-between p-2 rounded-lg bg-secondary/50"
- >
- <div className="flex items-center gap-2">
- <span className="text-sm text-muted-foreground">
- {index + 1}.
- </span>
- <Badge variant="outline">
- {vendor.vendorCode}
- </Badge>
- <span className="text-sm font-medium">
- {vendor.vendorName}
- </span>
- {vendor.country && (
- <Badge
- variant={vendor.country === "KR" || vendor.country === "한국" ? "default" : "secondary"}
- className="text-xs"
- >
- {vendor.country}
- </Badge>
- )}
- </div>
- <Button
- variant="ghost"
- size="sm"
- onClick={() => handleRemoveVendor(vendor.id)}
- className="h-8 w-8 p-0"
- >
- <X className="h-4 w-4" />
- </Button>
- </div>
- ))}
- </div>
- </div>
- )}
+ {/* 벤더 선택 */}
+ <VendorSelector
+ selectedVendors={selectedVendors}
+ onVendorsChange={handleVendorsChange}
+ singleSelect={false}
+ placeholder="벤더명 또는 코드로 검색..."
+ noValuePlaceHolder="벤더를 선택하세요"
+ showInitialData={true}
+ includeCountry={true}
+ />
{selectedVendors.length === 0 && (
<div className="text-center py-8 text-muted-foreground">
<p className="text-sm">아직 선택된 벤더가 없습니다.</p>
- <p className="text-xs mt-1">위 버튼을 클릭하여 벤더를 추가하세요.</p>
+ <p className="text-xs mt-1">위 필드를 클릭하여 벤더를 검색하고 추가하세요.</p>
</div>
)}
</div>
@@ -564,14 +443,16 @@ export function AddVendorDialog({
<div key={vendor.id} className="border rounded-lg p-4 space-y-3">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
- <Badge variant="outline">{vendor.vendorCode}</Badge>
+ <Badge variant="outline">{vendor.vendorCode || "-"}</Badge>
<span className="font-medium">{vendor.vendorName}</span>
- <Badge
- variant={isInternational ? "secondary" : "default"}
- className="text-xs"
- >
- {vendor.country || "미지정"}
- </Badge>
+ {vendor.country && (
+ <Badge
+ variant={isInternational ? "secondary" : "default"}
+ className="text-xs"
+ >
+ {vendor.country}
+ </Badge>
+ )}
</div>
</div>