From 14f61e24947fb92dd71ec0a7196a6e815f8e66da Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 21 Jul 2025 07:54:26 +0000 Subject: (최겸)기술영업 RFQ 담당자 초대, 요구사항 반영 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../signup/tech-vendor-item-selector-dialog.tsx | 254 +++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 components/signup/tech-vendor-item-selector-dialog.tsx (limited to 'components/signup/tech-vendor-item-selector-dialog.tsx') diff --git a/components/signup/tech-vendor-item-selector-dialog.tsx b/components/signup/tech-vendor-item-selector-dialog.tsx new file mode 100644 index 00000000..a69dec5d --- /dev/null +++ b/components/signup/tech-vendor-item-selector-dialog.tsx @@ -0,0 +1,254 @@ +"use client" + +import * as React from "react" +import { useState, useEffect } from "react" +import { Search, X } from "lucide-react" + +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { Input } from "@/components/ui/input" +import { Badge } from "@/components/ui/badge" +import { ScrollArea } from "@/components/ui/scroll-area" +import { Checkbox } from "@/components/ui/checkbox" + +interface Item { + itemCode: string + itemList: string + subItemList?: string + workType?: string + shipTypes?: string +} + +interface TechVendorItemSelectorDialogProps { + open: boolean + onOpenChange: (open: boolean) => void + vendorType: string | string[] + onItemsSelected: (selectedItems: string[]) => void +} + +export function TechVendorItemSelectorDialog({ + open, + onOpenChange, + vendorType, + onItemsSelected, +}: TechVendorItemSelectorDialogProps) { + const [items, setItems] = useState([]) + const [filteredItems, setFilteredItems] = useState([]) + const [searchTerm, setSearchTerm] = useState("") + const [selectedItems, setSelectedItems] = useState>(new Set()) + const [isLoading, setIsLoading] = useState(false) + + // 벤더 타입에 따른 아이템 조회 + useEffect(() => { + if (open && vendorType) { + loadItemsByVendorType() + } + }, [open, vendorType]) + + // 검색 필터링 + useEffect(() => { + if (searchTerm.trim() === "") { + setFilteredItems(items) + } else { + const filtered = items.filter( + (item) => + item.itemList.toLowerCase().includes(searchTerm.toLowerCase()) || + (item.subItemList && item.subItemList.toLowerCase().includes(searchTerm.toLowerCase())) || + item.itemCode.toLowerCase().includes(searchTerm.toLowerCase()) + ) + setFilteredItems(filtered) + } + }, [searchTerm, items]) + + const loadItemsByVendorType = async () => { + setIsLoading(true) + try { + // 서버 액션으로 아이템 조회 + const { getItemsByVendorType } = await import("@/lib/tech-vendors/service") + + let allItems: any[] = [] + + // 여러 벤더 타입인 경우 각각 조회하여 합치기 + if (Array.isArray(vendorType)) { + for (const type of vendorType) { + const result = await getItemsByVendorType(type, "") + if (result && result.data && result.data.length > 0) { + allItems = [...allItems, ...result.data] + } + } + } else { + // 단일 벤더 타입인 경우 + const result = await getItemsByVendorType(vendorType, "") + if (result && result.data && result.data.length > 0) { + allItems = result.data + } + } + + if (allItems.length > 0) { + // 중복 제거 (itemCode 기준) + const uniqueItems = allItems.filter((item, index, self) => + index === self.findIndex(t => t.itemCode === item.itemCode) + ) + + const itemsData = uniqueItems.map((item: any) => ({ + itemCode: item.itemCode || "", + itemList: item.itemList || "", + subItemList: item.subItemList || "", + workType: item.workType || "", + shipTypes: item.shipTypes || "", + })) + setItems(itemsData) + setFilteredItems(itemsData) + } else { + setItems([]) + setFilteredItems([]) + } + } catch (error) { + console.error("아이템 조회 실패:", error) + setItems([]) + setFilteredItems([]) + } finally { + setIsLoading(false) + } + } + + const handleItemToggle = (itemCode: string) => { + const newSelected = new Set(selectedItems) + if (newSelected.has(itemCode)) { + newSelected.delete(itemCode) + } else { + newSelected.add(itemCode) + } + setSelectedItems(newSelected) + } + + const handleConfirm = () => { + const selectedItemCodes = Array.from(selectedItems) + onItemsSelected(selectedItemCodes) + onOpenChange(false) + // 상태 초기화 + setSelectedItems(new Set()) + setSearchTerm("") + } + + const handleCancel = () => { + onOpenChange(false) + // 상태 초기화 + setSelectedItems(new Set()) + setSearchTerm("") + } + + return ( + + + + 공급가능품목 선택 + + {Array.isArray(vendorType) ? vendorType.join(", ") : vendorType} 관련 아이템 중에서 공급 가능한 품목을 선택해주세요. + + + +
+ {/* 검색바 */} +
+ + setSearchTerm(e.target.value)} + className="pl-10" + /> +
+ + {/* 선택된 아이템 표시 */} + {selectedItems.size > 0 && ( +
+
선택된 아이템 ({selectedItems.size}개)
+
+ {Array.from(selectedItems).map((itemCode) => { + const item = items.find((i) => i.itemCode === itemCode) + return ( + + {item?.itemList || itemCode} + + + ) + })} +
+
+ )} + + {/* 아이템 목록 */} +
+ + {isLoading ? ( +
로딩 중...
+ ) : filteredItems.length === 0 ? ( +
+ {searchTerm ? "검색 결과가 없습니다." : "아이템이 없습니다."} +
+ ) : ( +
+ {filteredItems.map((item) => ( +
+ handleItemToggle(item.itemCode)} + className="mt-1" + /> +
+
+ {item.itemList} + + {item.itemCode} + +
+ {item.subItemList && ( +
+ {item.subItemList} +
+ )} +
+ {item.workType && ( + 공종: {item.workType} + )} + {item.shipTypes && ( + 선종: {item.shipTypes} + )} +
+
+
+ ))} +
+ )} +
+
+
+ + + + + +
+
+ ) +} \ No newline at end of file -- cgit v1.2.3