diff --git a/front/src/components/table/Table.tsx b/front/src/components/table/Table.tsx index da7ea635a..7de44456b 100644 --- a/front/src/components/table/Table.tsx +++ b/front/src/components/table/Table.tsx @@ -9,12 +9,14 @@ import { import TableHeader from './table-header/TableHeader'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import styled from '@emotion/styled'; +import { SortType } from './table-header/SortAndFilterBar'; type OwnProps = { data: Array; columns: Array>; viewName: string; viewIcon?: IconProp; + onSortsUpdate?: React.Dispatch>; }; const StyledTable = styled.table` @@ -60,7 +62,13 @@ const StyledTableWithHeader = styled.div` flex: 1; `; -function Table({ data, columns, viewName, viewIcon }: OwnProps) { +function Table({ + data, + columns, + viewName, + viewIcon, + onSortsUpdate, +}: OwnProps) { const table = useReactTable({ data, columns, @@ -69,7 +77,11 @@ function Table({ data, columns, viewName, viewIcon }: OwnProps) { return ( - + {table.getHeaderGroups().map((headerGroup) => ( @@ -88,8 +100,8 @@ function Table({ data, columns, viewName, viewIcon }: OwnProps) { ))} - {table.getRowModel().rows.map((row) => ( - + {table.getRowModel().rows.map((row, index) => ( + {row.getVisibleCells().map((cell) => { return ( diff --git a/front/src/components/table/table-header/SortAndFilterBar.tsx b/front/src/components/table/table-header/SortAndFilterBar.tsx index 87c7abfc3..682b16260 100644 --- a/front/src/components/table/table-header/SortAndFilterBar.tsx +++ b/front/src/components/table/table-header/SortAndFilterBar.tsx @@ -10,7 +10,7 @@ type OwnProps = { export type SortType = { label: string; - order: string; + order: 'asc' | 'desc'; id: string; icon?: IconProp; }; diff --git a/front/src/components/table/table-header/TableHeader.tsx b/front/src/components/table/table-header/TableHeader.tsx index a3c861ce1..18d651dda 100644 --- a/front/src/components/table/table-header/TableHeader.tsx +++ b/front/src/components/table/table-header/TableHeader.tsx @@ -9,6 +9,7 @@ import { useState } from 'react'; type OwnProps = { viewName: string; viewIcon?: IconProp; + onSortsUpdate?: React.Dispatch>; }; const StyledContainer = styled.div` @@ -43,8 +44,9 @@ const StyledFilters = styled.div` margin-right: ${(props) => props.theme.spacing(2)}; `; -function TableHeader({ viewName, viewIcon }: OwnProps) { +function TableHeader({ viewName, viewIcon, onSortsUpdate }: OwnProps) { const [sorts, setSorts] = useState([] as Array); + const onSortItemSelect = (sortId: string) => { setSorts([ { @@ -53,6 +55,7 @@ function TableHeader({ viewName, viewIcon }: OwnProps) { id: sortId, }, ]); + onSortsUpdate && onSortsUpdate(sorts); }; const onSortItemUnSelect = (sortId: string) => { diff --git a/front/src/interfaces/person.interface.test.ts b/front/src/interfaces/person.interface.test.ts new file mode 100644 index 000000000..e5c01f812 --- /dev/null +++ b/front/src/interfaces/person.interface.test.ts @@ -0,0 +1,22 @@ +import { mapPerson } from './person.interface'; + +describe('mapPerson', () => { + it('should map person', () => { + const person = mapPerson({ + id: 1, + firstname: 'John', + lastname: 'Doe', + email: '', + phone: '', + city: '', + created_at: '', + company: { + __typename: '', + company_name: '', + company_domain: '', + }, + __typename: '', + }); + expect(person.fullName).toBe('John Doe'); + }); +}); diff --git a/front/src/pages/people/types.ts b/front/src/interfaces/person.interface.ts similarity index 51% rename from front/src/pages/people/types.ts rename to front/src/interfaces/person.interface.ts index 4afd0aeae..97be4406a 100644 --- a/front/src/pages/people/types.ts +++ b/front/src/interfaces/person.interface.ts @@ -1,5 +1,5 @@ -import { Company } from '../../interfaces/company.interface'; -import { Pipe } from '../../interfaces/pipe.interface'; +import { Company } from './company.interface'; +import { Pipe } from './pipe.interface'; export type Person = { fullName: string; @@ -28,3 +28,16 @@ export type GraphqlPerson = { phone: string; __typename: string; }; + +export const mapPerson = (person: GraphqlPerson): Person => ({ + fullName: `${person.firstname} ${person.lastname}`, + creationDate: new Date(person.created_at), + pipe: { name: 'coucou', id: 1, icon: 'faUser' }, + ...person, + company: { + id: 1, + name: person.company.company_name, + domain: person.company.company_domain, + }, + countryCode: 'FR', +}); diff --git a/front/src/pages/people/People.tsx b/front/src/pages/people/People.tsx index df4226800..65cff1c70 100644 --- a/front/src/pages/people/People.tsx +++ b/front/src/pages/people/People.tsx @@ -4,9 +4,9 @@ import Table from '../../components/table/Table'; import styled from '@emotion/styled'; import { peopleColumns } from './people-table'; import { gql, useQuery } from '@apollo/client'; -import { GraphqlPerson, Person } from './types'; -import { defaultData } from './default-data'; -import { mapPerson } from './mapper'; +import { GraphqlPerson, mapPerson } from '../../interfaces/person.interface'; +import { useState } from 'react'; +import { SortType } from '../../components/table/table-header/SortAndFilterBar'; const StyledPeopleContainer = styled.div` display: flex; @@ -14,8 +14,8 @@ const StyledPeopleContainer = styled.div` `; export const GET_PEOPLE = gql` - query GetPeople { - person { + query GetPeople($orderBy: [person_order_by!]) { + person(order_by: $orderBy) { id phone email @@ -31,20 +31,40 @@ export const GET_PEOPLE = gql` } `; -function People() { - const { data } = useQuery<{ person: GraphqlPerson[] }>(GET_PEOPLE); +// @TODO get those types from generated-code person-order-by +type OrderBy = Record; - const mydata: Person[] = data ? data.person.map(mapPerson) : defaultData; +const defaultOrderBy = [ + { + created_at: 'desc', + }, +]; + +const reduceSortsToOrderBy = (sorts: Array): OrderBy[] => { + const mappedSorts = sorts.reduce((acc, sort) => { + acc[sort.id] = sort.order; + return acc; + }, {} as OrderBy); + return [mappedSorts]; +}; + +function People() { + const [sorts, setSorts] = useState([] as Array); + const orderBy = sorts.length ? reduceSortsToOrderBy(sorts) : defaultOrderBy; + const { data } = useQuery<{ person: GraphqlPerson[] }>(GET_PEOPLE, { + variables: { orderBy: orderBy }, + }); return ( - {mydata && ( + {data && ( )} diff --git a/front/src/pages/people/__stories__/People.stories.tsx b/front/src/pages/people/__stories__/People.stories.tsx index 02ec4f45e..52bb7796d 100644 --- a/front/src/pages/people/__stories__/People.stories.tsx +++ b/front/src/pages/people/__stories__/People.stories.tsx @@ -16,6 +16,9 @@ const mocks = [ { request: { query: GET_PEOPLE, + variables: { + orderBy: [{ created_at: 'desc' }], + }, }, result: { data: { diff --git a/front/src/pages/people/__tests__/People.test.tsx b/front/src/pages/people/__tests__/People.test.tsx index ce20166a7..140004316 100644 --- a/front/src/pages/people/__tests__/People.test.tsx +++ b/front/src/pages/people/__tests__/People.test.tsx @@ -1,10 +1,12 @@ -import { render } from '@testing-library/react'; +import { render, waitFor } from '@testing-library/react'; import { PeopleDefault } from '../__stories__/People.stories'; -it('Checks the People page render', () => { +it('Checks the People page render', async () => { const { getByTestId } = render(); - const title = getByTestId('top-bar-title'); - expect(title).toHaveTextContent('People'); + await waitFor(() => { + const personChip = getByTestId('row-id-0'); + expect(personChip).toBeDefined(); + }); }); diff --git a/front/src/pages/people/default-data.ts b/front/src/pages/people/default-data.ts index e071b07f8..b0efc97a5 100644 --- a/front/src/pages/people/default-data.ts +++ b/front/src/pages/people/default-data.ts @@ -1,47 +1,69 @@ -import { Person } from './types'; +import { GraphqlPerson } from '../../interfaces/person.interface'; -export const defaultData: Array = [ +export const defaultData: Array = [ { - fullName: 'Alexandre Prot', - picture: 'http://placekitten.com/256', + id: 1, + __typename: 'Person', + firstname: 'Alexandre', + lastname: 'Prot', email: 'alexandre@qonto.com', - company: { id: 1, name: 'Qonto', domain: 'qonto.com' }, + company: { + company_name: 'Qonto', + company_domain: 'qonto.com', + __typename: 'Company', + }, phone: '06 12 34 56 78', - creationDate: new Date('Feb 23, 2018'), - pipe: { id: 1, name: 'Sales Pipeline', icon: 'faUser' }, + created_at: '2023-04-20T13:20:09.158312+00:00', + city: 'Paris', - countryCode: 'FR', }, { - fullName: 'Alexandre Prot', + id: 2, + __typename: 'Person', + firstname: 'Alexandre', + lastname: 'Prot', email: 'alexandre@qonto.com', - company: { id: 2, name: 'LinkedIn', domain: 'linkedin.com' }, + company: { + company_name: 'LinkedIn', + company_domain: 'linkedin.com', + __typename: 'Company', + }, phone: '06 12 34 56 78', - creationDate: new Date('Feb 22, 2018'), - pipe: { id: 1, name: 'Sales Pipeline', icon: 'faUser' }, + created_at: '2023-04-20T13:20:09.158312+00:00', + city: 'Paris', - countryCode: 'FR', }, { - fullName: 'Alexandre Prot', - picture: 'http://placekitten.com/256', + id: 3, + __typename: 'Person', + firstname: 'Alexandre', + lastname: 'Prot', email: 'alexandre@qonto.com', - company: { id: 5, name: 'Sequoia', domain: 'sequoiacap.com' }, + company: { + company_name: 'Sequoia', + company_domain: 'sequoiacap.com', + __typename: 'Company', + }, phone: '06 12 34 56 78', - creationDate: new Date('Feb 21, 2018'), - pipe: { id: 1, name: 'Sales Pipeline', icon: 'faUser' }, + created_at: '2023-04-20T13:20:09.158312+00:00', + city: 'Paris', - countryCode: 'FR', }, { - fullName: 'Alexandre Prot', + id: 4, + __typename: 'Person', + firstname: 'Alexandre', + lastname: 'Prot', email: 'alexandre@qonto.com', - company: { id: 2, name: 'Facebook', domain: 'facebook.com' }, + company: { + company_name: 'Facebook', + company_domain: 'facebook.com', + __typename: 'Company', + }, phone: '06 12 34 56 78', - creationDate: new Date('Feb 25, 2018'), - pipe: { id: 1, name: 'Sales Pipeline', icon: 'faUser' }, + created_at: '2023-04-20T13:20:09.158312+00:00', + city: 'Paris', - countryCode: 'FR', }, ]; diff --git a/front/src/pages/people/mapper.ts b/front/src/pages/people/mapper.ts deleted file mode 100644 index 5ae21b954..000000000 --- a/front/src/pages/people/mapper.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { GraphqlPerson, Person } from './types'; - -export const mapPerson = (person: GraphqlPerson): Person => ({ - fullName: `${person.firstname} ${person.lastname}`, - creationDate: new Date(person.created_at), - pipe: { name: 'coucou', id: 1, icon: 'faUser' }, - ...person, - company: { - id: 1, - name: person.company.company_name, - domain: person.company.company_domain, - }, - countryCode: 'FR', -}); diff --git a/front/src/pages/people/people-table.tsx b/front/src/pages/people/people-table.tsx index b1063a7eb..87728bace 100644 --- a/front/src/pages/people/people-table.tsx +++ b/front/src/pages/people/people-table.tsx @@ -15,7 +15,7 @@ import Checkbox from '../../components/form/Checkbox'; import HorizontalyAlignedContainer from '../../layout/containers/HorizontalyAlignedContainer'; import CompanyChip from '../../components/chips/CompanyChip'; import PersonChip from '../../components/chips/PersonChip'; -import { Person } from './types'; +import { Person } from '../../interfaces/person.interface'; const columnHelper = createColumnHelper(); export const peopleColumns = [