"use client"; import * as React from "react"; import { Search, Plus, X } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; import { useToast } from "@/hooks/use-toast"; import { getAllTechVendors, createTechVendorPossibleItem, getItemsByVendorType } from "@/lib/tech-vendor-possible-items/service"; interface TechVendor { id: number; vendorCode: string | null; vendorName: string; techVendorType: string; } interface ItemData { itemCode: string; itemList: string | null; workType: string | null; shipTypes?: string | null; subItemList?: string | null; } interface AddPossibleItemDialogProps { children?: React.ReactNode; onSuccess?: () => void; } export function AddPossibleItemDialog({ children, onSuccess }: AddPossibleItemDialogProps) { const { toast } = useToast(); const [open, setOpen] = React.useState(false); // 벤더 관련 상태 const [vendors, setVendors] = React.useState([]); const [filteredVendors, setFilteredVendors] = React.useState([]); const [vendorSearch, setVendorSearch] = React.useState(""); const [selectedVendor, setSelectedVendor] = React.useState(null); // 아이템 관련 상태 const [items, setItems] = React.useState([]); const [filteredItems, setFilteredItems] = React.useState([]); const [itemSearch, setItemSearch] = React.useState(""); const [selectedItems, setSelectedItems] = React.useState([]); const [isLoading, setIsLoading] = React.useState(false); // 벤더 목록 로드 React.useEffect(() => { if (open) { loadVendors(); } }, [open]); // 벤더 검색 필터링 React.useEffect(() => { if (!vendorSearch) { setFilteredVendors(vendors); } else { const filtered = vendors.filter(vendor => vendor.vendorName.toLowerCase().includes(vendorSearch.toLowerCase()) || vendor.vendorCode?.toLowerCase().includes(vendorSearch.toLowerCase()) ); setFilteredVendors(filtered); } }, [vendors, vendorSearch]); // 아이템 검색 필터링 React.useEffect(() => { if (!itemSearch) { setFilteredItems(items); } else { const filtered = items.filter(item => item.itemCode.toLowerCase().includes(itemSearch.toLowerCase()) || item.itemList?.toLowerCase().includes(itemSearch.toLowerCase()) || item.workType?.toLowerCase().includes(itemSearch.toLowerCase()) ); setFilteredItems(filtered); } }, [items, itemSearch]); const loadVendors = async () => { try { setIsLoading(true); const vendorData = await getAllTechVendors(); setVendors(vendorData); } catch (error) { console.error("Failed to load vendors:", error); toast({ title: "오류", description: "벤더 목록을 불러오는데 실패했습니다.", variant: "destructive", }); } finally { setIsLoading(false); } }; const loadItemsByVendorType = async (vendorTypes: string) => { try { setIsLoading(true); console.log("Loading items for vendor types:", vendorTypes); const itemData = await getItemsByVendorType(vendorTypes); console.log("Loaded items:", itemData.length, itemData); setItems(itemData); } catch (error) { console.error("Failed to load items:", error); toast({ title: "오류", description: "아이템 목록을 불러오는데 실패했습니다.", variant: "destructive", }); } finally { setIsLoading(false); } }; const handleVendorSelect = (vendor: TechVendor) => { setSelectedVendor(vendor); setSelectedItems([]); // 벤더 변경시 선택된 아이템 초기화 loadItemsByVendorType(vendor.techVendorType); }; const handleItemToggle = (item: ItemData) => { setSelectedItems(prev => { const isSelected = prev.some(i => i.itemCode === item.itemCode); if (isSelected) { return prev.filter(i => i.itemCode !== item.itemCode); } else { return [...prev, item]; } }); }; const handleSubmit = async () => { if (!selectedVendor || selectedItems.length === 0) return; try { setIsLoading(true); let successCount = 0; let errorCount = 0; for (const item of selectedItems) { const result = await createTechVendorPossibleItem({ vendorId: selectedVendor.id, itemCode: item.itemCode, workType: item.workType, shipTypes: item.shipTypes, itemList: item.itemList, subItemList: item.subItemList, }); if (result.success) { successCount++; } else { errorCount++; } } if (successCount > 0) { toast({ title: "성공", description: `${successCount}개의 아이템이 추가되었습니다.${errorCount > 0 ? ` (${errorCount}개 실패)` : ""}`, }); handleClose(); onSuccess?.(); } else { toast({ title: "오류", description: "아이템 추가에 실패했습니다.", variant: "destructive", }); } } catch (error) { console.error("Failed to add items:", error); toast({ title: "오류", description: "아이템 추가 중 오류가 발생했습니다.", variant: "destructive", }); } finally { setIsLoading(false); } }; const handleClose = () => { setOpen(false); setTimeout(() => { setSelectedVendor(null); setSelectedItems([]); setVendorSearch(""); setItemSearch(""); setVendors([]); setItems([]); setFilteredVendors([]); setFilteredItems([]); }, 200); }; const parseVendorTypes = (vendorType: string): string[] => { if (!vendorType) return []; // JSON 배열 형태인지 확인 if (vendorType.startsWith('[') && vendorType.endsWith(']')) { try { const parsed = JSON.parse(vendorType); return Array.isArray(parsed) ? parsed.filter(Boolean) : [vendorType]; } catch { return [vendorType]; } } // 콤마로 구분된 문자열인지 확인 if (vendorType.includes(',')) { return vendorType.split(',').map(t => t.trim()).filter(Boolean); } // 단일 문자열 return [vendorType.trim()].filter(Boolean); }; return ( {children || ( )} 벤더별 아이템 추가 왼쪽에서 벤더를 선택하고, 오른쪽에서 아이템을 선택하세요.
{/* 왼쪽: 벤더 선택/표시 */}
{!selectedVendor ? ( <>
setVendorSearch(e.target.value)} className="pl-10" />
{isLoading ? (
로딩 중...
) : filteredVendors.length === 0 ? (
검색 결과가 없습니다.
) : ( filteredVendors.map((vendor) => (
handleVendorSelect(vendor)} >
{vendor.vendorName}
{vendor.vendorCode}
{parseVendorTypes(vendor.techVendorType).map((type, index) => ( {type} ))}
)) )}
) : (
{selectedVendor?.vendorName}
{selectedVendor?.vendorCode}
{selectedVendor && parseVendorTypes(selectedVendor.techVendorType).map((type, index) => ( {type} ))}
)}
{/* 오른쪽: 아이템 선택 */}
{selectedVendor ? ( <>
setItemSearch(e.target.value)} className="pl-10" />
{selectedItems.length > 0 && (
{selectedItems.map((item) => ( {item.itemCode} { e.stopPropagation(); handleItemToggle(item); }} /> ))}
)}
{isLoading ? (
아이템 로딩 중...
) : filteredItems.length === 0 && items.length === 0 ? (
해당 벤더 타입에 대한 아이템이 없습니다.
) : filteredItems.length === 0 ? (
검색 결과가 없습니다.
) : ( filteredItems.map((item) => { const isSelected = selectedItems.some(i => i.itemCode === item.itemCode); return (
handleItemToggle(item)} >
{item.itemCode}
{item.itemList || "-"}
공종: {item.workType || "-"} {item.shipTypes && 선종: {item.shipTypes}} {item.subItemList && 서브아이템: {item.subItemList}}
); }) )}
) : (
왼쪽에서 벤더를 선택하세요.
)}
); }