mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-19 01:21:30 +03:00
Sammy/t 194 aau when i set sort back and forth the (#103)
* bugfix: use original row id in cells to make sure it rerenders * feature: implement multiple sorts * bugfix: recreate new array to make sure component rerenders * feature: orderBy is an array to keep orders * test: snapshot the searchTemplate methods * feature: remove the console log and return undefined * feature: use orderByTemplate instead of hardcoded orderBy * refactor: move sort and where filters helpers out of service * refactor: rename file helper * refactor: move assert function in test
This commit is contained in:
parent
f022bf8335
commit
b8cd842633
@ -87,7 +87,7 @@ const StyledTableScrollableContainer = styled.div`
|
||||
flex: 1;
|
||||
`;
|
||||
|
||||
function Table<TData, SortField extends string, FilterProperies>({
|
||||
function Table<TData extends { id: string }, SortField, FilterProperies>({
|
||||
data,
|
||||
columns,
|
||||
viewName,
|
||||
@ -140,7 +140,7 @@ function Table<TData, SortField extends string, FilterProperies>({
|
||||
<tr key={row.id} data-testid={`row-id-${row.index}`}>
|
||||
{row.getVisibleCells().map((cell) => {
|
||||
return (
|
||||
<td key={cell.id}>
|
||||
<td key={cell.id + row.original.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext(),
|
||||
|
@ -84,10 +84,11 @@ export function FilterDropdownButton<FilterProperties>({
|
||||
label: selectedFilter.label,
|
||||
value: value.displayValue,
|
||||
icon: selectedFilter.icon,
|
||||
where: selectedFilter.whereTemplate(
|
||||
where:
|
||||
selectedFilter.whereTemplate(
|
||||
selectedFilterOperand,
|
||||
value.value,
|
||||
),
|
||||
) || ({} as FilterProperties),
|
||||
searchResultMapper: selectedFilter.searchResultMapper,
|
||||
});
|
||||
setIsUnfolded(false);
|
||||
|
@ -41,7 +41,7 @@ const StyledCancelButton = styled.button`
|
||||
}
|
||||
`;
|
||||
|
||||
function SortAndFilterBar<SortField extends string, FilterProperties>({
|
||||
function SortAndFilterBar<SortField, FilterProperties>({
|
||||
sorts,
|
||||
onRemoveSort,
|
||||
filters,
|
||||
|
@ -8,9 +8,9 @@ type OwnProps<SortField> = {
|
||||
availableSorts: SortType<SortField>[];
|
||||
};
|
||||
|
||||
const options: Array<SelectedSortType<string>['order']> = ['asc', 'desc'];
|
||||
const options: Array<SelectedSortType<any>['order']> = ['asc', 'desc'];
|
||||
|
||||
export function SortDropdownButton<SortField extends string>({
|
||||
export function SortDropdownButton<SortField>({
|
||||
isSortSelected,
|
||||
availableSorts,
|
||||
onSortSelect,
|
||||
|
@ -66,7 +66,7 @@ const StyledFilters = styled.div`
|
||||
margin-right: ${(props) => props.theme.spacing(2)};
|
||||
`;
|
||||
|
||||
function TableHeader<SortField extends string, FilterProperties>({
|
||||
function TableHeader<SortField, FilterProperties>({
|
||||
viewName,
|
||||
viewIcon,
|
||||
availableSorts,
|
||||
@ -84,37 +84,40 @@ function TableHeader<SortField extends string, FilterProperties>({
|
||||
>([]);
|
||||
|
||||
const sortSelect = useCallback(
|
||||
(sort: SelectedSortType<SortField>) => {
|
||||
innerSetSorts([sort]);
|
||||
onSortsUpdate && onSortsUpdate([sort]);
|
||||
},
|
||||
[onSortsUpdate],
|
||||
);
|
||||
|
||||
const sortUnselect = useCallback(
|
||||
(sortId: string) => {
|
||||
const newSorts = [] as SelectedSortType<SortField>[];
|
||||
(newSort: SelectedSortType<SortField>) => {
|
||||
const newSorts = updateSortOrFilterByKey(sorts, newSort);
|
||||
innerSetSorts(newSorts);
|
||||
onSortsUpdate && onSortsUpdate(newSorts);
|
||||
},
|
||||
[onSortsUpdate],
|
||||
[onSortsUpdate, sorts],
|
||||
);
|
||||
|
||||
const sortUnselect = useCallback(
|
||||
(sortKey: string) => {
|
||||
const newSorts = sorts.filter((sort) => sort.key !== sortKey);
|
||||
innerSetSorts(newSorts);
|
||||
onSortsUpdate && onSortsUpdate(newSorts);
|
||||
},
|
||||
[onSortsUpdate, sorts],
|
||||
);
|
||||
|
||||
const filterSelect = useCallback(
|
||||
(filter: SelectedFilterType<FilterProperties>) => {
|
||||
innerSetFilters([filter]);
|
||||
onFiltersUpdate && onFiltersUpdate([filter]);
|
||||
const newFilters = updateSortOrFilterByKey(filters, filter);
|
||||
|
||||
innerSetFilters(newFilters);
|
||||
onFiltersUpdate && onFiltersUpdate(newFilters);
|
||||
},
|
||||
[onFiltersUpdate],
|
||||
[onFiltersUpdate, filters],
|
||||
);
|
||||
|
||||
const filterUnselect = useCallback(
|
||||
(filterId: SelectedFilterType<FilterProperties>['key']) => {
|
||||
const newFilters = [] as SelectedFilterType<FilterProperties>[];
|
||||
const newFilters = filters.filter((filter) => filter.key !== filterId);
|
||||
innerSetFilters(newFilters);
|
||||
onFiltersUpdate && onFiltersUpdate(newFilters);
|
||||
},
|
||||
[onFiltersUpdate],
|
||||
[onFiltersUpdate, filters],
|
||||
);
|
||||
|
||||
const filterSearch = useCallback(
|
||||
@ -161,3 +164,19 @@ function TableHeader<SortField extends string, FilterProperties>({
|
||||
}
|
||||
|
||||
export default TableHeader;
|
||||
|
||||
function updateSortOrFilterByKey<SortOrFilter extends { key: string }>(
|
||||
sorts: Readonly<SortOrFilter[]>,
|
||||
newSort: SortOrFilter,
|
||||
): SortOrFilter[] {
|
||||
const newSorts = [...sorts];
|
||||
const existingSortIndex = sorts.findIndex((sort) => sort.key === newSort.key);
|
||||
|
||||
if (existingSortIndex !== -1) {
|
||||
newSorts[existingSortIndex] = newSort;
|
||||
} else {
|
||||
newSorts.push(newSort);
|
||||
}
|
||||
|
||||
return newSorts;
|
||||
}
|
||||
|
@ -25,12 +25,14 @@ export const RegularSortAndFilterBar = ({ removeFunction }: OwnProps) => {
|
||||
order: 'asc',
|
||||
key: 'test_sort',
|
||||
icon: <FaArrowDown />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
{
|
||||
label: 'Test sort 2',
|
||||
order: 'desc',
|
||||
key: 'test_sort_2',
|
||||
icon: <FaArrowDown />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
]}
|
||||
onRemoveSort={removeFunction}
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
} from 'react-icons/fa';
|
||||
import { SortDropdownButton } from '../SortDropdownButton';
|
||||
import styled from '@emotion/styled';
|
||||
import { Order_By, People_Order_By } from '../../../../generated/graphql';
|
||||
|
||||
const component = {
|
||||
title: 'SortDropdownButton',
|
||||
@ -28,25 +29,31 @@ const availableSorts = [
|
||||
key: 'fullname',
|
||||
label: 'People',
|
||||
icon: <FaRegUser />,
|
||||
_type: 'custom_sort',
|
||||
orderByTemplate: () => ({ email: Order_By.Asc }),
|
||||
},
|
||||
{
|
||||
key: 'company_name',
|
||||
label: 'Company',
|
||||
icon: <FaRegBuilding />,
|
||||
_type: 'custom_sort',
|
||||
orderByTemplate: () => ({ email: Order_By.Asc }),
|
||||
},
|
||||
{
|
||||
key: 'email',
|
||||
label: 'Email',
|
||||
icon: <FaEnvelope />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
{ key: 'phone', label: 'Phone', icon: <FaPhone /> },
|
||||
{ key: 'phone', label: 'Phone', icon: <FaPhone />, _type: 'default_sort' },
|
||||
{
|
||||
key: 'created_at',
|
||||
label: 'Created at',
|
||||
icon: <FaCalendar />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
{ key: 'city', label: 'City', icon: <FaMapPin /> },
|
||||
] satisfies SortType[];
|
||||
{ key: 'city', label: 'City', icon: <FaMapPin />, _type: 'default_sort' },
|
||||
] satisfies SortType<People_Order_By>[];
|
||||
|
||||
const StyleDiv = styled.div`
|
||||
height: 200px;
|
||||
@ -57,7 +64,7 @@ export const RegularSortDropdownButton = ({ setSorts }: OwnProps) => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<StyleDiv>
|
||||
<SortDropdownButton
|
||||
<SortDropdownButton<People_Order_By>
|
||||
isSortSelected={true}
|
||||
availableSorts={availableSorts}
|
||||
onSortSelect={setSorts}
|
||||
|
@ -12,11 +12,12 @@ const component = {
|
||||
export default component;
|
||||
|
||||
export const RegularTableHeader = () => {
|
||||
const availableSorts: Array<SortType> = [
|
||||
const availableSorts: Array<SortType<Record<'created_at', 'asc'>>> = [
|
||||
{
|
||||
key: 'created_at',
|
||||
label: 'Created at',
|
||||
icon: <FaCalendar />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
];
|
||||
return (
|
||||
|
@ -19,6 +19,7 @@ it('Checks the default top option is Ascending', async () => {
|
||||
key: 'email',
|
||||
icon: <FaEnvelope />,
|
||||
order: 'asc',
|
||||
_type: 'default_sort',
|
||||
});
|
||||
});
|
||||
|
||||
@ -45,5 +46,6 @@ it('Checks the selection of Descending', async () => {
|
||||
key: 'email',
|
||||
icon: <FaEnvelope />,
|
||||
order: 'desc',
|
||||
_type: 'default_sort',
|
||||
});
|
||||
});
|
||||
|
33
front/src/components/table/table-header/helpers.ts
Normal file
33
front/src/components/table/table-header/helpers.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { Order_By } from '../../../generated/graphql';
|
||||
import { SelectedFilterType, SelectedSortType } from './interface';
|
||||
|
||||
export const reduceFiltersToWhere = <T>(
|
||||
filters: Array<SelectedFilterType<T>>,
|
||||
): T => {
|
||||
const where = filters.reduce((acc, filter) => {
|
||||
const { where } = filter;
|
||||
return { ...acc, ...where };
|
||||
}, {} as T);
|
||||
return where;
|
||||
};
|
||||
|
||||
const mapOrderToOrder_By = (order: string) => {
|
||||
if (order === 'asc') return Order_By.Asc;
|
||||
return Order_By.Desc;
|
||||
};
|
||||
|
||||
export const defaultOrderByTemplateFactory =
|
||||
(key: string) => (order: string) => ({
|
||||
[key]: order,
|
||||
});
|
||||
|
||||
export const reduceSortsToOrderBy = <OrderByTemplate>(
|
||||
sorts: Array<SelectedSortType<OrderByTemplate>>,
|
||||
): OrderByTemplate[] => {
|
||||
const mappedSorts = sorts.map((sort) => {
|
||||
if (sort._type === 'custom_sort')
|
||||
return sort.orderByTemplate(mapOrderToOrder_By(sort.order));
|
||||
return defaultOrderByTemplateFactory(sort.key as string)(sort.order);
|
||||
});
|
||||
return mappedSorts as OrderByTemplate[];
|
||||
};
|
@ -2,23 +2,27 @@ import { DocumentNode } from 'graphql';
|
||||
import { ReactNode } from 'react';
|
||||
import {
|
||||
Companies_Bool_Exp,
|
||||
Order_By,
|
||||
People_Bool_Exp,
|
||||
Users_Bool_Exp,
|
||||
} from '../../../generated/graphql';
|
||||
import { GraphqlQueryCompany } from '../../../interfaces/company.interface';
|
||||
import {
|
||||
SEARCH_COMPANY_QUERY,
|
||||
SEARCH_PEOPLE_QUERY,
|
||||
} from '../../../services/search/search';
|
||||
import { GraphqlQueryPerson } from '../../../interfaces/person.interface';
|
||||
|
||||
export type SortType<SortKey = string> = {
|
||||
export type SortType<OrderByTemplate> =
|
||||
| {
|
||||
_type: 'default_sort';
|
||||
label: string;
|
||||
key: SortKey;
|
||||
key: keyof OrderByTemplate & string;
|
||||
icon?: ReactNode;
|
||||
};
|
||||
}
|
||||
| {
|
||||
_type: 'custom_sort';
|
||||
label: string;
|
||||
key: string;
|
||||
icon?: ReactNode;
|
||||
orderByTemplate: (order: Order_By) => OrderByTemplate;
|
||||
};
|
||||
|
||||
export type SelectedSortType<SortField = string> = SortType<SortField> & {
|
||||
export type SelectedSortType<OrderByTemplate> = SortType<OrderByTemplate> & {
|
||||
order: 'asc' | 'desc';
|
||||
};
|
||||
|
||||
@ -30,7 +34,7 @@ export type FilterType<WhereTemplate, FilterValue = Record<string, any>> = {
|
||||
whereTemplate: (
|
||||
operand: FilterOperandType,
|
||||
value: FilterValue,
|
||||
) => WhereTemplate;
|
||||
) => WhereTemplate | undefined;
|
||||
searchQuery: DocumentNode;
|
||||
searchTemplate: (
|
||||
searchInput: string,
|
||||
@ -52,25 +56,3 @@ export type SelectedFilterType<WhereTemplate> = FilterType<WhereTemplate> & {
|
||||
operand: FilterOperandType;
|
||||
where: WhereTemplate;
|
||||
};
|
||||
|
||||
export function assertFilterUseCompanySearch<FilterValue>(
|
||||
filter: FilterType<People_Bool_Exp>,
|
||||
): filter is FilterType<People_Bool_Exp> & {
|
||||
searchResultMapper: (data: GraphqlQueryCompany) => {
|
||||
displayValue: string;
|
||||
value: FilterValue;
|
||||
};
|
||||
} {
|
||||
return filter.searchQuery === SEARCH_COMPANY_QUERY;
|
||||
}
|
||||
|
||||
export function assertFilterUsePeopleSearch<FilterValue>(
|
||||
filter: FilterType<People_Bool_Exp>,
|
||||
): filter is FilterType<People_Bool_Exp> & {
|
||||
searchResultMapper: (data: GraphqlQueryPerson) => {
|
||||
displayValue: string;
|
||||
value: FilterValue;
|
||||
};
|
||||
} {
|
||||
return filter.searchQuery === SEARCH_PEOPLE_QUERY;
|
||||
}
|
||||
|
@ -5,12 +5,12 @@ import { useState, useCallback } from 'react';
|
||||
import {
|
||||
CompaniesSelectedSortType,
|
||||
defaultOrderBy,
|
||||
reduceSortsToOrderBy,
|
||||
useCompaniesQuery,
|
||||
} from '../../services/companies';
|
||||
import Table from '../../components/table/Table';
|
||||
import { mapCompany } from '../../interfaces/company.interface';
|
||||
import { companiesColumns, sortsAvailable } from './companies-table';
|
||||
import { reduceSortsToOrderBy } from '../../components/table/table-header/helpers';
|
||||
|
||||
const StyledCompaniesContainer = styled.div`
|
||||
display: flex;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createColumnHelper } from '@tanstack/react-table';
|
||||
import { Company } from '../../interfaces/company.interface';
|
||||
import { OrderByFields, updateCompany } from '../../services/companies';
|
||||
import { updateCompany } from '../../services/companies';
|
||||
import ColumnHead from '../../components/table/ColumnHead';
|
||||
import Checkbox from '../../components/form/Checkbox';
|
||||
import CompanyChip from '../../components/chips/CompanyChip';
|
||||
@ -17,21 +17,24 @@ import {
|
||||
} from 'react-icons/fa';
|
||||
import ClickableCell from '../../components/table/ClickableCell';
|
||||
import PersonChip from '../../components/chips/PersonChip';
|
||||
import { SortType } from '../../components/table/table-header/interface';
|
||||
import EditableChip from '../../components/table/editable-cell/EditableChip';
|
||||
import { SortType } from '../../components/table/table-header/interface';
|
||||
import { Companies_Order_By } from '../../generated/graphql';
|
||||
|
||||
export const sortsAvailable = [
|
||||
{
|
||||
key: 'name',
|
||||
label: 'Name',
|
||||
icon: undefined,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
{
|
||||
key: 'domain_name',
|
||||
label: 'Domain',
|
||||
icon: undefined,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
] satisfies Array<SortType<OrderByFields>>;
|
||||
] satisfies Array<SortType<Companies_Order_By>>;
|
||||
|
||||
const columnHelper = createColumnHelper<Company>();
|
||||
export const companiesColumns = [
|
||||
|
@ -12,13 +12,15 @@ import { useCallback, useState } from 'react';
|
||||
import {
|
||||
PeopleSelectedSortType,
|
||||
defaultOrderBy,
|
||||
reduceFiltersToWhere,
|
||||
reduceSortsToOrderBy,
|
||||
usePeopleQuery,
|
||||
} from '../../services/people';
|
||||
import { useSearch } from '../../services/search/search';
|
||||
import { People_Bool_Exp } from '../../generated/graphql';
|
||||
import { SelectedFilterType } from '../../components/table/table-header/interface';
|
||||
import {
|
||||
reduceFiltersToWhere,
|
||||
reduceSortsToOrderBy,
|
||||
} from '../../components/table/table-header/helpers';
|
||||
|
||||
const StyledPeopleContainer = styled.div`
|
||||
display: flex;
|
||||
|
@ -93,3 +93,44 @@ Object {
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`PeopleFilter should render the serch city with the searchValue 1`] = `
|
||||
Object {
|
||||
"city": Object {
|
||||
"_ilike": "%Search value%",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`PeopleFilter should render the serch company_name with the searchValue 1`] = `
|
||||
Object {
|
||||
"name": Object {
|
||||
"_ilike": "%Search value%",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`PeopleFilter should render the serch email with the searchValue 1`] = `
|
||||
Object {
|
||||
"email": Object {
|
||||
"_ilike": "%Search value%",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`PeopleFilter should render the serch fullname with the searchValue 1`] = `
|
||||
Object {
|
||||
"_or": Array [
|
||||
Object {
|
||||
"firstname": Object {
|
||||
"_ilike": "%Search value%",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"lastname": Object {
|
||||
"_ilike": "%Search value%",
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
@ -1,12 +1,37 @@
|
||||
import {
|
||||
assertFilterUseCompanySearch,
|
||||
assertFilterUsePeopleSearch,
|
||||
} from '../../../components/table/table-header/interface';
|
||||
import { FilterType } from '../../../components/table/table-header/interface';
|
||||
import { People_Bool_Exp } from '../../../generated/graphql';
|
||||
import { GraphqlQueryCompany } from '../../../interfaces/company.interface';
|
||||
import { GraphqlQueryPerson } from '../../../interfaces/person.interface';
|
||||
import {
|
||||
SEARCH_COMPANY_QUERY,
|
||||
SEARCH_PEOPLE_QUERY,
|
||||
} from '../../../services/search/search';
|
||||
import { mockCompanyData } from '../../companies/__stories__/mock-data';
|
||||
import { defaultData } from '../default-data';
|
||||
import { availableFilters } from '../people-table';
|
||||
|
||||
function assertFilterUseCompanySearch<FilterValue>(
|
||||
filter: FilterType<People_Bool_Exp>,
|
||||
): filter is FilterType<People_Bool_Exp> & {
|
||||
searchResultMapper: (data: GraphqlQueryCompany) => {
|
||||
displayValue: string;
|
||||
value: FilterValue;
|
||||
};
|
||||
} {
|
||||
return filter.searchQuery === SEARCH_COMPANY_QUERY;
|
||||
}
|
||||
|
||||
function assertFilterUsePeopleSearch<FilterValue>(
|
||||
filter: FilterType<People_Bool_Exp>,
|
||||
): filter is FilterType<People_Bool_Exp> & {
|
||||
searchResultMapper: (data: GraphqlQueryPerson) => {
|
||||
displayValue: string;
|
||||
value: FilterValue;
|
||||
};
|
||||
} {
|
||||
return filter.searchQuery === SEARCH_PEOPLE_QUERY;
|
||||
}
|
||||
|
||||
const JohnDoeUser = defaultData.find(
|
||||
(user) => user.email === 'john@linkedin.com',
|
||||
) as GraphqlQueryPerson;
|
||||
@ -33,5 +58,8 @@ describe('PeopleFilter', () => {
|
||||
}
|
||||
}
|
||||
});
|
||||
it(`should render the serch ${filter.key} with the searchValue`, () => {
|
||||
expect(filter.searchTemplate('Search value')).toMatchSnapshot();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -17,12 +17,16 @@ import CompanyChip from '../../components/chips/CompanyChip';
|
||||
import { GraphqlQueryPerson, Person } from '../../interfaces/person.interface';
|
||||
import PipeChip from '../../components/chips/PipeChip';
|
||||
import EditableText from '../../components/table/editable-cell/EditableText';
|
||||
import { OrderByFields, updatePerson } from '../../services/people';
|
||||
import { updatePerson } from '../../services/people';
|
||||
import {
|
||||
FilterType,
|
||||
SortType,
|
||||
} from '../../components/table/table-header/interface';
|
||||
import { People_Bool_Exp } from '../../generated/graphql';
|
||||
import {
|
||||
Order_By,
|
||||
People_Bool_Exp,
|
||||
People_Order_By,
|
||||
} from '../../generated/graphql';
|
||||
import {
|
||||
SEARCH_COMPANY_QUERY,
|
||||
SEARCH_PEOPLE_QUERY,
|
||||
@ -36,25 +40,44 @@ export const availableSorts = [
|
||||
key: 'fullname',
|
||||
label: 'People',
|
||||
icon: <FaRegUser />,
|
||||
_type: 'custom_sort',
|
||||
orderByTemplate: (order: Order_By) => ({
|
||||
firstname: order,
|
||||
lastname: order,
|
||||
}),
|
||||
},
|
||||
{
|
||||
key: 'company_name',
|
||||
label: 'Company',
|
||||
icon: <FaRegBuilding />,
|
||||
_type: 'custom_sort',
|
||||
orderByTemplate: (order: Order_By) => ({ company: { name: order } }),
|
||||
},
|
||||
{
|
||||
key: 'email',
|
||||
label: 'Email',
|
||||
icon: <FaEnvelope />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
{
|
||||
key: 'phone',
|
||||
label: 'Phone',
|
||||
icon: <FaPhone />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
{ key: 'phone', label: 'Phone', icon: <FaPhone /> },
|
||||
{
|
||||
key: 'created_at',
|
||||
label: 'Created at',
|
||||
icon: <FaCalendar />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
{ key: 'city', label: 'City', icon: <FaMapPin /> },
|
||||
] satisfies Array<SortType<OrderByFields>>;
|
||||
{
|
||||
key: 'city',
|
||||
label: 'City',
|
||||
icon: <FaMapPin />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
] satisfies Array<SortType<People_Order_By>>;
|
||||
|
||||
const fullnameFilter = {
|
||||
key: 'fullname',
|
||||
@ -80,8 +103,6 @@ const fullnameFilter = {
|
||||
},
|
||||
};
|
||||
}
|
||||
console.error(Error(`Unhandled operand: ${operand.keyWord}`));
|
||||
return {};
|
||||
},
|
||||
searchQuery: SEARCH_PEOPLE_QUERY,
|
||||
searchTemplate: (searchInput: string) => ({
|
||||
@ -116,8 +137,6 @@ const companyFilter = {
|
||||
_not: { company: { name: { _eq: companyName } } },
|
||||
};
|
||||
}
|
||||
console.error(Error(`Unhandled operand: ${operand.keyWord}`));
|
||||
return {};
|
||||
},
|
||||
searchQuery: SEARCH_COMPANY_QUERY,
|
||||
searchTemplate: (searchInput: string) => ({
|
||||
@ -149,8 +168,6 @@ const emailFilter = {
|
||||
_not: { email: { _eq: email } },
|
||||
};
|
||||
}
|
||||
console.error(Error(`Unhandled operand: ${operand.keyWord}`));
|
||||
return {};
|
||||
},
|
||||
searchQuery: SEARCH_PEOPLE_QUERY,
|
||||
searchTemplate: (searchInput: string) => ({
|
||||
@ -182,8 +199,6 @@ const cityFilter = {
|
||||
_not: { city: { _eq: city } },
|
||||
};
|
||||
}
|
||||
console.error(Error(`Unhandled operand: ${operand.keyWord}`));
|
||||
return {};
|
||||
},
|
||||
searchQuery: SEARCH_PEOPLE_QUERY,
|
||||
searchTemplate: (searchInput: string) => ({
|
||||
|
@ -1,12 +1,18 @@
|
||||
import { CompaniesSelectedSortType, reduceSortsToOrderBy } from './select';
|
||||
import { reduceSortsToOrderBy } from '../../components/table/table-header/helpers';
|
||||
import { CompaniesSelectedSortType } from './select';
|
||||
|
||||
describe('reduceSortsToOrderBy', () => {
|
||||
it('should return an array of objects with the id as key and the order as value', () => {
|
||||
const sorts = [
|
||||
{ key: 'name', label: 'name', order: 'asc' },
|
||||
{ key: 'domain_name', label: 'domain_name', order: 'desc' },
|
||||
{ key: 'name', label: 'name', order: 'asc', _type: 'default_sort' },
|
||||
{
|
||||
key: 'domain_name',
|
||||
label: 'domain_name',
|
||||
order: 'desc',
|
||||
_type: 'default_sort',
|
||||
},
|
||||
] satisfies CompaniesSelectedSortType[];
|
||||
const result = reduceSortsToOrderBy(sorts);
|
||||
expect(result).toEqual([{ name: 'asc', domain_name: 'desc' }]);
|
||||
expect(result).toEqual([{ name: 'asc' }, { domain_name: 'desc' }]);
|
||||
});
|
||||
});
|
||||
|
@ -3,25 +3,7 @@ import { Order_By, Companies_Order_By } from '../../generated/graphql';
|
||||
import { GraphqlQueryCompany } from '../../interfaces/company.interface';
|
||||
import { SelectedSortType } from '../../components/table/table-header/interface';
|
||||
|
||||
export type OrderByFields = keyof Companies_Order_By | 'domain_name' | 'name';
|
||||
|
||||
export type CompaniesSelectedSortType = SelectedSortType<OrderByFields>;
|
||||
|
||||
const mapOrder = (order: 'asc' | 'desc'): Order_By => {
|
||||
return order === 'asc' ? Order_By.Asc : Order_By.Desc;
|
||||
};
|
||||
|
||||
export const reduceSortsToOrderBy = (
|
||||
sorts: Array<CompaniesSelectedSortType>,
|
||||
): Companies_Order_By[] => {
|
||||
const mappedSorts = sorts.reduce((acc, sort) => {
|
||||
const id = sort.key;
|
||||
const order = mapOrder(sort.order);
|
||||
acc[id] = order;
|
||||
return acc;
|
||||
}, {} as Companies_Order_By);
|
||||
return [mappedSorts];
|
||||
};
|
||||
export type CompaniesSelectedSortType = SelectedSortType<Companies_Order_By>;
|
||||
|
||||
export const GET_COMPANIES = gql`
|
||||
query GetCompanies($orderBy: [companies_order_by!]) {
|
||||
|
@ -1,12 +1,23 @@
|
||||
import { PeopleSelectedSortType, reduceSortsToOrderBy } from './select';
|
||||
import { reduceSortsToOrderBy } from '../../components/table/table-header/helpers';
|
||||
import { PeopleSelectedSortType } from './select';
|
||||
|
||||
describe('reduceSortsToOrderBy', () => {
|
||||
it('should return an array of objects with the id as key and the order as value', () => {
|
||||
const sorts = [
|
||||
{ key: 'firstname', label: 'firstname', order: 'asc' },
|
||||
{ key: 'lastname', label: 'lastname', order: 'desc' },
|
||||
{
|
||||
key: 'firstname',
|
||||
label: 'firstname',
|
||||
order: 'asc',
|
||||
_type: 'default_sort',
|
||||
},
|
||||
{
|
||||
key: 'lastname',
|
||||
label: 'lastname',
|
||||
order: 'desc',
|
||||
_type: 'default_sort',
|
||||
},
|
||||
] satisfies PeopleSelectedSortType[];
|
||||
const result = reduceSortsToOrderBy(sorts);
|
||||
expect(result).toEqual([{ firstname: 'asc', lastname: 'desc' }]);
|
||||
expect(result).toEqual([{ firstname: 'asc' }, { lastname: 'desc' }]);
|
||||
});
|
||||
});
|
||||
|
@ -5,47 +5,9 @@ import {
|
||||
People_Bool_Exp,
|
||||
People_Order_By,
|
||||
} from '../../generated/graphql';
|
||||
import {
|
||||
SelectedFilterType,
|
||||
SelectedSortType,
|
||||
} from '../../components/table/table-header/interface';
|
||||
import { SelectedSortType } from '../../components/table/table-header/interface';
|
||||
|
||||
export type OrderByFields = keyof People_Order_By | 'fullname' | 'company_name';
|
||||
|
||||
export type PeopleSelectedSortType = SelectedSortType<OrderByFields>;
|
||||
|
||||
const mapOrder = (order: 'asc' | 'desc'): Order_By => {
|
||||
return order === 'asc' ? Order_By.Asc : Order_By.Desc;
|
||||
};
|
||||
|
||||
export const reduceFiltersToWhere = <T>(
|
||||
filters: Array<SelectedFilterType<T>>,
|
||||
): T => {
|
||||
const where = filters.reduce((acc, filter) => {
|
||||
const { where } = filter;
|
||||
return { ...acc, ...where };
|
||||
}, {} as T);
|
||||
return where;
|
||||
};
|
||||
|
||||
export const reduceSortsToOrderBy = (
|
||||
sorts: Array<PeopleSelectedSortType>,
|
||||
): People_Order_By[] => {
|
||||
const mappedSorts = sorts.reduce((acc, sort) => {
|
||||
const id = sort.key;
|
||||
const order = mapOrder(sort.order);
|
||||
if (id === 'fullname') {
|
||||
acc['firstname'] = order;
|
||||
acc['lastname'] = order;
|
||||
} else if (id === 'company_name') {
|
||||
acc['company'] = { name: order };
|
||||
} else {
|
||||
acc[id] = order;
|
||||
}
|
||||
return acc;
|
||||
}, {} as People_Order_By);
|
||||
return [mappedSorts];
|
||||
};
|
||||
export type PeopleSelectedSortType = SelectedSortType<People_Order_By>;
|
||||
|
||||
export const GET_PEOPLE = gql`
|
||||
query GetPeople(
|
||||
|
Loading…
Reference in New Issue
Block a user