diff --git a/.eslintrc.js b/.eslintrc.js index c4d1e856..507e728c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,4 +1,3 @@ module.exports = { - extends: "@mate-academy/eslint-config-react-typescript", - // extends: "@mate-academy/eslint-config-react", + extends: "@mate-academy/eslint-config-react", }; diff --git a/README.md b/README.md index f1183f65..5eb92ea7 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # React - People table - Replace `` with your Github username in the - [DEMO LINK](https://.github.io/react_people-table/) + [DEMO LINK](https://zarichnyi.github.io/react_people-table/) - Follow the [React task guideline](https://github.com/mate-academy/react_task-guideline#react-tasks-guideline) ## If you don't use **Typescript** 1. Rename `.tsx` files to `.jsx` -1. use `eslint-config-react` in `.eslintrs.js` +1. use `eslint-config-react` in `.eslintrs.js` ## Basic tasks 1. Install all the NPM packages you need and types for them. diff --git a/package.json b/package.json index c427c7f8..9a193c4e 100755 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "@types/react": "^16.9.49", "@types/react-dom": "^16.9.8", "@types/react-router-dom": "^5.1.5", + "classnames": "^2.2.6", "node-sass": "^4.14.1", "react": "^16.13.1", "react-dom": "^16.13.1", diff --git a/src/App.js b/src/App.js new file mode 100644 index 00000000..c8ce9f15 --- /dev/null +++ b/src/App.js @@ -0,0 +1,34 @@ +import React from 'react'; +import { NavLink, Switch, Route, Redirect } from 'react-router-dom'; +import { Home } from './components/HomePage/Home'; +import { Peoples } from './components/PeoplePage/PeopleTable'; +import { PageNotFound } from './components/PageNotFound/PageNotFound'; + +import './App.scss'; + +const App = () => ( +
+ + + + + + + + + + + +
+); + +export default App; diff --git a/src/App.scss b/src/App.scss index dc81a344..d2a2ad79 100644 --- a/src/App.scss +++ b/src/App.scss @@ -1 +1,47 @@ // styles go here +ul { + list-style: none; +} + +html { + overflow-y: scroll; + box-sizing: border-box; +} + +body { + margin: 0; + background-color: #7FDBFF; +} + +#root { + margin: 0; +} + + +.App { + margin: 0; + padding: 0; +} + +.nav { + display: flex; + justify-content: center; + + &__block { + display: flex; + column-gap: 100px; + } + + &__link { + color: #023e8a; + font-size: 30px; + text-decoration: none; + padding: 10px; + border-radius: 10px; + border:2px solid transparent; + + &:hover { + border:2px solid black; + } + } +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx deleted file mode 100644 index e74ffd59..00000000 --- a/src/App.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -import './App.scss'; - -const App = () => ( -
-

People table

-
-); - -export default App; diff --git a/src/api/GetPeople.js b/src/api/GetPeople.js new file mode 100644 index 00000000..a6d1b5f0 --- /dev/null +++ b/src/api/GetPeople.js @@ -0,0 +1,9 @@ +// eslint-disable-next-line max-len +const peoples = 'https://mate-academy.github.io/react_people-table/api/people.json'; + +export const getPeople = async() => { + const response = await fetch(peoples); + const people = response.json(); + + return people; +}; diff --git a/src/components/HomePage/Home.jsx b/src/components/HomePage/Home.jsx new file mode 100644 index 00000000..fc95a377 --- /dev/null +++ b/src/components/HomePage/Home.jsx @@ -0,0 +1,6 @@ +import React from 'react'; +import './Home.scss'; + +export const Home = () => ( +

Home Page

+); diff --git a/src/components/HomePage/Home.scss b/src/components/HomePage/Home.scss new file mode 100644 index 00000000..43d77b55 --- /dev/null +++ b/src/components/HomePage/Home.scss @@ -0,0 +1,3 @@ +.title { + text-align: center; +} \ No newline at end of file diff --git a/src/components/PageNotFound/PageNotFound.jsx b/src/components/PageNotFound/PageNotFound.jsx new file mode 100644 index 00000000..a9310b2a --- /dev/null +++ b/src/components/PageNotFound/PageNotFound.jsx @@ -0,0 +1,4 @@ +import React from 'react'; +import './PageNotFound.scss'; + +export const PageNotFound = () => (

PAGE NOT FOUND

); diff --git a/src/components/PageNotFound/PageNotFound.scss b/src/components/PageNotFound/PageNotFound.scss new file mode 100644 index 00000000..43d77b55 --- /dev/null +++ b/src/components/PageNotFound/PageNotFound.scss @@ -0,0 +1,3 @@ +.title { + text-align: center; +} \ No newline at end of file diff --git a/src/components/PeoplePage/PeopleList.jsx b/src/components/PeoplePage/PeopleList.jsx new file mode 100644 index 00000000..3bbee003 --- /dev/null +++ b/src/components/PeoplePage/PeopleList.jsx @@ -0,0 +1,67 @@ +import React from 'react'; +import classNames from 'classnames'; +import propTypes from 'prop-types'; +import { useLocation } from 'react-router-dom'; +import { PersonName } from '../PersonName/PersonName'; +import './PeopleStyle.scss'; + +export const PeoplesList = ({ people }) => { + const location = useLocation(); + + const findParent = parentName => ( + people.find(person => person.name === parentName) + ); + + return ( + <> + {people.map((person) => { + const { slug, name, sex, born, died, motherName, fatherName } = person; + + return ( + + + + + {sex} + {born} + {died} + + {findParent(motherName) + ? ( + + ) + : <>{motherName} + } + + + {findParent(fatherName) + ? ( + + ) + : <>{fatherName} + } + + + ); + })} + + ); +}; diff --git a/src/components/PeoplePage/PeopleStyle.scss b/src/components/PeoplePage/PeopleStyle.scss new file mode 100644 index 00000000..352ccb84 --- /dev/null +++ b/src/components/PeoplePage/PeopleStyle.scss @@ -0,0 +1,34 @@ +.active { + background-color: #2a9d8f; +} + +.title { + text-align: center; +} + +.selected { + background-color: #06d6a0; +} + +.table { + margin: 0 auto; + border-spacing: 0; + + &__title-item { + padding: 10px; + background-color: #0077b6; + font-size: 18px; + } + + &__list-item { + padding: 15px 0; + } + + &__name-male { + color: #0077b6; + } + + &__name-female { + color: #dc2f02; + } +} diff --git a/src/components/PeoplePage/PeopleTable.jsx b/src/components/PeoplePage/PeopleTable.jsx new file mode 100644 index 00000000..087846c3 --- /dev/null +++ b/src/components/PeoplePage/PeopleTable.jsx @@ -0,0 +1,59 @@ +// eslint-disable-next-line no-unused-vars +import React, { useEffect, useState } from 'react'; +import { useLocation } from 'react-router-dom'; +import * as api from '../../api/GetPeople'; +import { PeoplesList } from './PeopleList'; +import { SearchInput } from '../SearchSection/SearchInput'; + +export const Peoples = () => { + const [people, setPeople] = useState(''); + const location = useLocation(); + const searchParams = new URLSearchParams(location.search); + const getUrlQuery = searchParams.get('query'); + + const tableTitle = ['Name', 'Sex', 'Born', 'Died', 'Mother', 'Father']; + + useEffect(() => { + api.getPeople().then((peopleFromServer) => { + setPeople(peopleFromServer); + localStorage.setItem('people', JSON.stringify(peopleFromServer)); + }); + }, []); + + useEffect(() => { + if (getUrlQuery) { + setPeople(JSON.parse(localStorage.getItem('people')).filter((person) => { + const { name, motherName, fatherName } = person; + + return (name.toLowerCase().includes(getUrlQuery) + || (motherName && motherName.toLowerCase().includes(getUrlQuery)) + || (fatherName && fatherName.toLowerCase().includes(getUrlQuery)) + ); + })); + } else { + setPeople(JSON.parse(localStorage.getItem('people'))); + } + }, [getUrlQuery]); + + return ( + <> +

Peoples Page

+ + + + + {tableTitle.map(item => ( + + ))} + + + + {people + ? + : 'Loading...' + } + +
{item}
+ + ); +}; diff --git a/src/components/PersonName/PersonName.jsx b/src/components/PersonName/PersonName.jsx new file mode 100644 index 00000000..353a2e82 --- /dev/null +++ b/src/components/PersonName/PersonName.jsx @@ -0,0 +1,19 @@ +import React from 'react'; +import classNames from 'classnames'; +import { Link } from 'react-router-dom'; +import './PersonName.scss'; + +export const PersonName = ({ name, slug, sex }) => { + + return ( + + { name} + + ); +}; diff --git a/src/components/PersonName/PersonName.scss b/src/components/PersonName/PersonName.scss new file mode 100644 index 00000000..3a6f5484 --- /dev/null +++ b/src/components/PersonName/PersonName.scss @@ -0,0 +1,6 @@ +.table { + &__list-link { + text-decoration: none; + font-size: 18px; + } +} \ No newline at end of file diff --git a/src/components/SearchSection/SearchInput.jsx b/src/components/SearchSection/SearchInput.jsx new file mode 100644 index 00000000..5e8de18c --- /dev/null +++ b/src/components/SearchSection/SearchInput.jsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { useHistory, useLocation } from 'react-router-dom'; +import './SearchInput.scss'; + +export const SearchInput = () => { + const history = useHistory(); + const location = useLocation(); + const searchParams = new URLSearchParams(location.search); + const query = searchParams.get('query') || ''; + + return ( +
+ { + searchParams.set('query', (event.target.value).toLocaleLowerCase()); + history.push({ + search: searchParams.toString() === 'query=' + ? '' + : searchParams.toString(), + }); + }} + /> +
+ ); +}; diff --git a/src/components/SearchSection/SearchInput.scss b/src/components/SearchSection/SearchInput.scss new file mode 100644 index 00000000..58171496 --- /dev/null +++ b/src/components/SearchSection/SearchInput.scss @@ -0,0 +1,12 @@ +.search_person_block { + display: flex; + justify-content: center; +} + +.search_person_input { + width: 30em; + height: 2em; + border-color: blue; + outline: none; + padding: 5px; +} \ No newline at end of file diff --git a/src/index.tsx b/src/index.js similarity index 61% rename from src/index.tsx rename to src/index.js index 60b2d961..6c3e450a 100644 --- a/src/index.tsx +++ b/src/index.js @@ -1,9 +1,12 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import { HashRouter } from 'react-router-dom'; import App from './App'; ReactDOM.render( - , + + + , document.getElementById('root'), ); diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts index c7466ceb..ece12df6 100644 --- a/src/react-app-env.d.ts +++ b/src/react-app-env.d.ts @@ -1,2 +1 @@ -// eslint-disable-next-line -/// +///