"use client"; import { useState, useEffect, useCallback, useRef } from "react"; import { apiClient } from "@/lib/api/client"; import { SubDataLookupConfig, SubDataState } from "@/types/repeater"; const LOG_PREFIX = { INFO: "[SubDataLookup]", DEBUG: "[SubDataLookup]", WARN: "[SubDataLookup]", ERROR: "[SubDataLookup]", }; export interface UseSubDataLookupProps { config: SubDataLookupConfig; linkValue: string | number | null; // 상위 항목의 연결 값 (예: item_code) itemIndex: number; // 상위 항목 인덱스 enabled?: boolean; // 기능 활성화 여부 } export interface UseSubDataLookupReturn { data: any[]; // 조회된 하위 데이터 isLoading: boolean; // 로딩 상태 error: string | null; // 에러 메시지 selectedItem: any | null; // 선택된 하위 항목 setSelectedItem: (item: any | null) => void; // 선택 항목 설정 isInputEnabled: boolean; // 조건부 입력 활성화 여부 maxValue: number | null; // 최대 입력 가능 값 isExpanded: boolean; // 확장 상태 setIsExpanded: (expanded: boolean) => void; // 확장 상태 설정 refetch: () => void; // 데이터 재조회 getSelectionSummary: () => string; // 선택 요약 텍스트 } /** * 하위 데이터 조회 훅 * 품목 선택 시 재고/단가 등 관련 데이터를 조회하고 관리 */ export function useSubDataLookup(props: UseSubDataLookupProps): UseSubDataLookupReturn { const { config, linkValue, itemIndex, enabled = true } = props; // 상태 const [data, setData] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [selectedItem, setSelectedItem] = useState(null); const [isExpanded, setIsExpanded] = useState(false); // 이전 linkValue 추적 (중복 호출 방지) const prevLinkValueRef = useRef(null); // 데이터 조회 함수 const fetchData = useCallback(async () => { // 비활성화 또는 linkValue 없으면 스킵 if (!enabled || !config?.enabled || !linkValue) { console.log(`${LOG_PREFIX.DEBUG} 조회 스킵:`, { enabled, configEnabled: config?.enabled, linkValue, itemIndex, }); setData([]); setSelectedItem(null); return; } const { tableName, linkColumn, additionalFilters } = config.lookup; if (!tableName || !linkColumn) { console.warn(`${LOG_PREFIX.WARN} 필수 설정 누락:`, { tableName, linkColumn }); return; } console.log(`${LOG_PREFIX.INFO} 하위 데이터 조회 시작:`, { tableName, linkColumn, linkValue, itemIndex, }); setIsLoading(true); setError(null); try { // 검색 조건 구성 - 정확한 값 매칭을 위해 equals 연산자 사용 const searchCondition: Record = { [linkColumn]: { value: linkValue, operator: "equals" }, ...additionalFilters, }; console.log(`${LOG_PREFIX.DEBUG} API 요청 조건:`, { tableName, linkColumn, linkValue, searchCondition, }); const response = await apiClient.post(`/table-management/tables/${tableName}/data`, { page: 1, size: 100, search: searchCondition, autoFilter: { enabled: true }, }); if (response.data?.success) { const items = response.data?.data?.data || response.data?.data || []; console.log(`${LOG_PREFIX.DEBUG} API 응답:`, { dataCount: items.length, firstItem: items[0], tableName, }); setData(items); } else { console.warn(`${LOG_PREFIX.WARN} API 응답 실패:`, response.data); setData([]); setError("데이터 조회에 실패했습니다"); } } catch (err: any) { console.error(`${LOG_PREFIX.ERROR} 하위 데이터 조회 실패:`, { error: err.message, config, linkValue, }); setError(err.message || "데이터 조회 중 오류가 발생했습니다"); setData([]); } finally { setIsLoading(false); } }, [enabled, config, linkValue, itemIndex]); // linkValue 변경 시 데이터 조회 useEffect(() => { // 같은 값이면 스킵 if (prevLinkValueRef.current === linkValue) { return; } prevLinkValueRef.current = linkValue; // linkValue가 없으면 초기화 if (!linkValue) { setData([]); setSelectedItem(null); setIsExpanded(false); return; } fetchData(); }, [linkValue, fetchData]); // 조건부 입력 활성화 여부 계산 const isInputEnabled = useCallback((): boolean => { if (!config?.enabled || !selectedItem) { return false; } const { requiredFields, requiredMode = "all" } = config.selection; if (!requiredFields || requiredFields.length === 0) { // 필수 필드가 없으면 선택만 하면 활성화 return true; } // 선택된 항목에서 필수 필드 값 확인 if (requiredMode === "any") { // 하나라도 있으면 OK return requiredFields.some((field) => { const value = selectedItem[field]; return value !== undefined && value !== null && value !== ""; }); } else { // 모두 있어야 OK return requiredFields.every((field) => { const value = selectedItem[field]; return value !== undefined && value !== null && value !== ""; }); } }, [config, selectedItem]); // 최대값 계산 const getMaxValue = useCallback((): number | null => { if (!config?.enabled || !selectedItem) { return null; } const { maxValueField } = config.conditionalInput; if (!maxValueField) { return null; } const maxValue = selectedItem[maxValueField]; return typeof maxValue === "number" ? maxValue : parseFloat(maxValue) || null; }, [config, selectedItem]); // 선택 요약 텍스트 생성 const getSelectionSummary = useCallback((): string => { if (!selectedItem) { return "선택 안됨"; } const { displayColumns, columnLabels } = config.lookup; const parts: string[] = []; displayColumns.forEach((col) => { const value = selectedItem[col]; if (value !== undefined && value !== null && value !== "") { const label = columnLabels?.[col] || col; parts.push(`${label}: ${value}`); } }); return parts.length > 0 ? parts.join(", ") : "선택됨"; }, [selectedItem, config?.lookup]); return { data, isLoading, error, selectedItem, setSelectedItem, isInputEnabled: isInputEnabled(), maxValue: getMaxValue(), isExpanded, setIsExpanded, refetch: fetchData, getSelectionSummary, }; }