import { useCallback, useEffect, useRef, useState } from 'react'; import { mergeOptions } from '@@/datatables/extend-options/mergeOptions'; import { withMeta } from '@@/datatables/extend-options/withMeta'; import { Datatable, Props as DatatableProps, PaginationProps, } from '../Datatable'; import { DefaultType } from '../types'; export const NEW_ROW_ID = -1; export const NEW_ROW_INDEX = 0; export const UNSET_EDITABLE_ROW = -1; interface Props extends Omit, 'meta'> { revertRow(): void; acceptRow(): void; } export function EditableDatatable({ dataset, revertRow, acceptRow, ...props }: Props & PaginationProps) { const [autoResetPageIndex, skipAutoResetPageIndex] = useSkipper(); const [data, setData] = useState(dataset); const [editableRow, setEditableRow] = useState(-1); const [editableRowOriginalData, setEditableRowOriginalData] = useState< D | undefined >(); useEffect(() => { setData(dataset); }, [dataset]); return ( // eslint-disable-next-line react/jsx-props-no-spreading {...props} dataset={data} extendTableOptions={mergeOptions( (options) => ({ ...options, autoResetPageIndex, }), withMeta({ getEditableRow: () => editableRow, getEditableRowOriginalData: () => editableRowOriginalData, editRow: (rowIndex: number, row: D) => { setEditableRow(rowIndex); setEditableRowOriginalData(row); }, updateRow: (rowIndex: number, value: D) => { // Skip page index reset until after next rerender skipAutoResetPageIndex(); setData((old: D[]) => old.map((row, index) => (index === rowIndex ? value : row)) ); }, revertRow, acceptRow, }) )} /> ); } function useSkipper() { const shouldSkipRef = useRef(true); const shouldSkip = shouldSkipRef.current; // Wrap a function with this to skip a pagination reset temporarily const skip = useCallback(() => { shouldSkipRef.current = false; }, []); useEffect(() => { shouldSkipRef.current = true; }); return [shouldSkip, skip] as const; }