Skip to content

Commit

Permalink
fix app behavior, vars names, DRY parts, change tag a to searchLink
Browse files Browse the repository at this point in the history
  • Loading branch information
KatOlista committed Oct 9, 2023
1 parent dbeac6d commit 8545f6a
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 73 deletions.
5 changes: 3 additions & 2 deletions src/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ export const Root = () => (
<Route path="/" element={<App />}>
<Route index element={<HomePage />} />
<Route path="home" element={<Navigate to="/" replace />} />
<Route path="people" element={<PeoplePage />} />
<Route path="people/:slug?" element={<PeoplePage />} />
<Route path="people">
<Route path=":slug?" element={<PeoplePage />} />
</Route>
<Route path="*" element={<NotFoundPage />} />
</Route>
</Routes>
Expand Down
24 changes: 19 additions & 5 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ export function addParent(people: Person[]) {
});
}

export function sortPeople(people: Person[], sortParam: SortParam | string) {
export function getSortedPeople(
people: Person[],
sortParam: SortParam | string,
) {
if (sortParam) {
return [...people].sort((a, b) => {
switch (sortParam) {
Expand All @@ -50,7 +53,14 @@ export function sortPeople(people: Person[], sortParam: SortParam | string) {
return [...people];
}

export function filterPeople(
const getFilteredPeopleHelper = (
name: string | null,
query: string,
) => {
return name?.toLowerCase().includes(query);
};

export function getFilteredPeople(
filterOption: FilterType,
people: Person[],
) {
Expand All @@ -71,9 +81,13 @@ export function filterPeople(

if (filterOption.query) {
filteredPeople = filteredPeople
.filter(person => person.name.includes(filterOption.query)
|| person.motherName?.includes(filterOption.query)
|| person.fatherName?.includes(filterOption.query));
.filter(person => {
const query = filterOption.query.toLowerCase();

return getFilteredPeopleHelper(person.name, query)
|| getFilteredPeopleHelper(person.motherName, query)
|| getFilteredPeopleHelper(person.fatherName, query);
});
}

return filteredPeople;
Expand Down
17 changes: 11 additions & 6 deletions src/components/ColumnNameItem/ColumnNameItem.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { useSearchParams } from 'react-router-dom';
import cn from 'classnames';

import { SearchLink } from '../SearchLink';
import { ColumnNames } from '../../types';
Expand Down Expand Up @@ -28,6 +29,10 @@ export const ColumnName: React.FC<Props> = ({ value }) => {
return { sort: null, order: null };
};

const hasFaSort = lowerCasedValue !== sort;
const hasFaSortUp = lowerCasedValue === sort && !order;
const hasFaSortDown = order && lowerCasedValue === sort;

return (
<th key={value}>
<span className="is-flex is-flex-wrap-nowrap">
Expand All @@ -36,13 +41,13 @@ export const ColumnName: React.FC<Props> = ({ value }) => {
params={getSortParams(lowerCasedValue)}
>
<span className="icon">
{lowerCasedValue !== sort && (<i className="fas fa-sort" />)}
{lowerCasedValue === sort && !order && (
<i className="fas fa-sort-up" />
)}
{order && lowerCasedValue === sort && (
<i className="fas fa-sort-down" />
<i className={cn(
'fas',
{ 'fa-sort': hasFaSort },
{ 'fa-sort-up': hasFaSortUp },
{ 'fa-sort-down': hasFaSortDown },
)}
/>
</span>
</SearchLink>
</span>
Expand Down
8 changes: 6 additions & 2 deletions src/components/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { NavLink } from 'react-router-dom';
import { NavLink, useSearchParams } from 'react-router-dom';
import cn from 'classnames';

export const Navbar = () => {
const [searchParams] = useSearchParams();
const getLinkClass = ({ isActive }: { isActive: boolean }) => cn(
'navbar-item',
{ 'has-background-grey-lighter': isActive },
Expand All @@ -24,7 +25,10 @@ export const Navbar = () => {
<NavLink
aria-current="page"
className={getLinkClass}
to="/people"
to={{
pathname: 'people',
search: searchParams.toString(),
}}
>
People
</NavLink>
Expand Down
17 changes: 7 additions & 10 deletions src/components/PeopleFilters/PeopleFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,10 @@ export const PeopleFilters = () => {
const centuries = searchParams.getAll('centuries') || [];

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

return (
Expand Down Expand Up @@ -80,12 +77,12 @@ export const PeopleFilters = () => {
</div>

<div className="panel-block">
<a
<SearchLink
className="button is-link is-outlined is-fullwidth"
href="#/people"
params={{ query: null, centuries: null, sex: null }}
>
Reset all filters
</a>
</SearchLink>
</div>
</nav>
);
Expand Down
42 changes: 5 additions & 37 deletions src/components/PeopleTable/PeopleTable.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,22 @@
import React, { useEffect, useState } from 'react';
import { Outlet, useParams, useSearchParams } from 'react-router-dom';
import React from 'react';
import { Outlet, useParams } from 'react-router-dom';

import { PersonItem } from '../PersonItem';
import { ColumnName } from '../ColumnNameItem';

import { filterPeople, sortPeople } from '../../api';

import { ColumnNames, FilterType, Person } from '../../types';
import { SortParam } from '../../types/SortParam';
import { DESC_SORT } from '../../utils/variables';
import { ColumnNames, Person } from '../../types';

type Props = {
people: Person[],
filteredPeople: Person[],
setFilteredPeople: React.Dispatch<React.SetStateAction<Person[]>>,
};

export const PeopleTable: React.FC<Props> = ({
people,
filteredPeople,
setFilteredPeople,
}) => {
const { slug } = useParams();
const selectedPersonSlug = slug || '';

const [sortedPeople, setSortedPeople] = useState(people);

const [searchParams] = useSearchParams();
const sort: typeof SortParam | string = searchParams.get('sort') || '';
const order = searchParams.get('order') || '';
const query = searchParams.get('query') || '';
const centuries = searchParams.getAll('centuries') || [];
const sex = searchParams.get('sex') || '';

const filters: FilterType = {
query,
centuries,
sex,
};

useEffect(() => {
setSortedPeople(sortPeople(people, sort));
}, [sort, query, centuries.length, sex]);

useEffect(() => {
setFilteredPeople(filterPeople(filters, sortedPeople));
}, [query, centuries.length, sex, sortedPeople]);

if (order === DESC_SORT) {
filteredPeople.reverse();
if (!filteredPeople.length) {
return null;
}

return (
Expand Down
2 changes: 1 addition & 1 deletion src/components/PersonLink/PersonLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const PersonLink: React.FC<Props> = ({ person }) => {

return (
<Link
to={`../people/${slug}?${searchParams.toString()}`}
to={`../${slug}?${searchParams.toString()}`}
className={cn({ 'has-text-danger': isFemale })}
>
{name}
Expand Down
44 changes: 34 additions & 10 deletions src/pages/PeoplePage/PeoplePage.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,49 @@
import { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';

import { addParent, getPeople } from '../../api';
import { Person } from '../../types';
import {
addParent,
getFilteredPeople,
getPeople,
getSortedPeople,
} from '../../api';

import { FilterType, Person } from '../../types';
import { PeopleFilters } from '../../components/PeopleFilters';
import { Loader } from '../../components/Loader';
import { PeopleTable } from '../../components/PeopleTable';
import { SortParam } from '../../types/SortParam';
import { DESC_SORT } from '../../utils/variables';

export const PeoplePage = () => {
const [people, setPeople] = useState<Person[]>([]);
const [filteredPeople, setFilteredPeople] = useState<Person[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [searchParams] = useSearchParams();
const sort: typeof SortParam | string = searchParams.get('sort') || '';
const sortedPeople = getSortedPeople(people, sort);

const order = searchParams.get('order') || '';
const query = searchParams.get('query') || '';
const centuries = searchParams.getAll('centuries') || [];
const sex = searchParams.get('sex') || '';

const filters: FilterType = {
query,
centuries,
sex,
};

const filteredPeople = getFilteredPeople(filters, sortedPeople);
const [isLoading, setIsLoading] = useState(true);
const [hasError, setHasError] = useState(false);

useEffect(() => {
setIsLoading(true);
if (order === DESC_SORT) {
filteredPeople.reverse();
}

useEffect(() => {
getPeople()
.then((peopleFromServer) => {
setPeople(addParent(peopleFromServer));
setFilteredPeople(addParent(peopleFromServer));
})
.catch(() => {
setHasError(true);
Expand All @@ -29,6 +54,7 @@ export const PeoplePage = () => {
});
}, []);

const hasPeopleFilter = !isLoading && !!people.length;
const hasErrorMessage = hasError && !isLoading;
const hasNoPeopleOnServer = !people.length && !hasError && !isLoading;
const hasNoMatchingPeople = !isLoading
Expand All @@ -42,7 +68,7 @@ export const PeoplePage = () => {
<div className="block">
<div className="columns is-desktop is-flex-direction-row-reverse">
<div className="column is-7-tablet is-narrow-desktop">
{!isLoading && (<PeopleFilters />)}
{hasPeopleFilter && (<PeopleFilters />)}
</div>

<div className="column">
Expand All @@ -67,9 +93,7 @@ export const PeoplePage = () => {

{!!people.length && (
<PeopleTable
people={people}
filteredPeople={filteredPeople}
setFilteredPeople={setFilteredPeople}
/>
)}
</div>
Expand Down

0 comments on commit 8545f6a

Please sign in to comment.