"use client" import * as React from "react" import type { DataTableAdvancedFilterField, DataTableFilterField, DataTableRowAction, } from "@/types/table" import { useDataTable } from "@/hooks/use-data-table" import { DataTable } from "@/components/data-table/data-table" import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-advanced-toolbar" import { getColumns } from "./contract-history-table-columns" import { ContractDetailParsed } from "@/db/schema/contract" import type { ColumnDef } from "@tanstack/react-table" import { getVendorContractHistoryExtended } from "../contract-history-service" interface ContractHistoryTableProps { vendorId: number onRowAction?: (action: DataTableRowAction) => void } // 컬럼 정보를 기반으로 필터 필드 생성하는 유틸리티 함수 function generateFilterFieldsFromColumns(columns: ColumnDef[]): { basic: DataTableFilterField[] advanced: DataTableAdvancedFilterField[] } { const basicFields: DataTableFilterField[] = [] const advancedFields: DataTableAdvancedFilterField[] = [] // 필터링에서 제외할 컬럼 ID들 const excludeIds = new Set(['select', 'contractDetail']) columns.forEach((column) => { // 타입 안전하게 accessorKey 추출 const accessorKey = (column as { accessorKey?: string }).accessorKey const header = (column as { header?: unknown }).header // 제외할 컬럼이나 accessorKey가 없는 경우 스킵 if (!accessorKey || excludeIds.has(accessorKey)) return // 헤더에서 타이틀 추출 let title = '' // accessorKey를 기반으로 한글 타이틀 매핑 (contract.ts 스키마 기준) const titleMap: Record = { contractNo: 'PO/계약번호', contractVersion: 'Rev. / 품번', status: '계약상태', projectName: '프로젝트', projectCode: 'PKG No.', vendorName: '협력업체', contractName: '계약명', materialGroupCode: '자재그룹코드', materialGroupName: '자재그룹명', paymentTerms: '지불조건', deliveryTerms: 'Incoterms', shippmentPlace: '선적지', deliveryDate: '계약납기일', deliveryLocation: '납품장소', priceIndexYn: '연동제대상', currency: '통화', totalAmount: '계약금액', advancePaymentYn: '선급금', startDate: 'PO/계약발송일', endDate: '계약종료일', electronicApprovalDate: 'PO/계약체결일', hasSignature: '전자서명상태', partialShippingAllowed: '분할선적허용', partialPaymentAllowed: '분할결제허용', createdAt: '생성일', updatedAt: '수정일', netTotal: '순총액', discount: '할인', tax: '세금', shippingFee: '배송비', remarks: '비고', version: '버전' } // 매핑된 타이틀이 있으면 사용 if (titleMap[accessorKey]) { title = titleMap[accessorKey] } else { // 함수형 헤더에서 추출 시도 if (typeof header === 'function') { try { const headerProps = header({ column: { id: accessorKey } }) if (React.isValidElement(headerProps) && headerProps.props && typeof headerProps.props === 'object' && 'title' in headerProps.props) { const props = headerProps.props as { title?: string } title = props.title || '' } } catch { // 헤더 함수 실행 실패 시 스킵 } } else if (typeof header === 'string') { title = header } } if (!title) return // 필터 타입 결정 (간단한 휴리스틱) const getFilterType = (key: string): "text" | "number" | "date" => { if (key.includes('Date') || key.includes('date') || key.includes('At')) return 'date' if (key.includes('Amount') || key.includes('amount') || key.includes('total') || key.includes('price')) return 'number' return 'text' } const filterType = getFilterType(accessorKey) // 기본 필터 (주요 필드만) const importantFields = ['contractNo', 'contractName', 'status', 'projectName', 'vendorName', 'currency'] if (importantFields.includes(accessorKey)) { basicFields.push({ id: accessorKey as keyof ContractDetailParsed, label: title, }) } // 고급 필터 (모든 필터링 가능한 필드) advancedFields.push({ id: accessorKey as keyof ContractDetailParsed, label: title, type: filterType, }) }) return { basic: basicFields, advanced: advancedFields } } export function ContractHistoryTable({ vendorId, onRowAction }: ContractHistoryTableProps) { // Row action state 관리 const [rowAction, setRowAction] = React.useState | null>(null) // 데이터 상태 관리 const [serviceData, setServiceData] = React.useState<{ data: ContractDetailParsed[] pageCount: number totalCount: number }>({ data: [], pageCount: 0, totalCount: 0 }) const [isLoading, setIsLoading] = React.useState(false) console.log('ContractHistoryTable data:', serviceData.data.length, 'contracts') // Row action이 발생하면 외부 핸들러 호출 React.useEffect(() => { if (rowAction && onRowAction) { onRowAction(rowAction) setRowAction(null) // Reset action after handling } }, [rowAction, onRowAction]) // 초기 데이터 로드 React.useEffect(() => { const loadInitialData = async () => { setIsLoading(true) try { const result = await getVendorContractHistoryExtended(vendorId, { page: 1, pageSize: 10 }) setServiceData(result) } catch (error) { console.error('Failed to load contract history:', error) setServiceData({ data: [], pageCount: 0, totalCount: 0 }) } finally { setIsLoading(false) } } loadInitialData() }, [vendorId]) const columns = React.useMemo( () => getColumns({ setRowAction }), [] ) // 컬럼 정보를 기반으로 동적으로 필터 필드 생성 const { basic: filterFields, advanced: advancedFilterFields } = React.useMemo(() => { return generateFilterFieldsFromColumns(columns) }, [columns]) // useDataTable 훅 사용 const { table, } = useDataTable({ data: serviceData.data, columns, pageCount: serviceData.pageCount, filterFields, enablePinning: true, enableAdvancedFilter: true, initialState: { sorting: [{ id: "contractNo", desc: false }], }, getRowId: (originalRow) => String(originalRow.id || 'unknown'), shallow: false, clearOnDefault: true, }) return (
{/* 로딩 상태가 아닐 때만 테이블 렌더링 */} {!isLoading ? ( <> {/* 도구 모음 */} {/* 테이블 렌더링 */} ) : ( /* 로딩 스켈레톤 */
계약 히스토리를 불러오는 중입니다...
{Array.from({ length: 10 }).map((_, i) => (
))}
)}
) }