diff --git a/src/app/features/balances-list/balances-list.tsx b/src/app/features/balances-list/balances-list.tsx index 810c02aa..c57aea1b 100644 --- a/src/app/features/balances-list/balances-list.tsx +++ b/src/app/features/balances-list/balances-list.tsx @@ -29,7 +29,7 @@ interface StacksBalanceViewerProps { account: StacksAccount; } -export function StacksBalanceViewer({ account }: StacksBalanceViewerProps) { +function StacksBalanceViewer({ account }: StacksBalanceViewerProps) { const stacksFtAssetBalances = useStacksFungibleTokenAssetBalancesAnchoredWithMetadata( account.address ); diff --git a/src/app/features/collectibles/collectibles.tsx b/src/app/features/collectibles/collectibles.tsx index 90ed2a4a..0dcbac12 100644 --- a/src/app/features/collectibles/collectibles.tsx +++ b/src/app/features/collectibles/collectibles.tsx @@ -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 ? : null} + {isNftMetadataEnabled && ( + + {account => } + + )} {whenWallet({ software: ( diff --git a/src/app/features/collectibles/components/stacks/stacks-crypto-assets.tsx b/src/app/features/collectibles/components/stacks/stacks-crypto-assets.tsx index 9eca46ed..77dab151 100644 --- a/src/app/features/collectibles/components/stacks/stacks-crypto-assets.tsx +++ b/src/app/features/collectibles/components/stacks/stacks-crypto-assets.tsx @@ -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(() => { diff --git a/src/app/features/suggested-first-steps/hooks/use-suggested-first-steps.ts b/src/app/features/suggested-first-steps/hooks/use-suggested-first-steps.ts index ff09ec14..e8ed9679 100644 --- a/src/app/features/suggested-first-steps/hooks/use-suggested-first-steps.ts +++ b/src/app/features/suggested-first-steps/hooks/use-suggested-first-steps.ts @@ -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); diff --git a/src/app/pages/home/home.loader.tsx b/src/app/pages/home/home.loader.tsx deleted file mode 100644 index 85c132db..00000000 --- a/src/app/pages/home/home.loader.tsx +++ /dev/null @@ -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 ; - return children(currentAccount); -} diff --git a/src/app/pages/home/home.tsx b/src/app/pages/home/home.tsx index 087f141c..6e7a64f7 100644 --- a/src/app/pages/home/home.tsx +++ b/src/app/pages/home/home.tsx @@ -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 {account => }; -} - -interface HomeContainerProps { - account: StacksAccount; -} -function HomeContainer({ account }: HomeContainerProps) { const { decodedAuthRequest } = useOnboardingState(); + + const stacksAccount = useCurrentStacksAccount(); const navigate = useNavigate(); useTrackFirstDeposit(); - const dispatch = useDispatch(); - useRouteHeader( <> @@ -51,8 +41,7 @@ function HomeContainer({ account }: HomeContainerProps) { actions={} > - - + ); diff --git a/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-holdings.hooks.ts b/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-holdings.hooks.ts index 511e46fb..ec050fe9 100644 --- a/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-holdings.hooks.ts +++ b/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-holdings.hooks.ts @@ -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[]) ?? []; -// } diff --git a/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-holdings.query.ts b/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-holdings.query.ts index 56e7363a..30cacb8d 100644 --- a/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-holdings.query.ts +++ b/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-holdings.query.ts @@ -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; 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; }; } -type FetchNonFungibleTokenHoldingsResp = Awaited< - ReturnType> ->; - export function useGetNonFungibleTokenHoldingsQuery< T extends unknown = FetchNonFungibleTokenHoldingsResp ->(address?: string, options?: AppUseQueryConfig) { +>(address: string, options?: AppUseQueryConfig) { 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) { +>(accounts: StacksAccount[], options?: AppUseQueryConfig) { 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, })), diff --git a/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-metadata.hooks.ts b/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-metadata.hooks.ts index 6e4c20d6..694755de 100644 --- a/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-metadata.hooks.ts +++ b/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-metadata.hooks.ts @@ -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( () => diff --git a/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-metadata.query.ts b/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-metadata.query.ts index 5bdcd233..5246d032 100644 --- a/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-metadata.query.ts +++ b/src/app/query/stacks/tokens/non-fungible-tokens/non-fungible-token-metadata.query.ts @@ -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[] { +export function useGetNonFungibleTokenMetadataListQuery( + account: StacksAccount +): UseQueryResult[] { 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); diff --git a/src/shared/models/api-types.ts b/src/shared/models/api-types.ts new file mode 100644 index 00000000..d01ea2e5 --- /dev/null +++ b/src/shared/models/api-types.ts @@ -0,0 +1,6 @@ +export interface Paginated { + limit: number; + offset: number; + total: number; + results: T; +}