From 5aec7ca7305f7feccbb69797c01a4e052a6d3d39 Mon Sep 17 00:00:00 2001 From: Sammy Teillet Date: Wed, 26 Apr 2023 16:19:34 +0200 Subject: [PATCH] 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 --- front/src/components/table/Table.tsx | 15 +- .../table/table-header/DropdownButton.tsx | 18 +++ .../table-header/FilterDropdownButton.tsx | 134 ++++++++++++++++++ .../table/table-header/SortAndFilterBar.tsx | 42 +++--- .../table/table-header/SortDropdownButton.tsx | 17 ++- .../table/table-header/TableHeader.tsx | 52 +++++-- .../FilterDropdownButton.stories.tsx | 77 ++++++++++ .../__stories__/SortAndFilterBar.stories.tsx | 14 +- .../SortDropdownButton.stories.tsx | 52 +++++-- .../__stories__/TableHeader.stories.tsx | 8 +- .../__tests__/FilterDropdownButton.test.tsx | 66 +++++++++ .../__tests__/SortDropdownButton.test.tsx | 10 +- .../table/table-header/interface.ts | 25 ++++ front/src/pages/people/People.tsx | 9 +- front/src/pages/people/people-table.tsx | 44 ++++-- front/src/services/people/select.test.ts | 4 +- front/src/services/people/select.ts | 4 +- 17 files changed, 521 insertions(+), 70 deletions(-) create mode 100644 front/src/components/table/table-header/FilterDropdownButton.tsx create mode 100644 front/src/components/table/table-header/__stories__/FilterDropdownButton.stories.tsx create mode 100644 front/src/components/table/table-header/__tests__/FilterDropdownButton.test.tsx create mode 100644 front/src/components/table/table-header/interface.ts diff --git a/front/src/components/table/Table.tsx b/front/src/components/table/Table.tsx index d0c4af908..30d1bf60d 100644 --- a/front/src/components/table/Table.tsx +++ b/front/src/components/table/Table.tsx @@ -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 = { data: Array; @@ -17,7 +21,8 @@ type OwnProps = { viewName: string; viewIcon?: IconProp; onSortsUpdate?: (sorts: Array>) => void; - sortsAvailable?: Array>; + availableSorts?: Array>; + availableFilters?: FilterType[]; }; const StyledTable = styled.table` @@ -77,7 +82,8 @@ function Table({ viewName, viewIcon, onSortsUpdate, - sortsAvailable, + availableSorts, + availableFilters, }: OwnProps) { const table = useReactTable({ data, @@ -91,7 +97,8 @@ function Table({ viewName={viewName} viewIcon={viewIcon} onSortsUpdate={onSortsUpdate} - sortsAvailable={sortsAvailable || []} + availableSorts={availableSorts} + availableFilters={availableFilters} /> diff --git a/front/src/components/table/table-header/DropdownButton.tsx b/front/src/components/table/table-header/DropdownButton.tsx index cdb901834..4de33b618 100644 --- a/front/src/components/table/table-header/DropdownButton.tsx +++ b/front/src/components/table/table-header/DropdownButton.tsx @@ -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>; + 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} @@ -142,8 +148,20 @@ function DropdownButton({ ); } +const StyleAngleDownContainer = styled.div` + margin-left: auto; +`; + +function DropdownTopOptionAngleDown() { + return ( + + + + ); +} DropdownButton.StyledDropdownItem = StyledDropdownItem; DropdownButton.StyledDropdownTopOption = StyledDropdownTopOption; +DropdownButton.StyledDropdownTopOptionAngleDown = DropdownTopOptionAngleDown; DropdownButton.StyledIcon = StyledIcon; export default DropdownButton; diff --git a/front/src/components/table/table-header/FilterDropdownButton.tsx b/front/src/components/table/table-header/FilterDropdownButton.tsx new file mode 100644 index 000000000..bd9e5e46f --- /dev/null +++ b/front/src/components/table/table-header/FilterDropdownButton.tsx @@ -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( + undefined, + ); + + const [selectedFilterOperand, setSelectedFilterOperand] = + useState(filterOperands[0]); + + const resetState = useCallback(() => { + setIsOptionUnfolded(false); + setSelectedFilter(undefined); + setSelectedFilterOperand(filterOperands[0]); + }, []); + + return ( + 0} + isUnfolded={isUnfolded} + setIsUnfolded={setIsUnfolded} + resetState={resetState} + > + {selectedFilter + ? isOptionUnfolded + ? filterOperands.map((filterOperand, index) => ( + { + setSelectedFilterOperand(filterOperand); + setIsOptionUnfolded(false); + }} + > + {filterOperand.label} + + )) + : [ + setSelectedFilter(undefined)} + > + + {selectedFilter.icon && ( + + )} + + {selectedFilter.label} + + , + setIsOptionUnfolded(true)} + > + {selectedFilterOperand.label} + + + , + someFieldRandomValue.map((value, index) => ( + { + setFilters([ + { + id: value, + operand: selectedFilterOperand, + label: selectedFilter.label, + value: value, + icon: selectedFilter.icon, + }, + ]); + setIsUnfolded(false); + setSelectedFilter(undefined); + }} + > + {value} + + )), + ] + : availableFilters.map((filter, index) => ( + { + setSelectedFilter(filter); + }} + > + + {filter.icon && } + + {filter.label} + + ))} + + ); +} diff --git a/front/src/components/table/table-header/SortAndFilterBar.tsx b/front/src/components/table/table-header/SortAndFilterBar.tsx index e21f4ca6f..8bf4b83d7 100644 --- a/front/src/components/table/table-header/SortAndFilterBar.tsx +++ b/front/src/components/table/table-header/SortAndFilterBar.tsx @@ -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 = { sorts: Array>; - onRemoveSort: (sortId: string) => void; -}; - -export type SortType = { - label: string; - id: SortIds; - icon?: IconProp; -}; - -export type SelectedSortType = SortType & { - order: 'asc' | 'desc'; + onRemoveSort: (sortId: SelectedSortType['key']) => void; + filters: Array; + onRemoveFilter: (filterId: SelectedFilterType['id']) => void; }; const StyledBar = styled.div` @@ -50,24 +42,40 @@ const StyledCancelButton = styled.button` function SortAndFilterBar({ sorts, onRemoveSort, + filters, + onRemoveFilter, }: OwnProps) { return ( {sorts.map((sort) => { return ( onRemoveSort(sort.id)} + onRemove={() => onRemoveSort(sort.key)} /> ); })} - {sorts.length > 0 && ( + {filters.map((filter) => { + return ( + onRemoveFilter(filter.id)} + /> + ); + })} + {filters.length + sorts.length > 0 && ( sorts.forEach((i) => onRemoveSort(i.id))} + onClick={() => { + sorts.forEach((i) => onRemoveSort(i.key)); + filters.forEach((i) => onRemoveFilter(i.id)); + }} > Cancel diff --git a/front/src/components/table/table-header/SortDropdownButton.tsx b/front/src/components/table/table-header/SortDropdownButton.tsx index 18e74aa34..703a898b8 100644 --- a/front/src/components/table/table-header/SortDropdownButton.tsx +++ b/front/src/components/table/table-header/SortDropdownButton.tsx @@ -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 = { sorts: SelectedSortType[]; setSorts: (sorts: SelectedSortType[]) => void; - sortsAvailable: SortType[]; + availableSorts: SortType[]; }; const options: Array['order']> = ['asc', 'desc']; export function SortDropdownButton({ - sortsAvailable, + availableSorts, setSorts, sorts, }: OwnProps) { @@ -32,12 +31,18 @@ export function SortDropdownButton({ [setSorts, selectedSortDirection], ); + const resetState = useCallback(() => { + setIsOptionUnfolded(false); + setSelectedSortDirection('asc'); + }, []); + return ( 0} isUnfolded={isUnfolded} setIsUnfolded={setIsUnfolded} + resetState={resetState} > {isOptionUnfolded ? options.map((option, index) => ( @@ -58,9 +63,9 @@ export function SortDropdownButton({ > {selectedSortDirection === 'asc' ? 'Ascending' : 'Descending'} - + , - ...sortsAvailable.map((sort, index) => ( + ...availableSorts.map((sort, index) => ( { diff --git a/front/src/components/table/table-header/TableHeader.tsx b/front/src/components/table/table-header/TableHeader.tsx index 5455bfcc4..a9e9641ed 100644 --- a/front/src/components/table/table-header/TableHeader.tsx +++ b/front/src/components/table/table-header/TableHeader.tsx @@ -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 = { viewName: string; viewIcon?: IconProp; onSortsUpdate?: (sorts: Array>) => void; - sortsAvailable: Array>; + onFiltersUpdate?: (sorts: Array) => void; + availableSorts?: Array>; + availableFilters?: FilterType[]; }; const StyledContainer = styled.div` @@ -56,7 +62,9 @@ function TableHeader({ viewName, viewIcon, onSortsUpdate, - sortsAvailable, + onFiltersUpdate, + availableSorts, + availableFilters, }: OwnProps) { const [sorts, innerSetSorts] = useState>>( [], @@ -79,6 +87,25 @@ function TableHeader({ [onSortsUpdate], ); + const [filters, innerSetFilters] = useState>([]); + + 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 ( @@ -89,18 +116,27 @@ function TableHeader({ {viewName} - + - {sorts.length > 0 && ( - + {sorts.length + filters.length > 0 && ( + )} ); diff --git a/front/src/components/table/table-header/__stories__/FilterDropdownButton.stories.tsx b/front/src/components/table/table-header/__stories__/FilterDropdownButton.stories.tsx new file mode 100644 index 000000000..8c873ef92 --- /dev/null +++ b/front/src/components/table/table-header/__stories__/FilterDropdownButton.stories.tsx @@ -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([]); + const outerSetFilters = useCallback( + (filters: SelectedFilterType[]) => { + innerSetFilters(filters); + setFilters(filters); + }, + [setFilters], + ); + return ( + + + + + + ); +}; diff --git a/front/src/components/table/table-header/__stories__/SortAndFilterBar.stories.tsx b/front/src/components/table/table-header/__stories__/SortAndFilterBar.stories.tsx index 44d13a566..d53e082b9 100644 --- a/front/src/components/table/table-header/__stories__/SortAndFilterBar.stories.tsx +++ b/front/src/components/table/table-header/__stories__/SortAndFilterBar.stories.tsx @@ -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', + }, + ]} /> ); diff --git a/front/src/components/table/table-header/__stories__/SortDropdownButton.stories.tsx b/front/src/components/table/table-header/__stories__/SortDropdownButton.stories.tsx index 76184affe..99e25b746 100644 --- a/front/src/components/table/table-header/__stories__/SortDropdownButton.stories.tsx +++ b/front/src/components/table/table-header/__stories__/SortDropdownButton.stories.tsx @@ -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 ( - + + + ); }; diff --git a/front/src/components/table/table-header/__stories__/TableHeader.stories.tsx b/front/src/components/table/table-header/__stories__/TableHeader.stories.tsx index d5d9376a5..0f2737a66 100644 --- a/front/src/components/table/table-header/__stories__/TableHeader.stories.tsx +++ b/front/src/components/table/table-header/__stories__/TableHeader.stories.tsx @@ -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 = [ + const availableSorts: Array = [ { - id: 'created_at', + key: 'created_at', label: 'Created at', icon: faCalendar, }, @@ -24,7 +24,7 @@ export const RegularTableHeader = () => { ); diff --git a/front/src/components/table/table-header/__tests__/FilterDropdownButton.test.tsx b/front/src/components/table/table-header/__tests__/FilterDropdownButton.test.tsx new file mode 100644 index 000000000..73e51b89b --- /dev/null +++ b/front/src/components/table/table-header/__tests__/FilterDropdownButton.test.tsx @@ -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( + , + ); + + 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( + , + ); + + 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'); + }); +}); diff --git a/front/src/components/table/table-header/__tests__/SortDropdownButton.test.tsx b/front/src/components/table/table-header/__tests__/SortDropdownButton.test.tsx index 0ae5efdad..5af531b2a 100644 --- a/front/src/components/table/table-header/__tests__/SortDropdownButton.test.tsx +++ b/front/src/components/table/table-header/__tests__/SortDropdownButton.test.tsx @@ -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', }, ]); diff --git a/front/src/components/table/table-header/interface.ts b/front/src/components/table/table-header/interface.ts new file mode 100644 index 000000000..16e765e90 --- /dev/null +++ b/front/src/components/table/table-header/interface.ts @@ -0,0 +1,25 @@ +import { IconProp } from '@fortawesome/fontawesome-svg-core'; + +export type SortType = { + label: string; + key: SortKey; + icon?: IconProp; +}; + +export type FilterType = { + 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 = SortType & { + order: 'asc' | 'desc'; +}; diff --git a/front/src/pages/people/People.tsx b/front/src/pages/people/People.tsx index fb0b8b737..cda71b36e 100644 --- a/front/src/pages/people/People.tsx +++ b/front/src/pages/people/People.tsx @@ -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} /> } diff --git a/front/src/pages/people/people-table.tsx b/front/src/pages/people/people-table.tsx index 077a55a94..985b1dc2d 100644 --- a/front/src/pages/people/people-table.tsx +++ b/front/src/pages/people/people-table.tsx @@ -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>; +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(); export const peopleColumns = [ columnHelper.accessor('fullName', { diff --git a/front/src/services/people/select.test.ts b/front/src/services/people/select.test.ts index 9121c08ae..52ff25b38 100644 --- a/front/src/services/people/select.test.ts +++ b/front/src/services/people/select.test.ts @@ -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' }]); diff --git a/front/src/services/people/select.ts b/front/src/services/people/select.ts index ee6d091c6..b06c55f46 100644 --- a/front/src/services/people/select.ts +++ b/front/src/services/people/select.ts @@ -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, ): 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;