Sammy/t 134 i see all filters in the dropdown (#78)

* feature: add filter dropdown

* test: add story for FilterDropdown

* feature: display filterOperand on top of dropdown

* feature: display filter operand

* feature: fix index and display selected filter

* refactor: set TopOption button inside dropdown file

* feature: move availableFilters outside the fitler component

* refactor: make the available sorts and filter optionnal

* refactor: rename availableSorts

* feature: add a resetState property on onOutsideClick

* feature: add filters and set  filters on Dropdown component

* feature: set filters on click in dropdown

* test: verify button is active after filters are set

* feature: display sorts and filters

* refactor: move SelectedFilters in SortAndFilter

* refactor: move SelectedFilters in dedicated file

* refactor: remove Id and use Key
This commit is contained in:
Sammy Teillet
2023-04-26 16:19:34 +02:00
committed by GitHub
parent 1c8a4058c3
commit 5aec7ca730
17 changed files with 521 additions and 70 deletions

View File

@ -9,7 +9,11 @@ import {
import TableHeader from './table-header/TableHeader';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import styled from '@emotion/styled';
import { SelectedSortType, SortType } from './table-header/SortAndFilterBar';
import {
FilterType,
SelectedSortType,
SortType,
} from './table-header/interface';
type OwnProps<TData, SortField> = {
data: Array<TData>;
@ -17,7 +21,8 @@ type OwnProps<TData, SortField> = {
viewName: string;
viewIcon?: IconProp;
onSortsUpdate?: (sorts: Array<SelectedSortType<SortField>>) => void;
sortsAvailable?: Array<SortType<SortField>>;
availableSorts?: Array<SortType<SortField>>;
availableFilters?: FilterType[];
};
const StyledTable = styled.table`
@ -77,7 +82,8 @@ function Table<TData, SortField extends string>({
viewName,
viewIcon,
onSortsUpdate,
sortsAvailable,
availableSorts,
availableFilters,
}: OwnProps<TData, SortField>) {
const table = useReactTable({
data,
@ -91,7 +97,8 @@ function Table<TData, SortField extends string>({
viewName={viewName}
viewIcon={viewIcon}
onSortsUpdate={onSortsUpdate}
sortsAvailable={sortsAvailable || []}
availableSorts={availableSorts}
availableFilters={availableFilters}
/>
<StyledTableScrollableContainer>
<StyledTable>

View File

@ -2,6 +2,8 @@ import styled from '@emotion/styled';
import { useRef, ReactNode } from 'react';
import { useOutsideAlerter } from '../../../hooks/useOutsideAlerter';
import { modalBackground } from '../../../layout/styles/themes';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faAngleDown } from '@fortawesome/pro-regular-svg-icons';
type OwnProps = {
label: string;
@ -9,6 +11,7 @@ type OwnProps = {
children?: ReactNode;
isUnfolded?: boolean;
setIsUnfolded?: React.Dispatch<React.SetStateAction<boolean>>;
resetState?: () => void;
};
const StyledDropdownButtonContainer = styled.div`
@ -114,6 +117,7 @@ function DropdownButton({
children,
isUnfolded = false,
setIsUnfolded,
resetState,
}: OwnProps) {
const onButtonClick = () => {
setIsUnfolded && setIsUnfolded(!isUnfolded);
@ -121,6 +125,7 @@ function DropdownButton({
const onOutsideClick = () => {
setIsUnfolded && setIsUnfolded(false);
resetState && resetState();
};
const dropdownRef = useRef(null);
@ -132,6 +137,7 @@ function DropdownButton({
isUnfolded={isUnfolded}
onClick={onButtonClick}
isActive={isActive}
aria-selected={isActive}
>
{label}
</StyledDropdownButton>
@ -142,8 +148,20 @@ function DropdownButton({
);
}
const StyleAngleDownContainer = styled.div`
margin-left: auto;
`;
function DropdownTopOptionAngleDown() {
return (
<StyleAngleDownContainer>
<FontAwesomeIcon icon={faAngleDown} />
</StyleAngleDownContainer>
);
}
DropdownButton.StyledDropdownItem = StyledDropdownItem;
DropdownButton.StyledDropdownTopOption = StyledDropdownTopOption;
DropdownButton.StyledDropdownTopOptionAngleDown = DropdownTopOptionAngleDown;
DropdownButton.StyledIcon = StyledIcon;
export default DropdownButton;

View File

@ -0,0 +1,134 @@
import { useCallback, useState } from 'react';
import DropdownButton from './DropdownButton';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { FilterType, SelectedFilterType } from './interface';
type OwnProps = {
filters: SelectedFilterType[];
setFilters: (sorts: SelectedFilterType[]) => void;
availableFilters: FilterType[];
};
type FilterOperandType = { label: string; id: string };
const filterOperands: FilterOperandType[] = [
{ label: 'Include', id: 'include' },
{ label: "Doesn't include", id: 'not-include' },
];
const someFieldRandomValue = [
'John Doe',
'Jane Doe',
'John Smith',
'Jane Smith',
'John Johnson',
'Jane Johnson',
'John Williams',
'Jane Williams',
'John Brown',
'Jane Brown',
'John Jones',
'Jane Jones',
];
export function FilterDropdownButton({
availableFilters,
setFilters,
filters,
}: OwnProps) {
const [isUnfolded, setIsUnfolded] = useState(false);
const [isOptionUnfolded, setIsOptionUnfolded] = useState(false);
const [selectedFilter, setSelectedFilter] = useState<FilterType | undefined>(
undefined,
);
const [selectedFilterOperand, setSelectedFilterOperand] =
useState<FilterOperandType>(filterOperands[0]);
const resetState = useCallback(() => {
setIsOptionUnfolded(false);
setSelectedFilter(undefined);
setSelectedFilterOperand(filterOperands[0]);
}, []);
return (
<DropdownButton
label="Filter"
isActive={filters.length > 0}
isUnfolded={isUnfolded}
setIsUnfolded={setIsUnfolded}
resetState={resetState}
>
{selectedFilter
? isOptionUnfolded
? filterOperands.map((filterOperand, index) => (
<DropdownButton.StyledDropdownItem
key={`select-filter-operand-${index}`}
onClick={() => {
setSelectedFilterOperand(filterOperand);
setIsOptionUnfolded(false);
}}
>
{filterOperand.label}
</DropdownButton.StyledDropdownItem>
))
: [
<DropdownButton.StyledDropdownTopOption
key={'selected-filter'}
onClick={() => setSelectedFilter(undefined)}
>
<DropdownButton.StyledIcon>
{selectedFilter.icon && (
<FontAwesomeIcon icon={selectedFilter.icon} />
)}
</DropdownButton.StyledIcon>
{selectedFilter.label}
<DropdownButton.StyledDropdownTopOptionAngleDown />
</DropdownButton.StyledDropdownTopOption>,
<DropdownButton.StyledDropdownTopOption
key={'selected-filter-operand'}
onClick={() => setIsOptionUnfolded(true)}
>
{selectedFilterOperand.label}
<DropdownButton.StyledDropdownTopOptionAngleDown />
</DropdownButton.StyledDropdownTopOption>,
someFieldRandomValue.map((value, index) => (
<DropdownButton.StyledDropdownItem
key={`fields-value-${index}`}
onClick={() => {
setFilters([
{
id: value,
operand: selectedFilterOperand,
label: selectedFilter.label,
value: value,
icon: selectedFilter.icon,
},
]);
setIsUnfolded(false);
setSelectedFilter(undefined);
}}
>
{value}
</DropdownButton.StyledDropdownItem>
)),
]
: availableFilters.map((filter, index) => (
<DropdownButton.StyledDropdownItem
key={`select-filter-${index}`}
onClick={() => {
setSelectedFilter(filter);
}}
>
<DropdownButton.StyledIcon>
{filter.icon && <FontAwesomeIcon icon={filter.icon} />}
</DropdownButton.StyledIcon>
{filter.label}
</DropdownButton.StyledDropdownItem>
))}
</DropdownButton>
);
}

View File

@ -1,21 +1,13 @@
import styled from '@emotion/styled';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import SortOrFilterChip from './SortOrFilterChip';
import { faArrowDown, faArrowUp } from '@fortawesome/pro-regular-svg-icons';
import { SelectedFilterType, SelectedSortType } from './interface';
type OwnProps<SortField> = {
sorts: Array<SelectedSortType<SortField>>;
onRemoveSort: (sortId: string) => void;
};
export type SortType<SortIds = string> = {
label: string;
id: SortIds;
icon?: IconProp;
};
export type SelectedSortType<SortField = string> = SortType<SortField> & {
order: 'asc' | 'desc';
onRemoveSort: (sortId: SelectedSortType<SortField>['key']) => void;
filters: Array<SelectedFilterType>;
onRemoveFilter: (filterId: SelectedFilterType['id']) => void;
};
const StyledBar = styled.div`
@ -50,24 +42,40 @@ const StyledCancelButton = styled.button`
function SortAndFilterBar<SortField extends string>({
sorts,
onRemoveSort,
filters,
onRemoveFilter,
}: OwnProps<SortField>) {
return (
<StyledBar>
{sorts.map((sort) => {
return (
<SortOrFilterChip
key={sort.id}
key={sort.key}
label={sort.label}
id={sort.id}
id={sort.key}
icon={sort.order === 'asc' ? faArrowDown : faArrowUp}
onRemove={() => onRemoveSort(sort.id)}
onRemove={() => onRemoveSort(sort.key)}
/>
);
})}
{sorts.length > 0 && (
{filters.map((filter) => {
return (
<SortOrFilterChip
key={filter.id}
label={`${filter.label}: ${filter.operand.label} ${filter.value}`}
id={filter.id}
icon={filter.icon}
onRemove={() => onRemoveFilter(filter.id)}
/>
);
})}
{filters.length + sorts.length > 0 && (
<StyledCancelButton
data-testid={'cancel-button'}
onClick={() => sorts.forEach((i) => onRemoveSort(i.id))}
onClick={() => {
sorts.forEach((i) => onRemoveSort(i.key));
filters.forEach((i) => onRemoveFilter(i.id));
}}
>
Cancel
</StyledCancelButton>

View File

@ -1,19 +1,18 @@
import { useCallback, useState } from 'react';
import DropdownButton from './DropdownButton';
import { SelectedSortType, SortType } from './SortAndFilterBar';
import { SelectedSortType, SortType } from './interface';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faAngleDown } from '@fortawesome/pro-regular-svg-icons';
type OwnProps<SortField> = {
sorts: SelectedSortType<SortField>[];
setSorts: (sorts: SelectedSortType<SortField>[]) => void;
sortsAvailable: SortType<SortField>[];
availableSorts: SortType<SortField>[];
};
const options: Array<SelectedSortType<string>['order']> = ['asc', 'desc'];
export function SortDropdownButton<SortField extends string>({
sortsAvailable,
availableSorts,
setSorts,
sorts,
}: OwnProps<SortField>) {
@ -32,12 +31,18 @@ export function SortDropdownButton<SortField extends string>({
[setSorts, selectedSortDirection],
);
const resetState = useCallback(() => {
setIsOptionUnfolded(false);
setSelectedSortDirection('asc');
}, []);
return (
<DropdownButton
label="Sort"
isActive={sorts.length > 0}
isUnfolded={isUnfolded}
setIsUnfolded={setIsUnfolded}
resetState={resetState}
>
{isOptionUnfolded
? options.map((option, index) => (
@ -58,9 +63,9 @@ export function SortDropdownButton<SortField extends string>({
>
{selectedSortDirection === 'asc' ? 'Ascending' : 'Descending'}
<FontAwesomeIcon icon={faAngleDown} />
<DropdownButton.StyledDropdownTopOptionAngleDown />
</DropdownButton.StyledDropdownTopOption>,
...sortsAvailable.map((sort, index) => (
...availableSorts.map((sort, index) => (
<DropdownButton.StyledDropdownItem
key={index + 1}
onClick={() => {

View File

@ -2,18 +2,24 @@ import styled from '@emotion/styled';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import DropdownButton from './DropdownButton';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import SortAndFilterBar, {
import {
FilterType,
SelectedFilterType,
SelectedSortType,
SortType,
} from './SortAndFilterBar';
} from './interface';
import { useCallback, useState } from 'react';
import { SortDropdownButton } from './SortDropdownButton';
import { FilterDropdownButton } from './FilterDropdownButton';
import SortAndFilterBar from './SortAndFilterBar';
type OwnProps<SortField> = {
viewName: string;
viewIcon?: IconProp;
onSortsUpdate?: (sorts: Array<SelectedSortType<SortField>>) => void;
sortsAvailable: Array<SortType<SortField>>;
onFiltersUpdate?: (sorts: Array<SelectedFilterType>) => void;
availableSorts?: Array<SortType<SortField>>;
availableFilters?: FilterType[];
};
const StyledContainer = styled.div`
@ -56,7 +62,9 @@ function TableHeader<SortField extends string>({
viewName,
viewIcon,
onSortsUpdate,
sortsAvailable,
onFiltersUpdate,
availableSorts,
availableFilters,
}: OwnProps<SortField>) {
const [sorts, innerSetSorts] = useState<Array<SelectedSortType<SortField>>>(
[],
@ -79,6 +87,25 @@ function TableHeader<SortField extends string>({
[onSortsUpdate],
);
const [filters, innerSetFilters] = useState<Array<SelectedFilterType>>([]);
const setFilters = useCallback(
(filters: SelectedFilterType[]) => {
innerSetFilters(filters);
onFiltersUpdate && onFiltersUpdate(filters);
},
[onFiltersUpdate],
);
const onFilterItemUnSelect = useCallback(
(filterId: SelectedFilterType['id']) => {
const newFilters = [] as SelectedFilterType[];
innerSetFilters(newFilters);
onFiltersUpdate && onFiltersUpdate(newFilters);
},
[onFiltersUpdate],
);
return (
<StyledContainer>
<StyledTableHeader>
@ -89,18 +116,27 @@ function TableHeader<SortField extends string>({
{viewName}
</StyledViewSection>
<StyledFilters>
<DropdownButton label="Filter" isActive={false}></DropdownButton>
<FilterDropdownButton
filters={filters}
setFilters={setFilters}
availableFilters={availableFilters || []}
/>
<SortDropdownButton
setSorts={setSorts}
sorts={sorts}
sortsAvailable={sortsAvailable}
availableSorts={availableSorts || []}
/>
<DropdownButton label="Settings" isActive={false}></DropdownButton>
</StyledFilters>
</StyledTableHeader>
{sorts.length > 0 && (
<SortAndFilterBar sorts={sorts} onRemoveSort={onSortItemUnSelect} />
{sorts.length + filters.length > 0 && (
<SortAndFilterBar
sorts={sorts}
onRemoveSort={onSortItemUnSelect}
filters={filters}
onRemoveFilter={onFilterItemUnSelect}
/>
)}
</StyledContainer>
);

View File

@ -0,0 +1,77 @@
import { ThemeProvider } from '@emotion/react';
import { lightTheme } from '../../../../layout/styles/themes';
import { FilterDropdownButton } from '../FilterDropdownButton';
import styled from '@emotion/styled';
import { FilterType, SelectedFilterType } from '../interface';
import {
faUser,
faBuildings,
faEnvelope,
faPhone,
faCalendar,
faMapPin,
} from '@fortawesome/pro-regular-svg-icons';
import { useCallback, useState } from 'react';
const component = {
title: 'FilterDropdownButton',
component: FilterDropdownButton,
};
export default component;
type OwnProps = {
setFilters: (filters: SelectedFilterType[]) => void;
};
const availableFilters = [
{
key: 'fullname',
label: 'People',
icon: faUser,
},
{
key: 'company_name',
label: 'Company',
icon: faBuildings,
},
{
key: 'email',
label: 'Email',
icon: faEnvelope,
},
{ key: 'phone', label: 'Phone', icon: faPhone },
{
key: 'created_at',
label: 'Created at',
icon: faCalendar,
},
{ key: 'city', label: 'City', icon: faMapPin },
] satisfies FilterType[];
const StyleDiv = styled.div`
height: 200px;
width: 200px;
`;
export const RegularFilterDropdownButton = ({ setFilters }: OwnProps) => {
const [filters, innerSetFilters] = useState<SelectedFilterType[]>([]);
const outerSetFilters = useCallback(
(filters: SelectedFilterType[]) => {
innerSetFilters(filters);
setFilters(filters);
},
[setFilters],
);
return (
<ThemeProvider theme={lightTheme}>
<StyleDiv>
<FilterDropdownButton
availableFilters={availableFilters}
filters={filters}
setFilters={outerSetFilters}
/>
</StyleDiv>
</ThemeProvider>
);
};

View File

@ -22,17 +22,27 @@ export const RegularSortAndFilterBar = ({ removeFunction }: OwnProps) => {
{
label: 'Test sort',
order: 'asc',
id: 'test_sort',
key: 'test_sort',
icon: faArrowDown,
},
{
label: 'Test sort 2',
order: 'desc',
id: 'test_sort_2',
key: 'test_sort_2',
icon: faArrowDown,
},
]}
onRemoveSort={removeFunction}
onRemoveFilter={removeFunction}
filters={[
{
label: 'People',
operand: { id: 'include', label: 'Include' },
id: 'test_filter',
icon: faArrowDown,
value: 'John Doe',
},
]}
/>
</ThemeProvider>
);

View File

@ -1,8 +1,16 @@
import { SelectedSortType, SortType } from '../SortAndFilterBar';
import { SelectedSortType, SortType } from '../interface';
import { ThemeProvider } from '@emotion/react';
import { lightTheme } from '../../../../layout/styles/themes';
import { faArrowDown } from '@fortawesome/pro-regular-svg-icons';
import {
faBuildings,
faCalendar,
faEnvelope,
faMapPin,
faPhone,
faUser,
} from '@fortawesome/pro-regular-svg-icons';
import { SortDropdownButton } from '../SortDropdownButton';
import styled from '@emotion/styled';
const component = {
title: 'SortDropdownButton',
@ -19,20 +27,44 @@ const sorts = [] satisfies SelectedSortType[];
const availableSorts = [
{
label: 'Email',
id: 'email',
icon: faArrowDown,
key: 'fullname',
label: 'People',
icon: faUser,
},
{
key: 'company_name',
label: 'Company',
icon: faBuildings,
},
{
key: 'email',
label: 'Email',
icon: faEnvelope,
},
{ key: 'phone', label: 'Phone', icon: faPhone },
{
key: 'created_at',
label: 'Created at',
icon: faCalendar,
},
{ key: 'city', label: 'City', icon: faMapPin },
] satisfies SortType[];
const StyleDiv = styled.div`
height: 200px;
width: 200px;
`;
export const RegularSortDropdownButton = ({ setSorts }: OwnProps) => {
return (
<ThemeProvider theme={lightTheme}>
<SortDropdownButton
sorts={sorts}
sortsAvailable={availableSorts}
setSorts={setSorts}
/>
<StyleDiv>
<SortDropdownButton
sorts={sorts}
availableSorts={availableSorts}
setSorts={setSorts}
/>
</StyleDiv>
</ThemeProvider>
);
};

View File

@ -2,7 +2,7 @@ import TableHeader from '../TableHeader';
import { ThemeProvider } from '@emotion/react';
import { lightTheme } from '../../../../layout/styles/themes';
import { faBuilding, faCalendar } from '@fortawesome/pro-regular-svg-icons';
import { SortType } from '../SortAndFilterBar';
import { SortType } from '../interface';
const component = {
title: 'TableHeader',
@ -12,9 +12,9 @@ const component = {
export default component;
export const RegularTableHeader = () => {
const sortsAvailable: Array<SortType> = [
const availableSorts: Array<SortType> = [
{
id: 'created_at',
key: 'created_at',
label: 'Created at',
icon: faCalendar,
},
@ -24,7 +24,7 @@ export const RegularTableHeader = () => {
<TableHeader
viewName="Test"
viewIcon={faBuilding}
sortsAvailable={sortsAvailable}
availableSorts={availableSorts}
/>
</ThemeProvider>
);

View File

@ -0,0 +1,66 @@
import { fireEvent, render, waitFor } from '@testing-library/react';
import { RegularFilterDropdownButton } from '../__stories__/FilterDropdownButton.stories';
import { faEnvelope } from '@fortawesome/pro-regular-svg-icons';
it('Checks the default top option is Include', async () => {
const setSorts = jest.fn();
const { getByText } = render(
<RegularFilterDropdownButton setFilters={setSorts} />,
);
const sortDropdownButton = getByText('Filter');
fireEvent.click(sortDropdownButton);
const sortByEmail = getByText('Email');
fireEvent.click(sortByEmail);
const filterByJohn = getByText('John Doe');
fireEvent.click(filterByJohn);
expect(setSorts).toHaveBeenCalledWith([
{
id: 'John Doe',
value: 'John Doe',
label: 'Email',
operand: { id: 'include', label: 'Include' },
icon: faEnvelope,
},
]);
});
it('Checks the selection of top option for Doesnot include', async () => {
const setSorts = jest.fn();
const { getByText } = render(
<RegularFilterDropdownButton setFilters={setSorts} />,
);
const sortDropdownButton = getByText('Filter');
fireEvent.click(sortDropdownButton);
const sortByEmail = getByText('Email');
fireEvent.click(sortByEmail);
const openOperandOptions = getByText('Include');
fireEvent.click(openOperandOptions);
const selectOperand = getByText("Doesn't include");
fireEvent.click(selectOperand);
const filterByJohn = getByText('John Doe');
fireEvent.click(filterByJohn);
expect(setSorts).toHaveBeenCalledWith([
{
id: 'John Doe',
value: 'John Doe',
label: 'Email',
operand: { id: 'not-include', label: "Doesn't include" },
icon: faEnvelope,
},
]);
const blueSortDropdownButton = getByText('Filter');
await waitFor(() => {
expect(blueSortDropdownButton).toHaveAttribute('aria-selected', 'true');
});
});

View File

@ -1,6 +1,6 @@
import { fireEvent, render } from '@testing-library/react';
import { RegularSortDropdownButton } from '../__stories__/SortDropdownButton.stories';
import { faArrowDown } from '@fortawesome/pro-regular-svg-icons';
import { faEnvelope } from '@fortawesome/pro-regular-svg-icons';
it('Checks the default top option is Ascending', async () => {
const setSorts = jest.fn();
@ -17,8 +17,8 @@ it('Checks the default top option is Ascending', async () => {
expect(setSorts).toHaveBeenCalledWith([
{
label: 'Email',
id: 'email',
icon: faArrowDown,
key: 'email',
icon: faEnvelope,
order: 'asc',
},
]);
@ -45,8 +45,8 @@ it('Checks the selection of Descending', async () => {
expect(setSorts).toHaveBeenCalledWith([
{
label: 'Email',
id: 'email',
icon: faArrowDown,
key: 'email',
icon: faEnvelope,
order: 'desc',
},
]);

View File

@ -0,0 +1,25 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
export type SortType<SortKey = string> = {
label: string;
key: SortKey;
icon?: IconProp;
};
export type FilterType<FilterKey = string> = {
label: string;
key: FilterKey;
icon: IconProp;
};
export type SelectedFilterType = {
id: string;
label: string;
value: string;
operand: { id: string; label: string };
icon: IconProp;
};
export type SelectedSortType<SortField = string> = SortType<SortField> & {
order: 'asc' | 'desc';
};

View File

@ -2,7 +2,11 @@ import { faUser, faList } from '@fortawesome/pro-regular-svg-icons';
import WithTopBarContainer from '../../layout/containers/WithTopBarContainer';
import Table from '../../components/table/Table';
import styled from '@emotion/styled';
import { peopleColumns, sortsAvailable } from './people-table';
import {
availableFilters,
peopleColumns,
availableSorts,
} from './people-table';
import { mapPerson } from '../../interfaces/person.interface';
import { useCallback, useState } from 'react';
import {
@ -38,7 +42,8 @@ function People() {
viewName="All People"
viewIcon={faList}
onSortsUpdate={updateSorts}
sortsAvailable={sortsAvailable}
availableSorts={availableSorts}
availableFilters={availableFilters}
/>
}
</StyledPeopleContainer>

View File

@ -17,35 +17,63 @@ import CompanyChip from '../../components/chips/CompanyChip';
import PersonChip from '../../components/chips/PersonChip';
import { Person } from '../../interfaces/person.interface';
import PipeChip from '../../components/chips/PipeChip';
import { SortType } from '../../components/table/table-header/SortAndFilterBar';
import EditableCell from '../../components/table/EditableCell';
import { OrderByFields, updatePerson } from '../../services/people';
import {
FilterType,
SortType,
} from '../../components/table/table-header/interface';
export const sortsAvailable = [
export const availableSorts = [
{
id: 'fullname',
key: 'fullname',
label: 'People',
icon: faUser,
},
{
id: 'company_name',
key: 'company_name',
label: 'Company',
icon: faBuildings,
},
{
id: 'email',
key: 'email',
label: 'Email',
icon: faEnvelope,
},
{ id: 'phone', label: 'Phone', icon: faPhone },
{ key: 'phone', label: 'Phone', icon: faPhone },
{
id: 'created_at',
key: 'created_at',
label: 'Created at',
icon: faCalendar,
},
{ id: 'city', label: 'City', icon: faMapPin },
{ key: 'city', label: 'City', icon: faMapPin },
] satisfies Array<SortType<OrderByFields>>;
export const availableFilters = [
{
key: 'fullname',
label: 'People',
icon: faUser,
},
{
key: 'company_name',
label: 'Company',
icon: faBuildings,
},
{
key: 'email',
label: 'Email',
icon: faEnvelope,
},
{ key: 'phone', label: 'Phone', icon: faPhone },
{
key: 'created_at',
label: 'Created at',
icon: faCalendar,
},
{ key: 'city', label: 'City', icon: faMapPin },
] satisfies FilterType[];
const columnHelper = createColumnHelper<Person>();
export const peopleColumns = [
columnHelper.accessor('fullName', {

View File

@ -3,8 +3,8 @@ import { PeopleSelectedSortType, reduceSortsToOrderBy } from './select';
describe('reduceSortsToOrderBy', () => {
it('should return an array of objects with the id as key and the order as value', () => {
const sorts = [
{ id: 'firstname', label: 'firstname', order: 'asc' },
{ id: 'lastname', label: 'lastname', order: 'desc' },
{ key: 'firstname', label: 'firstname', order: 'asc' },
{ key: 'lastname', label: 'lastname', order: 'desc' },
] satisfies PeopleSelectedSortType[];
const result = reduceSortsToOrderBy(sorts);
expect(result).toEqual([{ firstname: 'asc', lastname: 'desc' }]);

View File

@ -1,7 +1,7 @@
import { QueryResult, gql, useQuery } from '@apollo/client';
import { GraphqlQueryPerson } from '../../interfaces/person.interface';
import { SelectedSortType } from '../../components/table/table-header/SortAndFilterBar';
import { Order_By, People_Order_By } from '../../generated/graphql';
import { SelectedSortType } from '../../components/table/table-header/interface';
export type OrderByFields = keyof People_Order_By | 'fullname' | 'company_name';
@ -15,7 +15,7 @@ export const reduceSortsToOrderBy = (
sorts: Array<PeopleSelectedSortType>,
): People_Order_By[] => {
const mappedSorts = sorts.reduce((acc, sort) => {
const id = sort.id;
const id = sort.key;
const order = mapOrder(sort.order);
if (id === 'fullname') {
acc['firstname'] = order;