Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
11 changes: 4 additions & 7 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import { PeoplePage } from './components/PeoplePage';
import { Navbar } from './components/Navbar';

import './App.scss';
import { NavBar } from './components/NavBar';
import { Outlet } from 'react-router-dom';

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

<div className="section">
<div className="container">
<h1 className="title">Home Page</h1>
<h1 className="title">Page not found</h1>
<PeoplePage />
<Outlet />
</div>
</div>
</div>
Expand Down
35 changes: 35 additions & 0 deletions src/components/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { NavLink } from 'react-router-dom';

export const NavBar: React.FC = () => {
return (
<nav
data-cy="nav"
className="navbar is-fixed-top-touch has-shadow"
role="navigation"
aria-label="main navigation"
>
<div className="container">
<div className="navbar-brand">
<NavLink
className={({ isActive }) =>
`navbar-item ${isActive ? 'has-background-grey-lighter' : ''}`
}
to="/"
>
Home
</NavLink>

<NavLink
to="/people"
className={({ isActive }) =>
`navbar-item ${isActive ? 'has-background-grey-lighter' : ''}`
}
>
People
</NavLink>
</div>
</div>
</nav>
);
};
26 changes: 0 additions & 26 deletions src/components/Navbar.tsx

This file was deleted.

108 changes: 108 additions & 0 deletions src/components/People.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import React from 'react';
import { Person } from '../types';
import { Person as PersonComponent } from './Person';
import { Link, useParams, useSearchParams } from 'react-router-dom';
import { isSortKey, SortKey } from '../types/SortKey';
import cn from 'classnames';

interface PeopleProps {
people: Person[];
}

const headers = [
{ key: 'name', title: 'Name' },
{ key: 'sex', title: 'Sex' },
{ key: 'born', title: 'Born' },
{ key: 'died', title: 'Died' },
{ key: 'mother', title: 'Mother' },
{ key: 'father', title: 'Father' },
] as const;

function updateSortParams(
params: URLSearchParams,
sortKey: SortKey,
currentSort: string | null,
currentOrder: string | null,
) {
if (sortKey !== currentSort) {
params.set('sort', sortKey);
params.delete('order');

return;
}

if (!currentOrder) {
params.set('order', 'desc');

return;
}

params.delete('sort');
params.delete('order');
}

export const People: React.FC<PeopleProps> = ({ people }) => {
const { slug } = useParams();
const [searchParams] = useSearchParams();

const currentSort = searchParams.get('sort');
const currentOrder = searchParams.get('order');

function getSortIcon(key: SortKey) {
if (currentSort !== key) {
return 'fa-sort';
}

return currentOrder ? 'fa-sort-down' : 'fa-sort-up';
}

function getSortLink(sortKey: SortKey) {
const params = new URLSearchParams(searchParams);

updateSortParams(params, sortKey, currentSort, currentOrder);

return {
pathname: `/people${slug ? `/${slug}` : ''}`,
search: params.toString(),
};
}

if (people.length === 0) {
return <p data-cy="noPeopleMessage">There are no people on the server</p>;
}

return (
<table
data-cy="peopleTable"
className="table is-striped is-hoverable is-narrow is-fullwidth"
>
<thead>
<tr>
{headers.map(header => (
<th key={header.key}>
<span className="is-flex is-flex-wrap-nowrap">
{header.title}
{isSortKey(header.key) && (
<Link to={getSortLink(header.key)}>
<span className="icon">
<i className={cn('fas', getSortIcon(header.key))} />
</span>
</Link>
)}
</span>
</th>
))}
</tr>
</thead>
<tbody>
{people.map(person => (
<PersonComponent
key={person.slug}
person={person}
active={slug === person.slug}
/>
))}
</tbody>
</table>
);
};
96 changes: 0 additions & 96 deletions src/components/PeopleFilters.tsx

This file was deleted.

73 changes: 73 additions & 0 deletions src/components/PeopleFilters/PeopleCenturyFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react';
import cn from 'classnames';
import { Link, useParams, useSearchParams } from 'react-router-dom';

const centuries = ['16', '17', '18', '19', '20'] as const;

export const PeopleCenturyFilter: React.FC = () => {
const { slug } = useParams();
const [searchParams] = useSearchParams();

const selectedCenturies = searchParams.getAll('centuries');

function getCenturiesLink(century: string) {
const params = new URLSearchParams(searchParams);

if (selectedCenturies.includes(century)) {
const next = selectedCenturies.filter(item => item !== century);

params.delete('centuries');

next.forEach(item => params.append('centuries', item));
} else {
params.append('centuries', century);
}

return {
pathname: `/people${slug ? `/${slug}` : ''}`,
search: params.toString(),
};
}

function getAlllink() {
const params = new URLSearchParams(searchParams);

params.delete('centuries');

return {
pathname: `/people${slug ? `/${slug}` : ''}`,
search: params.toString(),
};
}

return (
<div className="level is-flex-grow-1 is-mobile" data-cy="CenturyFilter">
<div className="level-left">
{centuries.map(century => (
<Link
key={century}
data-cy="century"
className={cn('button mr-1', {
'is-info': selectedCenturies.includes(century),
})}
to={getCenturiesLink(century)}
>
{century}
</Link>
))}
</div>

<div className="level-right ml-4">
<Link
data-cy="centuryALL"
className={cn('button is-success', {
'is-outlined': selectedCenturies.length === 0,
})}
to={getAlllink()}
>
All
</Link>
</div>
</div>
);
};
Loading
Loading