"use client"; /** * useTableSettings — 날코딩 페이지용 테이블 설정 훅 * * TableSettingsModal과 함께 사용하여 컬럼 표시/숨김, 순서, 너비를 관리합니다. * 설정은 localStorage에 자동 저장/복원됩니다. * * @example * const ts = useTableSettings("item-info", TABLE_NAME, GRID_COLUMNS); * * // 툴바 버튼 * * * // 테이블 헤더 — GRID_COLUMNS 대신 ts.visibleColumns 사용 * {ts.visibleColumns.map(col => {col.label})} * * // 모달 (JSX 하단) * */ import React, { useState, useEffect, useCallback, useMemo } from "react"; import { loadTableSettings, type TableSettings, type BaseFilter } from "@/components/common/TableSettingsModal"; export function useTableSettings( settingsId: string, tableName: string, defaultColumns: T[], /** 초기 표시 컬럼 키 (미지정 시 defaultColumns 전체) */ initialVisibleKeys?: string[], ) { const [open, setOpen] = useState(false); const [visibleKeys, setVisibleKeys] = useState>( () => new Set(initialVisibleKeys || defaultColumns.map((c) => c.key)), ); const [columnWidths, setColumnWidths] = useState>({}); const [orderedKeys, setOrderedKeys] = useState( () => initialVisibleKeys || defaultColumns.map((c) => c.key), ); const [baseFilter, setBaseFilter] = useState(); // 초기 filterConfig: GRID_COLUMNS에 있는 컬럼만 필터 가능 (전부 비활성) const [filterConfig, setFilterConfig] = useState( () => defaultColumns.map((c) => ({ columnName: c.key, displayName: (c as any).label || c.key, enabled: false, filterType: "text" as const, width: 25, })), ); /** TableSettingsModal onSave에 전달할 콜백 */ const applySettings = useCallback( (settings: TableSettings) => { const visible = new Set(); const widths: Record = {}; const order: string[] = []; for (const cs of settings.columns) { if (cs.visible) { visible.add(cs.columnName); widths[cs.columnName] = cs.width; order.push(cs.columnName); } } // settings에 없는 새 컬럼은 초기 표시 목록에 있을 때만 보이도록 추가 const initKeys = initialVisibleKeys ? new Set(initialVisibleKeys) : new Set(defaultColumns.map((c) => c.key)); for (const col of defaultColumns) { if (!settings.columns.find((c) => c.columnName === col.key) && initKeys.has(col.key)) { visible.add(col.key); order.push(col.key); } } setVisibleKeys(visible); setColumnWidths(widths); setOrderedKeys(order); // 화면에 표시된 컬럼만 필터 가능하도록 제한 setFilterConfig( settings.filters?.filter((f) => visible.has(f.columnName)), ); // 기본 데이터 필터 setBaseFilter(settings.baseFilter); }, [defaultColumns, initialVisibleKeys], ); // 마운트 시 저장된 설정 복원 useEffect(() => { const saved = loadTableSettings(settingsId); if (saved) applySettings(saved); }, []); // eslint-disable-line react-hooks/exhaustive-deps /** 설정이 적용된 컬럼 목록 (순서 + 표시 필터 적용) */ const visibleColumns = useMemo((): T[] => { const colMap = new Map(defaultColumns.map((c) => [c.key, c])); const result: T[] = []; // 저장된 순서대로 for (const key of orderedKeys) { if (visibleKeys.has(key)) { const col = colMap.get(key); if (col) result.push(col); } } // orderedKeys에 없는 컬럼 (새로 추가된 것) for (const col of defaultColumns) { if (!orderedKeys.includes(col.key) && visibleKeys.has(col.key)) { result.push(col); } } return result.length > 0 ? result : defaultColumns; }, [defaultColumns, orderedKeys, visibleKeys]); /** 컬럼 표시 여부 확인 */ const isVisible = useCallback((key: string) => visibleKeys.has(key), [visibleKeys]); /** 컬럼 너비 가져오기 (설정값 or undefined) */ const getWidth = useCallback( (key: string): number | undefined => columnWidths[key], [columnWidths], ); /** TableHead/TableCell에 적용할 style 객체 (0 = 자동, 값 있으면 고정) */ const thStyle = useCallback( (key: string): React.CSSProperties | undefined => { const w = columnWidths[key]; if (!w || w <= 0) return undefined; // 0이면 브라우저 자동 return { width: `${w}px`, minWidth: `${w}px`, maxWidth: `${w}px` }; }, [columnWidths], ); return { /** 모달 open 상태 */ open, /** 모달 open 상태 setter */ setOpen, /** web-types API 호출용 테이블명 */ tableName, /** localStorage 키 */ settingsId, /** TableSettingsModal onSave 콜백 */ applySettings, /** 설정 적용된 컬럼 배열 (순서 + 표시 필터) */ visibleColumns, /** 특정 컬럼 표시 여부 */ isVisible, /** 특정 컬럼 너비 (px) */ getWidth, /** TableHead/TableCell style 객체 반환 */ thStyle, /** 필터 설정 */ filterConfig, /** 기본 데이터 필터 (예: division = '판매') */ baseFilter, /** GRID_COLUMNS 기본 컬럼 키 목록 (TableSettingsModal defaultVisibleKeys용) */ defaultVisibleKeys: initialVisibleKeys || defaultColumns.map((c) => c.key), }; }