From fe81e023e8a8fd5abe7260a987c863b89fd9f4eb Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sat, 6 Nov 2021 22:34:29 +0100 Subject: [PATCH] Moved table sorting icon to its own component wrapping the logic --- src/short-urls/ShortUrlsList.tsx | 6 ++---- src/tags/TagsTable.tsx | 13 ++++++------- src/utils/table/TableOrderIcon.tsx | 19 +++++++++++++++++++ src/visits/VisitsTable.tsx | 16 ++++------------ test/short-urls/ShortUrlsList.test.tsx | 8 ++++---- 5 files changed, 35 insertions(+), 27 deletions(-) create mode 100644 src/utils/table/TableOrderIcon.tsx diff --git a/src/short-urls/ShortUrlsList.tsx b/src/short-urls/ShortUrlsList.tsx index 8f3ed9e2..7c8fcda4 100644 --- a/src/short-urls/ShortUrlsList.tsx +++ b/src/short-urls/ShortUrlsList.tsx @@ -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) => boundToMercur }; const orderByColumn = (field: OrderableFields) => () => handleOrderBy(field, determineOrderDir(field, order.field, order.dir)); - const renderOrderIcon = (field: OrderableFields) => order.dir && order.field === field && - ; + const renderOrderIcon = (field: OrderableFields) => ; useEffect(() => { const { tag } = parseQuery<{ tag?: string }>(location.search); diff --git a/src/tags/TagsTable.tsx b/src/tags/TagsTable.tsx index e313ebd4..cf24542c 100644 --- a/src/tags/TagsTable.tsx +++ b/src/tags/TagsTable.tsx @@ -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) => ( 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 && - ; useEffect(() => { !isFirstLoad.current && setPage(1); @@ -43,12 +40,14 @@ export const TagsTable = (TagsTableRow: FC) => ( - + diff --git a/src/utils/table/TableOrderIcon.tsx b/src/utils/table/TableOrderIcon.tsx new file mode 100644 index 00000000..00434aad --- /dev/null +++ b/src/utils/table/TableOrderIcon.tsx @@ -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 { + currentOrder: Order; + field: T; + className?: string; +} + +export function TableOrderIcon( + { currentOrder, field, className = 'ml-1' }: TableOrderIconProps, +) { + if (!currentOrder.dir || currentOrder.field !== field) { + return null; + } + + return ; +} diff --git a/src/visits/VisitsTable.tsx b/src/visits/VisitsTable.tsx index 202f1357..842eac34 100644 --- a/src/visits/VisitsTable.tsx +++ b/src/visits/VisitsTable.tsx @@ -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 && ( - - ); + const renderOrderIcon = (field: OrderableFields) => + ; useEffect(() => { const listener = () => setIsMobileDevice(matchMobile()); diff --git a/test/short-urls/ShortUrlsList.test.tsx b/test/short-urls/ShortUrlsList.test.tsx index e000a09f..3524e3b7 100644 --- a/test/short-urls/ShortUrlsList.test.tsx +++ b/test/short-urls/ShortUrlsList.test.tsx @@ -77,15 +77,15 @@ describe('', () => { 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', () => {
Tag {renderOrderIcon('tag')} + Tag + - Short URLs {renderOrderIcon('shortUrls')} + Short URLs - Visits {renderOrderIcon('visits')} + Visits