Skip to content

Commit

Permalink
solved
Browse files Browse the repository at this point in the history
  • Loading branch information
DmytroSomik-MWG committed Nov 3, 2023
1 parent 463f841 commit a7ef529
Show file tree
Hide file tree
Showing 19 changed files with 29,975 additions and 933 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ implement the ability to filter and sort people in the table.
- Implement a solution following the [React task guideline](https://github.com/mate-academy/react_task-guideline#react-tasks-guideline).
- Use the [React TypeScript cheat sheet](https://mate-academy.github.io/fe-program/js/extra/react-typescript).
- Open one more terminal and run tests with `npm test` to ensure your solution is correct.
- Replace `<your_account>` with your Github username in the [DEMO LINK](https://<your_account>.github.io/react_people-table-advanced/) and add it to the PR description.
- Replace `<your_account>` with your Github username in the [DEMO LINK](https://silcki.github.io/react_people-table-advanced/) and add it to the PR description.
29,621 changes: 29,488 additions & 133 deletions package-lock.json

Large diffs are not rendered by default.

25 changes: 10 additions & 15 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
import { PeoplePage } from './components/PeoplePage';
import { Outlet } from 'react-router-dom';
import { Navbar } from './components/Navbar';

import './App.scss';

export const App = () => {
return (
<div data-cy="app">
<Navbar />

<div className="section">
<div className="container">
<h1 className="title">Home Page</h1>
<h1 className="title">Page not found</h1>
<PeoplePage />
</div>
export const App = () => (
<div data-cy="app">
<Navbar />
<main className="section">
<div className="container">
<Outlet />
</div>
</div>
);
};
</main>
</div>
);
30 changes: 30 additions & 0 deletions src/Root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
HashRouter,
Routes,
Route,
Navigate,
} from 'react-router-dom';
import { App } from './App';
import { HomePage } from './pages/HomePage';
import { NotFoundPage } from './pages/NotFoundPage';
import { PeoplePage } from './pages/PeoplePage';
import { PeopleProvider } from './store/PeopleContext';

export const Root = () => {
return (
<HashRouter>
<PeopleProvider>
<Routes>
<Route path="/" element={<App />}>
<Route path="*" element={<NotFoundPage />} />
<Route index element={<HomePage />} />
<Route path="people" element={<PeoplePage />}>
<Route path=":slug" element={<PeoplePage />} />
</Route>
<Route path="home" element={<Navigate to="/" replace />} />
</Route>
</Routes>
</PeopleProvider>
</HashRouter>
);
};
23 changes: 13 additions & 10 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
export const Navbar = () => {
import React from 'react';
import { NavLink } from 'react-router-dom';
import classNames from 'classnames';

export const Navbar: React.FC = () => {
const activeClass = (
{ isActive } : { isActive: boolean },
) => classNames('navbar-item', {
'has-background-grey-lighter': isActive,
});

return (
<nav
data-cy="nav"
Expand All @@ -8,15 +18,8 @@ export const Navbar = () => {
>
<div className="container">
<div className="navbar-brand">
<a className="navbar-item" href="#/">Home</a>

<a
aria-current="page"
className="navbar-item has-background-grey-lighter"
href="#/people"
>
People
</a>
<NavLink to="/" className={activeClass}>Home</NavLink>
<NavLink to="/people" className={activeClass}>People</NavLink>
</div>
</div>
</nav>
Expand Down
76 changes: 76 additions & 0 deletions src/components/People/People.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from 'react';
import { useParams } from 'react-router-dom';
import classNames from 'classnames';
import { Person } from '../../types';
import { PersonLink } from './PersonLink';
import { SortLink } from '../SortLink';

type Props = {
people: Person[];
};

export const People: React.FC<Props> = ({ people }) => {
const { slug } = useParams();
const realSlug = slug ?? null;

return (
<table
data-cy="peopleTable"
className="table is-striped is-hoverable is-narrow is-fullwidth"
>
<thead>
<tr>
<th>
<SortLink sortField="name">Name</SortLink>
</th>
<th>
<SortLink sortField="sex">Sex</SortLink>
</th>
<th>
<SortLink sortField="born">Born</SortLink>
</th>
<th>
<SortLink sortField="died">Died</SortLink>
</th>
<th>Mother</th>
<th>Father</th>
</tr>
</thead>

<tbody>
{people.map(person => (
<tr
data-cy="person"
key={person.slug}
className={classNames({
'has-background-warning': person.slug === realSlug,
})}
>
<td>
<PersonLink person={person} />
</td>
<td>{person.sex}</td>
<td>{person.born}</td>
<td>{person.died}</td>
<td>
{person.mother
? (
<PersonLink person={person.mother} />
) : (
person.motherName || '-'
)}
</td>
<td>
{person.father
? (
<PersonLink person={person.father} />
) : (
person.fatherName || '-'
)}
</td>
</tr>
))}
</tbody>
</table>
);
};
26 changes: 26 additions & 0 deletions src/components/People/PersonLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
import classNames from 'classnames';
import { Person } from '../../types';

type Props = {
person: Person;
};

export const PersonLink: React.FC<Props> = ({ person }) => {
const { search } = useLocation();

return (
<Link
to={{
pathname: person.slug,
search,
}}
className={classNames({
'has-text-danger': person.sex === 'f',
})}
>
{person.name}
</Link>
);
};
2 changes: 2 additions & 0 deletions src/components/People/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './PersonLink';
export * from './People';
119 changes: 69 additions & 50 deletions src/components/PeopleFilters.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,52 @@
import { useSearchParams } from 'react-router-dom';
import classNames from 'classnames';
import { usePeople } from '../store/PeopleContext';
import { getSearchWith } from '../utils/searchHelper';
import { SearchLink } from './SearchLink';

export const PeopleFilters = () => {
const [searchParams, setSearchParams] = useSearchParams();
const {
query,
sex,
centuries,
} = usePeople();

const handleQueryChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearchParams(
getSearchWith(searchParams, { query: event.target.value || null })
);
};

return (
<nav className="panel">
<p className="panel-heading">Filters</p>

<p className="panel-tabs" data-cy="SexFilter">
<a className="is-active" href="#/people">All</a>
<a className="" href="#/people?sex=m">Male</a>
<a className="" href="#/people?sex=f">Female</a>
<SearchLink
className={classNames({
'is-active': !sex,
})}
params={{ sex: null }}
>
All
</SearchLink>
<SearchLink
className={classNames({
'is-active': sex === 'm',
})}
params={{ sex: 'm' }}
>
Male
</SearchLink>
<SearchLink
className={classNames({
'is-active': sex === 'f',
})}
params={{ sex: 'f' }}
>
Female
</SearchLink>
</p>

<div className="panel-block">
Expand All @@ -16,6 +56,8 @@ export const PeopleFilters = () => {
type="search"
className="input"
placeholder="Search"
value={query}
onChange={handleQueryChange}
/>

<span className="icon is-left">
Expand All @@ -27,66 +69,43 @@ export const PeopleFilters = () => {
<div className="panel-block">
<div className="level is-flex-grow-1 is-mobile" data-cy="CenturyFilter">
<div className="level-left">
<a
data-cy="century"
className="button mr-1"
href="#/people?centuries=16"
>
16
</a>

<a
data-cy="century"
className="button mr-1 is-info"
href="#/people?centuries=17"
>
17
</a>

<a
data-cy="century"
className="button mr-1 is-info"
href="#/people?centuries=18"
>
18
</a>

<a
data-cy="century"
className="button mr-1 is-info"
href="#/people?centuries=19"
>
19
</a>

<a
data-cy="century"
className="button mr-1"
href="#/people?centuries=20"
>
20
</a>
{['16', '17', '18', '19', '20'].map(el => (
<SearchLink
className={classNames('button mr-1', {
'is-info': centuries.includes(el),
})}
params={{
century: centuries.includes(el.toString())
? centuries.filter((f) => f !== el)
: [...centuries, el],
}}
key={el}
>
{el}
</SearchLink>
))}
</div>

<div className="level-right ml-4">
<a
data-cy="centuryALL"
className="button is-success is-outlined"
href="#/people"
<SearchLink
className={classNames('button is-success', {
'is-outlined': !!centuries.length,
})}
params={{ century: null }}
>
All
</a>
</SearchLink>
</div>
</div>
</div>

<div className="panel-block">
<a
<SearchLink
className="button is-link is-outlined is-fullwidth"
href="#/people"
params={{ query: null, sex: null, century: null }}
>
Reset all filters
</a>
</SearchLink>
</div>
</nav>
);
Expand Down
Loading

0 comments on commit a7ef529

Please sign in to comment.