-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
made people-table-advanced #597
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,74 @@ | ||
export const PeopleFilters = () => { | ||
import { Link, useSearchParams } from 'react-router-dom'; | ||
import cn from 'classnames'; | ||
import { getSearchWith } from '../utils/searchHelper'; | ||
|
||
const centuriesArray = [ | ||
'16', '17', '18', '19', '20', | ||
]; | ||
|
||
export const PeopleFilters: React.FC = () => { | ||
const [searchParams, setSearchParams] = useSearchParams(); | ||
const centuries = searchParams.getAll('centuries') || []; | ||
const sex = searchParams.get('sex') || 'All'; | ||
const query = searchParams.get('query') || ''; | ||
|
||
const toggleCenturies = (century: string) => { | ||
if (!century) { | ||
return getSearchWith(searchParams, { | ||
centuries: [], | ||
}); | ||
} | ||
|
||
return getSearchWith(searchParams, { | ||
centuries: centuries.includes(century) | ||
? centuries.filter(ch => ch !== century) | ||
: [...centuries, century], | ||
}); | ||
}; | ||
|
||
const toggleSex = (newSex: string | null) => { | ||
if (newSex === 'All') { | ||
return getSearchWith(searchParams, { sex: null }); | ||
} | ||
|
||
return getSearchWith(searchParams, { sex: newSex }); | ||
}; | ||
|
||
const toggleQuery = (newQuery: string) => { | ||
const search = getSearchWith(searchParams, { query: newQuery }); | ||
|
||
setSearchParams(search); | ||
}; | ||
|
||
const toggleAllReset = () => { | ||
return getSearchWith( | ||
searchParams, { query: null, centuries: [], sex: null }, | ||
); | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here |
||
|
||
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> | ||
<Link | ||
className={cn({ 'is-active': sex === 'All' })} | ||
to={{ search: toggleSex('All') }} | ||
> | ||
All | ||
</Link> | ||
<Link | ||
className={cn({ 'is-active': sex === 'm' })} | ||
to={{ search: toggleSex('m') }} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can also use SearchLink There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For sure. Also render as a list (using |
||
> | ||
Male | ||
</Link> | ||
<Link | ||
className={cn({ 'is-active': sex === 'f' })} | ||
to={{ search: toggleSex('f') }} | ||
> | ||
Female | ||
</Link> | ||
</p> | ||
|
||
<div className="panel-block"> | ||
|
@@ -16,6 +78,8 @@ export const PeopleFilters = () => { | |
type="search" | ||
className="input" | ||
placeholder="Search" | ||
value={query} | ||
onChange={(event) => toggleQuery(event.target.value)} | ||
/> | ||
|
||
<span className="icon is-left"> | ||
|
@@ -27,66 +91,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> | ||
{centuriesArray.map((century) => ( | ||
<Link | ||
data-cy="century" | ||
className={cn('button mr-1', { | ||
'is-info': centuries.includes(century), | ||
})} | ||
to={{ | ||
search: toggleCenturies(century), | ||
}} | ||
> | ||
{century} | ||
</Link> | ||
))} | ||
</div> | ||
|
||
<div className="level-right ml-4"> | ||
<a | ||
<Link | ||
data-cy="centuryALL" | ||
className="button is-success is-outlined" | ||
href="#/people" | ||
className={cn('button is-success', { | ||
'is-outlined': centuries.length, | ||
})} | ||
to={{ search: toggleCenturies('') }} | ||
|
||
> | ||
All | ||
</a> | ||
</Link> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<div className="panel-block"> | ||
<a | ||
<Link | ||
className="button is-link is-outlined is-fullwidth" | ||
href="#/people" | ||
to={{ search: toggleAllReset() }} | ||
> | ||
Reset all filters | ||
</a> | ||
</Link> | ||
</div> | ||
</nav> | ||
); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,120 @@ | ||
import { useEffect, useState } from 'react'; | ||
import { useSearchParams } from 'react-router-dom'; | ||
import { PeopleFilters } from './PeopleFilters'; | ||
import { Loader } from './Loader'; | ||
import { PeopleTable } from './PeopleTable'; | ||
import { Person } from '../types'; | ||
import { getPeople } from '../api'; | ||
|
||
export const PeoplePage = () => { | ||
const [people, setPeople] = useState<Person[]>([]); | ||
const [isLoading, setIsLoading] = useState(false); | ||
const [isError, setIsError] = useState(false); | ||
|
||
const [searchParams] = useSearchParams(); | ||
const centuries = searchParams.getAll('centuries') || []; | ||
const sex = searchParams.get('sex') || 'All'; | ||
const query = searchParams.get('query') || ''; | ||
const sort = searchParams.get('sort') || ''; | ||
const order = searchParams.get('order') || ''; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't need it here |
||
|
||
useEffect(() => { | ||
setIsLoading(true); | ||
|
||
getPeople() | ||
.then((peopleFromServer) => setPeople(peopleFromServer)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
.catch(() => setIsError(true)) | ||
.finally(() => setIsLoading(false)); | ||
}, []); | ||
|
||
const getFilteredPeople = () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's move this function to separate file and receive |
||
let filteredPeople = [...people]; | ||
|
||
if (centuries.length) { | ||
filteredPeople = filteredPeople.filter( | ||
person => centuries.includes( | ||
Math.ceil(person.born / 100).toString(), | ||
), | ||
); | ||
} | ||
|
||
if (sex !== 'All') { | ||
filteredPeople = filteredPeople.filter(person => person.sex === sex); | ||
} | ||
|
||
if (query) { | ||
const validQuery = query.toLocaleLowerCase().trim(); | ||
|
||
filteredPeople = filteredPeople.filter( | ||
(person) => person.name.toLocaleLowerCase().includes(validQuery) | ||
|| person.fatherName?.toLocaleLowerCase().includes(validQuery) | ||
|| person.motherName?.toLocaleLowerCase().includes(validQuery), | ||
); | ||
} | ||
|
||
if (sort) { | ||
switch (sort) { | ||
case 'name': | ||
case 'sex': | ||
filteredPeople = filteredPeople.sort((person1, person2) => { | ||
return (order === 'desc') | ||
? person2[sort].localeCompare(person1[sort]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it looks like you repeat yourself |
||
: person1[sort].localeCompare(person2[sort]); | ||
}); | ||
break; | ||
case 'born': | ||
case 'died': | ||
filteredPeople = filteredPeople.sort((person1, person2) => { | ||
return (order === 'desc') | ||
? person2[sort] - person1[sort] | ||
: person1[sort] - person2[sort]; | ||
}); | ||
break; | ||
default: | ||
} | ||
} | ||
|
||
return filteredPeople; | ||
}; | ||
|
||
const visiblePeople = getFilteredPeople(); | ||
|
||
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 /> | ||
{!isLoading && ( | ||
<PeopleFilters /> | ||
)} | ||
</div> | ||
|
||
<div className="column"> | ||
<div className="box table-container"> | ||
<Loader /> | ||
|
||
<p data-cy="peopleLoadingError">Something went wrong</p> | ||
|
||
<p data-cy="noPeopleMessage"> | ||
There are no people on the server | ||
</p> | ||
{isLoading && ( | ||
<Loader /> | ||
)} | ||
|
||
<p>There are no people matching the current search criteria</p> | ||
{isError && ( | ||
<p data-cy="peopleLoadingError">Something went wrong</p> | ||
)} | ||
{!isLoading && !isError && !people.length && ( | ||
<p data-cy="noPeopleMessage"> | ||
There are no people on the server | ||
</p> | ||
)} | ||
{!visiblePeople.length && !isLoading && ( | ||
<p>There are no people matching the current search criteria</p> | ||
)} | ||
{!isLoading && !isError && !!visiblePeople.length && ( | ||
<PeopleTable | ||
people={people} | ||
visiblePeople={visiblePeople} | ||
/> | ||
)} | ||
|
||
<PeopleTable /> | ||
</div> | ||
</div> | ||
</div> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as I understand if we want to remove params, we should pass value = null