Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #561

Closed
wants to merge 3 commits into from
Closed

Dev #561

Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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://donizer.github.io/react_people-table-advanced/) and add it to the PR description.
26 changes: 11 additions & 15 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import { PeoplePage } from './components/PeoplePage';
import { Navbar } from './components/Navbar';
import { Outlet } from 'react-router-dom';
import { NavBar } from './components/NavBar/NavBar';

import './App.scss';

export const App = () => {
return (
<div data-cy="app">
<Navbar />
export const App = () => (
<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>
<main className="section">
<div className="container">
<Outlet />
</div>
</div>
);
};
</main>
</div>
);
3 changes: 3 additions & 0 deletions src/components/Home/Home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const Home = () => {
return <h1 className="title">Home Page</h1>;
};
33 changes: 33 additions & 0 deletions src/components/NavBar/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import classNames from 'classnames';
import { NavLink } from 'react-router-dom';

const getLinkClass = (isActive: boolean) => classNames('navbar-item', {
'has-background-grey-lighter': isActive,
});

export const NavBar = () => {
return (
<nav
className="navbar is-light is-fixed-top is-mobile has-shadow"
data-cy="nav"
>
<div className="container">
<div className="navbar-brand">
<NavLink
to=".."
end
className={({ isActive }) => getLinkClass(isActive)}
>
Home
</NavLink>
<NavLink
to="people"
className={({ isActive }) => getLinkClass(isActive)}
>
People
</NavLink>
</div>
</div>
</nav>
);
};
24 changes: 0 additions & 24 deletions src/components/Navbar.tsx

This file was deleted.

117 changes: 117 additions & 0 deletions src/components/People/PeopleFilters.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import classNames from 'classnames';
import { useContext } from 'react';
import { appContext } from '../../storage/AppContext/AppContext';
import { SearchParams, getSearchWith } from '../../utils/searchHelper';
import { SearchLink } from '../SearchLink';

export const PeopleFilters = () => {
const {
searchParams,
setSearchParams,
sex,
query,
centuries,
} = useContext(appContext);

const setSearchWith = (paramsToUpdate: SearchParams) => {
const search = getSearchWith(searchParams, paramsToUpdate);

setSearchParams(search);
};

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

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

<p className="panel-tabs" data-cy="SexFilter">
<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">
<p className="control has-icons-left">
<input
data-cy="NameFilter"
type="search"
className="input"
placeholder="Search"
value={query}
onChange={handleQueryChange}
/>

<span className="icon is-left">
<i className="fas fa-search" aria-hidden="true" />
</span>
</p>
</div>

<div className="panel-block">
<div className="level is-flex-grow-1 is-mobile" data-cy="CenturyFilter">
<div className="level-left">
{[16, 17, 18, 19, 20].map((number) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this arr to the variable.

const century = number.toString();

return (
<SearchLink
data-cy="century"
className={classNames('button mr-1', {
'is-info': centuries.includes(century),
})}
params={{
century: centuries.includes(century)
? centuries.filter((period) => period !== century)
: [...centuries, century],
}}
key={century}
>
{century}
</SearchLink>
);
})}
</div>

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

<div className="panel-block">
<SearchLink
className="button is-link is-outlined is-fullwidth"
params={{ query: null, sex: null, century: [] }}
>
Reset all filters
</SearchLink>
</div>
</nav>
);
};
53 changes: 53 additions & 0 deletions src/components/People/PeoplePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useContext, useEffect } from 'react';
import { appContext } from '../../storage/AppContext/AppContext';
import { Loader } from '../Loader';
import { PeopleTable } from './PeopleTable';
import { PeopleFilters } from './PeopleFilters';

export const PeoplePage = () => {
const {
visiblePeople, people, isLoading, error, fetchPeople,
} = useContext(appContext);

useEffect(() => {
fetchPeople();
}, []);

return (
<>
<h1 className="title">People Page</h1>

<div className="block">
<div className="columns is-desktop is-flex-direction-row-reverse">
<div className="column is-7-tablet is-narrow-desktop">
<PeopleFilters />
</div>

<div className="column">
<div className="box table-container">
{isLoading && <Loader />}

{error && (
<p data-cy="peopleLoadingError" className="has-text-danger">
{error}
</p>
)}

{!people.length && !isLoading && (
<p data-cy="noPeopleMessage">
There are no people on the server
</p>
)}

{!visiblePeople.length ? (
<p>There are no people matching the current search criteria</p>
) : (
<PeopleTable />
)}
</div>
</div>
</div>
</div>
</>
);
};
44 changes: 44 additions & 0 deletions src/components/People/PeopleTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useContext } from 'react';
import { appContext } from '../../storage/AppContext/AppContext';
import { PersonItem } from '../PersonItem/PersonItem';
import { SortButton } from './SortButton';

export const PeopleTable = () => {
const { visiblePeople } = useContext(appContext);

return (
<table
data-cy="peopleTable"
className="table is-striped is-hoverable is-narrow is-fullwidth"
>
<thead>
<tr>
<th>
<SortButton sortBy="name">Name</SortButton>
</th>

<th>
<SortButton sortBy="sex">Sex</SortButton>
</th>

<th>
<SortButton sortBy="born">Born</SortButton>
</th>

<th>
<SortButton sortBy="died">Died</SortButton>
</th>

<th>Mother</th>
<th>Father</th>
</tr>
</thead>

<tbody>
{visiblePeople.map((person) => (
<PersonItem person={person} key={person.slug} />
))}
</tbody>
</table>
);
};
42 changes: 42 additions & 0 deletions src/components/People/SortButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import classNames from 'classnames';
import { useContext } from 'react';
import { SearchLink } from '../SearchLink';
import { SearchParams } from '../../utils/searchHelper';
import { appContext } from '../../storage/AppContext/AppContext';

type Props = {
children: React.ReactNode;
sortBy: string;
};

export const SortButton: React.FC<Props> = ({ children, sortBy }) => {
const { sort, order } = useContext(appContext);

const isSortMatch = sort === sortBy;
const isOrderDesc = order === 'desc';
const isOrderDescCount = isOrderDesc ? 2 : 1;

const sortState = isSortMatch ? isOrderDescCount : 0;

const params: SearchParams = {
sort: sortState === 0 || sortState === 1 ? sortBy : null,
order: sortState === 1 ? 'desc' : null,
};

const iconClass = classNames('fas', {
'fa-sort': sortState === 0,
'fa-sort-up': sortState === 1,
'fa-sort-down': sortState === 2,
});

return (
<span className="is-flex is-flex-wrap-nowrap">
{children}
<SearchLink params={params}>
<span className="icon">
<i className={iconClass} />
</span>
</SearchLink>
</span>
);
};
Loading