From 5bef2462bbf45476962a5b6a535a7d5edd274b66 Mon Sep 17 00:00:00 2001 From: Matthew Wall Date: Wed, 31 Jul 2024 15:30:30 -0400 Subject: [PATCH 01/10] start work on implementing nftsV2 --- .../RecyclerAssetList2/NFTEmptyState.tsx | 0 .../RecyclerAssetList2/NFTLoadingSkeleton.tsx | 16 ++++ .../WrappedCollectiblesHeader.tsx | 25 +++--- .../RecyclerAssetList2/core/RowRenderer.tsx | 4 + .../core/ViewDimensions.tsx | 12 ++- .../RecyclerAssetList2/core/ViewTypes.ts | 2 + .../core/getLayoutProvider.tsx | 1 - .../core/useMemoBriefSectionData.ts | 8 +- src/components/list/ListHeaderMenu.tsx | 4 +- src/graphql/queries/arc.graphql | 15 +++- src/helpers/assets.ts | 88 ++++++++----------- src/helpers/buildWalletSections.tsx | 8 +- src/hooks/useNFTsSortBy.ts | 15 ++-- src/hooks/useWalletSectionsData.ts | 7 +- src/languages/en_US.json | 3 + src/resources/nfts/index.ts | 16 ++-- 16 files changed, 130 insertions(+), 94 deletions(-) create mode 100644 src/components/asset-list/RecyclerAssetList2/NFTEmptyState.tsx create mode 100644 src/components/asset-list/RecyclerAssetList2/NFTLoadingSkeleton.tsx diff --git a/src/components/asset-list/RecyclerAssetList2/NFTEmptyState.tsx b/src/components/asset-list/RecyclerAssetList2/NFTEmptyState.tsx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/components/asset-list/RecyclerAssetList2/NFTLoadingSkeleton.tsx b/src/components/asset-list/RecyclerAssetList2/NFTLoadingSkeleton.tsx new file mode 100644 index 00000000000..f351a0cacb1 --- /dev/null +++ b/src/components/asset-list/RecyclerAssetList2/NFTLoadingSkeleton.tsx @@ -0,0 +1,16 @@ +import React, { PropsWithChildren } from 'react'; +import { AssetListItemSkeleton } from '@/components/asset-list'; +import { Column } from '@/components/layout'; +import { times } from '@/helpers/utilities'; + +const NFTLoadingSkeleton = ({ items = 5 }) => ( + + + {times(items, index => ( + + ))} + + +); + +export default LoadingState; diff --git a/src/components/asset-list/RecyclerAssetList2/WrappedCollectiblesHeader.tsx b/src/components/asset-list/RecyclerAssetList2/WrappedCollectiblesHeader.tsx index 3ea62e41da6..bb233041e82 100644 --- a/src/components/asset-list/RecyclerAssetList2/WrappedCollectiblesHeader.tsx +++ b/src/components/asset-list/RecyclerAssetList2/WrappedCollectiblesHeader.tsx @@ -2,32 +2,31 @@ import React from 'react'; import { Box, Inline, Text } from '@/design-system'; import * as i18n from '@/languages'; import { ListHeaderMenu } from '@/components/list/ListHeaderMenu'; -import useNftSort, { CollectibleSortByOptions } from '@/hooks/useNFTsSortBy'; +import { NftCollectionSortCriterion } from '@/graphql/__generated__/arc'; +import useNftSort from '@/hooks/useNFTsSortBy'; const TokenFamilyHeaderHeight = 48; -const getIconForSortType = (selected: string) => { +const getIconForSortType = (selected: NftCollectionSortCriterion) => { switch (selected) { - case CollectibleSortByOptions.ABC: + case NftCollectionSortCriterion.Abc: return '􀋲'; - case CollectibleSortByOptions.FLOOR_PRICE: + case NftCollectionSortCriterion.FloorPrice: return '􀅺'; - case CollectibleSortByOptions.MOST_RECENT: + case NftCollectionSortCriterion.MostRecent: return '􀐫'; } - return ''; }; -const getMenuItemIcon = (value: CollectibleSortByOptions) => { +const getMenuItemIcon = (value: NftCollectionSortCriterion) => { switch (value) { - case CollectibleSortByOptions.ABC: + case NftCollectionSortCriterion.Abc: return 'list.bullet'; - case CollectibleSortByOptions.FLOOR_PRICE: + case NftCollectionSortCriterion.FloorPrice: return 'plus.forwardslash.minus'; - case CollectibleSortByOptions.MOST_RECENT: + case NftCollectionSortCriterion.MostRecent: return 'clock'; } - return ''; }; const CollectiblesHeader = () => { @@ -48,13 +47,13 @@ const CollectiblesHeader = () => { ({ + menuItems={Object.entries(NftCollectionSortCriterion).map(([key, value]) => ({ actionKey: value, actionTitle: i18n.t(i18n.l.nfts.sort[value]), icon: { iconType: 'SYSTEM', iconValue: getMenuItemIcon(value) }, menuState: nftSort === key ? 'on' : 'off', }))} - selectItem={string => updateNFTSort(string as CollectibleSortByOptions)} + selectItem={string => updateNFTSort(string as NftCollectionSortCriterion)} icon={getIconForSortType(nftSort)} text={i18n.t(i18n.l.nfts.sort[nftSort])} /> diff --git a/src/components/asset-list/RecyclerAssetList2/core/RowRenderer.tsx b/src/components/asset-list/RecyclerAssetList2/core/RowRenderer.tsx index 853fbe1cd9c..74909bc489d 100644 --- a/src/components/asset-list/RecyclerAssetList2/core/RowRenderer.tsx +++ b/src/components/asset-list/RecyclerAssetList2/core/RowRenderer.tsx @@ -123,6 +123,10 @@ function rowRenderer(type: CellType, { uid }: { uid: string }, _: unknown, exten ); case CellType.NFTS_HEADER: return ; + case CellType.NFTS_LOADING: + return ; + case CellType.NFTS_EMPTY: + return ; case CellType.FAMILY_HEADER: { const { name, image, total } = data as NFTFamilyExtraData; return ( diff --git a/src/components/asset-list/RecyclerAssetList2/core/ViewDimensions.tsx b/src/components/asset-list/RecyclerAssetList2/core/ViewDimensions.tsx index 2281de9c32e..5ed9e7af004 100644 --- a/src/components/asset-list/RecyclerAssetList2/core/ViewDimensions.tsx +++ b/src/components/asset-list/RecyclerAssetList2/core/ViewDimensions.tsx @@ -52,7 +52,17 @@ const ViewDimensions: Record = { [CellType.FAMILY_HEADER]: { height: TokenFamilyHeaderHeight }, [CellType.NFT]: { // @ts-expect-error - height: UniqueTokenRow.cardSize + UniqueTokenRow.cardMargin, + height: UniqueTokenRow.height, + width: deviceUtils.dimensions.width / 2 - 0.1, + }, + [CellType.NFT_LOADING]: { + // @ts-expect-error + height: UniqueTokenRow.height * 5, + width: deviceUtils.dimensions.width / 2 - 0.1, + }, + [CellType.NFT_EMPTY]: { + // @ts-expect-error + height: UniqueTokenRow.height * 5, width: deviceUtils.dimensions.width / 2 - 0.1, }, [CellType.NFT_SPACE_AFTER]: { height: 5 }, diff --git a/src/components/asset-list/RecyclerAssetList2/core/ViewTypes.ts b/src/components/asset-list/RecyclerAssetList2/core/ViewTypes.ts index 697d5aca3ca..79f53a21314 100644 --- a/src/components/asset-list/RecyclerAssetList2/core/ViewTypes.ts +++ b/src/components/asset-list/RecyclerAssetList2/core/ViewTypes.ts @@ -17,6 +17,8 @@ export enum CellType { PROFILE_NAME_ROW_SPACE_AFTER = 'PROFILE_NAME_ROW_SPACE_AFTER', PROFILE_STICKY_HEADER = 'PROFILE_STICKY_HEADER', NFTS_HEADER = 'NFTS_HEADER', + NFTS_LOADING = 'NFTS_LOADING', + NFTS_EMPTY = 'NFTS_EMPTY', NFTS_HEADER_SPACE_BEFORE = 'NFTS_HEADER_SPACE_BEFORE', NFTS_HEADER_SPACE_AFTER = 'NFTS_HEADER_SPACE_AFTER', FAMILY_HEADER = 'FAMILY_HEADER', diff --git a/src/components/asset-list/RecyclerAssetList2/core/getLayoutProvider.tsx b/src/components/asset-list/RecyclerAssetList2/core/getLayoutProvider.tsx index 82c89dd7dfe..13619bef984 100644 --- a/src/components/asset-list/RecyclerAssetList2/core/getLayoutProvider.tsx +++ b/src/components/asset-list/RecyclerAssetList2/core/getLayoutProvider.tsx @@ -2,7 +2,6 @@ import { Dimension, Layout, LayoutManager, LayoutProvider } from 'recyclerlistvi import ViewDimensions from './ViewDimensions'; import { BaseCellType, CellType } from './ViewTypes'; import { deviceUtils } from '@/utils'; -import { TrimmedCard } from '@/resources/cards/cardCollectionQuery'; const getStyleOverridesForIndex = (indices: number[]) => (index: number) => { if (indices.includes(index)) { diff --git a/src/components/asset-list/RecyclerAssetList2/core/useMemoBriefSectionData.ts b/src/components/asset-list/RecyclerAssetList2/core/useMemoBriefSectionData.ts index e3285e63fe6..e5e4cce678a 100644 --- a/src/components/asset-list/RecyclerAssetList2/core/useMemoBriefSectionData.ts +++ b/src/components/asset-list/RecyclerAssetList2/core/useMemoBriefSectionData.ts @@ -73,10 +73,10 @@ export default function useMemoBriefSectionData({ return false; } - // removes NFTS_HEADER if wallet doesn't have NFTs - if (data.type === CellType.NFTS_HEADER && !arr[arrIndex + 2]) { - return false; - } + // // removes NFTS_HEADER if wallet doesn't have NFTs + // if (data.type === CellType.NFTS_HEADER && !arr[arrIndex + 2]) { + // return false; + // } if (data.type === CellType.PROFILE_STICKY_HEADER) { stickyHeaders.push(index); diff --git a/src/components/list/ListHeaderMenu.tsx b/src/components/list/ListHeaderMenu.tsx index 289498f1432..f39df68a365 100644 --- a/src/components/list/ListHeaderMenu.tsx +++ b/src/components/list/ListHeaderMenu.tsx @@ -3,7 +3,7 @@ import ContextMenuButton from '@/components/native-context-menu/contextMenu'; import { ButtonPressAnimation } from '@/components/animations'; import { Bleed, Box, Inline, Text, useForegroundColor } from '@/design-system'; import { haptics } from '@/utils'; -import { CollectibleSortByOptions } from '@/hooks/useNFTsSortBy'; +import { NftCollectionSortCriterion } from '@/graphql/__generated__/arc'; type MenuItem = { actionKey: string; @@ -12,7 +12,7 @@ type MenuItem = { }; type ListHeaderMenuProps = { - selected: CollectibleSortByOptions; + selected: NftCollectionSortCriterion; menuItems: MenuItem[]; selectItem: (item: string) => void; icon: string; diff --git a/src/graphql/queries/arc.graphql b/src/graphql/queries/arc.graphql index 24c89874153..3cc55e9ba9c 100644 --- a/src/graphql/queries/arc.graphql +++ b/src/graphql/queries/arc.graphql @@ -298,8 +298,19 @@ fragment simpleHashPaymentToken on SimpleHashPaymentToken { decimals } -query getNFTs($walletAddress: String!) { - nfts(walletAddress: $walletAddress) { +enum NFTCollectionSortCriterion { + MOST_RECENT + ABC + FLOOR_PRICE +} + +enum SortDirection { + ASC + DESC +} + +query getNFTs($walletAddress: String!, $sortBy: NFTCollectionSortCriterion, $sortDirection: SortDirection) { + nftsV2(walletAddress: $walletAddress, sortBy: $sortBy, sortDirection: $sortDirection) { nft_id chain contract_address diff --git a/src/helpers/assets.ts b/src/helpers/assets.ts index 847e9d2f912..836eee3cc1b 100644 --- a/src/helpers/assets.ts +++ b/src/helpers/assets.ts @@ -5,9 +5,8 @@ import { AssetListType } from '@/components/asset-list/RecyclerAssetList2'; import { supportedNativeCurrencies } from '@/references'; import { getUniqueTokenFormat, getUniqueTokenType } from '@/utils'; import * as i18n from '@/languages'; -import * as ls from '@/storage'; import { UniqueAsset } from '@/entities'; -import { CollectibleSortByOptions } from '@/hooks/useNFTsSortBy'; +import { NftCollectionSortCriterion } from '@/graphql/__generated__/arc'; const COINS_TO_SHOW = 5; @@ -235,39 +234,15 @@ export const buildUniqueTokenList = (uniqueTokens: any, selectedShowcaseTokens: return rows; }; -const regex = RegExp(/\s*(the)\s/, 'i'); - -const sortCollectibles = (assetsByName: Dictionary, collectibleSortBy: string) => { - const families = Object.keys(assetsByName); - - switch (collectibleSortBy) { - case CollectibleSortByOptions.MOST_RECENT: - return families.sort((a, b) => { - const maxDateA = Math.max(Number(...assetsByName[a].map(asset => asset.acquisition_date))); - const maxDateB = Math.max(Number(...assetsByName[b].map(asset => asset.acquisition_date))); - return maxDateB - maxDateA; - }); - case CollectibleSortByOptions.ABC: - return families.sort((a, b) => a.replace(regex, '').toLowerCase().localeCompare(b.replace(regex, '').toLowerCase())); - case CollectibleSortByOptions.FLOOR_PRICE: - return families.sort((a, b) => { - const minPriceA = Math.min(...assetsByName[a].map(asset => (asset.floorPriceEth !== undefined ? asset.floorPriceEth : -1))); - const minPriceB = Math.min(...assetsByName[b].map(asset => (asset.floorPriceEth !== undefined ? asset.floorPriceEth : -1))); - return minPriceB - minPriceA; - }); - default: - return families; - } -}; - export const buildBriefUniqueTokenList = ( - uniqueTokens: any, + uniqueTokens: UniqueAsset[], selectedShowcaseTokens: any, sellingTokens: any[] = [], hiddenTokens: string[] = [], listType: AssetListType = 'wallet', isReadOnlyWallet = false, - nftSort: string = CollectibleSortByOptions.MOST_RECENT + nftSort: string, + isFetchingNfts: boolean ) => { const hiddenUniqueTokensIds = uniqueTokens .filter(({ fullUniqueId }: any) => hiddenTokens.includes(fullUniqueId)) @@ -277,7 +252,7 @@ export const buildBriefUniqueTokenList = ( .filter(({ uniqueId }: any) => selectedShowcaseTokens?.includes(uniqueId)) .map(({ uniqueId }: any) => uniqueId); - const filteredUniqueTokens = nonHiddenUniqueTokens.filter((token: any) => { + const filteredUniqueTokens = nonHiddenUniqueTokens.filter((token: UniqueAsset) => { if (listType === 'select-nft') { const format = getUniqueTokenFormat(token); const type = getUniqueTokenType(token); @@ -287,10 +262,7 @@ export const buildBriefUniqueTokenList = ( }); // group the assets by collection name - const assetsByName = groupBy(filteredUniqueTokens, token => token.familyName); - - // depending on the sort by option, sort the collections - const families2 = sortCollectibles(assetsByName, nftSort); + const assetsByName = groupBy(filteredUniqueTokens, token => token.familyName); const result = [ { @@ -342,25 +314,38 @@ export const buildBriefUniqueTokenList = ( } result.push({ type: 'NFT_SPACE_AFTER', uid: `showcase-space-after` }); } - for (const family of families2) { - result.push({ - // @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. - image: assetsByName[family][0].familyImage, - name: family, - total: assetsByName[family].length, - type: 'FAMILY_HEADER', - uid: family, - }); - const tokens = assetsByName[family].map(({ uniqueId }) => uniqueId); - for (let index = 0; index < tokens.length; index++) { - const uniqueId = tokens[index]; - // @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. - result.push({ index, type: 'NFT', uid: uniqueId, uniqueId }); + if (!Object.keys(assetsByName).length) { + if (!isFetchingNfts) { + // empty NFT section + result.push({ type: 'NFT_EMPTY', uid: `nft-empty`}); + } else { + // loading NFTs section (most likely from a sortBy change) but initial load too + result.push({ type: 'NFT_LOADING', uid: `nft-loading-${nftSort}`}); + } + } else { + for (const family of Object.keys(assetsByName)) { + result.push({ + // @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. + image: assetsByName[family][0].familyImage, + name: family, + total: assetsByName[family].length, + type: 'FAMILY_HEADER', + uid: family, + }); + const tokens = assetsByName[family].map(({ uniqueId }) => uniqueId); + for (let index = 0; index < tokens.length; index++) { + const uniqueId = tokens[index]; + + // @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. + result.push({ index, type: 'NFT', uid: uniqueId, uniqueId }); + } + + result.push({ type: 'NFT_SPACE_AFTER', uid: `${family}-space-after` }); } - - result.push({ type: 'NFT_SPACE_AFTER', uid: `${family}-space-after` }); } + + if (hiddenUniqueTokensIds.length > 0 && listType === 'wallet' && !isReadOnlyWallet) { result.push({ // @ts-expect-error "name" does not exist in type. @@ -382,6 +367,9 @@ export const buildBriefUniqueTokenList = ( result.push({ type: 'NFT_SPACE_AFTER', uid: `showcase-space-after` }); } + + console.log(result.map((r => r.type))); + return result; }; diff --git a/src/helpers/buildWalletSections.tsx b/src/helpers/buildWalletSections.tsx index 2557bf80487..e28b21ae6fe 100644 --- a/src/helpers/buildWalletSections.tsx +++ b/src/helpers/buildWalletSections.tsx @@ -49,6 +49,8 @@ const sellingTokensSelector = (state: any) => state.sellingTokens; const showcaseTokensSelector = (state: any) => state.showcaseTokens; const hiddenTokensSelector = (state: any) => state.hiddenTokens; const uniqueTokensSelector = (state: any) => state.uniqueTokens; +const nftSortSelector = (state: any) => state.nftSort; +const isFetchingNftsSelector = (state: any) => state.isFetchingNfts; const listTypeSelector = (state: any) => state.listType; const buildBriefWalletSections = (balanceSectionData: any, uniqueTokenFamiliesSection: any) => { @@ -109,8 +111,7 @@ const withBriefBalanceSection = ( isCoinListEdited: boolean, pinnedCoins: any, hiddenCoins: any, - collectibles: any, - nftSort: string + collectibles: any ) => { const { briefAssets, totalBalancesValue } = buildBriefCoinsList(sortedAssets, nativeCurrency, isCoinListEdited, pinnedCoins, hiddenCoins); @@ -217,7 +218,8 @@ const briefUniqueTokenDataSelector = createSelector( hiddenTokensSelector, listTypeSelector, isReadOnlyWalletSelector, - (state: any, nftSort: string) => nftSort, + nftSortSelector, + isFetchingNftsSelector, ], buildBriefUniqueTokenList ); diff --git a/src/hooks/useNFTsSortBy.ts b/src/hooks/useNFTsSortBy.ts index 544782ee1db..a9ce04a9018 100644 --- a/src/hooks/useNFTsSortBy.ts +++ b/src/hooks/useNFTsSortBy.ts @@ -1,29 +1,24 @@ import { useCallback } from 'react'; import { MMKV, useMMKVString } from 'react-native-mmkv'; import useAccountSettings from './useAccountSettings'; +import { NftCollectionSortCriterion } from '@/graphql/__generated__/arc'; const mmkv = new MMKV(); const getStorageKey = (accountAddress: string) => `nfts-sort-${accountAddress}`; -export enum CollectibleSortByOptions { - MOST_RECENT = 'most_recent', - ABC = 'abc', - FLOOR_PRICE = 'floor_price', -} - export const getNftSortForAddress = (accountAddress: string) => { mmkv.getString(getStorageKey(accountAddress)); }; export default function useNftSort(): { - nftSort: CollectibleSortByOptions; - updateNFTSort: (sortBy: CollectibleSortByOptions) => void; + nftSort: NftCollectionSortCriterion; + updateNFTSort: (sortBy: NftCollectionSortCriterion) => void; } { const { accountAddress } = useAccountSettings(); const [nftSort, setNftSort] = useMMKVString(getStorageKey(accountAddress)); const updateNFTSort = useCallback( - (sortBy: CollectibleSortByOptions) => { + (sortBy: NftCollectionSortCriterion) => { setNftSort(sortBy); }, [setNftSort] @@ -31,6 +26,6 @@ export default function useNftSort(): { return { updateNFTSort, - nftSort: (nftSort as CollectibleSortByOptions) || CollectibleSortByOptions.MOST_RECENT, + nftSort: (nftSort as NftCollectionSortCriterion) || NftCollectionSortCriterion.MostRecent, }; } diff --git a/src/hooks/useWalletSectionsData.ts b/src/hooks/useWalletSectionsData.ts index 9b2b60c9c4c..a12d3c420bb 100644 --- a/src/hooks/useWalletSectionsData.ts +++ b/src/hooks/useWalletSectionsData.ts @@ -20,12 +20,16 @@ export default function useWalletSectionsData({ const { isLoading: isLoadingUserAssets, data: sortedAssets = [] } = useSortedUserAssets(); const isWalletEthZero = useIsWalletEthZero(); + const { nftSort } = useNftSort(); + const { accountAddress, language, network, nativeCurrency } = useAccountSettings(); const { sendableUniqueTokens } = useSendableUniqueTokens(); const { data: { nfts: allUniqueTokens }, + isFetching: isFetchingNfts, } = useLegacyNFTs({ address: accountAddress, + sortBy: nftSort }); const { showcaseTokens } = useShowcaseTokens(); const { hiddenTokens } = useHiddenTokens(); @@ -35,8 +39,6 @@ export default function useWalletSectionsData({ const { isCoinListEdited } = useCoinListEdited(); - const { nftSort } = useNftSort(); - const walletSections = useMemo(() => { const accountInfo = { hiddenCoins, @@ -55,6 +57,7 @@ export default function useWalletSectionsData({ listType: type, showcaseTokens, uniqueTokens: allUniqueTokens, + isFetchingNfts, nftSort, }; diff --git a/src/languages/en_US.json b/src/languages/en_US.json index f9a5648332d..ff48be3fb3e 100644 --- a/src/languages/en_US.json +++ b/src/languages/en_US.json @@ -1315,8 +1315,11 @@ "nfts": { "selling": "Selling", "sort": { + "ABC": "Alphabetical", "abc": "Alphabetical", + "MOST_RECENT": "Recent", "most_recent": "Recent", + "FLOOR_PRICE": "Floor Price", "floor_price": "Floor Price" } }, diff --git a/src/resources/nfts/index.ts b/src/resources/nfts/index.ts index d7b1c88c198..e642449d67c 100644 --- a/src/resources/nfts/index.ts +++ b/src/resources/nfts/index.ts @@ -9,12 +9,13 @@ import { Network } from '@/helpers'; import { UniqueAsset } from '@/entities'; import { arcClient } from '@/graphql'; import { createSelector } from 'reselect'; +import { NftCollectionSortCriterion } from '@/graphql/__generated__/arc'; const NFTS_STALE_TIME = 600000; // 10 minutes const NFTS_CACHE_TIME_EXTERNAL = 3600000; // 1 hour const NFTS_CACHE_TIME_INTERNAL = 604800000; // 1 week -export const nftsQueryKey = ({ address }: { address: string }) => createQueryKey('nfts', { address }, { persisterVersion: 3 }); +export const nftsQueryKey = ({ address, sortBy }: { address: string; sortBy: NftCollectionSortCriterion }) => createQueryKey('nfts', { address, sortBy }, { persisterVersion: 4 }); export const nftListingQueryKey = ({ contractAddress, @@ -52,10 +53,10 @@ interface NFTData { type NFTQueryKey = ReturnType; const fetchNFTData: QueryFunction = async ({ queryKey }) => { - const [{ address }] = queryKey; - const queryResponse = await arcClient.getNFTs({ walletAddress: address }); + const [{ address, sortBy }] = queryKey; + const queryResponse = await arcClient.getNFTs({ walletAddress: address, sortBy }); - const nfts = queryResponse?.nfts?.map(nft => simpleHashNFTToUniqueAsset(nft, address)); + const nfts = queryResponse?.nftsV2?.map(nft => simpleHashNFTToUniqueAsset(nft, address)); // ⚠️ TODO: Delete this and rework the code that uses it const nftsMap = nfts?.reduce( @@ -75,14 +76,16 @@ const FALLBACK_DATA: NFTData = { nfts: [], nftsMap: {} }; export function useLegacyNFTs({ address, + sortBy = NftCollectionSortCriterion.MostRecent, config, }: { address: string; + sortBy?: NftCollectionSortCriterion; config?: QueryConfigWithSelect; }) { const isImportedWallet = useSelector((state: AppState) => isImportedWalletSelector(state, address)); - const { data, error, isFetching } = useQuery(nftsQueryKey({ address }), fetchNFTData, { + const { data, error, isFetching, isInitialLoading } = useQuery(nftsQueryKey({ address, sortBy }), fetchNFTData, { cacheTime: isImportedWallet ? NFTS_CACHE_TIME_INTERNAL : NFTS_CACHE_TIME_EXTERNAL, enabled: !!address, retry: 3, @@ -93,7 +96,8 @@ export function useLegacyNFTs({ return { data: (config?.select ? data ?? config.select(FALLBACK_DATA) : data ?? FALLBACK_DATA) as TSelected, error, - isInitialLoading: !data && isFetching, + isFetching, + isInitialLoading }; } From e2b1e76cc89d22862b10d93b8521009616513e6f Mon Sep 17 00:00:00 2001 From: Matthew Wall Date: Wed, 31 Jul 2024 17:29:37 -0400 Subject: [PATCH 02/10] add collectibles loading state and empty state --- .../RecyclerAssetList2/NFTEmptyState.tsx | 104 +++++++++++++++ .../RecyclerAssetList2/NFTLoadingSkeleton.tsx | 122 ++++++++++++++++-- .../RecyclerAssetList2/core/RowRenderer.tsx | 4 +- .../core/ViewDimensions.tsx | 12 +- src/components/skeleton/Skeleton.tsx | 7 + src/helpers/assets.ts | 11 +- src/languages/en_US.json | 4 +- 7 files changed, 235 insertions(+), 29 deletions(-) diff --git a/src/components/asset-list/RecyclerAssetList2/NFTEmptyState.tsx b/src/components/asset-list/RecyclerAssetList2/NFTEmptyState.tsx index e69de29bb2d..f7e53687f53 100644 --- a/src/components/asset-list/RecyclerAssetList2/NFTEmptyState.tsx +++ b/src/components/asset-list/RecyclerAssetList2/NFTEmptyState.tsx @@ -0,0 +1,104 @@ +import React, { useCallback } from 'react'; +import Animated from 'react-native-reanimated'; +import { Box, Inline, Stack, Text, useColorMode } from '@/design-system'; +import * as i18n from '@/languages'; +import { TokenFamilyHeaderHeight } from './NFTLoadingSkeleton'; +import { MINTS, useExperimentalFlag } from '@/config'; +import { useRemoteConfig } from '@/model/remoteConfig'; +import { IS_TEST } from '@/env'; +import { useMints } from '@/resources/mints'; +import { useAccountSettings } from '@/hooks'; +import { GestureHandlerButton } from '@/__swaps__/screens/Swap/components/GestureHandlerButton'; +import { StyleSheet } from 'react-native'; +import { LIGHT_SEPARATOR_COLOR, SEPARATOR_COLOR } from '@/__swaps__/screens/Swap/constants'; +import { analyticsV2 } from '@/analytics'; +import { convertRawAmountToRoundedDecimal } from '@/helpers/utilities'; +import { ethereumUtils } from '@/utils'; +import { navigateToMintCollection } from '@/resources/reservoir/mints'; + +type LaunchFeaturedMintButtonProps = { + featuredMint: ReturnType['data']['featuredMint']; +}; + +const LaunchFeaturedMintButton = ({ featuredMint }: LaunchFeaturedMintButtonProps) => { + const { isDarkMode } = useColorMode(); + + const handlePress = useCallback(() => { + if (featuredMint) { + analyticsV2.track(analyticsV2.event.mintsPressedFeaturedMintCard, { + contractAddress: featuredMint.contractAddress, + chainId: featuredMint.chainId, + totalMints: featuredMint.totalMints, + mintsLastHour: featuredMint.totalMints, + priceInEth: convertRawAmountToRoundedDecimal(featuredMint.mintStatus.price, 18, 6), + }); + const network = ethereumUtils.getNetworkFromChainId(featuredMint.chainId); + navigateToMintCollection(featuredMint.contract, featuredMint.mintStatus.price, network); + } + }, [featuredMint]); + + return ( + + + + + + Collect Now + + + + + + ); +}; + +export function NFTEmptyState() { + const { mints_enabled } = useRemoteConfig(); + const { accountAddress } = useAccountSettings(); + + const { + data: { featuredMint }, + } = useMints({ walletAddress: accountAddress }); + + const mintsEnabled = (useExperimentalFlag(MINTS) || mints_enabled) && !IS_TEST; + + return ( + + + + + 🌟 + + + + {i18n.t(i18n.l.nfts.empty)} + + + + {i18n.t(i18n.l.nfts.will_appear_here)} + + + {mintsEnabled && featuredMint && } + + + + ); +} + +const styles = StyleSheet.create({ + buttonPadding: { + paddingHorizontal: 24, + paddingVertical: 12, + }, +}); diff --git a/src/components/asset-list/RecyclerAssetList2/NFTLoadingSkeleton.tsx b/src/components/asset-list/RecyclerAssetList2/NFTLoadingSkeleton.tsx index f351a0cacb1..b157718e102 100644 --- a/src/components/asset-list/RecyclerAssetList2/NFTLoadingSkeleton.tsx +++ b/src/components/asset-list/RecyclerAssetList2/NFTLoadingSkeleton.tsx @@ -1,16 +1,112 @@ -import React, { PropsWithChildren } from 'react'; -import { AssetListItemSkeleton } from '@/components/asset-list'; -import { Column } from '@/components/layout'; -import { times } from '@/helpers/utilities'; +import React from 'react'; +import { StyleSheet, View } from 'react-native'; +import { useForegroundColor } from '@/design-system'; +import { useTheme } from '@/theme'; +import { opacity } from '@/__swaps__/utils/swaps'; +import { deviceUtils } from '@/utils'; -const NFTLoadingSkeleton = ({ items = 5 }) => ( - - - {times(items, index => ( - +export const TokenFamilyHeaderHeight = 50; + +const getRandomBetween = (min: number, max: number) => { + return Math.floor(Math.random() * (max - min + 1) + min); +}; + +const NFTItem = () => { + const { colors } = useTheme(); + const labelTertiary = useForegroundColor('labelTertiary'); + + return ( + + + + + + + + + + + + ); +}; + +const NFTLoadingSkeleton = ({ items = 5 }) => { + return ( + + {[...Array(items)].map((_, index) => ( + ))} - - -); + + ); +}; + +const sx = StyleSheet.create({ + container: { + flex: 1, + width: '100%', + }, + leftContainer: { + flexDirection: 'row', + alignItems: 'center', + }, + image: { + height: 30, + width: 30, + borderRadius: 15, + marginRight: 12, + }, + textContainer: { + justifyContent: 'center', + }, + title: { + width: deviceUtils.dimensions.width / 2, + height: 12, + borderRadius: 4, + marginBottom: 4, + paddingRight: 9, + }, + rightContainer: { + flexDirection: 'row', + alignItems: 'center', + marginRight: 10, + }, + amount: { + width: 23, + height: 16, + borderRadius: 4, + }, + chevron: { + height: 18, + width: 8, + }, + content: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + height: TokenFamilyHeaderHeight, + padding: 19, + paddingRight: 14, + width: '100%', + }, +}); -export default LoadingState; +export default NFTLoadingSkeleton; diff --git a/src/components/asset-list/RecyclerAssetList2/core/RowRenderer.tsx b/src/components/asset-list/RecyclerAssetList2/core/RowRenderer.tsx index 74909bc489d..af52c427c97 100644 --- a/src/components/asset-list/RecyclerAssetList2/core/RowRenderer.tsx +++ b/src/components/asset-list/RecyclerAssetList2/core/RowRenderer.tsx @@ -29,9 +29,10 @@ import { DiscoverMoreButton } from './DiscoverMoreButton'; import { RotatingLearnCard } from '@/components/cards/RotatingLearnCard'; import WrappedPosition from '../WrappedPosition'; import WrappedPositionsListHeader from '../WrappedPositionsListHeader'; -import * as lang from '@/languages'; import { RemoteCardCarousel } from '@/components/cards/remote-cards'; import WrappedCollectiblesHeader from '../WrappedCollectiblesHeader'; +import NFTLoadingSkeleton from '../NFTLoadingSkeleton'; +import { NFTEmptyState } from '../NFTEmptyState'; function rowRenderer(type: CellType, { uid }: { uid: string }, _: unknown, extendedState: ExtendedState) { const data = extendedState.additionalData[uid]; @@ -129,6 +130,7 @@ function rowRenderer(type: CellType, { uid }: { uid: string }, _: unknown, exten return ; case CellType.FAMILY_HEADER: { const { name, image, total } = data as NFTFamilyExtraData; + return ( = { height: UniqueTokenRow.height, width: deviceUtils.dimensions.width / 2 - 0.1, }, - [CellType.NFT_LOADING]: { - // @ts-expect-error - height: UniqueTokenRow.height * 5, - width: deviceUtils.dimensions.width / 2 - 0.1, + [CellType.NFTS_LOADING]: { + height: TokenFamilyHeaderHeight * 5, }, - [CellType.NFT_EMPTY]: { - // @ts-expect-error - height: UniqueTokenRow.height * 5, - width: deviceUtils.dimensions.width / 2 - 0.1, + [CellType.NFTS_EMPTY]: { + height: TokenFamilyHeaderHeight * 5, }, [CellType.NFT_SPACE_AFTER]: { height: 5 }, [CellType.LOADING_ASSETS]: { height: AssetListItemSkeletonHeight }, diff --git a/src/components/skeleton/Skeleton.tsx b/src/components/skeleton/Skeleton.tsx index 69d39e7a1ed..628090fc8a6 100644 --- a/src/components/skeleton/Skeleton.tsx +++ b/src/components/skeleton/Skeleton.tsx @@ -24,6 +24,13 @@ export const FakeAvatar = styled.View({ borderRadius: 20, }); +// @ts-expect-error Property 'View' does not exist on type... +export const FakeNFT = styled.View({ + ...position.sizeAsObject(32), + backgroundColor: ({ theme: { colors }, color }: FakeItemProps) => color ?? colors.skeleton, + borderRadius: 16, +}); + export const FakeRow = styled(Row).attrs({ align: 'flex-end', flex: 0, diff --git a/src/helpers/assets.ts b/src/helpers/assets.ts index 836eee3cc1b..bb60bd321bc 100644 --- a/src/helpers/assets.ts +++ b/src/helpers/assets.ts @@ -318,10 +318,10 @@ export const buildBriefUniqueTokenList = ( if (!Object.keys(assetsByName).length) { if (!isFetchingNfts) { // empty NFT section - result.push({ type: 'NFT_EMPTY', uid: `nft-empty`}); + result.push({ type: 'NFTS_EMPTY', uid: `nft-empty` }); } else { // loading NFTs section (most likely from a sortBy change) but initial load too - result.push({ type: 'NFT_LOADING', uid: `nft-loading-${nftSort}`}); + result.push({ type: 'NFTS_LOADING', uid: `nft-loading-${nftSort}` }); } } else { for (const family of Object.keys(assetsByName)) { @@ -336,16 +336,15 @@ export const buildBriefUniqueTokenList = ( const tokens = assetsByName[family].map(({ uniqueId }) => uniqueId); for (let index = 0; index < tokens.length; index++) { const uniqueId = tokens[index]; - + // @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. result.push({ index, type: 'NFT', uid: uniqueId, uniqueId }); } - + result.push({ type: 'NFT_SPACE_AFTER', uid: `${family}-space-after` }); } } - if (hiddenUniqueTokensIds.length > 0 && listType === 'wallet' && !isReadOnlyWallet) { result.push({ // @ts-expect-error "name" does not exist in type. @@ -368,7 +367,7 @@ export const buildBriefUniqueTokenList = ( result.push({ type: 'NFT_SPACE_AFTER', uid: `showcase-space-after` }); } - console.log(result.map((r => r.type))); + console.log(result.map(r => r.type)); return result; }; diff --git a/src/languages/en_US.json b/src/languages/en_US.json index ff48be3fb3e..1f2631ae2d3 100644 --- a/src/languages/en_US.json +++ b/src/languages/en_US.json @@ -1321,7 +1321,9 @@ "most_recent": "Recent", "FLOOR_PRICE": "Floor Price", "floor_price": "Floor Price" - } + }, + "empty": "Collectibles", + "will_appear_here": "Your Collectibles Will Appear Here" }, "nft_offers": { "card": { From 60c56ce58aa9adb2783437433c53a6fcad6860e2 Mon Sep 17 00:00:00 2001 From: Matthew Wall Date: Wed, 31 Jul 2024 17:44:18 -0400 Subject: [PATCH 03/10] fixes --- src/helpers/assets.ts | 4 ++-- src/helpers/buildWalletSections.tsx | 2 +- src/hooks/useRefreshAccountData.ts | 4 +++- src/hooks/useWalletSectionsData.ts | 5 +++-- src/resources/nfts/index.ts | 5 +++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/helpers/assets.ts b/src/helpers/assets.ts index bb60bd321bc..041ceb3694b 100644 --- a/src/helpers/assets.ts +++ b/src/helpers/assets.ts @@ -241,8 +241,8 @@ export const buildBriefUniqueTokenList = ( hiddenTokens: string[] = [], listType: AssetListType = 'wallet', isReadOnlyWallet = false, - nftSort: string, - isFetchingNfts: boolean + nftSort = NftCollectionSortCriterion.MostRecent, + isFetchingNfts = false ) => { const hiddenUniqueTokensIds = uniqueTokens .filter(({ fullUniqueId }: any) => hiddenTokens.includes(fullUniqueId)) diff --git a/src/helpers/buildWalletSections.tsx b/src/helpers/buildWalletSections.tsx index e28b21ae6fe..dca65e280da 100644 --- a/src/helpers/buildWalletSections.tsx +++ b/src/helpers/buildWalletSections.tsx @@ -238,6 +238,6 @@ const briefBalanceSectionSelector = createSelector( ); export const buildBriefWalletSectionsSelector = createSelector( - [briefBalanceSectionSelector, (state: any, nftSort: string) => briefUniqueTokenDataSelector(state, nftSort)], + [briefBalanceSectionSelector, (state: any) => briefUniqueTokenDataSelector(state)], buildBriefWalletSections ); diff --git a/src/hooks/useRefreshAccountData.ts b/src/hooks/useRefreshAccountData.ts index 4de563b7108..1475f8b5cf3 100644 --- a/src/hooks/useRefreshAccountData.ts +++ b/src/hooks/useRefreshAccountData.ts @@ -12,18 +12,20 @@ import { queryClient } from '@/react-query'; import { userAssetsQueryKey } from '@/resources/assets/UserAssetsQuery'; import { nftsQueryKey } from '@/resources/nfts'; import { positionsQueryKey } from '@/resources/defi/PositionsQuery'; +import useNftSort from './useNFTsSortBy'; export default function useRefreshAccountData() { const dispatch = useDispatch(); const { accountAddress, nativeCurrency } = useAccountSettings(); const [isRefreshing, setIsRefreshing] = useState(false); const profilesEnabled = useExperimentalFlag(PROFILES); + const { nftSort } = useNftSort(); const fetchAccountData = useCallback(async () => { const connectedToHardhat = getIsHardhatConnected(); queryClient.invalidateQueries({ - queryKey: nftsQueryKey({ address: accountAddress }), + queryKey: nftsQueryKey({ address: accountAddress, sortBy: nftSort }), }); queryClient.invalidateQueries({ queryKey: positionsQueryKey({ diff --git a/src/hooks/useWalletSectionsData.ts b/src/hooks/useWalletSectionsData.ts index a12d3c420bb..516b06fa9e0 100644 --- a/src/hooks/useWalletSectionsData.ts +++ b/src/hooks/useWalletSectionsData.ts @@ -29,7 +29,7 @@ export default function useWalletSectionsData({ isFetching: isFetchingNfts, } = useLegacyNFTs({ address: accountAddress, - sortBy: nftSort + sortBy: nftSort, }); const { showcaseTokens } = useShowcaseTokens(); const { hiddenTokens } = useHiddenTokens(); @@ -61,7 +61,7 @@ export default function useWalletSectionsData({ nftSort, }; - const { briefSectionsData, isEmpty } = buildBriefWalletSectionsSelector(accountInfo, nftSort); + const { briefSectionsData, isEmpty } = buildBriefWalletSectionsSelector(accountInfo); const hasNFTs = allUniqueTokens.length > 0; return { @@ -87,6 +87,7 @@ export default function useWalletSectionsData({ type, showcaseTokens, allUniqueTokens, + isFetchingNfts, nftSort, ]); return walletSections; diff --git a/src/resources/nfts/index.ts b/src/resources/nfts/index.ts index e642449d67c..78c58d44a34 100644 --- a/src/resources/nfts/index.ts +++ b/src/resources/nfts/index.ts @@ -15,7 +15,8 @@ const NFTS_STALE_TIME = 600000; // 10 minutes const NFTS_CACHE_TIME_EXTERNAL = 3600000; // 1 hour const NFTS_CACHE_TIME_INTERNAL = 604800000; // 1 week -export const nftsQueryKey = ({ address, sortBy }: { address: string; sortBy: NftCollectionSortCriterion }) => createQueryKey('nfts', { address, sortBy }, { persisterVersion: 4 }); +export const nftsQueryKey = ({ address, sortBy }: { address: string; sortBy: NftCollectionSortCriterion }) => + createQueryKey('nfts', { address, sortBy }, { persisterVersion: 4 }); export const nftListingQueryKey = ({ contractAddress, @@ -97,7 +98,7 @@ export function useLegacyNFTs({ data: (config?.select ? data ?? config.select(FALLBACK_DATA) : data ?? FALLBACK_DATA) as TSelected, error, isFetching, - isInitialLoading + isInitialLoading, }; } From 883df6a35eb1a56ea65fd25dfd199149ef687b6f Mon Sep 17 00:00:00 2001 From: Matthew Wall Date: Wed, 31 Jul 2024 19:56:22 -0400 Subject: [PATCH 04/10] temp chagne arc endpoint to dev workers endpoint --- src/graphql/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphql/config.js b/src/graphql/config.js index 8b809049e5b..8865f8618c2 100644 --- a/src/graphql/config.js +++ b/src/graphql/config.js @@ -22,7 +22,7 @@ exports.config = { document: './queries/arc.graphql', schema: { method: 'GET', - url: 'https://arc-graphql.rainbow.me/graphql', + url: 'https://arc-graphql.rainbowdotme.workers.dev/graphql', headers: { 'x-api-key': 'ARC_GRAPHQL_API_KEY', }, From 76ce2f2b887b369250ccc7e36599c47faf8cb4da Mon Sep 17 00:00:00 2001 From: Matthew Wall Date: Thu, 1 Aug 2024 09:53:27 -0400 Subject: [PATCH 05/10] rm unnecessary enums --- src/graphql/queries/arc.graphql | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/graphql/queries/arc.graphql b/src/graphql/queries/arc.graphql index 3cc55e9ba9c..4b8d55ebb58 100644 --- a/src/graphql/queries/arc.graphql +++ b/src/graphql/queries/arc.graphql @@ -298,17 +298,6 @@ fragment simpleHashPaymentToken on SimpleHashPaymentToken { decimals } -enum NFTCollectionSortCriterion { - MOST_RECENT - ABC - FLOOR_PRICE -} - -enum SortDirection { - ASC - DESC -} - query getNFTs($walletAddress: String!, $sortBy: NFTCollectionSortCriterion, $sortDirection: SortDirection) { nftsV2(walletAddress: $walletAddress, sortBy: $sortBy, sortDirection: $sortDirection) { nft_id From 519ed8dea6aa4dfed1467f585b53585506cc4541 Mon Sep 17 00:00:00 2001 From: Matthew Wall Date: Thu, 1 Aug 2024 10:07:44 -0400 Subject: [PATCH 06/10] rm log --- src/helpers/assets.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/helpers/assets.ts b/src/helpers/assets.ts index 041ceb3694b..b6cf424d7e8 100644 --- a/src/helpers/assets.ts +++ b/src/helpers/assets.ts @@ -367,8 +367,6 @@ export const buildBriefUniqueTokenList = ( result.push({ type: 'NFT_SPACE_AFTER', uid: `showcase-space-after` }); } - console.log(result.map(r => r.type)); - return result; }; From 9bf40d4780408c77bf965dc16bebdc528157f4ec Mon Sep 17 00:00:00 2001 From: Matthew Wall Date: Fri, 9 Aug 2024 10:27:01 -0400 Subject: [PATCH 07/10] cleanup --- .../asset-list/RecyclerAssetList2/NFTEmptyState.tsx | 4 ++-- .../RecyclerAssetList2/core/useMemoBriefSectionData.ts | 5 ----- src/graphql/config.js | 2 +- src/languages/en_US.json | 1 + 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/components/asset-list/RecyclerAssetList2/NFTEmptyState.tsx b/src/components/asset-list/RecyclerAssetList2/NFTEmptyState.tsx index f7e53687f53..a23be055a48 100644 --- a/src/components/asset-list/RecyclerAssetList2/NFTEmptyState.tsx +++ b/src/components/asset-list/RecyclerAssetList2/NFTEmptyState.tsx @@ -1,6 +1,6 @@ import React, { useCallback } from 'react'; import Animated from 'react-native-reanimated'; -import { Box, Inline, Stack, Text, useColorMode } from '@/design-system'; +import { Box, Stack, Text, useColorMode } from '@/design-system'; import * as i18n from '@/languages'; import { TokenFamilyHeaderHeight } from './NFTLoadingSkeleton'; import { MINTS, useExperimentalFlag } from '@/config'; @@ -50,7 +50,7 @@ const LaunchFeaturedMintButton = ({ featuredMint }: LaunchFeaturedMintButtonProp style={[{ backgroundColor: isDarkMode ? SEPARATOR_COLOR : LIGHT_SEPARATOR_COLOR }]} > - Collect Now + {i18n.t(i18n.l.nfts.collect_now)} diff --git a/src/components/asset-list/RecyclerAssetList2/core/useMemoBriefSectionData.ts b/src/components/asset-list/RecyclerAssetList2/core/useMemoBriefSectionData.ts index e5e4cce678a..875d7f91d90 100644 --- a/src/components/asset-list/RecyclerAssetList2/core/useMemoBriefSectionData.ts +++ b/src/components/asset-list/RecyclerAssetList2/core/useMemoBriefSectionData.ts @@ -73,11 +73,6 @@ export default function useMemoBriefSectionData({ return false; } - // // removes NFTS_HEADER if wallet doesn't have NFTs - // if (data.type === CellType.NFTS_HEADER && !arr[arrIndex + 2]) { - // return false; - // } - if (data.type === CellType.PROFILE_STICKY_HEADER) { stickyHeaders.push(index); } diff --git a/src/graphql/config.js b/src/graphql/config.js index 4d4166db265..ec58c6bd808 100644 --- a/src/graphql/config.js +++ b/src/graphql/config.js @@ -22,7 +22,7 @@ exports.config = { document: './queries/arc.graphql', schema: { method: 'GET', - url: 'https://arc-graphql.rainbowdotme.workers.dev/graphql', + url: 'https://arc-graphql.rainbow.me/graphql', headers: { 'x-api-key': 'ARC_GRAPHQL_API_KEY', }, diff --git a/src/languages/en_US.json b/src/languages/en_US.json index 95622619853..57b0cf11aeb 100644 --- a/src/languages/en_US.json +++ b/src/languages/en_US.json @@ -1323,6 +1323,7 @@ "floor_price": "Floor Price" }, "empty": "Collectibles", + "collect_now": "Collect Now", "will_appear_here": "Your Collectibles Will Appear Here" }, "nft_offers": { From 3064fa297d7f530c033dfe33e0087f153d698cdd Mon Sep 17 00:00:00 2001 From: Matthew Wall Date: Fri, 9 Aug 2024 15:49:41 -0400 Subject: [PATCH 08/10] change to isLoading --- src/hooks/useWalletSectionsData.ts | 2 +- src/resources/nfts/index.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hooks/useWalletSectionsData.ts b/src/hooks/useWalletSectionsData.ts index 516b06fa9e0..dba11b78658 100644 --- a/src/hooks/useWalletSectionsData.ts +++ b/src/hooks/useWalletSectionsData.ts @@ -26,7 +26,7 @@ export default function useWalletSectionsData({ const { sendableUniqueTokens } = useSendableUniqueTokens(); const { data: { nfts: allUniqueTokens }, - isFetching: isFetchingNfts, + isLoading: isFetchingNfts, } = useLegacyNFTs({ address: accountAddress, sortBy: nftSort, diff --git a/src/resources/nfts/index.ts b/src/resources/nfts/index.ts index 78c58d44a34..a39f3c6848d 100644 --- a/src/resources/nfts/index.ts +++ b/src/resources/nfts/index.ts @@ -86,7 +86,7 @@ export function useLegacyNFTs({ }) { const isImportedWallet = useSelector((state: AppState) => isImportedWalletSelector(state, address)); - const { data, error, isFetching, isInitialLoading } = useQuery(nftsQueryKey({ address, sortBy }), fetchNFTData, { + const { data, error, isLoading, isInitialLoading } = useQuery(nftsQueryKey({ address, sortBy }), fetchNFTData, { cacheTime: isImportedWallet ? NFTS_CACHE_TIME_INTERNAL : NFTS_CACHE_TIME_EXTERNAL, enabled: !!address, retry: 3, @@ -97,7 +97,7 @@ export function useLegacyNFTs({ return { data: (config?.select ? data ?? config.select(FALLBACK_DATA) : data ?? FALLBACK_DATA) as TSelected, error, - isFetching, + isLoading, isInitialLoading, }; } From dd2af8b3745eed28e4593a6f0e98f84dadc62fac Mon Sep 17 00:00:00 2001 From: Ben Goldberg Date: Fri, 9 Aug 2024 17:23:38 -0700 Subject: [PATCH 09/10] artistic flair --- .../RecyclerAssetList2/NFTLoadingSkeleton.tsx | 55 +++++-------------- src/graphql/config.js | 2 +- 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/src/components/asset-list/RecyclerAssetList2/NFTLoadingSkeleton.tsx b/src/components/asset-list/RecyclerAssetList2/NFTLoadingSkeleton.tsx index b157718e102..3e9788a0c0b 100644 --- a/src/components/asset-list/RecyclerAssetList2/NFTLoadingSkeleton.tsx +++ b/src/components/asset-list/RecyclerAssetList2/NFTLoadingSkeleton.tsx @@ -8,7 +8,7 @@ import { deviceUtils } from '@/utils'; export const TokenFamilyHeaderHeight = 50; const getRandomBetween = (min: number, max: number) => { - return Math.floor(Math.random() * (max - min + 1) + min); + return Math.random() * (max - min) + min; }; const NFTItem = () => { @@ -24,26 +24,21 @@ const NFTItem = () => { }, ]} > - + + - - - - - - ); @@ -63,10 +58,7 @@ const sx = StyleSheet.create({ container: { flex: 1, width: '100%', - }, - leftContainer: { - flexDirection: 'row', - alignItems: 'center', + gap: 5, }, image: { height: 30, @@ -79,32 +71,15 @@ const sx = StyleSheet.create({ }, title: { width: deviceUtils.dimensions.width / 2, - height: 12, - borderRadius: 4, - marginBottom: 4, + height: 14, + borderRadius: 7, paddingRight: 9, }, - rightContainer: { - flexDirection: 'row', - alignItems: 'center', - marginRight: 10, - }, - amount: { - width: 23, - height: 16, - borderRadius: 4, - }, - chevron: { - height: 18, - width: 8, - }, content: { flexDirection: 'row', - justifyContent: 'space-between', alignItems: 'center', height: TokenFamilyHeaderHeight, padding: 19, - paddingRight: 14, width: '100%', }, }); diff --git a/src/graphql/config.js b/src/graphql/config.js index ec58c6bd808..55f5e3a76b8 100644 --- a/src/graphql/config.js +++ b/src/graphql/config.js @@ -4,7 +4,7 @@ exports.config = { document: './queries/ens.graphql', schema: { method: 'POST', - url: 'https://api.thegraph.com/subgraphs/name/ensdomains/ens', + url: 'https://gateway-arbitrum.network.thegraph.com/api/35a75cae48aab2b771d1e53543a37a0f/subgraphs/id/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH', }, }, metadata: { From e665ac83d0b17035f1ab959ef184e6dcb5ebb516 Mon Sep 17 00:00:00 2001 From: Matthew Wall Date: Thu, 15 Aug 2024 13:29:36 -0400 Subject: [PATCH 10/10] fix lint --- src/hooks/useNFTsSortBy.ts | 2 +- src/hooks/useWatchPendingTxs.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hooks/useNFTsSortBy.ts b/src/hooks/useNFTsSortBy.ts index a9ce04a9018..345f20132a7 100644 --- a/src/hooks/useNFTsSortBy.ts +++ b/src/hooks/useNFTsSortBy.ts @@ -7,7 +7,7 @@ const mmkv = new MMKV(); const getStorageKey = (accountAddress: string) => `nfts-sort-${accountAddress}`; export const getNftSortForAddress = (accountAddress: string) => { - mmkv.getString(getStorageKey(accountAddress)); + return mmkv.getString(getStorageKey(accountAddress)) as NftCollectionSortCriterion; }; export default function useNftSort(): { diff --git a/src/hooks/useWatchPendingTxs.ts b/src/hooks/useWatchPendingTxs.ts index aed5c6fad25..51a710ff73d 100644 --- a/src/hooks/useWatchPendingTxs.ts +++ b/src/hooks/useWatchPendingTxs.ts @@ -15,6 +15,7 @@ import { usePendingTransactionsStore } from '@/state/pendingTransactions'; import { useNonceStore } from '@/state/nonces'; import { Address } from 'viem'; import { nftsQueryKey } from '@/resources/nfts'; +import { getNftSortForAddress } from './useNFTsSortBy'; export const useWatchPendingTransactions = ({ address }: { address: string }) => { const { storePendingTransactions, setPendingTransactions } = usePendingTransactionsStore(state => ({ @@ -46,7 +47,7 @@ export const useWatchPendingTransactions = ({ address }: { address: string }) => testnetMode: !!connectedToHardhat, }) ); - queryClient.invalidateQueries(nftsQueryKey({ address })); + queryClient.invalidateQueries(nftsQueryKey({ address, sortBy: getNftSortForAddress(address) })); }, [address, nativeCurrency] );