import React, { createContext, useContext, useState, useCallback, useMemo, ReactNode, } from "react"; import { TableRegistration, TableOptionsContextValue, } from "@/types/table-options"; import { useActiveTab } from "./ActiveTabContext"; const TableOptionsContext = createContext( undefined ); export const TableOptionsProvider: React.FC<{ children: ReactNode }> = ({ children, }) => { const [registeredTables, setRegisteredTables] = useState< Map >(new Map()); const [selectedTableId, setSelectedTableId] = useState(null); /** * 테이블 등록 */ const registerTable = useCallback((registration: TableRegistration) => { setRegisteredTables((prev) => { const newMap = new Map(prev); newMap.set(registration.tableId, registration); // 첫 번째 테이블이면 자동 선택 if (newMap.size === 1) { setSelectedTableId(registration.tableId); } return newMap; }); }, []); /** * 테이블 등록 해제 * 주의: * 1. selectedTableId를 의존성으로 사용하면 무한 루프 발생 가능 * 2. 재등록 시에도 unregister가 호출되므로 selectedTableId를 변경하면 안됨 */ const unregisterTable = useCallback( (tableId: string) => { setRegisteredTables((prev) => { const newMap = new Map(prev); newMap.delete(tableId); return newMap; }); // 🚫 selectedTableId를 변경하지 않음 // 이유: useEffect 재실행 시 cleanup → register 순서로 호출되는데, // cleanup에서 selectedTableId를 null로 만들면 필터 설정이 초기화됨 // 다른 테이블이 선택되어야 하면 TableSearchWidget에서 자동 선택함 }, [] // 의존성 없음 - 무한 루프 방지 ); /** * 특정 테이블 조회 */ const getTable = useCallback( (tableId: string) => { return registeredTables.get(tableId); }, [registeredTables] ); /** * 테이블 데이터 건수 업데이트 */ const updateTableDataCount = useCallback((tableId: string, count: number) => { setRegisteredTables((prev) => { const table = prev.get(tableId); if (table) { // 기존 테이블 정보에 dataCount만 업데이트 const updatedTable = { ...table, dataCount: count }; const newMap = new Map(prev); newMap.set(tableId, updatedTable); return newMap; } return prev; }); }, []); // ActiveTab context 사용 (optional - 에러 방지) const activeTabContext = useActiveTab(); /** * 현재 활성 탭의 테이블만 반환 */ const getActiveTabTables = useCallback(() => { const allTables = Array.from(registeredTables.values()); const activeTabIds = activeTabContext.getAllActiveTabIds(); // 활성 탭이 없으면 탭에 속하지 않은 테이블만 반환 if (activeTabIds.length === 0) { return allTables.filter(table => !table.parentTabId); } // 활성 탭에 속한 테이블 + 탭에 속하지 않은 테이블 return allTables.filter(table => !table.parentTabId || activeTabIds.includes(table.parentTabId) ); }, [registeredTables, activeTabContext]); /** * 특정 탭의 테이블만 반환 */ const getTablesForTab = useCallback((tabId: string) => { const allTables = Array.from(registeredTables.values()); return allTables.filter(table => table.parentTabId === tabId); }, [registeredTables]); return ( {children} ); }; /** * Context Hook */ export const useTableOptions = () => { const context = useContext(TableOptionsContext); if (!context) { throw new Error("useTableOptions must be used within TableOptionsProvider"); } return context; };