From 0c4dc41248e35cf28ba1ff9514cf245fd9baa5f2 Mon Sep 17 00:00:00 2001 From: Alexandra Protyanova Date: Thu, 12 Oct 2023 12:36:56 +0300 Subject: [PATCH 1/2] awesome people table --- src/App.jsx | 112 +++++++++++++++++++++++++++++++ src/App.tsx | 43 ------------ src/components/Button.jsx | 19 ++++++ src/components/PeopleFilters.jsx | 54 +++++++++++++++ src/components/PeopleHeader.jsx | 12 ++++ src/components/PeopleTable.jsx | 107 +++++++++++++++++++++++++++++ src/{index.tsx => index.jsx} | 2 +- 7 files changed, 305 insertions(+), 44 deletions(-) create mode 100644 src/App.jsx delete mode 100644 src/App.tsx create mode 100644 src/components/Button.jsx create mode 100644 src/components/PeopleFilters.jsx create mode 100644 src/components/PeopleHeader.jsx create mode 100644 src/components/PeopleTable.jsx rename src/{index.tsx => index.jsx} (70%) diff --git a/src/App.jsx b/src/App.jsx new file mode 100644 index 00000000..c9eccae3 --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,112 @@ +import React, { useState } from 'react'; +import { Button } from './components/Button'; +import { PeopleTable } from './components/PeopleTable'; + +import '@fortawesome/fontawesome-free/css/all.css'; +import 'bulma/css/bulma.css'; +import './App.scss'; + +import peopleFromServer from './people.json'; +import cn from 'classnames'; +import { PeopleHeader } from './components/PeopleHeader'; +import { PeopleFilters } from './components/PeopleFilters'; + +export const FILTERBYSEX = { + ALL: 'all', + M: 'm', + F: 'f', +}; + +export const SORTBY = { + NAME: 'name', + SEX: 'sex', + BORN: 'born', +}; + +function getFilteredPeople(people, sex, query) { + let filteredPeople = [...people]; + + if (query) { + const normalizedQuery = query.toLowerCase(); + + filteredPeople = filteredPeople.filter(person => ( + person.name.toLowerCase().startsWith(normalizedQuery) + )) + } + + if (sex !== 'all') { + filteredPeople = filteredPeople.filter(person => person.sex === sex); + } + + return filteredPeople; +} + +function sortPeople(people, sortBy) { + let sortedPeople = [...people]; + + if (!Object.keys(sortBy).length) { + return sortedPeople; + } + + const [property] = Object.entries(sortBy); + + const [key, value] = property; + + switch (key) { + case SORTBY.BORN: + sortedPeople.sort((a, b) => { + return value === 'ASC' + ? a.born - b.born + : b.born - a.born + }); + break; + + case SORTBY.NAME: + case SORTBY.SEX: + sortedPeople.sort((a, b) => { + return value === 'ASC' + ? a[key].localeCompare(b[key]) + : b[key].localeCompare(a[key]) + }) + break; + + default: + return sortedPeople; + } + + return sortedPeople; +} + +export const App = () => { + const [selectedPeople, setSelectedPeople] = useState([]); + const [filterBy, setFilterBy] = useState(FILTERBYSEX.ALL); + const [query, setQuery] = useState(''); + const [sortBy, setSortBy] = useState({}); + + const peopleForRendering = getFilteredPeople(peopleFromServer, filterBy, query); + const visiblePeople = sortPeople(peopleForRendering, sortBy); + + const selectedPeopleNames = selectedPeople.map(person => person.name).join(', '); + + return ( +
+ + + + + +
+ ); +} diff --git a/src/App.tsx b/src/App.tsx deleted file mode 100644 index 5d253930..00000000 --- a/src/App.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; - -import '@fortawesome/fontawesome-free/css/all.css'; -import 'bulma/css/bulma.css'; -import './App.scss'; - -// import peopleFromServer from './people.json'; - -export class App extends React.Component { - state = {}; - - render() { - return ( -
-

People table

- - - - - - - - - - - - - - - - - - - - - - - -
namesexborn
Carolus Haverbekem1832
Emma de Millianof1842
-
- ); - } -} diff --git a/src/components/Button.jsx b/src/components/Button.jsx new file mode 100644 index 00000000..db9a8b58 --- /dev/null +++ b/src/components/Button.jsx @@ -0,0 +1,19 @@ + +export const Button = ({ + type = 'button', + onClick, + className = 'button', + children, + ...props +}) => { + return ( + + ) +} diff --git a/src/components/PeopleFilters.jsx b/src/components/PeopleFilters.jsx new file mode 100644 index 00000000..953ce7a7 --- /dev/null +++ b/src/components/PeopleFilters.jsx @@ -0,0 +1,54 @@ +import React, { useState } from 'react'; +import { Button } from './Button'; +import cn from 'classnames'; +import { SORTBY, FILTERBYSEX } from '../App'; + +export const PeopleFilters = ({ + setFilterBy, + filterBy, + setQuery, +}) => { + return ( + <> + + + + + + + { + setQuery(event.target.value); + }} + /> + + ); +} diff --git a/src/components/PeopleHeader.jsx b/src/components/PeopleHeader.jsx new file mode 100644 index 00000000..14a6e7ae --- /dev/null +++ b/src/components/PeopleHeader.jsx @@ -0,0 +1,12 @@ + +export const PeopleHeader = ({ selectedPeopleNames }) => { + return ( +

+ {selectedPeopleNames.length === 0 ? ( + 'People table' + ) : ( + `Selected person is ${selectedPeopleNames}` + )} +

+ ) +}; diff --git a/src/components/PeopleTable.jsx b/src/components/PeopleTable.jsx new file mode 100644 index 00000000..1a2ce45a --- /dev/null +++ b/src/components/PeopleTable.jsx @@ -0,0 +1,107 @@ +import React, { useCallback, useState } from 'react'; +import cn from 'classnames'; +import { SORTBY, FILTERBYSEX } from '../App'; +import { Button } from './Button'; + + +function isSelected(selected, current) { + return selected === current; +} + +export const PeopleTable = ({ + setSortBy, + sortBy, + peopleToRender, + selectedPeople, + setSelectedPeople +}) => { + + return ( + + + + + + + + + {peopleToRender.map((person) => { + const isSelected = selectedPeople.includes(person); + + return ( + { + isSelected + ? setSelectedPeople(selectedPeople.filter(p => p.slug !== person.slug)) + : setSelectedPeople([...selectedPeople, person]) + }} + className={cn({ + 'has-background-warning': isSelected, + })} + > + + + + {isSelected ? ( + + ) : ( + + )} + + ) + })} + +
+ + + + + +
{person.name} + {person.sex} + {person.born}
+ ) +} diff --git a/src/index.tsx b/src/index.jsx similarity index 70% rename from src/index.tsx rename to src/index.jsx index b69de798..22a3129e 100644 --- a/src/index.tsx +++ b/src/index.jsx @@ -2,7 +2,7 @@ import { createRoot } from 'react-dom/client'; import { App } from './App'; const root = createRoot( - document.getElementById('root') as HTMLDivElement, + document.getElementById('root'), ); root.render(); From 6bce400fa17a17ee07ecb3643bc03b60ae061fc9 Mon Sep 17 00:00:00 2001 From: Alexandra Protyanova Date: Thu, 12 Oct 2023 12:51:14 +0300 Subject: [PATCH 2/2] linter fixe --- src/App.jsx | 43 +++++++++-------------- src/components/Button.jsx | 6 ++-- src/components/PeopleFilters.jsx | 18 +++++----- src/components/PeopleHeader.jsx | 3 +- src/components/PeopleTable.jsx | 60 ++++++++++++++++++-------------- src/constants.js | 11 ++++++ 6 files changed, 75 insertions(+), 66 deletions(-) create mode 100644 src/constants.js diff --git a/src/App.jsx b/src/App.jsx index c9eccae3..718b1932 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,27 +1,15 @@ +/* eslint-disable import/order */ import React, { useState } from 'react'; -import { Button } from './components/Button'; -import { PeopleTable } from './components/PeopleTable'; import '@fortawesome/fontawesome-free/css/all.css'; import 'bulma/css/bulma.css'; import './App.scss'; import peopleFromServer from './people.json'; -import cn from 'classnames'; import { PeopleHeader } from './components/PeopleHeader'; import { PeopleFilters } from './components/PeopleFilters'; - -export const FILTERBYSEX = { - ALL: 'all', - M: 'm', - F: 'f', -}; - -export const SORTBY = { - NAME: 'name', - SEX: 'sex', - BORN: 'born', -}; +import { PeopleTable } from './components/PeopleTable'; +import { FILTERBYSEX, SORTBY } from './constants'; function getFilteredPeople(people, sex, query) { let filteredPeople = [...people]; @@ -31,7 +19,7 @@ function getFilteredPeople(people, sex, query) { filteredPeople = filteredPeople.filter(person => ( person.name.toLowerCase().startsWith(normalizedQuery) - )) + )); } if (sex !== 'all') { @@ -42,7 +30,7 @@ function getFilteredPeople(people, sex, query) { } function sortPeople(people, sortBy) { - let sortedPeople = [...people]; + const sortedPeople = [...people]; if (!Object.keys(sortBy).length) { return sortedPeople; @@ -57,7 +45,7 @@ function sortPeople(people, sortBy) { sortedPeople.sort((a, b) => { return value === 'ASC' ? a.born - b.born - : b.born - a.born + : b.born - a.born; }); break; @@ -66,27 +54,30 @@ function sortPeople(people, sortBy) { sortedPeople.sort((a, b) => { return value === 'ASC' ? a[key].localeCompare(b[key]) - : b[key].localeCompare(a[key]) - }) - break; + : b[key].localeCompare(a[key]); + }); + break; default: - return sortedPeople; + return sortedPeople; } return sortedPeople; } -export const App = () => { +export const App = () => { const [selectedPeople, setSelectedPeople] = useState([]); const [filterBy, setFilterBy] = useState(FILTERBYSEX.ALL); const [query, setQuery] = useState(''); const [sortBy, setSortBy] = useState({}); - const peopleForRendering = getFilteredPeople(peopleFromServer, filterBy, query); + const peopleForRendering = getFilteredPeople( + peopleFromServer, filterBy, query, + ); const visiblePeople = sortPeople(peopleForRendering, sortBy); - const selectedPeopleNames = selectedPeople.map(person => person.name).join(', '); + const selectedPeopleNames = selectedPeople.map(person => person.name) + .join(', '); return (
@@ -109,4 +100,4 @@ export const App = () => { />
); -} +}; diff --git a/src/components/Button.jsx b/src/components/Button.jsx index db9a8b58..796e69a2 100644 --- a/src/components/Button.jsx +++ b/src/components/Button.jsx @@ -1,4 +1,3 @@ - export const Button = ({ type = 'button', onClick, @@ -9,11 +8,12 @@ export const Button = ({ return ( - ) -} + ); +}; diff --git a/src/components/PeopleFilters.jsx b/src/components/PeopleFilters.jsx index 953ce7a7..aa204835 100644 --- a/src/components/PeopleFilters.jsx +++ b/src/components/PeopleFilters.jsx @@ -1,7 +1,7 @@ -import React, { useState } from 'react'; -import { Button } from './Button'; +import React from 'react'; import cn from 'classnames'; -import { SORTBY, FILTERBYSEX } from '../App'; +import { Button } from './Button'; +import { FILTERBYSEX } from '../constants'; export const PeopleFilters = ({ setFilterBy, @@ -12,10 +12,10 @@ export const PeopleFilters = ({ <>