Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/modules/zerion-api/hooks/useSearchQueryFungibles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useQuery } from '@tanstack/react-query';
import { ZerionAPI } from 'src/modules/zerion-api/zerion-api.client';
import type { Response } from 'src/modules/zerion-api/requests/search-query-fungibles';

export function useSearchQueryFungibles({
query,
currency,
chain,
limit = 5,
}: {
query: string;
currency: string;
chain?: string;
limit?: number;
}) {
return useQuery<Response | null>({
queryKey: ['searchQueryFungibles', query, currency, chain, limit],
queryFn: () => {
return ZerionAPI.searchQueryFungibles({
query,
currency,
chain,
limit,
});
},
enabled: query.trim().length > 0,
staleTime: 30000,
suspense: false,
});
}
34 changes: 34 additions & 0 deletions src/modules/zerion-api/requests/search-query-fungibles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { ClientOptions } from '../shared';
import { ZerionHttpClient } from '../shared';
import type { Fungible } from '../types/Fungible';
import type { ZerionApiContext } from '../zerion-api-bare';

interface Payload {
/** @description Search phrase can be any text, wallet address, or wallet handle. */
query: string;
/** @description Currency to convert prices if section items include them. */
currency: string;
/** @description The network ID to search within. */
chain?: string;
/** @description Limit for each search section items count. */
limit?: number;
}

export interface Response {
data: Fungible[];
errors?: { title: string; detail: string }[];
}

export function searchQueryFungibles(
this: ZerionApiContext,
{ query, currency, chain, limit = 5 }: Payload,
options?: ClientOptions
) {
const params = new URLSearchParams({ query, currency, limit: String(limit) });
if (chain != null) {
params.append('chain', chain);
}
const endpoint = `search/query-fungibles/v1?${params}`;
const kyOptions = this.getKyOptions();
return ZerionHttpClient.get<Response>({ endpoint, ...options }, kyOptions);
}
2 changes: 2 additions & 0 deletions src/modules/zerion-api/zerion-api-bare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { walletGetAssetDetails } from './requests/wallet-get-asset-details';
import { assetGetFungiblePnl } from './requests/asset-get-fungible-pnl';
import { assetGetChart } from './requests/asset-get-chart';
import { searchQuery } from './requests/search-query';
import { searchQueryFungibles } from './requests/search-query-fungibles';

export interface ZerionApiContext {
getAddressProviderHeader(address: string): Promise<string>;
Expand All @@ -46,6 +47,7 @@ export const ZerionApiBare = {
walletGetAssetDetails,
assetGetChart,
searchQuery,
searchQueryFungibles,
};

export type ZerionApiClient = ZerionApiContext & typeof ZerionApiBare;
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ETH, EmptyAddressPosition } from '@zeriontech/transactions';
import type { Asset } from 'defi-sdk';
import { useAssetsPrices } from 'defi-sdk';
import React, { useCallback, useMemo, useState } from 'react';
import type { Chain } from 'src/modules/networks/Chain';
import { useNetworks } from 'src/modules/networks/useNetworks';
import { AssetSelect } from 'src/ui/pages/SendForm/AssetSelect';
import type { Props as AssetSelectProps } from 'src/ui/pages/SendForm/AssetSelect';
import { useAssetsInfoPaginatedQuery } from 'src/ui/shared/requests/useAssetsInfoPaginated';
import { UIText } from 'src/ui/ui-kit/UIText';
import { capitalize } from 'capitalize-ts';
import { UnstyledButton } from 'src/ui/ui-kit/UnstyledButton';
Expand All @@ -14,8 +14,30 @@ import { getAssetImplementationInChain } from 'src/modules/networks/asset';
import { useCurrency } from 'src/modules/currency/useCurrency';
import { useQuery } from '@tanstack/react-query';
import type { BareAddressPosition } from 'src/shared/types/BareAddressPosition';
import { useSearchQueryFungibles } from 'src/modules/zerion-api/hooks/useSearchQueryFungibles';
import type { Fungible } from 'src/modules/zerion-api/types/Fungible';
import { getPopularTokens } from '../../../shared/getPopularTokens';

function convertFungibleToAsset(fungible: Fungible): Asset {
return {
id: fungible.id,
asset_code: fungible.id,
name: fungible.name,
symbol: fungible.symbol,
icon_url: fungible.iconUrl || null,
decimals: 18,
is_displayable: true,
is_verified: fungible.verified,
type: null,
implementations: fungible.implementations,
price: {
changed_at: 0,
relative_change_24h: fungible.meta.relativeChange1d || 0,
value: fungible.meta.price || 0,
},
};
}

export function MarketAssetSelect({
chain,
selectedItem,
Expand Down Expand Up @@ -94,57 +116,30 @@ export function MarketAssetSelect({
popularAssetCodesAreLoading,
]);

const {
items: marketAssets,
hasNextPage,
fetchNextPage,
isLoading: marketAssetsAreLoading,
isFetchingNextPage,
} = useAssetsInfoPaginatedQuery(
{
const { data: searchResults, isLoading: searchResultsAreLoading } =
useSearchQueryFungibles({
query,
currency,
search_query: query,
order_by: query ? {} : { market_cap: 'desc' },
chain: shouldQueryByChain ? chain.toString() : null,
},
{ suspense: false }
);

const popularAssetCodeSet = useMemo(
() =>
new Set(popularPositions.map((position) => position.asset.asset_code)),
[popularPositions]
);
chain: shouldQueryByChain ? chain.toString() : undefined,
limit: 15,
});

const marketPositions = useMemo(() => {
if (marketAssets) {
return marketAssets
.filter(
(item): item is Exclude<typeof item, null> =>
!popularAssetCodeSet.has(item.asset.asset_code)
)
.map(
(item) =>
positionsMap.get(item.asset.id) ||
new EmptyAddressPosition({ asset: item.asset, chain })
);
const searchPositions = useMemo(() => {
if (searchResults) {
return searchResults.data.map(
(item) =>
positionsMap.get(item.id) ||
new EmptyAddressPosition({
asset: convertFungibleToAsset(item),
chain,
})
);
} else {
return [];
}
}, [chain, marketAssets, popularAssetCodeSet, positionsMap]);
}, [chain, searchResults, positionsMap]);

const items = useMemo(
() => [...popularPositions, ...marketPositions],
[popularPositions, marketPositions]
);
const getGroupName = useCallback(
(position: BareAddressPosition) => {
return popularAssetCodeSet.has(position.asset.asset_code)
? 'Popular'
: 'Others';
},
[popularAssetCodeSet]
);
const items = query ? searchPositions : popularPositions;

const currentItem = selectedItem || savedSelectedItem;
if (!currentItem) {
Expand Down Expand Up @@ -179,12 +174,6 @@ export function MarketAssetSelect({
}}
chain={chain}
selectedItem={currentItem}
getGroupName={query ? undefined : getGroupName}
pagination={{
fetchMore: fetchNextPage,
hasMore: Boolean(hasNextPage),
isLoading: marketAssetsAreLoading || isFetchingNextPage,
}}
noItemsMessage="No assets found"
dialogTitle="Receive"
renderListTitle={() =>
Expand All @@ -207,7 +196,7 @@ export function MarketAssetSelect({
}
onQueryDidChange={handleQueryDidChange}
onClosed={() => setSearchAllNetworks(false)}
isLoading={isLoading}
isLoading={isLoading || searchResultsAreLoading}
/>
);
}
48 changes: 0 additions & 48 deletions src/ui/shared/requests/useAssetsInfoPaginated.ts

This file was deleted.