Files
Frontend/src/views/react-table/EditableDataTables.tsx
T
2026-02-19 01:15:36 +03:30

158 lines
4.0 KiB
TypeScript

'use client'
// React Imports
import { useEffect, useState } from 'react'
// MUI Imports
import Card from '@mui/material/Card'
import CardHeader from '@mui/material/CardHeader'
// Third-party Imports
import { createColumnHelper, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'
import type { ColumnDef, Row, RowData, Column, Table } from '@tanstack/react-table'
// Type Imports
import type { DataType } from './data'
// Style Imports
import styles from '@core/styles/table.module.css'
// Data Imports
import defaultData from './data'
// Column Definitions
const columnHelper = createColumnHelper<DataType>()
const columns = [
columnHelper.accessor('fullName', {
header: 'Name'
}),
columnHelper.accessor('email', {
header: 'Email'
}),
columnHelper.accessor('start_date', {
header: 'Date'
}),
columnHelper.accessor('experience', {
header: 'Experience'
}),
columnHelper.accessor('age', {
header: 'Age'
})
]
declare module '@tanstack/react-table' {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface TableMeta<TData extends RowData> {
updateData: (rowIndex: number, columnId: string, value: unknown) => void
}
}
// Custom cell component that handles input with state and side-effects
interface EditableCellProps<TData extends RowData> {
getValue: () => unknown
row: Row<TData>
column: Column<TData>
table: Table<TData>
}
const EditableCell = <TData extends RowData>({ getValue, row, column, table }: EditableCellProps<TData>) => {
// Vars
const initialValue = getValue()
// States
const [value, setValue] = useState(initialValue)
const onBlur = () => {
table.options.meta?.updateData(row.index, column.id, value)
}
useEffect(() => {
setValue(initialValue)
}, [initialValue])
return <input value={value as string} onChange={e => setValue(e.target.value)} onBlur={onBlur} />
}
// Give our default column cell renderer editing superpowers!
const defaultColumn: Partial<ColumnDef<DataType>> = {
cell: ({ getValue, row, column, table }) => {
return <EditableCell getValue={getValue} row={row} column={column} table={table} />
}
}
const EditableDataTables = () => {
// States
const [data, setData] = useState(() => defaultData)
// Hooks
const table = useReactTable({
data,
columns,
defaultColumn,
getCoreRowModel: getCoreRowModel(),
filterFns: {
fuzzy: () => false
},
// Provide our updateData function to our table meta
meta: {
updateData: (rowIndex, columnId, value) => {
setData(old =>
old.map((row, index) => {
if (index === rowIndex) {
return {
...old[rowIndex]!,
[columnId]: value
}
}
return row
})
)
}
}
})
return (
<Card>
<CardHeader title='Editable Table' />
<div className='overflow-x-auto'>
<table className={styles.table}>
<thead>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id}>
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table
.getRowModel()
.rows.slice(0, 10)
.map(row => {
return (
<tr key={row.id}>
{row.getVisibleCells().map(cell => {
return (
<td key={cell.id} className={styles.cellWithInput}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
</div>
</Card>
)
}
export default EditableDataTables