Moved table sorting icon to its own component wrapping the logic

This commit is contained in:
Alejandro Celaya 2021-11-06 22:34:29 +01:00
parent 5906921eec
commit fe81e023e8
5 changed files with 35 additions and 27 deletions

View file

@ -1,5 +1,3 @@
import { faCaretDown as caretDownIcon, faCaretUp as caretUpIcon } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { head, keys, values } from 'ramda';
import { FC, useEffect, useState } from 'react';
import { RouteComponentProps } from 'react-router';
@ -10,6 +8,7 @@ import { getServerId, SelectedServer } from '../servers/data';
import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
import { parseQuery } from '../utils/helpers/query';
import { Topics } from '../mercure/helpers/Topics';
import { TableOrderIcon } from '../utils/table/TableOrderIcon';
import { ShortUrlsList as ShortUrlsListState } from './reducers/shortUrlsList';
import { OrderableFields, ShortUrlsListParams, SORTABLE_FIELDS } from './reducers/shortUrlsListParams';
import { ShortUrlsTableProps } from './ShortUrlsTable';
@ -52,8 +51,7 @@ const ShortUrlsList = (ShortUrlsTable: FC<ShortUrlsTableProps>) => boundToMercur
};
const orderByColumn = (field: OrderableFields) => () =>
handleOrderBy(field, determineOrderDir(field, order.field, order.dir));
const renderOrderIcon = (field: OrderableFields) => order.dir && order.field === field &&
<FontAwesomeIcon icon={order.dir === 'ASC' ? caretUpIcon : caretDownIcon} className="ml-1" />;
const renderOrderIcon = (field: OrderableFields) => <TableOrderIcon currentOrder={order} field={field} />;
useEffect(() => {
const { tag } = parseQuery<{ tag?: string }>(location.search);

View file

@ -1,12 +1,11 @@
import { FC, useEffect, useRef } from 'react';
import { splitEvery } from 'ramda';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCaretDown as caretDownIcon, faCaretUp as caretUpIcon } from '@fortawesome/free-solid-svg-icons';
import { RouteChildrenProps } from 'react-router';
import { SimpleCard } from '../utils/SimpleCard';
import SimplePaginator from '../common/SimplePaginator';
import { useQueryState } from '../utils/helpers/hooks';
import { parseQuery } from '../utils/helpers/query';
import { TableOrderIcon } from '../utils/table/TableOrderIcon';
import { OrderableFields, TagsListChildrenProps, TagsOrder } from './data/TagsListChildrenProps';
import { TagsTableRowProps } from './TagsTableRow';
import './TagsTable.scss';
@ -27,8 +26,6 @@ export const TagsTable = (TagsTableRow: FC<TagsTableRowProps>) => (
const pages = splitEvery(TAGS_PER_PAGE, sortedTags);
const showPaginator = pages.length > 1;
const currentPage = pages[page - 1] ?? [];
const renderOrderIcon = (field: OrderableFields) => currentOrder.dir && currentOrder.field === field &&
<FontAwesomeIcon icon={currentOrder.dir === 'ASC' ? caretUpIcon : caretDownIcon} className="ml-1" />;
useEffect(() => {
!isFirstLoad.current && setPage(1);
@ -43,12 +40,14 @@ export const TagsTable = (TagsTableRow: FC<TagsTableRowProps>) => (
<table className="table table-hover mb-0">
<thead className="responsive-table__header">
<tr>
<th className="tags-table__header-cell" onClick={orderByColumn('tag')}>Tag {renderOrderIcon('tag')}</th>
<th className="tags-table__header-cell" onClick={orderByColumn('tag')}>
Tag <TableOrderIcon currentOrder={currentOrder} field="tag" />
</th>
<th className="tags-table__header-cell text-lg-right" onClick={orderByColumn('shortUrls')}>
Short URLs {renderOrderIcon('shortUrls')}
Short URLs <TableOrderIcon currentOrder={currentOrder} field="shortUrls" />
</th>
<th className="tags-table__header-cell text-lg-right" onClick={orderByColumn('visits')}>
Visits {renderOrderIcon('visits')}
Visits <TableOrderIcon currentOrder={currentOrder} field="visits" />
</th>
<th className="tags-table__header-cell" />
</tr>

View file

@ -0,0 +1,19 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCaretDown as caretDownIcon, faCaretUp as caretUpIcon } from '@fortawesome/free-solid-svg-icons';
import { Order } from '../helpers/ordering';
interface TableOrderIconProps<T> {
currentOrder: Order<T>;
field: T;
className?: string;
}
export function TableOrderIcon<T extends string = string>(
{ currentOrder, field, className = 'ml-1' }: TableOrderIconProps<T>,
) {
if (!currentOrder.dir || currentOrder.field !== field) {
return null;
}
return <FontAwesomeIcon icon={currentOrder.dir === 'ASC' ? caretUpIcon : caretDownIcon} className={className} />;
}

View file

@ -1,12 +1,7 @@
import { useEffect, useMemo, useState, useRef } from 'react';
import classNames from 'classnames';
import { min, splitEvery } from 'ramda';
import {
faCaretDown as caretDownIcon,
faCaretUp as caretUpIcon,
faCheck as checkIcon,
faRobot as botIcon,
} from '@fortawesome/free-solid-svg-icons';
import { faCheck as checkIcon, faRobot as botIcon } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { UncontrolledTooltip } from 'reactstrap';
import SimplePaginator from '../common/SimplePaginator';
@ -16,6 +11,7 @@ import { prettify } from '../utils/helpers/numbers';
import { supportsBotVisits } from '../utils/helpers/features';
import { SelectedServer } from '../servers/data';
import { Time } from '../utils/Time';
import { TableOrderIcon } from '../utils/table/TableOrderIcon';
import { NormalizedOrphanVisit, NormalizedVisit } from './types';
import './VisitsTable.scss';
@ -72,12 +68,8 @@ const VisitsTable = ({
const orderByColumn = (field: OrderableFields) =>
() => setOrder({ field, dir: determineOrderDir(field, order.field, order.dir) });
const renderOrderIcon = (field: OrderableFields) => order.dir && order.field === field && (
<FontAwesomeIcon
icon={order.dir === 'ASC' ? caretUpIcon : caretDownIcon}
className="visits-table__header-icon"
/>
);
const renderOrderIcon = (field: OrderableFields) =>
<TableOrderIcon currentOrder={order} field={field} className="visits-table__header-icon" />;
useEffect(() => {
const listener = () => setIsMobileDevice(matchMobile());

View file

@ -77,15 +77,15 @@ describe('<ShortUrlsList />', () => {
it('invokes order icon rendering', () => {
const renderIcon = (field: OrderableFields) =>
(wrapper.find(ShortUrlsTable).prop('renderOrderIcon') as (field: OrderableFields) => ReactElement | null)(field);
(wrapper.find(ShortUrlsTable).prop('renderOrderIcon') as (field: OrderableFields) => ReactElement)(field);
expect(renderIcon('visits')).toEqual(undefined);
expect(renderIcon('visits').props.currentOrder).toEqual({});
wrapper.find(SortingDropdown).simulate('change', 'visits');
expect(renderIcon('visits')).toEqual(undefined);
expect(renderIcon('visits').props.currentOrder).toEqual({ field: 'visits' });
wrapper.find(SortingDropdown).simulate('change', 'visits', 'ASC');
expect(renderIcon('visits')).not.toEqual(undefined);
expect(renderIcon('visits').props.currentOrder).toEqual({ field: 'visits', dir: 'ASC' });
});
it('handles order by through table', () => {