Simplifies search through relations usage (#126)
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import {
|
||||
ColumnDef,
|
||||
@ -7,15 +8,10 @@ import {
|
||||
useReactTable,
|
||||
} from '@tanstack/react-table';
|
||||
import TableHeader from './table-header/TableHeader';
|
||||
import styled from '@emotion/styled';
|
||||
import {
|
||||
FilterConfigType,
|
||||
SelectedFilterType,
|
||||
} from '../../interfaces/filters/interface';
|
||||
import {
|
||||
SearchableType,
|
||||
SearchConfigType,
|
||||
} from '../../interfaces/search/interface';
|
||||
import { SortType, SelectedSortType } from '../../interfaces/sorts/interface';
|
||||
|
||||
declare module 'react' {
|
||||
@ -34,19 +30,8 @@ type OwnProps<
|
||||
viewIcon?: React.ReactNode;
|
||||
availableSorts?: Array<SortType<SortField>>;
|
||||
availableFilters?: FilterConfigType<TData>[];
|
||||
filterSearchResults?: {
|
||||
results: {
|
||||
render: (value: SearchableType) => string;
|
||||
value: SearchableType;
|
||||
}[];
|
||||
loading: boolean;
|
||||
};
|
||||
onSortsUpdate?: (sorts: Array<SelectedSortType<SortField>>) => void;
|
||||
onFiltersUpdate?: (sorts: Array<SelectedFilterType<TData>>) => void;
|
||||
onFilterSearch?: (
|
||||
filter: SearchConfigType<any> | null,
|
||||
searchValue: string,
|
||||
) => void;
|
||||
onRowSelectionChange?: (rowSelection: string[]) => void;
|
||||
};
|
||||
|
||||
@ -112,10 +97,8 @@ const Table = <
|
||||
viewIcon,
|
||||
availableSorts,
|
||||
availableFilters,
|
||||
filterSearchResults,
|
||||
onSortsUpdate,
|
||||
onFiltersUpdate,
|
||||
onFilterSearch,
|
||||
onRowSelectionChange,
|
||||
}: OwnProps<TData, SortField>,
|
||||
ref: React.ForwardedRef<{ resetRowSelection: () => void } | undefined>,
|
||||
@ -156,10 +139,8 @@ const Table = <
|
||||
viewIcon={viewIcon}
|
||||
availableSorts={availableSorts}
|
||||
availableFilters={availableFilters as FilterConfigType<any>[]}
|
||||
filterSearchResults={filterSearchResults}
|
||||
onSortsUpdate={onSortsUpdate}
|
||||
onFiltersUpdate={onFiltersUpdate}
|
||||
onFilterSearch={onFilterSearch}
|
||||
/>
|
||||
<StyledTableScrollableContainer>
|
||||
<StyledTable>
|
||||
|
||||
@ -7,31 +7,19 @@ import {
|
||||
SelectedFilterType,
|
||||
} from '../../../interfaces/filters/interface';
|
||||
import {
|
||||
SearchConfigType,
|
||||
SearchableType,
|
||||
} from '../../../interfaces/search/interface';
|
||||
SearchResultsType,
|
||||
useSearch,
|
||||
} from '../../../services/api/search/search';
|
||||
import { SearchableType } from '../../../interfaces/search/interface';
|
||||
|
||||
type OwnProps<TData extends FilterableFieldsType> = {
|
||||
isFilterSelected: boolean;
|
||||
availableFilters: FilterConfigType<TData>[];
|
||||
filterSearchResults?: {
|
||||
results: {
|
||||
render: (value: SearchableType) => string;
|
||||
value: SearchableType;
|
||||
}[];
|
||||
loading: boolean;
|
||||
};
|
||||
onFilterSelect: (filter: SelectedFilterType<TData>) => void;
|
||||
onFilterSearch: (
|
||||
filter: SearchConfigType<any> | null,
|
||||
searchValue: string,
|
||||
) => void;
|
||||
};
|
||||
|
||||
export const FilterDropdownButton = <TData extends FilterableFieldsType>({
|
||||
availableFilters,
|
||||
filterSearchResults,
|
||||
onFilterSearch,
|
||||
onFilterSelect,
|
||||
isFilterSelected,
|
||||
}: OwnProps<TData>) => {
|
||||
@ -47,12 +35,14 @@ export const FilterDropdownButton = <TData extends FilterableFieldsType>({
|
||||
FilterOperandType<TData> | undefined
|
||||
>(undefined);
|
||||
|
||||
const [filterSearchResults, setSearchInput, setFilterSearch] = useSearch();
|
||||
|
||||
const resetState = useCallback(() => {
|
||||
setIsOptionUnfolded(false);
|
||||
setSelectedFilter(undefined);
|
||||
setSelectedFilterOperand(undefined);
|
||||
onFilterSearch(null, '');
|
||||
}, [onFilterSearch]);
|
||||
setFilterSearch(null);
|
||||
}, [setFilterSearch]);
|
||||
|
||||
const renderSelectOptionItems = selectedFilter?.operands.map(
|
||||
(filterOperand, index) => (
|
||||
@ -69,7 +59,7 @@ export const FilterDropdownButton = <TData extends FilterableFieldsType>({
|
||||
);
|
||||
|
||||
const renderSearchResults = (
|
||||
filterSearchResults: NonNullable<OwnProps<TData>['filterSearchResults']>,
|
||||
filterSearchResults: SearchResultsType<SearchableType>,
|
||||
selectedFilter: FilterConfigType<TData>,
|
||||
selectedFilterOperand: FilterOperandType<TData>,
|
||||
) => {
|
||||
@ -108,7 +98,8 @@ export const FilterDropdownButton = <TData extends FilterableFieldsType>({
|
||||
onClick={() => {
|
||||
setSelectedFilter(filter);
|
||||
setSelectedFilterOperand(filter.operands[0]);
|
||||
onFilterSearch(filter.searchConfig, '');
|
||||
setFilterSearch(filter.searchConfig);
|
||||
setSearchInput('');
|
||||
}}
|
||||
>
|
||||
<DropdownButton.StyledIcon>{filter.icon}</DropdownButton.StyledIcon>
|
||||
@ -134,9 +125,10 @@ export const FilterDropdownButton = <TData extends FilterableFieldsType>({
|
||||
<input
|
||||
type="text"
|
||||
placeholder={selectedFilter.label}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) =>
|
||||
onFilterSearch(selectedFilter.searchConfig, event.target.value)
|
||||
}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
setFilterSearch(selectedFilter.searchConfig);
|
||||
setSearchInput(event.target.value);
|
||||
}}
|
||||
/>
|
||||
</DropdownButton.StyledSearchField>
|
||||
{filterSearchResults &&
|
||||
|
||||
@ -9,10 +9,6 @@ import {
|
||||
FilterConfigType,
|
||||
SelectedFilterType,
|
||||
} from '../../../interfaces/filters/interface';
|
||||
import {
|
||||
SearchableType,
|
||||
SearchConfigType,
|
||||
} from '../../../interfaces/search/interface';
|
||||
import {
|
||||
SortType,
|
||||
SelectedSortType,
|
||||
@ -23,19 +19,8 @@ type OwnProps<SortField, TData extends FilterableFieldsType> = {
|
||||
viewIcon?: ReactNode;
|
||||
availableSorts?: Array<SortType<SortField>>;
|
||||
availableFilters?: FilterConfigType<TData>[];
|
||||
filterSearchResults?: {
|
||||
results: {
|
||||
render: (value: SearchableType) => string;
|
||||
value: SearchableType;
|
||||
}[];
|
||||
loading: boolean;
|
||||
};
|
||||
onSortsUpdate?: (sorts: Array<SelectedSortType<SortField>>) => void;
|
||||
onFiltersUpdate?: (sorts: Array<SelectedFilterType<TData>>) => void;
|
||||
onFilterSearch?: (
|
||||
filter: SearchConfigType<any> | null,
|
||||
searchValue: string,
|
||||
) => void;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@ -79,10 +64,8 @@ function TableHeader<SortField, TData extends FilterableFieldsType>({
|
||||
viewIcon,
|
||||
availableSorts,
|
||||
availableFilters,
|
||||
filterSearchResults,
|
||||
onSortsUpdate,
|
||||
onFiltersUpdate,
|
||||
onFilterSearch,
|
||||
}: OwnProps<SortField, TData>) {
|
||||
const [sorts, innerSetSorts] = useState<Array<SelectedSortType<SortField>>>(
|
||||
[],
|
||||
@ -128,13 +111,6 @@ function TableHeader<SortField, TData extends FilterableFieldsType>({
|
||||
[onFiltersUpdate, filters],
|
||||
);
|
||||
|
||||
const filterSearch = useCallback(
|
||||
(filter: SearchConfigType<any> | null, searchValue: string) => {
|
||||
onFilterSearch && onFilterSearch(filter, searchValue);
|
||||
},
|
||||
[onFilterSearch],
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledTableHeader>
|
||||
@ -146,9 +122,7 @@ function TableHeader<SortField, TData extends FilterableFieldsType>({
|
||||
<FilterDropdownButton
|
||||
isFilterSelected={filters.length > 0}
|
||||
availableFilters={availableFilters || []}
|
||||
filterSearchResults={filterSearchResults}
|
||||
onFilterSelect={filterSelect}
|
||||
onFilterSearch={filterSearch}
|
||||
/>
|
||||
<SortDropdownButton<SortField>
|
||||
isSortSelected={sorts.length > 0}
|
||||
|
||||
@ -3,13 +3,10 @@ import { lightTheme } from '../../../../layout/styles/themes';
|
||||
import { FilterDropdownButton } from '../FilterDropdownButton';
|
||||
import styled from '@emotion/styled';
|
||||
import { useCallback, useState } from 'react';
|
||||
import {
|
||||
SEARCH_PEOPLE_QUERY,
|
||||
useSearch,
|
||||
} from '../../../../services/api/search/search';
|
||||
import { SEARCH_PEOPLE_QUERY } from '../../../../services/api/search/search';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { mockData } from '../../../../pages/people/__tests__/__data__/mock-data';
|
||||
import { availableFilters } from '../../../../pages/people/people-table';
|
||||
import { availableFilters } from '../../../../pages/people/people-filters';
|
||||
import { Person } from '../../../../interfaces/entities/person.interface';
|
||||
import {
|
||||
FilterableFieldsType,
|
||||
@ -90,7 +87,6 @@ const InnerRegularFilterDropdownButton = ({
|
||||
setFilter: setFilters,
|
||||
}: OwnProps<Person>) => {
|
||||
const [, innerSetFilters] = useState<SelectedFilterType<Person>>();
|
||||
const [filterSearchResults, setSearhInput, setFilterSearch] = useSearch();
|
||||
|
||||
const outerSetFilters = useCallback(
|
||||
(filter: SelectedFilterType<Person>) => {
|
||||
@ -105,11 +101,6 @@ const InnerRegularFilterDropdownButton = ({
|
||||
availableFilters={availableFilters}
|
||||
isFilterSelected={true}
|
||||
onFilterSelect={outerSetFilters}
|
||||
filterSearchResults={filterSearchResults}
|
||||
onFilterSearch={(filter, searchValue) => {
|
||||
setSearhInput(searchValue);
|
||||
setFilterSearch(filter);
|
||||
}}
|
||||
/>
|
||||
</StyleDiv>
|
||||
);
|
||||
|
||||
@ -3,11 +3,28 @@ import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../../layout/styles/themes';
|
||||
import { FaRegBuilding, FaCalendar } from 'react-icons/fa';
|
||||
import { SortType } from '../../../../interfaces/sorts/interface';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { EMPTY_QUERY } from '../../../../services/api/search/search';
|
||||
|
||||
const component = {
|
||||
title: 'TableHeader',
|
||||
component: TableHeader,
|
||||
};
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: EMPTY_QUERY,
|
||||
variables: {
|
||||
where: undefined,
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
searchResults: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default component;
|
||||
|
||||
@ -21,12 +38,14 @@ export const RegularTableHeader = () => {
|
||||
},
|
||||
];
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<TableHeader
|
||||
viewName="Test"
|
||||
viewIcon={<FaRegBuilding />}
|
||||
availableSorts={availableSorts}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
<MockedProvider mocks={mocks}>
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<TableHeader
|
||||
viewName="Test"
|
||||
viewIcon={<FaRegBuilding />}
|
||||
availableSorts={availableSorts}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
</MockedProvider>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user