mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2025-01-09 17:57:26 +03:00
Moved table sorting icon to its own component wrapping the logic
This commit is contained in:
parent
5906921eec
commit
fe81e023e8
5 changed files with 35 additions and 27 deletions
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
19
src/utils/table/TableOrderIcon.tsx
Normal file
19
src/utils/table/TableOrderIcon.tsx
Normal 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} />;
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
Loading…
Reference in a new issue