add sort-picker

This commit is contained in:
Pavel Mineev
2021-08-08 14:25:10 -05:00
committed by Umputun
parent e5e9d5a10e
commit 3314ed30a8
2 changed files with 138 additions and 0 deletions
@@ -0,0 +1,50 @@
import '@testing-library/jest-dom';
import { fireEvent, waitFor } from '@testing-library/preact';
import { h } from 'preact';
import { render } from 'tests/utils';
import * as commentsActions from 'store/comments/actions';
import type { StoreState } from 'store';
import { SortPicker } from './sort-picker';
const defaultState = { comments: {} as StoreState['comments'], hiddenUsers: {} };
const stateWithSort = { comments: { sort: '-active' } as StoreState['comments'] };
describe('<SortPicker />', () => {
it('should render sort picker with options', () => {
const { container, queryAllByText, queryByText } = render(<SortPicker />, defaultState);
expect(container.querySelectorAll('option')).toHaveLength(8);
expect(queryAllByText('Best')).toHaveLength(2);
expect(queryByText('Sort by')).toBeInTheDocument();
});
it('should has static class names', () => {
const { container } = render(<SortPicker />, defaultState);
expect(container.querySelector('.sort-picker')).toBeInTheDocument();
});
it('should render selected element', () => {
const { container, queryAllByText } = render(<SortPicker />, stateWithSort);
expect(queryAllByText('Recently updated')).toHaveLength(2);
expect(container.querySelector<HTMLOptionElement>('[value="-active"]')?.selected).toBeTruthy();
});
it('should change selected store', async () => {
const nextOption = '-controversy';
const updateSorting = jest.spyOn(commentsActions, 'updateSorting');
const { container } = render(<SortPicker />, defaultState);
const select = container.querySelector('select') as HTMLSelectElement;
expect(select).toBeInTheDocument();
fireEvent.change(select, { target: { value: nextOption } });
await waitFor(() => expect(updateSorting).toHaveBeenCalledWith(nextOption));
expect(container.querySelector<HTMLOptionElement>(`[value="${nextOption}"]`)?.selected).toBeTruthy();
});
});
+88
View File
@@ -0,0 +1,88 @@
import { h } from 'preact';
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import { useMemo } from 'preact/hooks';
import { useSelector, useDispatch } from 'react-redux';
import { StoreState } from 'store';
import { Select } from 'components/select';
import { updateSorting } from 'store/comments/actions';
import type { Sorting } from 'common/types';
export function SortPicker() {
const dispatch = useDispatch();
const intl = useIntl();
const [items, itemsById] = useMemo(() => {
const sortOptions = {
'-score': intl.formatMessage(messages.best),
'+score': intl.formatMessage(messages.worst),
'-time': intl.formatMessage(messages.newest),
'+time': intl.formatMessage(messages.oldest),
'-active': intl.formatMessage(messages.recentlyUpdated),
'+active': intl.formatMessage(messages.leastRecentlyUpdated),
'-controversy': intl.formatMessage(messages.mostControversial),
'+controversy': intl.formatMessage(messages.leastControversial),
};
type SortItem = { value: string; label: string };
const sortItems: SortItem[] = Object.entries(sortOptions).map(([k, v]) => ({ value: k, label: v }));
const sortById = sortItems.reduce(
(accum, s) => ({ ...accum, [s.value]: s }),
{} as Record<keyof typeof sortOptions, SortItem>
);
return [sortItems, sortById];
}, [intl]);
const sort = useSelector((s: StoreState) => s.comments.sort) || items[0].value;
const selected = itemsById[sort];
function handleSortChange(evt: Event) {
const { value } = evt.target as HTMLOptionElement;
if (!(value in itemsById)) {
return;
}
dispatch(updateSorting(value as Sorting));
}
return (
<span className="sort-picker">
<FormattedMessage id="sort-by" defaultMessage="Sort by" />{' '}
<Select items={items} selected={selected} onChange={handleSortChange} />
</span>
);
}
const messages = defineMessages({
best: {
id: 'commentsSort.best',
defaultMessage: 'Best',
},
worst: {
id: 'commentsSort.worst',
defaultMessage: 'Worst',
},
newest: {
id: 'commentsSort.newest',
defaultMessage: 'Newest',
},
oldest: {
id: 'commentsSort.oldest',
defaultMessage: 'Oldest',
},
recentlyUpdated: {
id: 'commentsSort.recently-updated',
defaultMessage: 'Recently updated',
},
leastRecentlyUpdated: {
id: 'commentsSort.least-recently-updated',
defaultMessage: 'Least recently updated',
},
mostControversial: {
id: 'commentsSort.most-controversial',
defaultMessage: 'Most controversial',
},
leastControversial: {
id: 'commentsSort.least-controversial',
defaultMessage: 'Least controversial',
},
});