From a55e75d29efc4061a5fa3a7c76e7b71aa69c925a Mon Sep 17 00:00:00 2001 From: Denys Cheporniuk Date: Sun, 23 Oct 2022 22:39:58 +0300 Subject: [PATCH 1/4] initial commit --- package.json | 2 +- src/App.scss | 8 + src/App.tsx | 45 ++-- src/components/Button/Button.tsx | 15 ++ src/components/Button/index.ts | 1 + src/components/PeopleTable/PeopleTable.tsx | 237 +++++++++++++++++++++ src/components/PeopleTable/index.ts | 1 + 7 files changed, 286 insertions(+), 23 deletions(-) create mode 100644 src/components/Button/Button.tsx create mode 100644 src/components/Button/index.ts create mode 100644 src/components/PeopleTable/PeopleTable.tsx create mode 100644 src/components/PeopleTable/index.ts diff --git a/package.json b/package.json index 2b097dc1..1cc7b2bd 100755 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "@cypress/webpack-dev-server": "^1.8.4", "@mate-academy/cypress-tools": "^1.0.4", "@mate-academy/eslint-config-react-typescript": "^1.0.11", - "@mate-academy/scripts": "^1.2.3", + "@mate-academy/scripts": "^1.2.8", "@mate-academy/students-ts-config": "*", "@mate-academy/stylelint-config": "*", "@types/node": "^17.0.45", diff --git a/src/App.scss b/src/App.scss index 93f0af3a..4d26146b 100644 --- a/src/App.scss +++ b/src/App.scss @@ -2,3 +2,11 @@ iframe { display: none; } + +button { + cursor: pointer; +} + +tr { + transition: 0.3s background-color; +} diff --git a/src/App.tsx b/src/App.tsx index f6361547..a3cb0745 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,35 +4,36 @@ import '@fortawesome/fontawesome-free/css/all.css'; import 'bulma/css/bulma.css'; import './App.scss'; -import peopleFromServer from './people.json'; +import { Loader } from './components/Loader'; +import { PeopleTable } from './components/PeopleTable'; -export class App extends React.Component { - state = {}; +type State = { + isLoaded: boolean; +}; + +export class App extends React.Component<{}, State> { + state: Readonly = { + isLoaded: false, + }; + + componentDidMount() { + setTimeout(() => { + this.setState({ + isLoaded: true, + }); + }, 1000); + } render() { + const { isLoaded } = this.state; + return (

People table

- - - - - - - - - - - {peopleFromServer.map(person => ( - - - - - - ))} - -
namesexborn
{person.name}{person.sex}{person.born}
+ {isLoaded + ? + : }
); } diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx new file mode 100644 index 00000000..33fd3cf8 --- /dev/null +++ b/src/components/Button/Button.tsx @@ -0,0 +1,15 @@ +import React from 'react'; + +type Props = React.ButtonHTMLAttributes & { + children: React.ReactNode; +}; + +export const Button: React.FC = ({ children, className, ...props }) => ( + +); diff --git a/src/components/Button/index.ts b/src/components/Button/index.ts new file mode 100644 index 00000000..8b166a86 --- /dev/null +++ b/src/components/Button/index.ts @@ -0,0 +1 @@ +export * from './Button'; diff --git a/src/components/PeopleTable/PeopleTable.tsx b/src/components/PeopleTable/PeopleTable.tsx new file mode 100644 index 00000000..5c50f603 --- /dev/null +++ b/src/components/PeopleTable/PeopleTable.tsx @@ -0,0 +1,237 @@ +import React from 'react'; +import classNames from 'classnames'; +import { Person } from '../../types/Person'; +import { Button } from '../Button'; +import peopleFromServer from '../../people.json'; + +enum SortField { + Name = 'name', + Slug = 'slug', + Born = 'born', + Died = 'died', + Null = 'null', +} + +type State = { + selectedPeople: Person[]; + people: Person[]; + sortField: SortField; +}; + +function sortByField(items: Person[], field: SortField) { + return [...items].sort((personA, personB) => { + switch (field) { + case SortField.Born: + case SortField.Died: + return personA[field] - personB[field]; + + case SortField.Name: + case SortField.Slug: + return personA[field].localeCompare(personB[field]); + + default: + return 0; + } + }); +} + +export class PeopleTable extends React.Component<{}, State> { + state: Readonly = { + selectedPeople: [], + people: peopleFromServer, + sortField: SortField.Null, + }; + + moveDown = (person: Person) => { + this.setState((state: State) => { + const peopleCopy = [...state.people]; + + const personIndex = peopleCopy.findIndex( + personA => personA.slug === person.slug, + ); + + if (personIndex === peopleCopy.length - 1) { + return null; + } + + peopleCopy[personIndex + 1] = person; + peopleCopy[personIndex] = state.people[personIndex + 1]; + + return ({ + people: peopleCopy, + }); + }); + }; + + moveUp = (person: Person) => { + this.setState((state: State) => { + const peopleCopy = [...state.people]; + + const personIndex = peopleCopy.findIndex( + personA => personA.slug === person.slug, + ); + + if (personIndex === 0) { + return null; + } + + peopleCopy[personIndex - 1] = person; + peopleCopy[personIndex] = state.people[personIndex - 1]; + + return ({ + people: peopleCopy, + }); + }); + }; + + selectPerson = (person: Person) => { + this.setState(({ selectedPeople }) => { + const newSelectedPeople = [...selectedPeople, person]; + + return ({ + selectedPeople: newSelectedPeople, + }); + }); + }; + + unselectPerson = (person: Person) => { + this.setState(({ selectedPeople }) => ({ + selectedPeople: selectedPeople.filter( + selectedPerson => selectedPerson.slug !== person.slug, + ), + })); + }; + + clearSelectedPeople = () => { + this.setState({ + selectedPeople: [], + }); + }; + + setSortField = (sortField: SortField) => { + this.setState({ + sortField, + }); + } + + render() { + const { + selectedPeople, + people, + sortField, + } = this.state; + + if (people.length === 0) { + return ( +

No people data yet

+ ); + } + + function isPersonSelected(person: Person) { + return selectedPeople.some( + selectedPerson => selectedPerson.slug === person.slug, + ); + } + + const visiblePeople = sortByField(people, sortField); + + return ( + + + + + + + + + + + + + + {visiblePeople.map(person => ( + + + + + + + + + + ))} + +
+ {selectedPeople.length > 0 && ( +
select + name + + this.setSortField(SortField.Name)} + > + + + + + sexborn
+ {isPersonSelected(person) + ? ( + + ) + : ( + + )} + + {person.name} + {person.sex}{person.born} + + + +
+ ); + } +} diff --git a/src/components/PeopleTable/index.ts b/src/components/PeopleTable/index.ts new file mode 100644 index 00000000..45984e7c --- /dev/null +++ b/src/components/PeopleTable/index.ts @@ -0,0 +1 @@ +export * from './PeopleTable'; From 945fe49c84520808c47cfd896fd3d82442f4ee2d Mon Sep 17 00:00:00 2001 From: Denys Cheporniuk Date: Sun, 23 Oct 2022 23:45:42 +0300 Subject: [PATCH 2/4] implement react people table --- src/App.tsx | 42 ++- src/components/PeopleTable/PeopleTable.tsx | 296 +++++++++------------ 2 files changed, 146 insertions(+), 192 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index a3cb0745..e9cb3635 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import '@fortawesome/fontawesome-free/css/all.css'; import 'bulma/css/bulma.css'; @@ -7,34 +7,22 @@ import './App.scss'; import { Loader } from './components/Loader'; import { PeopleTable } from './components/PeopleTable'; -type State = { - isLoaded: boolean; -}; - -export class App extends React.Component<{}, State> { - state: Readonly = { - isLoaded: false, - }; +export const App: React.FC = () => { + const [isLoaded, setLoading] = useState(false); - componentDidMount() { + useEffect(() => { setTimeout(() => { - this.setState({ - isLoaded: true, - }); + setLoading(true); }, 1000); - } + }, []); - render() { - const { isLoaded } = this.state; + return ( +
+

People table

- return ( -
-

People table

- - {isLoaded - ? - : } -
- ); - } -} + {isLoaded + ? + : } +
+ ); +}; diff --git a/src/components/PeopleTable/PeopleTable.tsx b/src/components/PeopleTable/PeopleTable.tsx index 5c50f603..c5dfbbb9 100644 --- a/src/components/PeopleTable/PeopleTable.tsx +++ b/src/components/PeopleTable/PeopleTable.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import classNames from 'classnames'; import { Person } from '../../types/Person'; import { Button } from '../Button'; @@ -12,12 +12,6 @@ enum SortField { Null = 'null', } -type State = { - selectedPeople: Person[]; - people: Person[]; - sortField: SortField; -}; - function sortByField(items: Person[], field: SortField) { return [...items].sort((personA, personB) => { switch (field) { @@ -35,203 +29,175 @@ function sortByField(items: Person[], field: SortField) { }); } -export class PeopleTable extends React.Component<{}, State> { - state: Readonly = { - selectedPeople: [], - people: peopleFromServer, - sortField: SortField.Null, - }; +export const PeopleTable: React.FC<{}> = () => { + const [people, setPeople] = useState(peopleFromServer); + const [selectedPeople, setSelectedPeople] = useState([]); + const [sortField, setSortField] = useState(SortField.Null); - moveDown = (person: Person) => { - this.setState((state: State) => { - const peopleCopy = [...state.people]; + const moveDown = (person: Person) => { + setPeople(currentPeople => { + const peopleCopy = [...currentPeople]; const personIndex = peopleCopy.findIndex( personA => personA.slug === person.slug, ); if (personIndex === peopleCopy.length - 1) { - return null; + return currentPeople; } peopleCopy[personIndex + 1] = person; - peopleCopy[personIndex] = state.people[personIndex + 1]; + peopleCopy[personIndex] = currentPeople[personIndex + 1]; - return ({ - people: peopleCopy, - }); + return peopleCopy; }); }; - moveUp = (person: Person) => { - this.setState((state: State) => { - const peopleCopy = [...state.people]; + const moveUp = (person: Person) => { + setPeople(currentPeople => { + const peopleCopy = [...currentPeople]; const personIndex = peopleCopy.findIndex( personA => personA.slug === person.slug, ); if (personIndex === 0) { - return null; + return currentPeople; } peopleCopy[personIndex - 1] = person; - peopleCopy[personIndex] = state.people[personIndex - 1]; + peopleCopy[personIndex] = currentPeople[personIndex - 1]; - return ({ - people: peopleCopy, - }); + return peopleCopy; }); }; - selectPerson = (person: Person) => { - this.setState(({ selectedPeople }) => { - const newSelectedPeople = [...selectedPeople, person]; - - return ({ - selectedPeople: newSelectedPeople, - }); - }); + const selectPerson = (person: Person) => { + setSelectedPeople(currentPeople => [...currentPeople, person]); }; - unselectPerson = (person: Person) => { - this.setState(({ selectedPeople }) => ({ - selectedPeople: selectedPeople.filter( + const unselectPerson = (person: Person) => { + setSelectedPeople((currentPeople) => ( + currentPeople.filter( selectedPerson => selectedPerson.slug !== person.slug, - ), - })); + ) + )); }; - clearSelectedPeople = () => { - this.setState({ - selectedPeople: [], - }); + const clearSelectedPeople = () => { + setSelectedPeople([]); }; - setSortField = (sortField: SortField) => { - this.setState({ - sortField, - }); - } - - render() { - const { - selectedPeople, - people, - sortField, - } = this.state; - - if (people.length === 0) { - return ( -

No people data yet

- ); - } - - function isPersonSelected(person: Person) { - return selectedPeople.some( - selectedPerson => selectedPerson.slug === person.slug, - ); - } + const isPersonSelected = (person: Person) => { + return selectedPeople.some( + selectedPerson => selectedPerson.slug === person.slug, + ); + }; - const visiblePeople = sortByField(people, sortField); + const visiblePeople = sortByField(people, sortField); + if (people.length === 0) { return ( - - - - - - - - - - - +

No people data yet

+ ); + } - - {visiblePeople.map(person => ( - + + + + + + + + + + + + + {visiblePeople.map(person => ( + + + - + + - - - - - - - ))} - -
- {selectedPeople.length > 0 && ( -
select - name - - this.setSortField(SortField.Name)} - > - - - - - sexborn
+ {selectedPeople.length > 0 && ( +
select + name + + setSortField(SortField.Name)} + > + + + + + sexborn
+ {isPersonSelected(person) + ? ( + + ) + : ( + + )} + - - {isPersonSelected(person) - ? ( - - ) - : ( - - )} - + {person.sex}{person.born} + {person.sex}{person.born} - - - -
- ); - } -} + ↓ + + + + + + + + ))} + + + ); +}; From 337a2c26692d0d58028319a6b06a68cb736da849 Mon Sep 17 00:00:00 2001 From: Denys Cheporniuk Date: Tue, 25 Oct 2022 12:10:07 +0300 Subject: [PATCH 3/4] add SelectedPeople and PeopleList components --- src/App.tsx | 8 +- src/components/PeopleList/PeopleList.tsx | 118 +++++++ src/components/PeopleList/index.ts | 1 + src/components/PeopleTable/PeopleTable.tsx | 289 ++++++------------ .../SelectedPeople/SelectedPeople.tsx | 39 +++ src/components/SelectedPeople/index.ts | 1 + src/people.json | 156 +++++++--- src/types/Person.ts | 2 + src/types/SortFields.ts | 8 + 9 files changed, 383 insertions(+), 239 deletions(-) create mode 100644 src/components/PeopleList/PeopleList.tsx create mode 100644 src/components/PeopleList/index.ts create mode 100644 src/components/SelectedPeople/SelectedPeople.tsx create mode 100644 src/components/SelectedPeople/index.ts create mode 100644 src/types/SortFields.ts diff --git a/src/App.tsx b/src/App.tsx index e9cb3635..7cd1f6e3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,14 +5,14 @@ import 'bulma/css/bulma.css'; import './App.scss'; import { Loader } from './components/Loader'; -import { PeopleTable } from './components/PeopleTable'; +import { PeopleList } from './components/PeopleList'; export const App: React.FC = () => { - const [isLoaded, setLoading] = useState(false); + const [isLoaded, setIsLoaded] = useState(false); useEffect(() => { setTimeout(() => { - setLoading(true); + setIsLoaded(true); }, 1000); }, []); @@ -21,7 +21,7 @@ export const App: React.FC = () => {

People table

{isLoaded - ? + ? : } ); diff --git a/src/components/PeopleList/PeopleList.tsx b/src/components/PeopleList/PeopleList.tsx new file mode 100644 index 00000000..32d3b421 --- /dev/null +++ b/src/components/PeopleList/PeopleList.tsx @@ -0,0 +1,118 @@ +import React, { useState } from 'react'; +import { Person } from '../../types/Person'; +import peopleFromServer from '../../people.json'; +import {SelectedPeople} from "../SelectedPeople"; +import {PeopleTable} from "../PeopleTable"; +import {SortField} from "../../types/SortFields"; + +function sortByField(items: Person[], field: SortField) { + return [...items].sort((personA, personB) => { + switch (field) { + case SortField.Born: + case SortField.Died: + return personA[field] - personB[field]; + + case SortField.Name: + case SortField.Slug: + return personA[field].localeCompare(personB[field]); + + default: + return 0; + } + }); +} + +export const PeopleList: React.FC<{}> = () => { + const [people, setPeople] = useState(peopleFromServer); + + const moveDown = (person: Person) => { + setPeople(currentPeople => { + const peopleCopy = [...currentPeople]; + + const personIndex = peopleCopy.findIndex( + personA => personA.slug === person.slug, + ); + + if (personIndex === peopleCopy.length - 1) { + return currentPeople; + } + + peopleCopy[personIndex + 1] = person; + peopleCopy[personIndex] = currentPeople[personIndex + 1]; + + return peopleCopy; + }); + }; + + const moveUp = (person: Person) => { + setPeople(currentPeople => { + const peopleCopy = [...currentPeople]; + + const personIndex = peopleCopy.findIndex( + personA => personA.slug === person.slug, + ); + + if (personIndex === 0) { + return currentPeople; + } + + peopleCopy[personIndex - 1] = person; + peopleCopy[personIndex] = currentPeople[personIndex - 1]; + + return peopleCopy; + }); + }; + + const selectionToggler = (personId: string) => { + setPeople(currentPeople => ( + currentPeople.map(person => { + if (person.id === personId) { + return { + ...person, + selected: !person.selected, + } + } + + return person; + }) + )) + } + + const clearSelectedPeople = () => { + setPeople(currentPeople => ( + currentPeople.map(person => ({ + ...person, + selected: false, + })) + )) + }; + + const sortPeople = (field: SortField) => { + setPeople(currentPeople => ( + sortByField(currentPeople, field) + )); + }; + + if (people.length === 0) { + return ( +

No people data yet

+ ); + } + + return ( + <> + + + + + ); +}; diff --git a/src/components/PeopleList/index.ts b/src/components/PeopleList/index.ts new file mode 100644 index 00000000..487eb57c --- /dev/null +++ b/src/components/PeopleList/index.ts @@ -0,0 +1 @@ +export * from './PeopleList'; diff --git a/src/components/PeopleTable/PeopleTable.tsx b/src/components/PeopleTable/PeopleTable.tsx index c5dfbbb9..6dff63b8 100644 --- a/src/components/PeopleTable/PeopleTable.tsx +++ b/src/components/PeopleTable/PeopleTable.tsx @@ -1,203 +1,100 @@ -import React, { useState } from 'react'; -import classNames from 'classnames'; -import { Person } from '../../types/Person'; -import { Button } from '../Button'; -import peopleFromServer from '../../people.json'; - -enum SortField { - Name = 'name', - Slug = 'slug', - Born = 'born', - Died = 'died', - Null = 'null', -} - -function sortByField(items: Person[], field: SortField) { - return [...items].sort((personA, personB) => { - switch (field) { - case SortField.Born: - case SortField.Died: - return personA[field] - personB[field]; - - case SortField.Name: - case SortField.Slug: - return personA[field].localeCompare(personB[field]); - - default: - return 0; - } - }); +import React from "react"; +import cn from "classnames"; +import { Button } from "../Button"; +import {SortField} from "../../types/SortFields"; +import {Person} from "../../types/Person"; + +type Props = { + people: Person[]; + moveUp: (person: Person) => void; + moveDown: (person: Person) => void; + selectionToggler: (personId: string) => void; + sortPeople: (field: SortField) => void; } -export const PeopleTable: React.FC<{}> = () => { - const [people, setPeople] = useState(peopleFromServer); - const [selectedPeople, setSelectedPeople] = useState([]); - const [sortField, setSortField] = useState(SortField.Null); - - const moveDown = (person: Person) => { - setPeople(currentPeople => { - const peopleCopy = [...currentPeople]; - - const personIndex = peopleCopy.findIndex( - personA => personA.slug === person.slug, - ); - - if (personIndex === peopleCopy.length - 1) { - return currentPeople; - } - - peopleCopy[personIndex + 1] = person; - peopleCopy[personIndex] = currentPeople[personIndex + 1]; - - return peopleCopy; - }); - }; - - const moveUp = (person: Person) => { - setPeople(currentPeople => { - const peopleCopy = [...currentPeople]; - - const personIndex = peopleCopy.findIndex( - personA => personA.slug === person.slug, - ); - - if (personIndex === 0) { - return currentPeople; - } - - peopleCopy[personIndex - 1] = person; - peopleCopy[personIndex] = currentPeople[personIndex - 1]; - - return peopleCopy; - }); - }; - - const selectPerson = (person: Person) => { - setSelectedPeople(currentPeople => [...currentPeople, person]); - }; - - const unselectPerson = (person: Person) => { - setSelectedPeople((currentPeople) => ( - currentPeople.filter( - selectedPerson => selectedPerson.slug !== person.slug, - ) - )); - }; - - const clearSelectedPeople = () => { - setSelectedPeople([]); - }; - - const isPersonSelected = (person: Person) => { - return selectedPeople.some( - selectedPerson => selectedPerson.slug === person.slug, - ); - }; - - const visiblePeople = sortByField(people, sortField); - - if (people.length === 0) { - return ( -

No people data yet

- ); - } - - return ( - - - - - - - + + ))} + +
- {selectedPeople.length > 0 && ( -
select - name - - setSortField(SortField.Name)} +export const PeopleTable: React.FC = ({ + people, + moveUp, + moveDown, + selectionToggler, + sortPeople, +}) => ( + + + + + + + + + + + + {people.map(person => ( + + - - - - - - {visiblePeople.map(person => ( - + + - + + - - - - - - - ))} - -
select + name + + sortPeople(SortField.Name)} + > + + + + + sexborn
+ sexborn
- - {isPersonSelected(person) - ? ( - - ) - : ( - - )} - + {person.sex}{person.born} + {person.sex}{person.born} - - - -
- ); -}; + ↓ + + + +
+ +
+); diff --git a/src/components/SelectedPeople/SelectedPeople.tsx b/src/components/SelectedPeople/SelectedPeople.tsx new file mode 100644 index 00000000..ea8fc7dc --- /dev/null +++ b/src/components/SelectedPeople/SelectedPeople.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { Person } from '../../types/Person'; + +type Props = { + people: Person[]; + clearSelectedPeople: () => void; +} + +export const SelectedPeople: React.FC = ({ + people, + clearSelectedPeople, +}) => { + const selectedPeople = people.filter(person => person.selected); + + if (selectedPeople.length === 0) { + return ( +

+ No selected people +

+ ) + } + + return ( +
+
+ ) +} diff --git a/src/components/SelectedPeople/index.ts b/src/components/SelectedPeople/index.ts new file mode 100644 index 00000000..006681ba --- /dev/null +++ b/src/components/SelectedPeople/index.ts @@ -0,0 +1 @@ +export * from './SelectedPeople'; diff --git a/src/people.json b/src/people.json index c9a921dd..20e75582 100644 --- a/src/people.json +++ b/src/people.json @@ -1,353 +1,431 @@ [ { + "selected": false, "name": "Carolus Haverbeke", "sex": "m", "born": 1832, "died": 1905, "fatherName": "Carel Haverbeke", "motherName": "Maria van Brussel", - "slug": "carolus-haverbeke-1832" + "slug": "carolus-haverbeke-1832", + "id": "80e2e424-ecbc-4b43-98fc-80912106bd3e" }, { + "selected": false, "name": "Emma de Milliano", "sex": "f", "born": 1876, "died": 1956, "fatherName": "Petrus de Milliano", "motherName": "Sophia van Damme", - "slug": "emma-de-milliano-1876" + "slug": "emma-de-milliano-1876", + "id": "245e79e8-16f2-46f2-acda-03d224832211" }, { + "selected": false, "name": "Maria de Rycke", "sex": "f", "born": 1683, "died": 1724, "fatherName": "Frederik de Rycke", "motherName": "Laurentia van Vlaenderen", - "slug": "maria-de-rycke-1683" + "slug": "maria-de-rycke-1683", + "id": "d7460ec8-530e-4a8e-82dd-447f8a9cd5ae" }, { + "selected": false, "name": "Jan van Brussel", "sex": "m", "born": 1714, "died": 1748, "fatherName": "Jacobus van Brussel", "motherName": "Joanna van Rooten", - "slug": "jan-van-brussel-1714" + "slug": "jan-van-brussel-1714", + "id": "ac9aadf0-122d-4733-b99e-f8299902875e" }, { + "selected": false, "name": "Philibert Haverbeke", "sex": "m", "born": 1907, "died": 1997, "fatherName": "Emile Haverbeke", "motherName": "Emma de Milliano", - "slug": "philibert-haverbeke-1907" + "slug": "philibert-haverbeke-1907", + "id": "4bbe4da6-acc0-46d4-be93-fbe7ec3415cd" }, { + "selected": false, "name": "Jan Frans van Brussel", "sex": "m", "born": 1761, "died": 1833, "fatherName": "Jacobus Bernardus van Brussel", "motherName": null, - "slug": "jan-frans-van-brussel-1761" + "slug": "jan-frans-van-brussel-1761", + "id": "ff033b7e-83a1-4471-961a-a846c0964b0c" }, { + "selected": false, "name": "Pauwels van Haverbeke", "sex": "m", "born": 1535, "died": 1582, "fatherName": "N. van Haverbeke", "motherName": null, - "slug": "pauwels-van-haverbeke-1535" + "slug": "pauwels-van-haverbeke-1535", + "id": "79dbd0be-c254-4e76-992e-cdb48bab4477" }, { + "selected": false, "name": "Clara Aernoudts", "sex": "f", "born": 1918, "died": 2012, "fatherName": "Henry Aernoudts", "motherName": "Sidonie Coene", - "slug": "clara-aernoudts-1918" + "slug": "clara-aernoudts-1918", + "id": "196d4d1b-19f5-4630-af34-1791767b602f" }, { + "selected": false, "name": "Emile Haverbeke", "sex": "m", "born": 1877, "died": 1968, "fatherName": "Carolus Haverbeke", "motherName": "Maria Sturm", - "slug": "emile-haverbeke-1877" + "slug": "emile-haverbeke-1877", + "id": "29ef4f9e-5cb2-4765-bb91-b216bb53c645" }, { + "selected": false, "name": "Lieven de Causmaecker", "sex": "m", "born": 1696, "died": 1724, "fatherName": "Carel de Causmaecker", "motherName": "Joanna Claes", - "slug": "lieven-de-causmaecker-1696" + "slug": "lieven-de-causmaecker-1696", + "id": "5c0e79ef-9d9c-484e-8367-9f9c90ccbcfb" }, { + "selected": false, "name": "Pieter Haverbeke", "sex": "m", "born": 1602, "died": 1642, "fatherName": "Lieven van Haverbeke", "motherName": null, - "slug": "pieter-haverbeke-1602" + "slug": "pieter-haverbeke-1602", + "id": "af16931d-21f1-4f0a-ae7c-fec6f9dfc4e5" }, { + "selected": false, "name": "Livina Haverbeke", "sex": "f", "born": 1692, "died": 1743, "fatherName": "Daniel Haverbeke", "motherName": "Joanna de Pape", - "slug": "livina-haverbeke-1692" + "slug": "livina-haverbeke-1692", + "id": "bfa53e2c-3c1b-4349-b396-a2a051274550" }, { + "selected": false, "name": "Pieter Bernard Haverbeke", "sex": "m", "born": 1695, "died": 1762, "fatherName": "Willem Haverbeke", "motherName": "Petronella Wauters", - "slug": "pieter-bernard-haverbeke-1695" + "slug": "pieter-bernard-haverbeke-1695", + "id": "2638569b-1f3a-4aac-9308-89bf0e9f6825" }, { + "selected": false, "name": "Lieven van Haverbeke", "sex": "m", "born": 1570, "died": 1636, "fatherName": "Pauwels van Haverbeke", "motherName": "Lievijne Jans", - "slug": "lieven-van-haverbeke-1570" + "slug": "lieven-van-haverbeke-1570", + "id": "f545659f-0c55-4ecf-9546-97b66cd0332b" }, { + "selected": false, "name": "Joanna de Causmaecker", "sex": "f", "born": 1762, "died": 1807, "fatherName": "Bernardus de Causmaecker", "motherName": null, - "slug": "joanna-de-causmaecker-1762" + "slug": "joanna-de-causmaecker-1762", + "id": "e0a22678-4b36-433b-89d7-4d5e9cd27d43" }, { + "selected": false, "name": "Willem Haverbeke", "sex": "m", "born": 1668, "died": 1731, "fatherName": "Lieven Haverbeke", "motherName": "Elisabeth Hercke", - "slug": "willem-haverbeke-1668" + "slug": "willem-haverbeke-1668", + "id": "7ca2c432-274d-430b-8b84-91ba8bb04651" }, { + "selected": false, "name": "Pieter Antone Haverbeke", "sex": "m", "born": 1753, "died": 1798, "fatherName": "Jan Francies Haverbeke", "motherName": "Petronella de Decker", - "slug": "pieter-antone-haverbeke-1753" + "slug": "pieter-antone-haverbeke-1753", + "id": "beac3fd7-a67d-47e5-9314-a9fe35b7f822" }, { + "selected": false, "name": "Maria van Brussel", "sex": "f", "born": 1801, "died": 1834, "fatherName": "Jan Frans van Brussel", "motherName": "Joanna de Causmaecker", - "slug": "maria-van-brussel-1801" + "slug": "maria-van-brussel-1801", + "id": "b7469884-00ad-4eac-aa8e-b5873765d5f7" }, { + "selected": false, "name": "Angela Haverbeke", "sex": "f", "born": 1728, "died": 1734, "fatherName": "Pieter Bernard Haverbeke", "motherName": "Livina de Vrieze", - "slug": "angela-haverbeke-1728" + "slug": "angela-haverbeke-1728", + "id": "658b4e03-f620-43b2-8642-982f153ca483" }, { + "selected": false, "name": "Elisabeth Haverbeke", "sex": "f", "born": 1711, "died": 1754, "fatherName": "Jan Haverbeke", "motherName": "Maria de Rycke", - "slug": "elisabeth-haverbeke-1711" + "slug": "elisabeth-haverbeke-1711", + "id": "64d72b93-fdab-4702-8851-af88918a034c" }, { + "selected": false, "name": "Lievijne Jans", "sex": "f", "born": 1542, "died": 1582, "fatherName": null, "motherName": null, - "slug": "lievijne-jans-1542" + "slug": "lievijne-jans-1542", + "id": "0c9e7d61-4681-4b13-ac1a-d106806924e1" }, { + "selected": false, "name": "Bernardus de Causmaecker", "sex": "m", "born": 1721, "died": 1789, "fatherName": "Lieven de Causmaecker", "motherName": "Livina Haverbeke", - "slug": "bernardus-de-causmaecker-1721" + "slug": "bernardus-de-causmaecker-1721", + "id": "410ebb42-b987-47a4-8a0f-ebc6d06cb798" }, { + "selected": false, "name": "Jacoba Lammens", "sex": "f", "born": 1699, "died": 1740, "fatherName": "Lieven Lammens", "motherName": "Livina de Vrieze", - "slug": "jacoba-lammens-1699" + "slug": "jacoba-lammens-1699", + "id": "186318d9-fd1e-46ba-bf4b-8f1d52530f9a" }, { + "selected": false, "name": "Pieter de Decker", "sex": "m", "born": 1705, "died": 1780, "fatherName": "Joos de Decker", "motherName": "Petronella van de Steene", - "slug": "pieter-de-decker-1705" + "slug": "pieter-de-decker-1705", + "id": "371ad187-976f-4d06-9640-67bf82c85adb" }, { + "selected": false, "name": "Joanna de Pape", "sex": "f", "born": 1654, "died": 1723, "fatherName": "Vincent de Pape", "motherName": "Petronella Wauters", - "slug": "joanna-de-pape-1654" + "slug": "joanna-de-pape-1654", + "id": "5b74f55e-67f0-4805-ab03-cedd9571eb27" }, { + "selected": false, "name": "Daniel Haverbeke", "sex": "m", "born": 1652, "died": 1723, "fatherName": "Lieven Haverbeke", "motherName": "Elisabeth Hercke", - "slug": "daniel-haverbeke-1652" + "slug": "daniel-haverbeke-1652", + "id": "cd17b587-efc8-4708-a568-0a150d931eb8" }, { + "selected": false, "name": "Lieven Haverbeke", "sex": "m", "born": 1631, "died": 1676, "fatherName": "Pieter Haverbeke", "motherName": "Anna van Hecke", - "slug": "lieven-haverbeke-1631" + "slug": "lieven-haverbeke-1631", + "id": "b5d91ab5-0955-40a3-bd17-7b19dfa7efe6" }, { + "selected": false, "name": "Martina de Pape", "sex": "f", "born": 1666, "died": 1727, "fatherName": "Vincent de Pape", "motherName": "Petronella Wauters", - "slug": "martina-de-pape-1666" + "slug": "martina-de-pape-1666", + "id": "c7dd2ac1-8f99-4171-80b3-e748720cbe9e" }, { + "selected": false, "name": "Jan Francies Haverbeke", "sex": "m", "born": 1725, "died": 1779, "fatherName": "Pieter Bernard Haverbeke", "motherName": "Livina de Vrieze", - "slug": "jan-francies-haverbeke-1725" + "slug": "jan-francies-haverbeke-1725", + "id": "4558bad9-533f-4fc6-aa82-14af28a98519" }, { + "selected": false, "name": "Maria Haverbeke", "sex": "m", "born": 1905, "died": 1997, "fatherName": "Emile Haverbeke", "motherName": "Emma de Milliano", - "slug": "maria-haverbeke-1905" + "slug": "maria-haverbeke-1905", + "id": "31f8dcb0-1875-4b5f-855b-bdfa62d8549d" }, { + "selected": false, "name": "Petronella de Decker", "sex": "f", "born": 1731, "died": 1781, "fatherName": "Pieter de Decker", "motherName": "Livina Haverbeke", - "slug": "petronella-de-decker-1731" + "slug": "petronella-de-decker-1731", + "id": "d090e67f-6671-434b-b1fd-243d6d50ee71" }, { + "selected": false, "name": "Livina Sierens", "sex": "f", "born": 1761, "died": 1826, "fatherName": "Jan Sierens", "motherName": "Maria van Waes", - "slug": "livina-sierens-1761" + "slug": "livina-sierens-1761", + "id": "05c1bdbb-dc7e-4bd8-98e8-c4db91052439" }, { + "selected": false, "name": "Laurentia Haverbeke", "sex": "f", "born": 1710, "died": 1786, "fatherName": "Jan Haverbeke", "motherName": "Maria de Rycke", - "slug": "laurentia-haverbeke-1710" + "slug": "laurentia-haverbeke-1710", + "id": "2742212c-2e66-494e-858a-d34649693e80" }, { + "selected": false, "name": "Carel Haverbeke", "sex": "m", "born": 1796, "died": 1837, "fatherName": "Pieter Antone Haverbeke", "motherName": "Livina Sierens", - "slug": "carel-haverbeke-1796" + "slug": "carel-haverbeke-1796", + "id": "71b6e760-c32b-4bfd-8373-2a706370d6c4" }, { + "selected": false, "name": "Elisabeth Hercke", "sex": "f", "born": 1632, "died": 1674, "fatherName": "Willem Hercke", "motherName": "Margriet de Brabander", - "slug": "elisabeth-hercke-1632" + "slug": "elisabeth-hercke-1632", + "id": "5639bb8d-fb69-4b99-bab5-65b139ac5e27" }, { + "selected": false, "name": "Jan Haverbeke", "sex": "m", "born": 1671, "died": 1731, "fatherName": "Lieven Haverbeke", "motherName": "Elisabeth Hercke", - "slug": "jan-haverbeke-1671" + "slug": "jan-haverbeke-1671", + "id": "ab40cc90-5cc2-41da-b0a1-2aa2163c36cf" }, { + "selected": false, "name": "Anna van Hecke", "sex": "f", "born": 1607, "died": 1670, "fatherName": "Paschasius van Hecke", "motherName": "Martijntken Beelaert", - "slug": "anna-van-hecke-1607" + "slug": "anna-van-hecke-1607", + "id": "5fb52e13-020f-4254-bdf3-13559aa7fd89" }, { + "selected": false, "name": "Maria Sturm", "sex": "f", "born": 1835, "died": 1917, "fatherName": "Charles Sturm", "motherName": "Seraphina Spelier", - "slug": "maria-sturm-1835" + "slug": "maria-sturm-1835", + "id": "c0ebb75a-90e6-4f7c-aae2-d73e02aaee53" }, { + "selected": false, "name": "Jacobus Bernardus van Brussel", "sex": "m", "born": 1736, "died": 1809, "fatherName": "Jan van Brussel", "motherName": "Elisabeth Haverbeke", - "slug": "jacobus-bernardus-van-brussel-1736" + "slug": "jacobus-bernardus-van-brussel-1736", + "id": "72df7d4e-12d8-4739-bf1e-8325e31d3cc9" } ] diff --git a/src/types/Person.ts b/src/types/Person.ts index 5e65e546..721e66dc 100644 --- a/src/types/Person.ts +++ b/src/types/Person.ts @@ -1,4 +1,5 @@ export interface Person { + id: string; born: number; died: number; fatherName: string | null; @@ -6,4 +7,5 @@ export interface Person { name: string; sex: string; slug: string; + selected: boolean; } diff --git a/src/types/SortFields.ts b/src/types/SortFields.ts new file mode 100644 index 00000000..8cba342b --- /dev/null +++ b/src/types/SortFields.ts @@ -0,0 +1,8 @@ + +export enum SortField { + Name = 'name', + Slug = 'slug', + Born = 'born', + Died = 'died', + Null = 'null', +} From f684407207205ffbc1984f0929637696e21514b3 Mon Sep 17 00:00:00 2001 From: Denys Cheporniuk Date: Tue, 25 Oct 2022 12:10:20 +0300 Subject: [PATCH 4/4] add SelectedPeople and PeopleList components --- src/components/PeopleList/PeopleList.tsx | 14 +++--- src/components/PeopleTable/PeopleTable.tsx | 47 ++++++++++--------- .../SelectedPeople/SelectedPeople.tsx | 8 ++-- src/types/SortFields.ts | 1 - 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/components/PeopleList/PeopleList.tsx b/src/components/PeopleList/PeopleList.tsx index 32d3b421..13663868 100644 --- a/src/components/PeopleList/PeopleList.tsx +++ b/src/components/PeopleList/PeopleList.tsx @@ -1,9 +1,9 @@ import React, { useState } from 'react'; import { Person } from '../../types/Person'; import peopleFromServer from '../../people.json'; -import {SelectedPeople} from "../SelectedPeople"; -import {PeopleTable} from "../PeopleTable"; -import {SortField} from "../../types/SortFields"; +import { SelectedPeople } from '../SelectedPeople'; +import { PeopleTable } from '../PeopleTable'; +import { SortField } from '../../types/SortFields'; function sortByField(items: Person[], field: SortField) { return [...items].sort((personA, personB) => { @@ -70,13 +70,13 @@ export const PeopleList: React.FC<{}> = () => { return { ...person, selected: !person.selected, - } + }; } return person; }) - )) - } + )); + }; const clearSelectedPeople = () => { setPeople(currentPeople => ( @@ -84,7 +84,7 @@ export const PeopleList: React.FC<{}> = () => { ...person, selected: false, })) - )) + )); }; const sortPeople = (field: SortField) => { diff --git a/src/components/PeopleTable/PeopleTable.tsx b/src/components/PeopleTable/PeopleTable.tsx index 6dff63b8..e3f059ac 100644 --- a/src/components/PeopleTable/PeopleTable.tsx +++ b/src/components/PeopleTable/PeopleTable.tsx @@ -1,8 +1,8 @@ -import React from "react"; -import cn from "classnames"; -import { Button } from "../Button"; -import {SortField} from "../../types/SortFields"; -import {Person} from "../../types/Person"; +import React from 'react'; +import cn from 'classnames'; +import { Button } from '../Button'; +import { SortField } from '../../types/SortFields'; +import { Person } from '../../types/Person'; type Props = { people: Person[]; @@ -10,7 +10,7 @@ type Props = { moveDown: (person: Person) => void; selectionToggler: (personId: string) => void; sortPeople: (field: SortField) => void; -} +}; export const PeopleTable: React.FC = ({ people, @@ -21,23 +21,23 @@ export const PeopleTable: React.FC = ({ }) => ( - - - + + - - - + sortPeople(SortField.Name)} + > + + + + + + + + @@ -61,7 +61,8 @@ export const PeopleTable: React.FC = ({ cn('fas', { 'fa-minus': person.selected, 'fa-plus': !person.selected, - })} + }) + } /> diff --git a/src/components/SelectedPeople/SelectedPeople.tsx b/src/components/SelectedPeople/SelectedPeople.tsx index ea8fc7dc..728ed03f 100644 --- a/src/components/SelectedPeople/SelectedPeople.tsx +++ b/src/components/SelectedPeople/SelectedPeople.tsx @@ -4,7 +4,7 @@ import { Person } from '../../types/Person'; type Props = { people: Person[]; clearSelectedPeople: () => void; -} +}; export const SelectedPeople: React.FC = ({ people, @@ -17,7 +17,7 @@ export const SelectedPeople: React.FC = ({

No selected people

- ) + ); } return ( @@ -35,5 +35,5 @@ export const SelectedPeople: React.FC = ({ ))} - ) -} + ); +}; diff --git a/src/types/SortFields.ts b/src/types/SortFields.ts index 8cba342b..708e655b 100644 --- a/src/types/SortFields.ts +++ b/src/types/SortFields.ts @@ -1,4 +1,3 @@ - export enum SortField { Name = 'name', Slug = 'slug',
select - name +
select + name - sortPeople(SortField.Name)} - > - - - - - sexborn
sexborn