Commit b1942126 authored by isstuev's avatar isstuev

add filters and tests

parent dd630ffd
......@@ -13,8 +13,8 @@ import AddressTokens from './AddressTokens';
const ADDRESS_HASH = addressMock.withName.hash;
const API_URL_ADDRESS = buildApiUrl('address', { hash: ADDRESS_HASH });
const API_URL_TOKENS = buildApiUrl('address_tokens', { hash: ADDRESS_HASH });
const API_URL_NFT = buildApiUrl('address_nfts', { hash: ADDRESS_HASH });
const API_URL_COLLECTIONS = buildApiUrl('address_collections', { hash: ADDRESS_HASH });
const API_URL_NFT = buildApiUrl('address_nfts', { hash: ADDRESS_HASH }) + '?type=';
const API_URL_COLLECTIONS = buildApiUrl('address_collections', { hash: ADDRESS_HASH }) + '?type=';
const nextPageParams = {
items_count: 50,
......
......@@ -19,7 +19,7 @@ import PopoverFilter from 'ui/shared/filters/PopoverFilter';
import TokenTypeFilter from 'ui/shared/filters/TokenTypeFilter';
import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import RadioButtonGroup from 'ui/shared/RadioButtonGroup';
import RadioButtonGroup from 'ui/shared/radioButtonGroup/RadioButtonGroup';
import RoutedTabs from 'ui/shared/Tabs/RoutedTabs';
import AddressCollections from './tokens/AddressCollections';
......@@ -73,7 +73,6 @@ const AddressTokens = () => {
scrollRef,
options: {
enabled: tab === 'tokens_nfts' && nftDisplayType === 'collection',
refetchOnMount: false,
placeholderData: generateListStub<'address_collections'>(ADDRESS_COLLECTION, 10, { next_page_params: null }),
},
filters: { type: tokenTypes },
......@@ -85,7 +84,6 @@ const AddressTokens = () => {
scrollRef,
options: {
enabled: tab === 'tokens_nfts' && nftDisplayType === 'list',
refetchOnMount: false,
placeholderData: generateListStub<'address_nfts'>(ADDRESS_NFT_1155, 10, { next_page_params: null }),
},
filters: { type: tokenTypes },
......@@ -108,14 +106,16 @@ const AddressTokens = () => {
</PopoverFilter>
);
const hasActiveFilters = Boolean(tokenTypes?.length);
const tabs = [
{ id: 'tokens_erc20', title: 'ERC-20', component: <ERC20Tokens tokensQuery={ erc20Query }/> },
{
id: 'tokens_nfts',
title: 'NFTs',
component: nftDisplayType === 'list' ?
<AddressNFTs tokensQuery={ nftsQuery }/> :
<AddressCollections collectionsQuery={ collectionsQuery } address={ hash }/>,
<AddressNFTs tokensQuery={ nftsQuery } hasActiveFilters={ hasActiveFilters }/> :
<AddressCollections collectionsQuery={ collectionsQuery } address={ hash } hasActiveFilters={ hasActiveFilters }/>,
},
];
......@@ -139,11 +139,17 @@ const AddressTokens = () => {
pagination = erc20Query.pagination;
}
const hasNftData =
(!nftsQuery.isPlaceholderData && nftsQuery.data?.items.length) ||
(!collectionsQuery.isPlaceholderData && collectionsQuery.data?.items.length);
const isNftTab = tab !== 'tokens' && tab !== 'tokens_erc20';
const rightSlot = (
<>
<HStack spacing={ 3 }>
{ tab !== 'tokens' && tab !== 'tokens_erc20' && nftDisplayTypeRadio }
{ tab !== 'tokens' && tab !== 'tokens_erc20' && nftTypeFilter }
{ isNftTab && (hasNftData || hasActiveFilters) && nftDisplayTypeRadio }
{ isNftTab && (hasNftData || hasActiveFilters) && nftTypeFilter }
</HStack>
{ pagination.isVisible && !isMobile && <Pagination { ...pagination }/> }
</>
......
......@@ -4,6 +4,7 @@ import React from 'react';
import { route } from 'nextjs-routes';
import useIsMobile from 'lib/hooks/useIsMobile';
import { apos } from 'lib/html-entities';
import ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
import TokenEntity from 'ui/shared/entities/token/TokenEntity';
......@@ -18,9 +19,10 @@ import NFTItemContainer from './NFTItemContainer';
type Props = {
collectionsQuery: QueryWithPagesResult<'address_collections'>;
address: string;
hasActiveFilters: boolean;
}
const AddressCollections = ({ collectionsQuery, address }: Props) => {
const AddressCollections = ({ collectionsQuery, address, hasActiveFilters }: Props) => {
const isMobile = useIsMobile();
const { isError, isPlaceholderData, data, pagination } = collectionsQuery;
......@@ -56,11 +58,9 @@ const AddressCollections = ({ collectionsQuery, address }: Props) => {
<Skeleton isLoaded={ !isPlaceholderData } mr={ 3 }>
<Text variant="secondary" whiteSpace="pre">{ ` - ${ Number(item.amount).toLocaleString() } item${ Number(item.amount) > 1 ? 's' : '' }` }</Text>
</Skeleton>
{ hasOverload && (
<LinkInternal href={ collectionUrl } isLoading={ isPlaceholderData }>
<Skeleton isLoaded={ !isPlaceholderData }>View in collection</Skeleton>
</LinkInternal>
) }
<LinkInternal href={ collectionUrl } isLoading={ isPlaceholderData }>
<Skeleton isLoaded={ !isPlaceholderData }>View in collection</Skeleton>
</LinkInternal>
</Flex>
<Grid
w="100%"
......@@ -105,6 +105,10 @@ const AddressCollections = ({ collectionsQuery, address }: Props) => {
emptyText="There are no tokens of selected type."
content={ content }
actionBar={ actionBar }
filterProps={{
emptyFilteredText: `Couldn${ apos }t find any token that matches your query.`,
hasActiveFilters,
}}
/>
);
};
......
......@@ -2,6 +2,7 @@ import { Grid } from '@chakra-ui/react';
import React from 'react';
import useIsMobile from 'lib/hooks/useIsMobile';
import { apos } from 'lib/html-entities';
import ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/pagination/Pagination';
......@@ -11,9 +12,10 @@ import NFTItem from './NFTItem';
type Props = {
tokensQuery: QueryWithPagesResult<'address_nfts'>;
hasActiveFilters: boolean;
}
const AddressNFTs = ({ tokensQuery }: Props) => {
const AddressNFTs = ({ tokensQuery, hasActiveFilters }: Props) => {
const isMobile = useIsMobile();
const { isError, isPlaceholderData, data, pagination } = tokensQuery;
......@@ -53,6 +55,10 @@ const AddressNFTs = ({ tokensQuery }: Props) => {
emptyText="There are no tokens of selected type."
content={ content }
actionBar={ actionBar }
filterProps={{
emptyFilteredText: `Couldn${ apos }t find any token that matches your query.`,
hasActiveFilters,
}}
/>
);
};
......
......@@ -6,7 +6,7 @@ type Props = {
className?: string;
};
const NFTItem = ({ children, className }: Props) => {
const NFTItemContainer = ({ children, className }: Props) => {
return (
<Box
w={{ base: '100%', lg: '210px' }}
......@@ -24,4 +24,4 @@ const NFTItem = ({ children, className }: Props) => {
);
};
export default chakra(NFTItem);
export default chakra(NFTItemContainer);
......@@ -105,7 +105,7 @@ const Tokens = () => {
</PopoverFilter>
) : (
<PopoverFilter isActive={ tokenTypes && tokenTypes.length > 0 } contentProps={{ w: '200px' }} appliedFiltersNum={ tokenTypes?.length }>
<TokenTypeFilter onChange={ handleTokenTypesChange } defaultValue={ tokenTypes } nftOnly={ false }/>
<TokenTypeFilter<TokenType> onChange={ handleTokenTypesChange } defaultValue={ tokenTypes } nftOnly={ false }/>
</PopoverFilter>
);
......
......@@ -56,7 +56,7 @@ const TokenTransferFilter = ({
</>
) }
<Text variant="secondary" fontWeight={ 600 }>Type</Text>
<TokenTypeFilter onChange={ onTypeFilterChange } defaultValue={ defaultTypeFilters } nftOnly={ false }/>
<TokenTypeFilter<TokenType> onChange={ onTypeFilterChange } defaultValue={ defaultTypeFilters } nftOnly={ false }/>
</PopoverFilter>
);
};
......
import { Box } from '@chakra-ui/react';
import { test, expect } from '@playwright/experimental-ct-react';
import React from 'react';
import TestApp from 'playwright/TestApp';
import RadioButtonGroupTest from './specs/RadioButtonGroupTest';
test('radio button group', async({ mount }) => {
const component = await mount(
<TestApp>
<Box w="400px" p="10px">
<RadioButtonGroupTest/>
</Box>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
......@@ -85,7 +85,7 @@ const RadioButtonGroup = <T extends string>({ onChange, name, defaultValue, opti
const group = getRootProps();
return (
<ButtonGroup { ...group } isAttached size="sm" display="grid" gridTemplateColumns="1fr 1fr">
<ButtonGroup { ...group } isAttached size="sm" display="grid" gridTemplateColumns={ `repeat(${ options.length }, 1fr)` }>
{ options.map((option) => {
const props = getRadioProps({ value: option.value });
return <RadioButton { ...props } key={ option.value } { ...option }/>;
......
import React from 'react';
import RadioButtonGroup from '../RadioButtonGroup';
const TestIcon = ({ className }: {className?: string}) => {
return (
<svg viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg" className={ className }>
{ /* eslint-disable-next-line max-len */ }
<path fillRule="evenodd" clipRule="evenodd" d="M3.5 11a7.5 7.5 0 1 1 15 0 7.5 7.5 0 0 1-15 0ZM11 1C5.477 1 1 5.477 1 11s4.477 10 10 10 10-4.477 10-10S16.523 1 11 1Zm1.25 5a1.25 1.25 0 1 0-2.5 0v5c0 .69.56 1.25 1.25 1.25h5a1.25 1.25 0 1 0 0-2.5h-3.75V6Z" fill="currentColor" stroke="transparent" strokeWidth=".6" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
);
};
type Test = 'v1' | 'v2' | 'v3';
const RadioButtonGroupTest = () => {
return (
<RadioButtonGroup<Test>
// eslint-disable-next-line react/jsx-no-bind
onChange={ () => {} }
defaultValue="v1"
name="test"
options={ [
{ value: 'v1', title: 'test option 1', icon: TestIcon, onlyIcon: false },
{ value: 'v2', title: 'test 2', onlyIcon: false },
{ value: 'v2', title: 'test 2', icon: TestIcon, onlyIcon: true },
] }
/>
);
};
export default RadioButtonGroupTest;
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