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

implement the ability to filter and sort people in the table #516

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

KatOlista
Copy link

Copy link

@BudnikOleksii BudnikOleksii left a comment

Choose a reason for hiding this comment

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

Looks great 👍
Left some suggestions, check them

src/api.ts Outdated
Comment on lines 6 to 19
export const NOT_SET_VALUE = '-';

export enum ColumnNames {
Name = 'Name',
Sex = 'Sex',
Born = 'Born',
Died = 'Died',
}

export enum PersonSex {
All = '',
Male = 'm',
Female = 'f',
}

Choose a reason for hiding this comment

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

Move constants to the constants file/folder and enums/types to the types folder

src/api.ts Outdated
Comment on lines 21 to 25
export type FilterType = {
query: string | '';
centuries: string[];
sex: string | '';
};

Choose a reason for hiding this comment

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

Suggested change
export type FilterType = {
query: string | '';
centuries: string[];
sex: string | '';
};
export type FilterType = {
query: string;
centuries: string[];
sex: string;
};

An empty string is still a string

src/api.ts Outdated
Comment on lines 40 to 45
function getParent(people: Person[], parentName: string) {
return people.find(({ name }) => name === parentName);
}

export function addParent(people: Person[]) {
return people.map(person => {

Choose a reason for hiding this comment

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

Move all helpers to the helpers or utils folder.

src/api.ts Outdated
Comment on lines 46 to 61
let mother;
let father;

if (person.motherName) {
mother = getParent(people, person.motherName);
}

if (person.fatherName) {
father = getParent(people, person.fatherName);
}

return {
...person,
mother,
father,
};

Choose a reason for hiding this comment

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

Suggested change
let mother;
let father;
if (person.motherName) {
mother = getParent(people, person.motherName);
}
if (person.fatherName) {
father = getParent(people, person.fatherName);
}
return {
...person,
mother,
father,
};
const { motherName, fatherName } = person;
return {
...person,
mother: motherName ? getParent(people, motherName) : motherName,
father: getParent(people, fatherName), // or like this, and if no fatherName just return from the getParent function
};

src/api.ts Outdated
Comment on lines 68 to 69
switch (sortParam) {
case ('name'): {

Choose a reason for hiding this comment

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

sortParam should be enum

src/api.ts Outdated
Comment on lines 77 to 83
case ('born'): {
return a[sortParam] - (b[sortParam]);
}

case ('died'): {
return a[sortParam] - (b[sortParam]);
}

Choose a reason for hiding this comment

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

Suggested change
case ('born'): {
return a[sortParam] - (b[sortParam]);
}
case ('died'): {
return a[sortParam] - (b[sortParam]);
}
case (SortParam.born):
case (SortParam.died): {
return a[sortParam] - (b[sortParam]);
}

You can combine cases if they do a similar job

src/api.ts Outdated
Comment on lines 99 to 107
return people
.filter(person => {
if (filterOption.sex) {
return person.sex === filterOption.sex;
}

return person;
})
.filter(person => {

Choose a reason for hiding this comment

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

You iterate through an array of people every time even some of filterOption is not set

Comment on lines 53 to 55
if (order === 'desc') {
filteredPeople.reverse();
}

Choose a reason for hiding this comment

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

'desc' looks like a magic number, and reverse mutate your array

Copy link
Author

Choose a reason for hiding this comment

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

but I used reverse to the array copy, not to the original array. Is it a problem in this case?

Comment on lines 11 to 14
enum Sex {
FEMALE = 'f',
MALE = 'm',
}

Choose a reason for hiding this comment

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

enums should be stored in types folder/file

Copy link

@Moroz-Dmytro Moroz-Dmytro left a comment

Choose a reason for hiding this comment

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

I have person with name "Emma" in table, but I see empty state
image

When I have empty state, table header should not be displayed

  1. When I click on "People" -> my search params dissapear
image
  1. When I open "People" page I see Filter panel for a second

src/Root.tsx Outdated
Comment on lines 19 to 20
<Route path="people" element={<PeoplePage />} />
<Route path="people/:slug?" element={<PeoplePage />} />

Choose a reason for hiding this comment

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

Suggested change
<Route path="people" element={<PeoplePage />} />
<Route path="people/:slug?" element={<PeoplePage />} />
<Route path="people">
<Route path=":slug?" element={<PeoplePage />} />
</Route>

src/api.ts Outdated
});
}

export function sortPeople(people: Person[], sortParam: SortParam | string) {

Choose a reason for hiding this comment

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

Suggested change
export function sortPeople(people: Person[], sortParam: SortParam | string) {
export function getSortedPeople(people: Person[], sortParam: SortParam | string) {

src/api.ts Outdated
return [...people];
}

export function filterPeople(

Choose a reason for hiding this comment

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

Suggested change
export function filterPeople(
export function getFilteredPeople(

src/api.ts Outdated
Comment on lines 74 to 76
.filter(person => person.name.includes(filterOption.query)
|| person.motherName?.includes(filterOption.query)
|| person.fatherName?.includes(filterOption.query));

Choose a reason for hiding this comment

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

DRY

Comment on lines 39 to 43
{lowerCasedValue !== sort && (<i className="fas fa-sort" />)}
{lowerCasedValue === sort && !order && (
<i className="fas fa-sort-up" />
)}
{order && lowerCasedValue === sort && (

Choose a reason for hiding this comment

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

DRY, create variable for repeatable part of code

Comment on lines 18 to 24
if (!event.target.value) {
setSearchParams(getSearchWith(searchParams,
{ query: null }));
} else {
setSearchParams(getSearchWith(searchParams,
{ query: event.target.value }));
}

Choose a reason for hiding this comment

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

Suggested change
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
})
);

Comment on lines 83 to 88
<a
className="button is-link is-outlined is-fullwidth"
href="#/people"
>
Reset all filters
</a>

Choose a reason for hiding this comment

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

Use SearchLink here

@KatOlista KatOlista requested a review from Moroz-Dmytro October 9, 2023 16:39
Copy link

@roman-mirzoian roman-mirzoian left a comment

Choose a reason for hiding this comment

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

Good job, but pay attention to the comments.

Comment on lines +20 to +30
const getSortParams = (sortOption: string) => {
if (sortOption !== sort) {
return { sort: sortOption, order: null };
}

if (sort === sortOption && !order) {
return { sort: sortOption, order: 'desc' };
}

return { sort: null, order: null };
};

Choose a reason for hiding this comment

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

It is better to define this function outside the component so that it is not created every time a new render is performed.

Comment on lines +17 to +94
export function addParent(people: Person[]) {
return people.map(person => {
const { motherName, fatherName } = person;

return {
...person,
mother: motherName ? getParent(people, motherName) : undefined,
father: fatherName ? getParent(people, fatherName) : undefined,
};
});
}

export function getSortedPeople(
people: Person[],
sortParam: SortParam | string,
) {
if (sortParam) {
return [...people].sort((a, b) => {
switch (sortParam) {
case (SortParam.Name):
case (SortParam.Sex): {
return a[sortParam].localeCompare(b[sortParam]);
}

case (SortParam.Born):
case (SortParam.Died): {
return a[sortParam] - (b[sortParam]);
}

default: {
return 0;
}
}
});
}

return [...people];
}

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

export function getFilteredPeople(
filterOption: FilterType,
people: Person[],
) {
let filteredPeople = people;

if (filterOption.sex) {
filteredPeople = filteredPeople
.filter(person => person.sex === filterOption.sex);
}

if (filterOption.centuries.length) {
filteredPeople = filteredPeople.filter(person => {
const personBirthCentury = Math.ceil(person.born / YEARS_IN_CENTURY);

return filterOption.centuries.includes(personBirthCentury.toString());
});
}

if (filterOption.query) {
filteredPeople = filteredPeople
.filter(person => {
const query = filterOption.query.toLowerCase();

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

return filteredPeople;
}

Choose a reason for hiding this comment

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

These functions have nothing to do with the API, so they should be moved to a separate file

Comment on lines +6 to +9
const getLinkClass = ({ isActive }: { isActive: boolean }) => cn(
'navbar-item',
{ 'has-background-grey-lighter': isActive },
);

Choose a reason for hiding this comment

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

It is better to define this function outside the component so that it is not created every time a new render is performed.

@@ -0,0 +1,10 @@
export const NOT_SET_VALUE = '-';

export const YEARS_IN_CENTURY = 100;

Choose a reason for hiding this comment

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

Suggested change
export const YEARS_IN_CENTURY = 100;
export const CENTURY_DIVIDER = 100;


export const YEARS_IN_CENTURY = 100;

export const DESC_SORT = 'desc';

Choose a reason for hiding this comment

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

Suggested change
export const DESC_SORT = 'desc';
export const DESCENDING_SORT = 'desc';

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants