refactor: nft hooks

This commit is contained in:
kyranjamie
2023-07-25 20:41:35 +01:00
committed by kyranjamie
parent aa5d9048d4
commit 559fba678b
11 changed files with 65 additions and 85 deletions

View File

@@ -29,7 +29,7 @@ interface StacksBalanceViewerProps {
account: StacksAccount;
}
export function StacksBalanceViewer({ account }: StacksBalanceViewerProps) {
function StacksBalanceViewer({ account }: StacksBalanceViewerProps) {
const stacksFtAssetBalances = useStacksFungibleTokenAssetBalancesAnchoredWithMetadata(
account.address
);

View File

@@ -6,6 +6,7 @@ import { useQueryClient } from '@tanstack/react-query';
import { RouteUrls } from '@shared/route-urls';
import { useWalletType } from '@app/common/use-wallet-type';
import { CurrentStacksAccountLoader } from '@app/components/stacks-account-loader';
import { useConfigNftMetadataEnabled } from '@app/query/common/remote-config/remote-config.query';
import { AddCollectible } from './components/add-collectible';
@@ -44,7 +45,11 @@ export function Collectibles() {
ledger: null,
})}
{isNftMetadataEnabled ? <StacksCryptoAssets /> : null}
{isNftMetadataEnabled && (
<CurrentStacksAccountLoader>
{account => <StacksCryptoAssets account={account} />}
</CurrentStacksAccountLoader>
)}
{whenWallet({
software: (

View File

@@ -4,16 +4,17 @@ import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { parseIfValidPunycode } from '@app/common/utils';
import { useCurrentAccountNames } from '@app/query/stacks/bns/bns.hooks';
import { useStacksNonFungibleTokensMetadata } from '@app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-metadata.hooks';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
import { StacksBnsName } from './stacks-bns-name';
import { StacksNonFungibleTokens } from './stacks-non-fungible-tokens';
export function StacksCryptoAssets() {
const currentAccount = useCurrentStacksAccount();
interface StacksCryptoAssetsProps {
account: StacksAccount;
}
export function StacksCryptoAssets({ account }: StacksCryptoAssetsProps) {
const { data: names = [] } = useCurrentAccountNames();
const stacksNftsMetadataResp = useStacksNonFungibleTokensMetadata();
const stacksNftsMetadataResp = useStacksNonFungibleTokensMetadata(account);
const analytics = useAnalytics();
useEffect(() => {

View File

@@ -34,10 +34,10 @@ export function useSuggestedFirstSteps() {
const stepsStatus = useSuggestedFirstStepsStatus();
const { data: nonFungibleTokenHoldings } = useGetNonFungibleTokenHoldingsQuery(
currentAccount?.address
currentAccount?.address!
);
const firstFiveAccounts = accounts?.slice(0, 5);
const firstFiveAccounts = accounts?.slice(0, 5) ?? [];
const accountsAvailableStxBalance = useAllAccountsAvailableStxBalance(firstFiveAccounts);
const accountsNonFungibleTokenHoldings =
useAllAccountsNonFungibleTokenHoldingsTotal(firstFiveAccounts);

View File

@@ -1,12 +0,0 @@
import { FullPageLoadingSpinner } from '@app/components/loading-spinner';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
interface HomeLoaderProps {
children(data?: StacksAccount): React.JSX.Element;
}
export function HomeLoader({ children }: HomeLoaderProps) {
const currentAccount = useCurrentStacksAccount();
// if (!currentAccount) return <FullPageLoadingSpinner />;
return children(currentAccount);
}

View File

@@ -1,4 +1,3 @@
import { useDispatch } from 'react-redux';
import { Outlet, useNavigate } from 'react-router-dom';
import { RouteUrls } from '@shared/route-urls';
@@ -11,28 +10,19 @@ import { Header } from '@app/components/header';
import { InAppMessages } from '@app/features/hiro-messages/in-app-messages';
import { SuggestedFirstSteps } from '@app/features/suggested-first-steps/suggested-first-steps';
import { HomeActions } from '@app/pages/home/components/home-actions';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
import { keyActions } from '@app/store/keys/key.actions';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { CurrentAccount } from './components/account-area';
import { HomeTabs } from './components/home-tabs';
import { HomeLayout } from './components/home.layout';
import { HomeLoader } from './home.loader';
export function Home() {
return <HomeLoader>{account => <HomeContainer account={account} />}</HomeLoader>;
}
interface HomeContainerProps {
account: StacksAccount;
}
function HomeContainer({ account }: HomeContainerProps) {
const { decodedAuthRequest } = useOnboardingState();
const stacksAccount = useCurrentStacksAccount();
const navigate = useNavigate();
useTrackFirstDeposit();
const dispatch = useDispatch();
useRouteHeader(
<>
<InAppMessages />
@@ -51,8 +41,7 @@ function HomeContainer({ account }: HomeContainerProps) {
actions={<HomeActions />}
>
<HomeTabs>
<button onClick={() => dispatch(keyActions.debugKillStacks())}>kill stacks</button>
<Outlet context={{ address: account?.address }} />
<Outlet context={{ address: stacksAccount?.address }} />
</HomeTabs>
</HomeLayout>
);

View File

@@ -2,42 +2,19 @@ import { useMemo } from 'react';
import BigNumber from 'bignumber.js';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
import {
useGetNonFungibleTokenHoldingsListQuery,
useGetNonFungibleTokenHoldingsQuery,
} from './non-fungible-token-holdings.query';
import { useGetNonFungibleTokenHoldingsListQuery } from './non-fungible-token-holdings.query';
export function useAllAccountsNonFungibleTokenHoldingsTotal(accounts?: StacksAccount[]) {
export function useAllAccountsNonFungibleTokenHoldingsTotal(accounts: StacksAccount[]) {
const accountsNftHoldings = useGetNonFungibleTokenHoldingsListQuery(accounts);
return useMemo(
() =>
accountsNftHoldings.reduce((acc, nftHoldings) => {
return acc.plus(nftHoldings.data?.total || 0);
}, new BigNumber(0)),
accountsNftHoldings.reduce(
(acc, nftHoldings) => acc.plus(nftHoldings.data?.total || 0),
new BigNumber(0)
),
[accountsNftHoldings]
);
}
interface NonFungibleTokenHoldingListResult {
asset_identifier: string;
value: {
hex: string;
repr: string;
};
block_height: number;
tx_id: string;
}
// export function useAccountNonFungibleTokenHoldings() {
// const currentAccount = useCurrentStacksAccount();
// const { data: nonFungibleTokenHoldings } = useGetNonFungibleTokenHoldingsQuery(
// currentAccount?.address
// );
// return (nonFungibleTokenHoldings?.results as NonFungibleTokenHoldingListResult[]) ?? [];
// }

View File

@@ -1,5 +1,7 @@
import { useQueries, useQuery } from '@tanstack/react-query';
import { Paginated } from '@shared/models/api-types';
import { AppUseQueryConfig } from '@app/query/query-config';
import { StacksClient } from '@app/query/stacks/stacks-client';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
@@ -10,36 +12,42 @@ import { RateLimiter, useHiroApiRateLimiter } from '../../rate-limiter';
const staleTime = 15 * 60 * 1000; // 15 min
const queryOptions = {
cacheTime: staleTime,
staleTime,
} as const;
interface NonFungibleTokenHoldingListResult {
asset_identifier: string;
value: {
hex: string;
repr: string;
};
block_height: number;
tx_id: string;
}
const queryOptions = { cacheTime: staleTime, staleTime } as const;
type FetchNonFungibleTokenHoldingsResp = Paginated<NonFungibleTokenHoldingListResult[]>;
function fetchNonFungibleTokenHoldings(client: StacksClient, limiter: RateLimiter) {
return async (address?: string) => {
return async (address: string) => {
if (!address) return;
await limiter.removeTokens(1);
return client.nonFungibleTokensApi.getNftHoldings({
principal: address,
limit: 50,
});
}) as unknown as Promise<FetchNonFungibleTokenHoldingsResp>;
};
}
type FetchNonFungibleTokenHoldingsResp = Awaited<
ReturnType<ReturnType<typeof fetchNonFungibleTokenHoldings>>
>;
export function useGetNonFungibleTokenHoldingsQuery<
T extends unknown = FetchNonFungibleTokenHoldingsResp
>(address?: string, options?: AppUseQueryConfig<FetchNonFungibleTokenHoldingsResp, T>) {
>(address: string, options?: AppUseQueryConfig<FetchNonFungibleTokenHoldingsResp, T>) {
const client = useStacksClientUnanchored();
const network = useCurrentNetworkState();
const limiter = useHiroApiRateLimiter();
return useQuery({
enabled: !!address,
queryKey: ['get-nft-holdings', address, network.chain.stacks.url],
queryFn: () => fetchNonFungibleTokenHoldings(client, limiter)(address),
queryFn: () => fetchNonFungibleTokenHoldings(client, limiter)(address) as any,
...queryOptions,
...options,
});
@@ -47,15 +55,15 @@ export function useGetNonFungibleTokenHoldingsQuery<
export function useGetNonFungibleTokenHoldingsListQuery<
T extends unknown = FetchNonFungibleTokenHoldingsResp
>(accounts?: StacksAccount[], options?: AppUseQueryConfig<FetchNonFungibleTokenHoldingsResp, T>) {
>(accounts: StacksAccount[], options?: AppUseQueryConfig<FetchNonFungibleTokenHoldingsResp, T>) {
const client = useStacksClientUnanchored();
const network = useCurrentNetworkState();
const limiter = useHiroApiRateLimiter();
return useQueries({
queries: (accounts ?? []).map(account => ({
queries: accounts.map(account => ({
queryKey: ['get-nft-holdings', account.address, network.chain.stacks.url],
queryFn: () => fetchNonFungibleTokenHoldings(client, limiter)(account.address),
queryFn: () => fetchNonFungibleTokenHoldings(client, limiter)(account.address) as any,
...queryOptions,
...options,
})),

View File

@@ -1,10 +1,12 @@
import { useMemo } from 'react';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
import { isNftAsset } from '../token-metadata.utils';
import { useGetNonFungibleTokenMetadataListQuery } from './non-fungible-token-metadata.query';
export function useStacksNonFungibleTokensMetadata() {
const respList = useGetNonFungibleTokenMetadataListQuery();
export function useStacksNonFungibleTokensMetadata(account: StacksAccount) {
const respList = useGetNonFungibleTokenMetadataListQuery(account);
return useMemo(
() =>

View File

@@ -3,11 +3,13 @@ import { UseQueryResult, useQueries } from '@tanstack/react-query';
import { pullContractIdFromIdentity } from '@app/common/utils';
import { QueryPrefixes } from '@app/query/query-prefixes';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
import { useTokenMetadataClient } from '@app/store/common/api-clients.hooks';
import { RateLimiter, useHiroApiRateLimiter } from '../../rate-limiter';
import { TokenMetadataClient } from '../../token-metadata-client';
import { NftAssetResponse } from '../token-metadata.utils';
import { useGetNonFungibleTokenHoldingsQuery } from './non-fungible-token-holdings.query';
const queryOptions = {
refetchOnWindowFocus: true,
@@ -27,13 +29,15 @@ function fetchNonFungibleTokenMetadata(client: TokenMetadataClient, limiter: Rat
};
}
export function useGetNonFungibleTokenMetadataListQuery(): UseQueryResult<NftAssetResponse>[] {
export function useGetNonFungibleTokenMetadataListQuery(
account: StacksAccount
): UseQueryResult<NftAssetResponse>[] {
const client = useTokenMetadataClient();
const limiter = useHiroApiRateLimiter();
const nftHoldings = useAccountNonFungibleTokenHoldings();
const nftHoldings = useGetNonFungibleTokenHoldingsQuery(account.address);
return useQueries({
queries: nftHoldings.map(nft => {
queries: (nftHoldings.data?.results ?? []).map(nft => {
const principal = pullContractIdFromIdentity(nft.asset_identifier);
const tokenId = getTokenId(nft.value.hex);

View File

@@ -0,0 +1,6 @@
export interface Paginated<T> {
limit: number;
offset: number;
total: number;
results: T;
}