Sammy/t 192 aau whan i select does not include it is (#99)

* feature: add operand list to filters

* feature: implement not include

* feature: add operand on filters

* feature: use filters operand instead of defaults

* test: adapt test with new operands

* refactor: remove useless %% in gql where

* test: test fullname filter

* test: add test for where rendering of filters
This commit is contained in:
Sammy Teillet
2023-05-05 10:25:06 +02:00
committed by GitHub
parent 89dc5b4d60
commit 9cd57083f1
10 changed files with 243 additions and 80 deletions

View File

@ -16,11 +16,6 @@ type OwnProps<FilterProperties> = {
) => void;
};
const filterOperands: FilterOperandType[] = [
{ label: 'Include', id: 'include', keyWord: 'ilike' },
{ label: "Doesn't include", id: 'not-include', keyWord: 'not_ilike' },
];
export function FilterDropdownButton<FilterProperties>({
availableFilters,
filterSearchResults,
@ -36,33 +31,37 @@ export function FilterDropdownButton<FilterProperties>({
FilterType<FilterProperties> | undefined
>(undefined);
const [selectedFilterOperand, setSelectedFilterOperand] =
useState<FilterOperandType>(filterOperands[0]);
const [selectedFilterOperand, setSelectedFilterOperand] = useState<
FilterOperandType | undefined
>(undefined);
const resetState = useCallback(() => {
setIsOptionUnfolded(false);
setSelectedFilter(undefined);
setSelectedFilterOperand(filterOperands[0]);
setSelectedFilterOperand(undefined);
onFilterSearch(null, '');
}, [onFilterSearch]);
const renderSelectOptionItems = filterOperands.map((filterOperand, index) => (
<DropdownButton.StyledDropdownItem
key={`select-filter-operand-${index}`}
onClick={() => {
setSelectedFilterOperand(filterOperand);
setIsOptionUnfolded(false);
}}
>
{filterOperand.label}
</DropdownButton.StyledDropdownItem>
));
const renderSelectOptionItems = selectedFilter?.operands.map(
(filterOperand, index) => (
<DropdownButton.StyledDropdownItem
key={`select-filter-operand-${index}`}
onClick={() => {
setSelectedFilterOperand(filterOperand);
setIsOptionUnfolded(false);
}}
>
{filterOperand.label}
</DropdownButton.StyledDropdownItem>
),
);
const renderSearchResults = (
filterSearchResults: NonNullable<
OwnProps<FilterProperties>['filterSearchResults']
>,
selectedFilter: FilterType<FilterProperties>,
selectedFilterOperand: FilterOperandType,
) => {
if (filterSearchResults.loading) {
return (
@ -76,6 +75,7 @@ export function FilterDropdownButton<FilterProperties>({
key={`fields-value-${index}`}
onClick={() => {
onFilterSelect({
...selectedFilter,
key: value.displayValue,
operand: selectedFilterOperand,
searchQuery: selectedFilter.searchQuery,
@ -104,6 +104,7 @@ export function FilterDropdownButton<FilterProperties>({
key={`select-filter-${index}`}
onClick={() => {
setSelectedFilter(filter);
setSelectedFilterOperand(filter.operands[0]);
onFilterSearch(filter, '');
}}
>
@ -112,7 +113,10 @@ export function FilterDropdownButton<FilterProperties>({
</DropdownButton.StyledDropdownItem>
));
function renderFilterDropdown(selectedFilter: FilterType<FilterProperties>) {
function renderFilterDropdown(
selectedFilter: FilterType<FilterProperties>,
selectedFilterOperand: FilterOperandType,
) {
return (
<>
<DropdownButton.StyledDropdownTopOption
@ -133,7 +137,11 @@ export function FilterDropdownButton<FilterProperties>({
/>
</DropdownButton.StyledSearchField>
{filterSearchResults &&
renderSearchResults(filterSearchResults, selectedFilter)}
renderSearchResults(
filterSearchResults,
selectedFilter,
selectedFilterOperand,
)}
</>
);
}
@ -146,10 +154,10 @@ export function FilterDropdownButton<FilterProperties>({
setIsUnfolded={setIsUnfolded}
resetState={resetState}
>
{selectedFilter
{selectedFilter && selectedFilterOperand
? isOptionUnfolded
? renderSelectOptionItems
: renderFilterDropdown(selectedFilter)
: renderFilterDropdown(selectedFilter, selectedFilterOperand)
: renderSelectFilterITems}
</DropdownButton>
);

View File

@ -100,6 +100,10 @@ const availableFilters = [
displayValue: data.firstname + ' ' + data.lastname,
value: data.firstname,
}),
operands: [
{ label: 'Equal', id: 'equal', keyWord: 'equal' },
{ label: 'Not equal', id: 'not-equal', keyWord: 'not_equal' },
],
},
] satisfies FilterType<People_Bool_Exp>[];

View File

@ -56,6 +56,7 @@ export const RegularSortAndFilterBar = ({ removeFunction }: OwnProps) => {
displayValue: 'John Doe',
value: data.firstname,
}),
operands: [],
},
]}
/>

View File

@ -28,16 +28,16 @@ it('Checks the default top option is Include', async () => {
value: 'Alexandre Prot',
label: 'People',
operand: {
id: 'include',
keyWord: 'ilike',
label: 'Include',
id: 'equal',
keyWord: 'equal',
label: 'Equal',
},
icon: <FaUsers />,
}),
);
});
it('Checks the selection of top option for Doesnot include', async () => {
it('Checks the selection of top option for Not Equal', async () => {
const setFilters = jest.fn();
const { getByText } = render(
<RegularFilterDropdownButton setFilter={setFilters} />,
@ -49,10 +49,10 @@ it('Checks the selection of top option for Doesnot include', async () => {
const filterByPeople = getByText('People');
fireEvent.click(filterByPeople);
const openOperandOptions = getByText('Include');
const openOperandOptions = getByText('Equal');
fireEvent.click(openOperandOptions);
const selectOperand = getByText("Doesn't include");
const selectOperand = getByText('Not equal');
fireEvent.click(selectOperand);
await waitFor(() => {
@ -69,9 +69,9 @@ it('Checks the selection of top option for Doesnot include', async () => {
value: 'Alexandre Prot',
label: 'People',
operand: {
id: 'not-include',
keyWord: 'not_ilike',
label: "Doesn't include",
id: 'not-equal',
keyWord: 'not_equal',
label: 'Not equal',
},
icon: <FaUsers />,
}),
@ -122,9 +122,9 @@ it('Calls the filters when typing a new name', async () => {
value: 'Jane Doe',
label: 'People',
operand: {
id: 'include',
keyWord: 'ilike',
label: 'Include',
id: 'equal',
keyWord: 'equal',
label: 'Equal',
},
icon: <FaUsers />,
}),

View File

@ -16,22 +16,29 @@ export type SelectedSortType<SortField = string> = SortType<SortField> & {
order: 'asc' | 'desc';
};
export type FilterType<WhereTemplate, T = Record<string, string>> = {
export type FilterType<WhereTemplate, FilterValue = Record<string, any>> = {
operands: FilterOperandType[];
label: string;
key: string;
icon: ReactNode;
whereTemplate: (operand: FilterOperandType, value: T) => WhereTemplate;
whereTemplate: (
operand: FilterOperandType,
value: FilterValue,
) => WhereTemplate;
searchQuery: DocumentNode;
searchTemplate: (
searchInput: string,
) => People_Bool_Exp | Companies_Bool_Exp | Users_Bool_Exp;
searchResultMapper: (data: any) => { displayValue: string; value: T };
searchResultMapper: (data: any) => {
displayValue: string;
value: FilterValue;
};
};
export type FilterOperandType = {
label: string;
id: string;
keyWord: 'ilike' | 'not_ilike';
keyWord: 'ilike' | 'not_ilike' | 'equal' | 'not_equal';
};
export type SelectedFilterType<WhereTemplate> = FilterType<WhereTemplate> & {