"use client" import * as React from "react" import type { DataTableAdvancedFilterField, DataTableRowAction, } from "@/types/table" import { useDataTable } from "@/hooks/use-data-table" import { DataTable } from "@/components/data-table/data-table" import { getColumns, EditingCellState } from "./rfq-table-column" import { useEffect, useCallback, useRef, useMemo } from "react" import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-advanced-toolbar" import { RFQTableToolbarActions } from "./rfq-table-toolbar-actions" import { ProcurementRfqsView } from "@/db/schema" import { getPORfqs } from "../services" import { toast } from "sonner" import { updateRfqRemark } from "@/lib/procurement-rfqs/services" import { useSearchParams } from "next/navigation" import { useTablePresets } from "@/components/data-table/use-table-presets" import { TablePresetManager } from "@/components/data-table/data-table-preset" import { Loader2 } from "lucide-react" interface RFQListTableProps { data?: Awaited>; onSelectRFQ?: (rfq: ProcurementRfqsView | null) => void; onDataRefresh?: () => void; maxHeight?: string | number; } export function RFQListTable({ data, onSelectRFQ, onDataRefresh, maxHeight }: RFQListTableProps) { const searchParams = useSearchParams() const [rowAction, setRowAction] = React.useState | null>(null) const [editingCell, setEditingCell] = React.useState(null) const [localData, setLocalData] = React.useState(data || { data: [], pageCount: 0, total: 0 }) const [isMounted, setIsMounted] = React.useState(false) // 초기 설정 정의 const initialSettings = React.useMemo(() => ({ page: parseInt(searchParams.get('page') || '1'), perPage: parseInt(searchParams.get('perPage') || '10'), sort: searchParams.get('sort') ? JSON.parse(searchParams.get('sort')!) : [{ id: "updatedAt", desc: true }], filters: searchParams.get('filters') ? JSON.parse(searchParams.get('filters')!) : [], joinOperator: (searchParams.get('joinOperator') as "and" | "or") || "and", basicFilters: searchParams.get('basicFilters') ? JSON.parse(searchParams.get('basicFilters')!) : [], basicJoinOperator: (searchParams.get('basicJoinOperator') as "and" | "or") || "and", search: searchParams.get('search') || '', from: searchParams.get('from') || undefined, to: searchParams.get('to') || undefined, columnVisibility: {}, columnOrder: [], pinnedColumns: { left: [], right: [] }, groupBy: [], expandedRows: [] }), [searchParams]) // DB 기반 프리셋 훅 사용 const { presets, activePresetId, hasUnsavedChanges, isLoading: presetsLoading, createPreset, applyPreset, updatePreset, deletePreset, setDefaultPreset, renamePreset, updateClientState, getCurrentSettings, } = useTablePresets('rfq-list-table', initialSettings) // 클라이언트 마운트 체크 useEffect(() => { setIsMounted(true) }, []) // 데이터 변경 감지 useEffect(() => { setLocalData(data || { data: [], pageCount: 0, total: 0 }) }, [data]) // 비고 업데이트 함수 const updateRemark = async (rfqId: number, remark: string) => { try { if (localData && localData.data) { const rowIndex = localData.data.findIndex(row => row.id === rfqId); if (rowIndex >= 0) { const newData = [...localData.data]; newData[rowIndex] = { ...newData[rowIndex], remark }; setLocalData({ ...localData, data: newData }); } } const result = await updateRfqRemark(rfqId, remark); if (result.success) { toast.success("비고가 업데이트되었습니다"); if (onDataRefresh) { onDataRefresh(); } } else { toast.error(result.message || "업데이트 중 오류가 발생했습니다"); } } catch (error) { console.error("비고 업데이트 오류:", error); toast.error("업데이트 중 오류가 발생했습니다"); } } // 행 액션 처리 useEffect(() => { if (rowAction) { switch (rowAction.type) { case "select": if (onSelectRFQ) { onSelectRFQ(rowAction.row.original) } break; case "update": console.log("Update rfq:", rowAction.row.original) break; case "delete": console.log("Delete rfq:", rowAction.row.original) break; } setRowAction(null) } }, [rowAction, onSelectRFQ]) const columns = React.useMemo( () => getColumns({ setRowAction, editingCell, setEditingCell, updateRemark }), [setRowAction, editingCell, setEditingCell, updateRemark] ) // 고급 필터 필드 정의 const advancedFilterFields: DataTableAdvancedFilterField[] = [ { id: "rfqCode", label: "RFQ No.", type: "text", }, { id: "projectCode", label: "프로젝트", type: "text", }, { id: "itemCode", label: "자재그룹", type: "text", }, { id: "itemName", label: "자재명", type: "text", }, { id: "rfqSealedYn", label: "RFQ 밀봉여부", type: "text", }, { id: "majorItemMaterialCode", label: "자재코드", type: "text", }, { id: "rfqSendDate", label: "RFQ 전송일", type: "date", }, { id: "dueDate", label: "RFQ 마감일", type: "date", }, { id: "createdByUserName", label: "요청자", type: "text", }, ] // 현재 설정 가져오기 const currentSettings = useMemo(() => { return getCurrentSettings() }, [getCurrentSettings]) // useDataTable 초기 상태 설정 const initialState = useMemo(() => { console.log('Setting initial state:', currentSettings) return { sorting: initialSettings.sort.filter(sortItem => { const columnExists = columns.some(col => col.accessorKey === sortItem.id) return columnExists }) as any, columnVisibility: currentSettings.columnVisibility, columnPinning: currentSettings.pinnedColumns, } }, [currentSettings, initialSettings.sort, columns]) // useDataTable 훅 설정 const { table } = useDataTable({ data: localData?.data || [], columns, pageCount: localData?.pageCount || 0, rowCount: localData?.total || 0, filterFields: [], enablePinning: true, enableAdvancedFilter: true, initialState, getRowId: (originalRow) => String(originalRow.id), shallow: false, clearOnDefault: true, columnResizeMode: "onEnd", }) // 테이블 상태 변경 감지 및 자동 저장 const lastKnownStateRef = useRef<{ columnVisibility: string columnPinning: string columnOrder: string[] }>({ columnVisibility: '{}', columnPinning: '{"left":[],"right":[]}', columnOrder: [] }) const checkAndUpdateTableState = useCallback(() => { if (!presetsLoading && !activePresetId) return try { const currentVisibility = table.getState().columnVisibility const currentPinning = table.getState().columnPinning // 컬럼 순서 가져오기 const allColumns = table.getAllColumns() const leftPinned = table.getLeftHeaderGroups()[0]?.headers.map(h => h.column.id) || [] const rightPinned = table.getRightHeaderGroups()[0]?.headers.map(h => h.column.id) || [] const center = table.getCenterHeaderGroups()[0]?.headers.map(h => h.column.id) || [] const currentOrder = [...leftPinned, ...center, ...rightPinned] const visibilityString = JSON.stringify(currentVisibility) const pinningString = JSON.stringify(currentPinning) const orderString = JSON.stringify(currentOrder) // 실제 변경이 있을 때만 업데이트 if ( visibilityString !== lastKnownStateRef.current.columnVisibility || pinningString !== lastKnownStateRef.current.columnPinning || orderString !== JSON.stringify(lastKnownStateRef.current.columnOrder) ) { console.log('Table state changed, updating preset...') const newClientState = { columnVisibility: currentVisibility, columnOrder: currentOrder, pinnedColumns: currentPinning, } // 상태 업데이트 전에 기록 lastKnownStateRef.current = { columnVisibility: visibilityString, columnPinning: pinningString, columnOrder: currentOrder } updateClientState(newClientState) } } catch (error) { console.error('Error checking table state:', error) } }, [activePresetId, table, updateClientState, presetsLoading ]) // 주기적으로 테이블 상태 체크 useEffect(() => { if (!isMounted || !activePresetId) return console.log('Starting table state polling') const intervalId = setInterval(checkAndUpdateTableState, 500) return () => { clearInterval(intervalId) console.log('Stopped table state polling') } }, [isMounted, activePresetId, checkAndUpdateTableState]) // 프리셋 적용 시 테이블 상태 업데이트 useEffect(() => { if (isMounted && activePresetId && currentSettings) { const settings = currentSettings console.log('Applying preset settings to table:', settings) const currentVisibility = table.getState().columnVisibility const currentPinning = table.getState().columnPinning if ( JSON.stringify(currentVisibility) !== JSON.stringify(settings.columnVisibility) || JSON.stringify(currentPinning) !== JSON.stringify(settings.pinnedColumns) ) { console.log('Updating table state to match preset...') // 테이블 상태 업데이트 table.setColumnVisibility(settings.columnVisibility) table.setColumnPinning(settings.pinnedColumns) // 상태 저장소 업데이트 lastKnownStateRef.current = { columnVisibility: JSON.stringify(settings.columnVisibility), columnPinning: JSON.stringify(settings.pinnedColumns), columnOrder: settings.columnOrder || [] } } } }, [isMounted, activePresetId, currentSettings, table]) // 로딩 중일 때는 스켈레톤 표시 if (!isMounted) { return (
테이블 설정을 로드하는 중...
) } return (
{/* DB 기반 테이블 프리셋 매니저 */} presets={presets} activePresetId={activePresetId} currentSettings={currentSettings} hasUnsavedChanges={hasUnsavedChanges} isLoading={presetsLoading} onCreatePreset={createPreset} onUpdatePreset={updatePreset} onDeletePreset={deletePreset} onApplyPreset={applyPreset} onSetDefaultPreset={setDefaultPreset} onRenamePreset={renamePreset} /> {/* 기존 툴바 액션들 */}
) }