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.tsx b/src/App.tsx index f6361547..33474132 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,39 +1,28 @@ -import React from 'react'; +import { FC, useEffect, useState } from 'react'; import '@fortawesome/fontawesome-free/css/all.css'; import 'bulma/css/bulma.css'; import './App.scss'; -import peopleFromServer from './people.json'; +import { PeopleTable } from './components/PeopleTable/PeopleTable'; +import { Loader } from './components/Loader'; -export class App extends React.Component { - state = {}; +export const App: FC = () => { + const [isLoaded, setIsLoaded] = useState(false); - render() { - return ( -
-

People table

+ useEffect(() => { + setTimeout(() => { + setIsLoaded(true); + }, 1000); + }, []); - - - - - - - - + return ( +
+

People table

-
- {peopleFromServer.map(person => ( - - - - - - ))} - -
namesexborn
{person.name}{person.sex}{person.born}
-
- ); - } -} + {!isLoaded && } + + {isLoaded && } + + ); +}; diff --git a/src/components/PeopleTable/PeopleTable.scss b/src/components/PeopleTable/PeopleTable.scss new file mode 100644 index 00000000..6cb93e78 --- /dev/null +++ b/src/components/PeopleTable/PeopleTable.scss @@ -0,0 +1,3 @@ +.isSelected { + background-color: yellowgreen; +} diff --git a/src/components/PeopleTable/PeopleTable.tsx b/src/components/PeopleTable/PeopleTable.tsx new file mode 100644 index 00000000..ba0a9e49 --- /dev/null +++ b/src/components/PeopleTable/PeopleTable.tsx @@ -0,0 +1,231 @@ +import { ChangeEvent, useState } from 'react'; +import classNames from 'classnames'; + +import peopleFromServer from '../../people.json'; +import { Person } from '../../types/Person'; +import './PeopleTable.scss'; + +export const PeopleTable = () => { + const [people, setPeople] = useState(peopleFromServer); + const [selectedPeople, setSelectedPeople] = useState([]); + const [query, setQuery] = useState(''); + const [sex, setSex] = useState(''); + + // region Methods + const handlePersonSelection = (personToAdd: Person) => { + setSelectedPeople((prevSelectedPeople) => ([ + ...prevSelectedPeople, + personToAdd, + ])); + }; + + const handlePersonUnselection = (personToRemove: Person) => { + setSelectedPeople((prevSelectedPeople) => prevSelectedPeople + .filter( + person => person.slug !== personToRemove.slug, + )); + }; + + const handleMoveDown = (personToMoveDown: Person) => { + const peopleCopy = [...people]; + + const personIndex = peopleCopy.findIndex( + person => person.slug === personToMoveDown.slug, + ); + + if (personIndex === peopleCopy.length - 1) { + return; + } + + setPeople((prevPeople) => ([ + ...prevPeople.slice(0, personIndex), + prevPeople[personIndex + 1], + prevPeople[personIndex], + ...prevPeople.slice(personIndex + 2), + ])); + }; + + const handleMoveUp = (personToMoveDown: Person) => { + const peopleCopy = [...people]; + + const personIndex = peopleCopy.findIndex( + person => person.slug === personToMoveDown.slug, + ); + + if (personIndex === 0) { + return; + } + + const swap = peopleCopy[personIndex]; + + peopleCopy[personIndex] = peopleCopy[personIndex - 1]; + peopleCopy[personIndex - 1] = swap; + + setPeople(peopleCopy); + }; + + const isSelected = (personToCheck: Person) => { + return selectedPeople.some( + person => person.slug === personToCheck.slug, + ); + }; + + const clearSelectedPeople = () => { + setSelectedPeople([]); + }; + // endregion + + const handleInputChange = (event: ChangeEvent) => { + setQuery(event.target.value); + }; + + let visiblePeople = [...people]; + + if (sex !== '') { + visiblePeople = visiblePeople.filter(person => person.sex === sex); + } + + if (query !== '') { + const normalizedQuery = query.toLocaleLowerCase(); + + visiblePeople = visiblePeople.filter(person => { + person.motherName?.toLocaleLowerCase(); // === null + + if (person.motherName) { + person.motherName.toLocaleLowerCase(); + } else { + return person.motherName; + } + + + const stringToCheck = ` + ${person.name} + ${person.motherName || ''} + ${person?.fatherName || ''} + `; + + return stringToCheck.toLocaleLowerCase().includes(normalizedQuery); + }); + } + + return ( + + + + + + + + + + + + + + + + {visiblePeople.map(person => ( + + + + + + + + + + + ))} + +
+

+ + {selectedPeople.map(person => person.name).join(', ')} +

+ +
+
+ + + + + +
+ +
+
+ +
+
+
+
-nameMother nameFather namesexbornreorder
+ {isSelected(person) + ? ( + + ) + : ( + + )} + + {person.name} + {person.motherName || '-'}{person.fatherName || '-'}{person.sex}{person.born} + + + +
+ ); +};