Commit 73cad84f authored by tom's avatar tom

refactor Sort

parent dab03ebf
...@@ -2,9 +2,8 @@ import { Box, Flex, Hide, Show, Text } from '@chakra-ui/react'; ...@@ -2,9 +2,8 @@ import { Box, Flex, Hide, Show, Text } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import type { VerifiedContract, VerifiedContractsFilters } from 'types/api/contracts'; import type { VerifiedContractsFilters } from 'types/api/contracts';
import compareBns from 'lib/bigint/compareBns';
import useDebounce from 'lib/hooks/useDebounce'; import useDebounce from 'lib/hooks/useDebounce';
import useQueryWithPages from 'lib/hooks/useQueryWithPages'; import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import { apos } from 'lib/html-entities'; import { apos } from 'lib/html-entities';
...@@ -17,56 +16,18 @@ import PageTitle from 'ui/shared/Page/PageTitle'; ...@@ -17,56 +16,18 @@ import PageTitle from 'ui/shared/Page/PageTitle';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList'; import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable'; import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import type { Sort, SortField } from 'ui/verifiedContracts/utils'; import Sort from 'ui/shared/sort/Sort';
import type { SortField, Sort as TSort } from 'ui/verifiedContracts/utils';
import { SORT_OPTIONS, sortFn, getNextSortValue } from 'ui/verifiedContracts/utils';
import VerifiedContractsFilter from 'ui/verifiedContracts/VerifiedContractsFilter'; import VerifiedContractsFilter from 'ui/verifiedContracts/VerifiedContractsFilter';
import VerifiedContractsList from 'ui/verifiedContracts/VerifiedContractsList'; import VerifiedContractsList from 'ui/verifiedContracts/VerifiedContractsList';
import VerifiedContractsSort from 'ui/verifiedContracts/VerifiedContractsSort';
import VerifiedContractsTable from 'ui/verifiedContracts/VerifiedContractsTable'; import VerifiedContractsTable from 'ui/verifiedContracts/VerifiedContractsTable';
const SORT_SEQUENCE: Record<SortField, Array<Sort | undefined>> = {
balance: [ 'balance-desc', 'balance-asc', undefined ],
txs: [ 'txs-desc', 'txs-asc', undefined ],
};
const getNextSortValue = (field: SortField) => (prevValue: Sort | undefined) => {
const sequence = SORT_SEQUENCE[field];
const curIndex = sequence.findIndex((sort) => sort === prevValue);
const nextIndex = curIndex + 1 > sequence.length - 1 ? 0 : curIndex + 1;
return sequence[nextIndex];
};
const sortFn = (sort: Sort | undefined) => (a: VerifiedContract, b: VerifiedContract) => {
switch (sort) {
case 'balance-desc': {
const result = compareBns(b.coin_balance, a.coin_balance);
return a.coin_balance === b.coin_balance ? 0 : result;
}
case 'balance-asc': {
const result = compareBns(a.coin_balance, b.coin_balance);
return a.coin_balance === b.coin_balance ? 0 : result;
}
case 'txs-desc': {
const result = (a.tx_count || 0) > (b.tx_count || 0) ? -1 : 1;
return a.tx_count === b.tx_count ? 0 : result;
}
case 'txs-asc': {
const result = (a.tx_count || 0) > (b.tx_count || 0) ? 1 : -1;
return a.tx_count === b.tx_count ? 0 : result;
}
default:
return 0;
}
};
const VerifiedContracts = () => { const VerifiedContracts = () => {
const router = useRouter(); const router = useRouter();
const [ searchTerm, setSearchTerm ] = React.useState(getQueryParamString(router.query.q) || undefined); const [ searchTerm, setSearchTerm ] = React.useState(getQueryParamString(router.query.q) || undefined);
const [ type, setType ] = React.useState(getQueryParamString(router.query.filter) as VerifiedContractsFilters['filter'] || undefined); const [ type, setType ] = React.useState(getQueryParamString(router.query.filter) as VerifiedContractsFilters['filter'] || undefined);
const [ sort, setSort ] = React.useState<Sort>(); const [ sort, setSort ] = React.useState<TSort>();
const debouncedSearchTerm = useDebounce(searchTerm || '', 300); const debouncedSearchTerm = useDebounce(searchTerm || '', 300);
...@@ -114,25 +75,29 @@ const VerifiedContracts = () => { ...@@ -114,25 +75,29 @@ const VerifiedContracts = () => {
); );
const sortButton = ( const sortButton = (
<VerifiedContractsSort <Sort
options={ SORT_OPTIONS }
sort={ sort } sort={ sort }
setSort={ setSort } setSort={ setSort }
isActive={ Boolean(sort) }
/> />
); );
const bar = ( const bar = (
<> <>
<Flex columnGap={ 3 } mb={ 6 } display={{ base: 'flex', lg: 'none' }}> <Show below="lg" ssr={ false }>
{ typeFilter } <Flex columnGap={ 3 } mb={ 6 }>
{ sortButton }
{ filterInput }
</Flex>
<ActionBar mt={ -6 }>
<Flex columnGap={ 3 } display={{ base: 'none', lg: 'flex' }}>
{ typeFilter } { typeFilter }
{ sortButton }
{ filterInput } { filterInput }
</Flex> </Flex>
</Show>
<ActionBar mt={ -6 }>
<Hide below="lg" ssr={ false }>
<Flex columnGap={ 3 }>
{ typeFilter }
{ filterInput }
</Flex>
</Hide>
{ isPaginationVisible && <Pagination ml="auto" { ...pagination }/> } { isPaginationVisible && <Pagination ml="auto" { ...pagination }/> }
</ActionBar> </ActionBar>
</> </>
......
...@@ -9,25 +9,20 @@ import { ...@@ -9,25 +9,20 @@ import {
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import SortButton from 'ui/shared/SortButton'; import SortButton from './SortButton';
import type { Sort } from './utils'; export interface Option<Sort extends string> {
title: string;
id: Sort | undefined;
}
interface Props { interface Props<Sort extends string> {
isActive: boolean; options: Array<Option<Sort>>;
sort: Sort | undefined; sort: Sort | undefined;
setSort: (val: Sort | undefined) => void; setSort: (value: Sort | undefined) => void;
} }
const SORT_OPTIONS = [ const Sort = <Sort extends string>({ sort, setSort, options }: Props<Sort>) => {
{ title: 'Default', id: undefined },
{ title: 'Balance ascending', id: 'balance-asc' },
{ title: 'Balance descending', id: 'balance-desc' },
{ title: 'Txs count ascending', id: 'txs-asc' },
{ title: 'Txs count descending', id: 'txs-desc' },
];
const VerifiedContractSorting = ({ isActive, sort, setSort }: Props) => {
const { isOpen, onToggle } = useDisclosure(); const { isOpen, onToggle } = useDisclosure();
const setSortingFromMenu = React.useCallback((val: string | Array<string>) => { const setSortingFromMenu = React.useCallback((val: string | Array<string>) => {
...@@ -39,13 +34,13 @@ const VerifiedContractSorting = ({ isActive, sort, setSort }: Props) => { ...@@ -39,13 +34,13 @@ const VerifiedContractSorting = ({ isActive, sort, setSort }: Props) => {
<Menu> <Menu>
<MenuButton> <MenuButton>
<SortButton <SortButton
isActive={ isOpen || isActive } isActive={ isOpen || Boolean(sort) }
onClick={ onToggle } onClick={ onToggle }
/> />
</MenuButton> </MenuButton>
<MenuList minWidth="240px" zIndex="popover"> <MenuList minWidth="240px" zIndex="popover">
<MenuOptionGroup value={ sort } title="Sort by" type="radio" onChange={ setSortingFromMenu }> <MenuOptionGroup value={ sort } title="Sort by" type="radio" onChange={ setSortingFromMenu }>
{ SORT_OPTIONS.map((option) => ( { options.map((option) => (
<MenuItemOption <MenuItemOption
key={ option.id || 'default' } key={ option.id || 'default' }
value={ option.id } value={ option.id }
...@@ -59,4 +54,4 @@ const VerifiedContractSorting = ({ isActive, sort, setSort }: Props) => { ...@@ -59,4 +54,4 @@ const VerifiedContractSorting = ({ isActive, sort, setSort }: Props) => {
); );
}; };
export default React.memo(chakra(VerifiedContractSorting)); export default React.memo(chakra(Sort)) as typeof Sort;
import { HStack, chakra } from '@chakra-ui/react'; import { HStack, chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { Sort } from 'types/client/txs-sort'; import type { Sort as TSort } from 'types/client/txs-sort';
// import FilterInput from 'ui/shared/filters/FilterInput'; // import FilterInput from 'ui/shared/filters/FilterInput';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import type { Props as PaginationProps } from 'ui/shared/Pagination'; import type { Props as PaginationProps } from 'ui/shared/Pagination';
import TxsSorting from 'ui/txs/TxsSorting'; import type { Option } from 'ui/shared/sort/Sort';
import Sort from 'ui/shared/sort/Sort';
// import TxsFilters from './TxsFilters'; // import TxsFilters from './TxsFilters';
const SORT_OPTIONS: Array<Option<TSort>> = [
{ title: 'Default', id: undefined },
{ title: 'Value ascending', id: 'val-asc' },
{ title: 'Value descending', id: 'val-desc' },
{ title: 'Fee ascending', id: 'fee-asc' },
{ title: 'Fee descending', id: 'fee-desc' },
];
type Props = { type Props = {
sorting: Sort; sorting: TSort;
setSorting: (val: Sort) => void; setSorting: (val: TSort | undefined) => void;
paginationProps: PaginationProps; paginationProps: PaginationProps;
className?: string; className?: string;
showPagination?: boolean; showPagination?: boolean;
...@@ -26,10 +35,10 @@ const TxsHeaderMobile = ({ filterComponent, sorting, setSorting, paginationProps ...@@ -26,10 +35,10 @@ const TxsHeaderMobile = ({ filterComponent, sorting, setSorting, paginationProps
<ActionBar className={ className }> <ActionBar className={ className }>
<HStack> <HStack>
{ filterComponent } { filterComponent }
<TxsSorting <Sort
isActive={ Boolean(sorting) } options={ SORT_OPTIONS }
setSorting={ setSorting } setSort={ setSorting }
sorting={ sorting } sort={ sorting }
/> />
{ /* api is not implemented */ } { /* api is not implemented */ }
{ /* <FilterInput { /* <FilterInput
......
import {
chakra,
Menu,
MenuButton,
MenuList,
MenuOptionGroup,
MenuItemOption,
useDisclosure,
} from '@chakra-ui/react';
import React from 'react';
import type { Sort } from 'types/client/txs-sort';
import SortButton from 'ui/shared/SortButton';
interface Props {
isActive: boolean;
sorting: Sort;
setSorting: (val: Sort) => void;
}
const SORT_OPTIONS = [
{ title: 'Default', id: '' },
{ title: 'Value ascending', id: 'val-asc' },
{ title: 'Value descending', id: 'val-desc' },
{ title: 'Fee ascending', id: 'fee-asc' },
{ title: 'Fee descending', id: 'fee-desc' },
];
const TxsSorting = ({ isActive, sorting, setSorting }: Props) => {
const { isOpen, onToggle } = useDisclosure();
const setSortingFromMenu = React.useCallback((val: string | Array<string>) => {
const value = val as Sort | Array<Sort>;
setSorting(Array.isArray(value) ? value[0] : value);
}, [ setSorting ]);
return (
<Menu>
<MenuButton>
<SortButton
isActive={ isOpen || isActive }
onClick={ onToggle }
/>
</MenuButton>
<MenuList minWidth="240px">
<MenuOptionGroup value={ sorting } title="Sort by" type="radio" onChange={ setSortingFromMenu }>
{ SORT_OPTIONS.map((option) => (
<MenuItemOption
key={ option.id }
value={ option.id }
>
{ option.title }
</MenuItemOption>
)) }
</MenuOptionGroup>
</MenuList>
</Menu>
);
};
export default chakra(TxsSorting);
...@@ -10,7 +10,7 @@ import sortTxs from 'lib/tx/sortTxs'; ...@@ -10,7 +10,7 @@ import sortTxs from 'lib/tx/sortTxs';
type HookResult = UseQueryResult<TxsResponse> & { type HookResult = UseQueryResult<TxsResponse> & {
sorting: Sort; sorting: Sort;
setSortByField: (field: 'val' | 'fee') => () => void; setSortByField: (field: 'val' | 'fee') => () => void;
setSortByValue: (value: Sort) => void; setSortByValue: (value: Sort | undefined) => void;
} }
export default function useTxsSort( export default function useTxsSort(
...@@ -45,7 +45,7 @@ export default function useTxsSort( ...@@ -45,7 +45,7 @@ export default function useTxsSort(
}); });
}, [ ]); }, [ ]);
const setSortByValue = React.useCallback((value: Sort) => { const setSortByValue = React.useCallback((value: Sort | undefined) => {
setSorting((prevVal: Sort) => { setSorting((prevVal: Sort) => {
let newVal: Sort = ''; let newVal: Sort = '';
if (value !== prevVal) { if (value !== prevVal) {
......
export type Sort = 'balance-asc' | 'balance-desc' | 'txs-asc' | 'txs-desc'; import type { VerifiedContract } from 'types/api/contracts';
import compareBns from 'lib/bigint/compareBns';
import type { Option } from 'ui/shared/sort/Sort';
export type SortField = 'balance' | 'txs'; export type SortField = 'balance' | 'txs';
export type Sort = `${ SortField }-asc` | `${ SortField }-desc`;
export const SORT_OPTIONS: Array<Option<Sort>> = [
{ title: 'Default', id: undefined },
{ title: 'Balance descending', id: 'balance-desc' },
{ title: 'Balance ascending', id: 'balance-asc' },
{ title: 'Txs count descending', id: 'txs-desc' },
{ title: 'Txs count ascending', id: 'txs-asc' },
];
const SORT_SEQUENCE: Record<SortField, Array<Sort | undefined>> = {
balance: [ 'balance-desc', 'balance-asc', undefined ],
txs: [ 'txs-desc', 'txs-asc', undefined ],
};
export const getNextSortValue = (field: SortField) => (prevValue: Sort | undefined) => {
const sequence = SORT_SEQUENCE[field];
const curIndex = sequence.findIndex((sort) => sort === prevValue);
const nextIndex = curIndex + 1 > sequence.length - 1 ? 0 : curIndex + 1;
return sequence[nextIndex];
};
export const sortFn = (sort: Sort | undefined) => (a: VerifiedContract, b: VerifiedContract) => {
switch (sort) {
case 'balance-asc':
case 'balance-desc': {
const result = compareBns(b.coin_balance, a.coin_balance) * (sort.includes('desc') ? 1 : -1);
return a.coin_balance === b.coin_balance ? 0 : result;
}
case 'txs-asc':
case 'txs-desc': {
const result = ((a.tx_count || 0) > (b.tx_count || 0) ? -1 : 1) * (sort.includes('desc') ? 1 : -1);
return a.tx_count === b.tx_count ? 0 : result;
}
default:
return 0;
}
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment