Commit 5e28210d authored by isstuev's avatar isstuev

search by label

parent 46e795fe
import type { SearchResultToken, SearchResultBlock, SearchResultAddressOrContract, SearchResultTx, SearchResult } from 'types/api/search';
import type { SearchResultToken, SearchResultBlock, SearchResultAddressOrContract, SearchResultTx, SearchResultLabel, SearchResult } from 'types/api/search';
export const token1: SearchResultToken = {
address: '0x377c5F2B300B25a534d4639177873b7fEAA56d4B',
......@@ -41,6 +41,13 @@ export const contract1: SearchResultAddressOrContract = {
url: '/address/0xb64a30399f7F6b0C154c2E7Af0a3ec7B0A5b131a',
};
export const label1: SearchResultLabel = {
address: '0xb64a30399f7F6b0C154c2E7Af0a3ec7B0A5b131a',
name: 'utko',
type: 'label' as const,
url: '/address/0xb64a30399f7F6b0C154c2E7Af0a3ec7B0A5b131a',
};
export const tx1: SearchResultTx = {
tx_hash: '0x349d4025d03c6faec117ee10ac0bce7c7a805dd2cbff7a9f101304d9a8a525dd',
type: 'transaction' as const,
......
......@@ -17,6 +17,13 @@ export interface SearchResultAddressOrContract {
url?: string; // not used by the frontend, we build the url ourselves
}
export interface SearchResultLabel {
type: 'label';
address: string;
name: string;
url?: string; // not used by the frontend, we build the url ourselves
}
export interface SearchResultBlock {
type: 'block';
block_number: number | string;
......@@ -30,7 +37,7 @@ export interface SearchResultTx {
url?: string; // not used by the frontend, we build the url ourselves
}
export type SearchResultItem = SearchResultToken | SearchResultAddressOrContract | SearchResultBlock | SearchResultTx;
export type SearchResultItem = SearchResultToken | SearchResultAddressOrContract | SearchResultBlock | SearchResultTx | SearchResultLabel;
export interface SearchResult {
items: Array<SearchResultItem>;
......
......@@ -20,6 +20,7 @@ test('search by name +@mobile +@dark-mode', async({ mount, page }) => {
searchMock.token1,
searchMock.token2,
searchMock.contract1,
searchMock.label1,
],
}),
}));
......
......@@ -5,6 +5,7 @@ import React from 'react';
import type { SearchResultItem } from 'types/api/search';
import blockIcon from 'icons/block.svg';
import labelIcon from 'icons/publictags.svg';
import txIcon from 'icons/transactions.svg';
import highlightText from 'lib/highlightText';
import trimTokenSymbol from 'lib/token/trimTokenSymbol';
......@@ -58,6 +59,23 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
);
}
case 'label': {
return (
<Flex alignItems="flex-start">
<Icon as={ labelIcon } boxSize={ 6 } mr={ 2 } color="gray.500"/>
<LinkInternal
ml={ 2 }
href={ route({ pathname: '/address/[hash]', query: { hash: data.address } }) }
fontWeight={ 700 }
wordBreak="break-all"
isLoading={ isLoading }
>
<Skeleton isLoaded={ !isLoading } dangerouslySetInnerHTML={{ __html: highlightText(data.name, searchTerm) }}/>
</LinkInternal>
</Flex>
);
}
case 'block': {
const shouldHighlightHash = data.block_hash.toLowerCase() === searchTerm.toLowerCase();
return (
......
......@@ -5,6 +5,7 @@ import React from 'react';
import type { SearchResultItem } from 'types/api/search';
import blockIcon from 'icons/block.svg';
import labelIcon from 'icons/publictags.svg';
import txIcon from 'icons/transactions.svg';
import highlightText from 'lib/highlightText';
import trimTokenSymbol from 'lib/token/trimTokenSymbol';
......@@ -93,6 +94,32 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => {
);
}
case 'label': {
return (
<>
<Td fontSize="sm">
<Flex alignItems="center">
<Icon as={ labelIcon } boxSize={ 6 } mr={ 2 } color="gray.500"/>
<LinkInternal
ml={ 2 }
href={ route({ pathname: '/address/[hash]', query: { hash: data.address } }) }
fontWeight={ 700 }
wordBreak="break-all"
isLoading={ isLoading }
>
<Skeleton isLoaded={ !isLoading } dangerouslySetInnerHTML={{ __html: highlightText(data.name, searchTerm) }}/>
</LinkInternal>
</Flex>
</Td>
<Td fontSize="sm" verticalAlign="middle">
<Skeleton isLoaded={ !isLoading } whiteSpace="nowrap" overflow="hidden">
<HashStringShortenDynamic hash={ data.address }/>
</Skeleton>
</Td>
</>
);
}
case 'block': {
const shouldHighlightHash = data.block_hash.toLowerCase() === searchTerm.toLowerCase();
......
......@@ -51,6 +51,28 @@ test('search by name +@mobile +@dark-mode', async({ mount, page }) => {
await expect(page).toHaveScreenshot({ clip: { x: 0, y: 0, width: 1200, height: 500 } });
});
test('search by tag +@mobile +@dark-mode', async({ mount, page }) => {
const API_URL = buildApiUrl('search') + '?q=o';
await page.route(API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify({
items: [
searchMock.label1,
],
}),
}));
await mount(
<TestApp>
<SearchBar/>
</TestApp>,
);
await page.getByPlaceholder(/search/i).type('o');
await page.waitForResponse(API_URL);
await expect(page).toHaveScreenshot({ clip: { x: 0, y: 0, width: 1200, height: 500 } });
});
test('search by address hash +@mobile', async({ mount, page }) => {
const API_URL = buildApiUrl('search') + `?q=${ searchMock.address1.address }`;
await page.route(API_URL, (route) => route.fulfill({
......
......@@ -7,6 +7,7 @@ import React from 'react';
import type { SearchResultItem } from 'types/api/search';
import blockIcon from 'icons/block.svg';
import labelIcon from 'icons/publictags.svg';
import txIcon from 'icons/transactions.svg';
import highlightText from 'lib/highlightText';
import AddressIcon from 'ui/shared/address/AddressIcon';
......@@ -28,7 +29,8 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) =>
return route({ pathname: '/token/[hash]', query: { hash: data.address } });
}
case 'contract':
case 'address': {
case 'address':
case 'label': {
return route({ pathname: '/address/[hash]', query: { hash: data.address } });
}
case 'transaction': {
......@@ -76,6 +78,21 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) =>
</>
);
}
case 'label': {
return (
<>
<Icon as={ labelIcon } boxSize={ 6 } mr={ 2 } color="gray.500"/>
<Text fontWeight={ 700 } ml={ 2 } w="200px" overflow="hidden" whiteSpace="nowrap" textOverflow="ellipsis" flexShrink={ 0 }>
<span dangerouslySetInnerHTML={{ __html: highlightText(data.name, searchTerm) }}/>
</Text>
{ !isMobile && (
<Text overflow="hidden" whiteSpace="nowrap" ml={ 2 } variant="secondary">
<HashStringShortenDynamic hash={ data.address } isTooltipDisabled/>
</Text>
) }
</>
);
}
case 'block': {
const shouldHighlightHash = data.block_hash.toLowerCase() === searchTerm.toLowerCase();
return (
......@@ -109,7 +126,8 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) =>
}
switch (data.type) {
case 'token': {
case 'token':
case 'label': {
return (
<Text variant="secondary" whiteSpace="nowrap" overflow="hidden">
<HashStringShortenDynamic hash={ data.address } isTooltipDisabled/>
......
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