Commit 1de38065 authored by Max Alekseenko's avatar Max Alekseenko

replace old sort component

parent e2a32ee8
import {
Box,
useColorModeValue,
Button,
Skeleton,
} from '@chakra-ui/react';
import React from 'react';
import useIsMobile from 'lib/hooks/useIsMobile';
import IconSvg from 'ui/shared/IconSvg';
import SortButtonMobile from 'ui/shared/sort/SortButton';
type ButtonProps = {
isMenuOpen: boolean;
onClick: () => void;
isLoading?: boolean;
children: React.ReactNode;
};
const SortButton = ({ children, isMenuOpen, onClick, isLoading }: ButtonProps, ref: React.ForwardedRef<HTMLButtonElement>) => {
const isMobile = useIsMobile();
const primaryColor = useColorModeValue('blackAlpha.800', 'whiteAlpha.800');
const secondaryColor = useColorModeValue('blackAlpha.600', 'whiteAlpha.600');
return (
<Skeleton isLoaded={ !isLoading }>
{ isMobile ? (
<SortButtonMobile ref={ ref } isActive={ isMenuOpen } onClick={ onClick }/>
) : (
<Button
ref={ ref }
size="sm"
variant="outline"
onClick={ onClick }
color={ primaryColor }
fontWeight="600"
borderColor="transparent"
px={ 2 }
data-selected={ isMenuOpen }
>
<Box
as={ isMenuOpen ? 'div' : 'span' }
color={ isMenuOpen ? 'inherit' : secondaryColor }
fontWeight="400"
mr={ 1 }
transition={ isMenuOpen ? 'none' : 'inherit' }
>Sort by</Box>
{ children }
<IconSvg
name="arrows/east-mini"
boxSize={ 5 }
ml={ 1 }
transform={ isMenuOpen ? 'rotate(90deg)' : 'rotate(-90deg)' }
/>
</Button>
) }
</Skeleton>
);
};
export default React.forwardRef(SortButton);
import {
Popover,
PopoverTrigger,
PopoverContent,
PopoverBody,
useDisclosure,
useRadioGroup,
} from '@chakra-ui/react';
import React from 'react';
import SortButton from './Button';
import Option from './Option';
import type { TOption } from './Option';
interface Props {
name: string;
options: Array<TOption>;
defaultValue?: string;
isLoading?: boolean;
onChange: (nextValue: 'default' | 'security_score') => void;
}
const SortMenu = ({ name, options, isLoading, onChange, defaultValue }: Props) => {
const { isOpen, onToggle, onClose } = useDisclosure();
const handleChange = (nextValue: 'default' | 'security_score') => {
onChange(nextValue);
onClose();
};
const { value, getRootProps, getRadioProps } = useRadioGroup({
name,
defaultValue,
onChange: handleChange,
});
const root = getRootProps();
return (
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy>
<PopoverTrigger>
<SortButton isMenuOpen={ isOpen } isLoading={ isLoading } onClick={ onToggle }>
{ options.find(option => option.value === value)?.label }
</SortButton>
</PopoverTrigger>
<PopoverContent w="fit-content" minW="165px">
<PopoverBody { ...root } py={ 2 } px={ 0 } display="flex" flexDir="column">
{ options.map((option) => {
const radio = getRadioProps({ value: option.value });
return (
<Option key={ option.value } { ...radio }>
{ option.label }
</Option>
);
}) }
</PopoverBody>
</PopoverContent>
</Popover>
);
};
export default React.memo(SortMenu);
......@@ -11,6 +11,7 @@ import useFetch from 'lib/hooks/useFetch';
import { MARKETPLACE_APP } from 'stubs/marketplace';
import useSecurityReports from './useSecurityReports';
import type { SortValue } from './utils';
const feature = config.features.marketplace;
......@@ -88,7 +89,7 @@ export default function useMarketplaceApps(
enabled: feature.isEnabled && Boolean(snapshotFavoriteApps),
});
const [ sorting, setSorting ] = React.useState<'default' | 'security_score'>('default');
const [ sorting, setSorting ] = React.useState<SortValue>();
const appsWithSecurityReports = React.useMemo(() =>
data?.map((app) => ({ ...app, securityReport: securityReports?.[app.id] })),
......
......@@ -2,6 +2,14 @@ import type { NextRouter } from 'next/router';
import getQueryParamString from 'lib/router/getQueryParamString';
import removeQueryParam from 'lib/router/removeQueryParam';
import type { TOption } from 'ui/shared/sort/Option';
export type SortValue = 'security_score';
export const SORT_OPTIONS: Array<TOption<SortValue>> = [
{ title: 'Default', id: undefined },
{ title: 'Security score', id: 'security_score' },
];
export function getAppUrl(url: string | undefined, router: NextRouter) {
if (!url) {
......
......@@ -135,9 +135,10 @@ const NameDomainsActionBar = ({
const sortButton = (
<Sort
name="name_domains_sorting"
defaultValue={ sort }
options={ SORT_OPTIONS }
sort={ sort }
setSort={ onSortChange }
onChange={ onSortChange }
isLoading={ isInitialLoading }
/>
);
......
import type { EnsLookupSorting } from 'types/api/ens';
import getNextSortValueShared from 'ui/shared/sort/getNextSortValue';
import type { Option } from 'ui/shared/sort/Sort';
import type { TOption } from 'ui/shared/sort/Option';
export type SortField = EnsLookupSorting['sort'];
export type Sort = `${ EnsLookupSorting['sort'] }-${ EnsLookupSorting['order'] }`;
export const SORT_OPTIONS: Array<Option<Sort>> = [
export const SORT_OPTIONS: Array<TOption<Sort>> = [
{ title: 'Default', id: undefined },
{ title: 'Registered on descending', id: 'registration_date-DESC' },
{ title: 'Registered on ascending', id: 'registration_date-ASC' },
......
......@@ -13,12 +13,13 @@ import ContractListModal from 'ui/marketplace/ContractListModal';
import MarketplaceAppModal from 'ui/marketplace/MarketplaceAppModal';
import MarketplaceDisclaimerModal from 'ui/marketplace/MarketplaceDisclaimerModal';
import MarketplaceList from 'ui/marketplace/MarketplaceList';
import SortMenu from 'ui/marketplace/SortMenu/Menu';
import { SORT_OPTIONS } from 'ui/marketplace/utils';
import FilterInput from 'ui/shared/filters/FilterInput';
import IconSvg from 'ui/shared/IconSvg';
import type { IconName } from 'ui/shared/IconSvg';
import LinkExternal from 'ui/shared/links/LinkExternal';
import PageTitle from 'ui/shared/Page/PageTitle';
import Sort from 'ui/shared/sort/Sort';
import TabsWithScroll from 'ui/shared/Tabs/TabsWithScroll';
import useMarketplace from '../marketplace/useMarketplace';
......@@ -186,13 +187,9 @@ const Marketplace = () => {
<Flex mb={{ base: 4, lg: 6 }} gap={{ base: 2, lg: 3 }}>
{ feature.securityReportsUrl && (
<SortMenu
<Sort
name="dapps_sorting"
defaultValue="default"
options={ [
{ value: 'default', label: 'Default' },
{ value: 'security_score', label: 'Security score' },
] }
options={ SORT_OPTIONS }
onChange={ setSorting }
isLoading={ isPlaceholderData }
/>
......
......@@ -97,9 +97,10 @@ const Validators = () => {
const sortButton = (
<Sort
name="validators_sorting"
defaultValue={ sort }
options={ SORT_OPTIONS }
sort={ sort }
setSort={ handleSortChange }
onChange={ handleSortChange }
/>
);
......
......@@ -97,9 +97,11 @@ const VerifiedContracts = () => {
const sortButton = (
<Sort
name="verified_contracts_sorting"
defaultValue={ sort }
options={ SORT_OPTIONS }
sort={ sort }
setSort={ handleSortChange }
onChange={ handleSortChange }
isLoading={ isPlaceholderData }
/>
);
......
import {
Box,
useColorModeValue,
Button,
Skeleton,
chakra,
} from '@chakra-ui/react';
import React from 'react';
import IconSvg from 'ui/shared/IconSvg';
type ButtonProps = {
isMenuOpen: boolean;
onClick: () => void;
isLoading?: boolean;
children: React.ReactNode;
className?: string;
};
const ButtonDesktop = ({ children, isMenuOpen, onClick, isLoading, className }: ButtonProps, ref: React.ForwardedRef<HTMLButtonElement>) => {
const primaryColor = useColorModeValue('blackAlpha.800', 'whiteAlpha.800');
const secondaryColor = useColorModeValue('blackAlpha.600', 'whiteAlpha.600');
return (
<Skeleton isLoaded={ !isLoading }>
<Button
className={ className }
ref={ ref }
size="sm"
variant="outline"
onClick={ onClick }
color={ primaryColor }
fontWeight="600"
borderColor="transparent"
px={ 2 }
data-selected={ isMenuOpen }
>
<Box
as={ isMenuOpen ? 'div' : 'span' }
color={ isMenuOpen ? 'inherit' : secondaryColor }
fontWeight="400"
mr={ 1 }
transition={ isMenuOpen ? 'none' : 'inherit' }
>Sort by</Box>
{ children }
<IconSvg
name="arrows/east-mini"
boxSize={ 5 }
ml={ 1 }
transform={ isMenuOpen ? 'rotate(90deg)' : 'rotate(-90deg)' }
/>
</Button>
</Skeleton>
);
};
export default chakra(React.forwardRef(ButtonDesktop));
......@@ -10,7 +10,7 @@ type Props = {
isLoading?: boolean;
}
const SortButton = ({ onClick, isActive, className, isLoading }: Props, ref: React.ForwardedRef<HTMLButtonElement>) => {
const ButtonMobile = ({ onClick, isActive, className, isLoading }: Props, ref: React.ForwardedRef<HTMLButtonElement>) => {
if (isLoading) {
return <Skeleton className={ className } w="36px" h="32px" borderRadius="base"/>;
}
......@@ -32,4 +32,4 @@ const SortButton = ({ onClick, isActive, className, isLoading }: Props, ref: Rea
);
};
export default chakra(React.forwardRef(SortButton));
export default chakra(React.forwardRef(ButtonMobile));
......@@ -8,9 +8,9 @@ import React from 'react';
import IconSvg from 'ui/shared/IconSvg';
export interface TOption {
value: string;
label: string;
export interface TOption<Sort extends string> {
id: Sort | undefined;
title: string;
}
type OptionProps = ReturnType<ReturnType<typeof useRadioGroup>['getRadioProps']>;
......
import {
chakra,
Menu,
MenuButton,
MenuList,
MenuOptionGroup,
MenuItemOption,
Popover,
PopoverTrigger,
PopoverContent,
PopoverBody,
useDisclosure,
useRadioGroup,
chakra,
} from '@chakra-ui/react';
import React from 'react';
import SortButton from './SortButton';
import useIsMobile from 'lib/hooks/useIsMobile';
export interface Option<Sort extends string> {
title: string;
id: Sort | undefined;
}
import SortButtonDesktop from './ButtonDesktop';
import SortButtonMobile from './ButtonMobile';
import Option from './Option';
import type { TOption } from './Option';
interface Props<Sort extends string> {
options: Array<Option<Sort>>;
sort: Sort | undefined;
setSort: (value: Sort | undefined) => void;
name: string;
options: Array<TOption<Sort>>;
defaultValue?: Sort;
isLoading?: boolean;
onChange: (value: Sort | undefined) => void;
}
const Sort = <Sort extends string>({ sort, setSort, options, isLoading }: Props<Sort>) => {
const { isOpen, onToggle } = useDisclosure();
const Sort = <Sort extends string>({ name, options, isLoading, onChange, defaultValue }: Props<Sort>) => {
const isMobile = useIsMobile(false);
const { isOpen, onToggle, onClose } = useDisclosure();
const handleChange = (value: Sort) => {
onChange(value);
onClose();
};
const { value, getRootProps, getRadioProps } = useRadioGroup({
name,
defaultValue,
onChange: handleChange,
});
const setSortingFromMenu = React.useCallback((val: string | Array<string>) => {
const value = val as Sort | Array<Sort>;
setSort(Array.isArray(value) ? value[0] : value);
}, [ setSort ]);
const root = getRootProps();
return (
<Menu>
<MenuButton as="div">
<SortButton
isActive={ isOpen || Boolean(sort) }
onClick={ onToggle }
isLoading={ isLoading }
/>
</MenuButton>
<MenuList minWidth="240px" zIndex="popover">
<MenuOptionGroup value={ sort } title="Sort by" type="radio" onChange={ setSortingFromMenu }>
{ options.map((option) => (
<MenuItemOption
key={ option.id || 'default' }
value={ option.id }
>
{ option.title }
</MenuItemOption>
)) }
</MenuOptionGroup>
</MenuList>
</Menu>
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy>
<PopoverTrigger>
{ isMobile ? (
<SortButtonMobile isActive={ isOpen || Boolean(value) } onClick={ onToggle } isLoading={ isLoading }/>
) : (
<SortButtonDesktop isMenuOpen={ isOpen } isLoading={ isLoading } onClick={ onToggle }>
{ options.find((option: TOption<Sort>) => option.id === value || (!option.id && !value))?.title }
</SortButtonDesktop>
) }
</PopoverTrigger>
<PopoverContent w="fit-content" minW="165px">
<PopoverBody { ...root } py={ 2 } px={ 0 } display="flex" flexDir="column">
{ options.map((option, index) => {
const radio = getRadioProps({ value: option.id });
return (
<Option key={ index } { ...radio } isChecked={ radio.isChecked || (!option.id && !value) }>
{ option.title }
</Option>
);
}) }
</PopoverBody>
</PopoverContent>
</Popover>
);
};
......
import type { Query } from 'nextjs-routes';
import type { Option } from 'ui/shared/sort/Sort';
import type { TOption } from 'ui/shared/sort/Option';
export default function getSortValueFromQuery<SortValue extends string>(query: Query, sortOptions: Array<Option<SortValue>>) {
export default function getSortValueFromQuery<SortValue extends string>(query: Query, sortOptions: Array<TOption<SortValue>>) {
if (!query.sort || !query.order) {
return undefined;
}
......
......@@ -45,9 +45,10 @@ const TokensActionBar = ({
<HStack spacing={ 3 } mb={ 6 } display={{ base: 'flex', lg: 'none' }}>
{ filter }
<Sort
name="tokens_sorting"
defaultValue={ sort }
options={ SORT_OPTIONS }
setSort={ onSortChange }
sort={ sort }
onChange={ onSortChange }
/>
{ searchInput }
</HStack>
......
......@@ -4,9 +4,9 @@ import type { TokensSortingValue } from 'types/api/tokens';
import config from 'configs/app';
import getFilterValuesFromQuery from 'lib/getFilterValuesFromQuery';
import { TOKEN_TYPE_IDS } from 'lib/token/tokenTypes';
import type { Option } from 'ui/shared/sort/Sort';
import type { TOption } from 'ui/shared/sort/Option';
export const SORT_OPTIONS: Array<Option<TokensSortingValue>> = [
export const SORT_OPTIONS: Array<TOption<TokensSortingValue>> = [
{ title: 'Default', id: undefined },
{ title: 'Price ascending', id: 'fiat_value-asc' },
{ title: 'Price descending', id: 'fiat_value-desc' },
......
......@@ -30,9 +30,10 @@ const TxsHeaderMobile = ({ filterComponent, sorting, setSorting, paginationProps
<HStack>
{ filterComponent }
<Sort
name="transactions_sorting"
defaultValue={ sorting }
options={ SORT_OPTIONS }
setSort={ setSorting }
sort={ sorting }
onChange={ setSorting }
isLoading={ paginationProps.isLoading }
/>
{ /* api is not implemented */ }
......
......@@ -5,11 +5,11 @@ import type { TransactionsSortingValue, TxsResponse } from 'types/api/transactio
import type { ResourceError } from 'lib/api/resources';
import * as cookies from 'lib/cookies';
import type { Option } from 'ui/shared/sort/Sort';
import type { TOption } from 'ui/shared/sort/Option';
import sortTxs from './sortTxs';
export const SORT_OPTIONS: Array<Option<TransactionsSortingValue>> = [
export const SORT_OPTIONS: Array<TOption<TransactionsSortingValue>> = [
{ title: 'Default', id: undefined },
{ title: 'Value ascending', id: 'value-asc' },
{ title: 'Value descending', id: 'value-desc' },
......
import type { ValidatorsSortingValue, ValidatorsSortingField } from 'types/api/validators';
import type { Option } from 'ui/shared/sort/Sort';
import type { TOption } from 'ui/shared/sort/Option';
export const SORT_OPTIONS: Array<Option<ValidatorsSortingValue>> = [
export const SORT_OPTIONS: Array<TOption<ValidatorsSortingValue>> = [
{ title: 'Default', id: undefined },
{ title: 'Status descending', id: 'state-desc' },
{ title: 'Status ascending', id: 'state-asc' },
......
import type { VerifiedContractsSortingValue, VerifiedContractsSortingField } from 'types/api/verifiedContracts';
import type { Option } from 'ui/shared/sort/Sort';
import type { TOption } from 'ui/shared/sort/Option';
export const SORT_OPTIONS: Array<Option<VerifiedContractsSortingValue>> = [
export const SORT_OPTIONS: Array<TOption<VerifiedContractsSortingValue>> = [
{ title: 'Default', id: undefined },
{ title: 'Balance descending', id: 'balance-desc' },
{ title: 'Balance ascending', id: 'balance-asc' },
......
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