"use client" import * as React from "react" import { Check, ChevronsUpDown, Loader } from "lucide-react" import { Button } from "@/components/ui/button" import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from "@/components/ui/command" import { Popover, PopoverTrigger, PopoverContent } from "@/components/ui/popover" import { cn } from "@/lib/utils" import { useDebounce } from "@/hooks/use-debounce" import { getBudgetaryRfqs, type BudgetaryRfq } from "../service" interface BudgetaryRfqSelectorProps { selectedRfqId?: number; onRfqSelect: (rfq: BudgetaryRfq | null) => void; placeholder?: string; } export function BudgetaryRfqSelector({ selectedRfqId, onRfqSelect, placeholder = "Budgetary RFQ 선택..." }: BudgetaryRfqSelectorProps) { const [searchTerm, setSearchTerm] = React.useState(""); const debouncedSearchTerm = useDebounce(searchTerm, 300); const [open, setOpen] = React.useState(false); const [loading, setLoading] = React.useState(false); const [budgetaryRfqs, setBudgetaryRfqs] = React.useState([]); const [selectedRfq, setSelectedRfq] = React.useState(null); const [page, setPage] = React.useState(1); const [hasMore, setHasMore] = React.useState(true); const [totalCount, setTotalCount] = React.useState(0); const listRef = React.useRef(null); // 초기 선택된 RFQ가 있을 경우 로드 React.useEffect(() => { if (selectedRfqId && open) { const loadSelectedRfq = async () => { try { const result = await getBudgetaryRfqs({ limit: 1, // null을 undefined로 변환하여 타입 오류 해결 projectId: selectedRfq?.projectId ?? undefined }); if ('rfqs' in result && result.rfqs) { // 옵셔널 체이닝 또는 조건부 검사로 undefined 체크 const foundRfq = result.rfqs.find(rfq => rfq.id === selectedRfqId); if (foundRfq) { setSelectedRfq(foundRfq); } } } catch (error) { console.error("선택된 RFQ 로드 오류:", error); } }; if (!selectedRfq || selectedRfq.id !== selectedRfqId) { loadSelectedRfq(); } } }, [selectedRfqId, open, selectedRfq]); // 검색어 변경 시 데이터 리셋 및 재로드 React.useEffect(() => { if (open) { setPage(1); setHasMore(true); setBudgetaryRfqs([]); loadBudgetaryRfqs(1, true); } }, [debouncedSearchTerm, open]); // 데이터 로드 함수 const loadBudgetaryRfqs = async (pageToLoad: number, reset = false) => { if (!open) return; setLoading(true); try { const limit = 20; // 한 번에 로드할 항목 수 const result = await getBudgetaryRfqs({ search: debouncedSearchTerm, limit, offset: (pageToLoad - 1) * limit, }); if ('rfqs' in result && result.rfqs) { if (reset) { setBudgetaryRfqs(result.rfqs); } else { setBudgetaryRfqs(prev => [...prev, ...result.rfqs]); } setTotalCount(result.totalCount); setHasMore(result.rfqs.length === limit && (pageToLoad * limit) < result.totalCount); setPage(pageToLoad); } } catch (error) { console.error("Budgetary RFQs 로드 오류:", error); } finally { setLoading(false); } }; // 무한 스크롤 처리 const handleScroll = () => { if (listRef.current) { const { scrollTop, scrollHeight, clientHeight } = listRef.current; // 스크롤이 90% 이상 내려갔을 때 다음 페이지 로드 if (scrollTop + clientHeight >= scrollHeight * 0.9 && !loading && hasMore) { loadBudgetaryRfqs(page + 1); } } }; // RFQ를 프로젝트별로 그룹화하는 함수 const groupRfqsByProject = (rfqs: BudgetaryRfq[]) => { const groups: Record = {}; // 'No Project' 그룹 기본 생성 groups['no-project'] = { projectId: null, projectCode: null, projectName: null, rfqs: [] }; // 프로젝트별로 RFQ 그룹화 rfqs.forEach(rfq => { const key = rfq.projectId ? `project-${rfq.projectId}` : 'no-project'; if (!groups[key] && rfq.projectId) { groups[key] = { projectId: rfq.projectId, projectCode: rfq.projectCode, projectName: rfq.projectName, rfqs: [] }; } groups[key].rfqs.push(rfq); }); // 필터링된 결과가 있는 그룹만 남기기 return Object.values(groups).filter(group => group.rfqs.length > 0); }; // 그룹화된 RFQ 목록 const groupedRfqs = React.useMemo(() => { return groupRfqsByProject(budgetaryRfqs); }, [budgetaryRfqs]); // RFQ 선택 처리 const handleRfqSelect = (rfq: BudgetaryRfq | null) => { setSelectedRfq(rfq); onRfqSelect(rfq); setOpen(false); }; return ( 검색 결과가 없습니다 handleRfqSelect(null)} > 선택 안함 {groupedRfqs.map((group, index) => ( {group.rfqs.map((rfq) => ( handleRfqSelect(rfq)} > {rfq.rfqCode || ""} - {rfq.description || ""} ))} ))} {loading && (
)} {!loading && !hasMore && budgetaryRfqs.length > 0 && (
총 {totalCount}개 중 {budgetaryRfqs.length}개 표시됨
)}
); }