"use client"; import React, { useMemo, useState } from "react"; import { ChevronDown, ChevronUp, Loader2, AlertCircle, Check, Package, Search } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { cn } from "@/lib/utils"; import { SubDataLookupConfig } from "@/types/repeater"; import { useSubDataLookup } from "./useSubDataLookup"; export interface SubDataLookupPanelProps { config: SubDataLookupConfig; linkValue: string | number | null; // 상위 항목의 연결 값 (예: item_code) itemIndex: number; // 상위 항목 인덱스 onSelectionChange: (selectedItem: any | null, maxValue: number | null) => void; disabled?: boolean; className?: string; } /** * 하위 데이터 조회 패널 * 품목 선택 시 재고/단가 등 관련 데이터를 표시하고 선택할 수 있는 패널 */ export const SubDataLookupPanel: React.FC = ({ config, linkValue, itemIndex, onSelectionChange, disabled = false, className, }) => { const { data, isLoading, error, selectedItem, setSelectedItem, isInputEnabled, maxValue, isExpanded, setIsExpanded, refetch, getSelectionSummary, } = useSubDataLookup({ config, linkValue, itemIndex, enabled: !disabled, }); // 선택 핸들러 const handleSelect = (item: any) => { if (disabled) return; // 이미 선택된 항목이면 선택 해제 const newSelectedItem = selectedItem?.id === item.id ? null : item; setSelectedItem(newSelectedItem); // 최대값 계산 let newMaxValue: number | null = null; if (newSelectedItem && config.conditionalInput.maxValueField) { const val = newSelectedItem[config.conditionalInput.maxValueField]; newMaxValue = typeof val === "number" ? val : parseFloat(val) || null; } onSelectionChange(newSelectedItem, newMaxValue); }; // 컬럼 라벨 가져오기 const getColumnLabel = (columnName: string): string => { return config.lookup.columnLabels?.[columnName] || columnName; }; // 표시할 컬럼 목록 const displayColumns = config.lookup.displayColumns || []; // 요약 정보 표시용 선택 상태 const summaryText = useMemo(() => { if (!selectedItem) return null; return getSelectionSummary(); }, [selectedItem, getSelectionSummary]); // linkValue가 없으면 렌더링하지 않음 if (!linkValue) { return null; } // 인라인 모드 렌더링 if (config.ui?.expandMode === "inline" || !config.ui?.expandMode) { return (
{/* 토글 버튼 및 요약 */}
{/* 선택 요약 표시 */} {selectedItem && summaryText && (
{summaryText}
)}
{/* 확장된 패널 */} {isExpanded && (
{/* 에러 상태 */} {error && (
{error}
)} {/* 로딩 상태 */} {isLoading && (
조회 중...
)} {/* 데이터 없음 */} {!isLoading && !error && data.length === 0 && (
{config.ui?.emptyMessage || "재고 데이터가 없습니다"}
)} {/* 데이터 테이블 */} {!isLoading && !error && data.length > 0 && ( {displayColumns.map((col) => ( ))} {data.map((item, idx) => { const isSelected = selectedItem?.id === item.id; return ( handleSelect(item)} className={cn( "cursor-pointer border-t transition-colors", isSelected ? "bg-blue-50" : "hover:bg-gray-100", disabled && "cursor-not-allowed opacity-50", )} > {displayColumns.map((col) => ( ))} ); })}
선택 {getColumnLabel(col)}
{isSelected && }
{item[col] ?? "-"}
)}
)} {/* 필수 선택 안내 */} {!isInputEnabled && selectedItem && config.selection.requiredFields.length > 0 && (

{config.selection.requiredFields.map((f) => getColumnLabel(f)).join(", ")}을(를) 선택해주세요

)}
); } // 모달 모드 렌더링 if (config.ui?.expandMode === "modal") { return (
{/* 재고 조회 버튼 및 요약 */}
{/* 선택 요약 표시 */} {selectedItem && summaryText && (
{summaryText}
)}
{/* 필수 선택 안내 */} {!isInputEnabled && selectedItem && config.selection.requiredFields.length > 0 && (

{config.selection.requiredFields.map((f) => getColumnLabel(f)).join(", ")}을(를) 선택해주세요

)} {/* 모달 */} 재고 현황 출고할 재고를 선택하세요. 창고/위치별 재고 수량을 확인할 수 있습니다.
{/* 에러 상태 */} {error && (
{error}
)} {/* 로딩 상태 */} {isLoading && (
재고 조회 중...
)} {/* 데이터 없음 */} {!isLoading && !error && data.length === 0 && (
{config.ui?.emptyMessage || "해당 품목의 재고가 없습니다"}
)} {/* 데이터 테이블 */} {!isLoading && !error && data.length > 0 && ( {displayColumns.map((col) => ( ))} {data.map((item, idx) => { const isSelected = selectedItem?.id === item.id; return ( handleSelect(item)} className={cn( "cursor-pointer border-t transition-colors", isSelected ? "bg-blue-50" : "hover:bg-gray-50", disabled && "cursor-not-allowed opacity-50", )} > {displayColumns.map((col) => ( ))} ); })}
선택 {getColumnLabel(col)}
{isSelected && }
{item[col] ?? "-"}
)}
); } // 기본값: inline 모드로 폴백 (설정이 없거나 알 수 없는 모드인 경우) return (
{selectedItem && summaryText && (
{summaryText}
)}
); }; SubDataLookupPanel.displayName = "SubDataLookupPanel";