From f1913fa6e2456ae1f0ac30139e1e1da13eabfb6c Mon Sep 17 00:00:00 2001 From: "Collin M. Barrett" Date: Mon, 2 Sep 2019 11:34:55 -0500 Subject: [PATCH] implement free-form search on name and description columns --- .../src/components/listsTable/ListsTable.tsx | 10 ++- src/FilterLists.Web.V2/src/hooks/index.ts | 2 + .../src/hooks/useSearchColumnFilter.tsx | 62 +++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/FilterLists.Web.V2/src/hooks/useSearchColumnFilter.tsx diff --git a/src/FilterLists.Web.V2/src/components/listsTable/ListsTable.tsx b/src/FilterLists.Web.V2/src/components/listsTable/ListsTable.tsx index 07b5e09c9..538a37129 100644 --- a/src/FilterLists.Web.V2/src/components/listsTable/ListsTable.tsx +++ b/src/FilterLists.Web.V2/src/components/listsTable/ListsTable.tsx @@ -2,7 +2,7 @@ import { Table } from 'antd'; import React from 'react'; import { RouteComponentProps } from 'react-router'; -import { useTablePageSizer } from '../../hooks'; +import { useSearchColumnFilter, useTablePageSizer } from '../../hooks'; import { Language } from '../../interfaces/Language'; import { License } from '../../interfaces/License'; import { List } from '../../interfaces/List'; @@ -28,6 +28,8 @@ interface Props { export const ListsTable = (props: RouteComponentProps & Props) => { const { lists, languages, licenses, software, tags, ...routeComponentProps } = props; const tablePageSize = useTablePageSizer(); + const searchNameColumn = useSearchColumnFilter(nameof("name")); + const searchDescriptionColumn = useSearchColumnFilter(nameof("description")); return ( dataSource={lists} @@ -56,6 +58,9 @@ export const ListsTable = (props: RouteComponentProps & Props) => { width={tablePageSize.isNarrowWindow ? undefined : 200} className={styles.nogrow} fixed="left" + filterDropdown={searchNameColumn.filterDropdown} + filterIcon={searchNameColumn.filterIcon} + onFilter={searchNameColumn.onFilter} render={(name: string) =>
{name}
} /> {tablePageSize.isNarrowWindow @@ -64,6 +69,9 @@ export const ListsTable = (props: RouteComponentProps & Props) => { title="Description" dataIndex={nameof("description")} className={styles.nogrow} + filterDropdown={searchDescriptionColumn.filterDropdown} + filterIcon={searchDescriptionColumn.filterIcon} + onFilter={searchDescriptionColumn.onFilter} render={(description: string, list: List) => { + filterDropdown?: React.ReactNode | ((props: FilterDropdownProps) => React.ReactNode); + filterIcon?: React.ReactNode | ((filtered: boolean) => React.ReactNode); + onFilter?: (value: any, record: T) => boolean; +} + +export const useSearchColumnFilter = (dataIndex: string) => { + const [filterProps, setFilterProps] = useState>({ + filterDropdown: undefined, + filterIcon: undefined, + onFilter: undefined + }); + useEffect(() => { + const handleSearch = (confirm?: () => void) => { + confirm && confirm(); + }; + const handleReset = (clearFilters?: (selectedKeys: string[]) => void) => { + clearFilters && clearFilters([]); + }; + setFilterProps({ + filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => ( +
+ setSelectedKeys && setSelectedKeys(e.target.value ? [e.target.value] : [])} + onPressEnter={() => handleSearch(confirm)} + style={{ width: 188, marginBottom: 8, display: 'block' }} /> + + +
+ ), + filterIcon: filtered => ( + + ), + onFilter: (value, record) => { + const searchValue = (record as any)[dataIndex]; + return searchValue && searchValue + .toString() + .toLowerCase() + .includes(value.toLowerCase()) + } + }) + }, [dataIndex]); + return filterProps; +}; \ No newline at end of file