import { useCallback, useMemo, useState } from 'react'; import { Column, Filters, useFilters, UseFiltersColumnOptions, UseFiltersInstanceProps, UseFiltersOptions, UseFiltersState, } from 'react-table'; import { filter, includes, map, values } from 'lodash-es'; import { FILTER_ACTIONS, FilterSetter, IRelatableStateInstance, TableAddOnReturn, } from '../relatable.types'; import { IFilterFieldProps, TextFilter } from '../components/renderers'; export interface IWithFiltersOptions extends UseFiltersOptions { defaultFilterCell?: React.FC; onFilterChange?: FilterSetter; // react-table state override https://react-table.js.org/api/useFilters // with custom filter value array filters?: Filters[]; } export interface IWithFiltersState extends UseFiltersState { } export interface IWithFiltersInstance extends UseFiltersInstanceProps, IRelatableStateInstance> { onCustomFilterChange: FilterSetter; defaultColumn: Partial & UseFiltersColumnOptions>; } export default function withFilters(options: IWithFiltersOptions = {}): TableAddOnReturn { const { defaultFilterCell, filters: theirFilters, onFilterChange, ...rest } = options; const [ourFilters, setOurFilters] = useState>([]); const filters = theirFilters || ourFilters; const stateParams = { filters }; const onCustomFilterChange: FilterSetter = useCallback((column, action, values) => { if (onFilterChange) { onFilterChange(column, action, values); return; } if (action === FILTER_ACTIONS.FILTER_CLEAR) { setOurFilters(filter(ourFilters, ({ id }) => id === column.id)); return; } if (action === FILTER_ACTIONS.FILTER_ADD) { setOurFilters([ ...ourFilters, ...map(values, (value) => ({id: column.id, value})) ]); return; } setOurFilters(filter(ourFilters, ({ id, value }) => !(id === column.id && includes(values, value)))); }, [onFilterChange, ourFilters, setOurFilters]); const tableParams = { ...rest, onCustomFilterChange, defaultColumn: { Filter: defaultFilterCell || TextFilter, }, }; return [ withFilters.name, null, ({ canFilter }) => canFilter, ({ defaultColumn }) => useMemo((): Partial => ({ ...tableParams, defaultColumn: { ...defaultColumn, ...tableParams.defaultColumn, }, }), [defaultColumn, defaultFilterCell, onCustomFilterChange, ...values(rest)]), () => useMemo(() => stateParams, [filters]), useFilters, ]; }