diff --git a/src/components/ens-profile/ProfileSheetHeader.tsx b/src/components/ens-profile/ProfileSheetHeader.tsx index f6743da71df..b707a650370 100644 --- a/src/components/ens-profile/ProfileSheetHeader.tsx +++ b/src/components/ens-profile/ProfileSheetHeader.tsx @@ -50,7 +50,7 @@ export default function ProfileSheetHeader({ }); const isImagesFetched = isAvatarFetched && isCoverFetched; - const uniqueTokens = useUserNftsStore()(state => state?.nfts); + const uniqueTokens = useUserNftsStore(state => state.getData()?.nfts); const avatarUrl = avatar?.imageUrl; const { onPress: onPressAvatar } = useOpenENSNFTHandler({ diff --git a/src/components/expanded-state/ens/InfoRow.tsx b/src/components/expanded-state/ens/InfoRow.tsx index 0ee0e577bd1..1c2303e02f6 100644 --- a/src/components/expanded-state/ens/InfoRow.tsx +++ b/src/components/expanded-state/ens/InfoRow.tsx @@ -178,10 +178,9 @@ function ImageValue({ ensName, url, value }: { ensName?: string; url?: string; v const { data: address } = useENSAddress({ name: ensName || '' }); - const userNftsStore = useUserNftsStore(); - const uniqueTokensAccount = userNftsStore(state => state.nfts); + const uniqueTokensAccount = useUserNftsStore(state => state.getData()?.nfts); const externalNftStore = useNftsStore(address ?? ''); - const uniqueTokensProfile = externalNftStore(state => state.nfts); + const uniqueTokensProfile = externalNftStore(state => state.getData()?.nfts); const isSelf = address === accountAddress; const uniqueTokens = isSelf ? uniqueTokensAccount : uniqueTokensProfile; diff --git a/src/hooks/useENSModifiedRegistration.ts b/src/hooks/useENSModifiedRegistration.ts index ae2b9a37f41..e8e8a8af8e8 100644 --- a/src/hooks/useENSModifiedRegistration.ts +++ b/src/hooks/useENSModifiedRegistration.ts @@ -56,7 +56,7 @@ export default function useENSModifiedRegistration({ } = {}) { const dispatch = useDispatch(); const { records, initialRecords, name, mode } = useENSRegistration(); - const uniqueTokens = useUserNftsStore()(state => state.nfts); + const uniqueTokens = useUserNftsStore(state => state.getData()?.nfts || []); const fetchEnabled = mode === REGISTRATION_MODES.EDIT || mode === REGISTRATION_MODES.RENEW || mode === REGISTRATION_MODES.SET_NAME; const { data: avatar, isSuccess: isAvatarSuccess } = useENSAvatar(name, { diff --git a/src/hooks/useENSPendingRegistrations.tsx b/src/hooks/useENSPendingRegistrations.tsx index 63a3473bcf3..42be4b283e2 100644 --- a/src/hooks/useENSPendingRegistrations.tsx +++ b/src/hooks/useENSPendingRegistrations.tsx @@ -28,7 +28,7 @@ export default function useENSPendingRegistrations() { return { accountRegistrations, pendingRegistrations }; }); - const uniqueTokens = useUserNftsStore()(state => state.nfts); + const uniqueTokens = useUserNftsStore(state => state.getData()?.nfts || []); const registrationImages = useMemo(() => { const registrationImagesArray = pendingRegistrations?.map(({ name, records }) => { const avatarUrl = getENSNFTAvatarUrl(uniqueTokens, records?.avatar); diff --git a/src/hooks/useSendableUniqueTokens.ts b/src/hooks/useSendableUniqueTokens.ts index 68880bc428e..225db520576 100644 --- a/src/hooks/useSendableUniqueTokens.ts +++ b/src/hooks/useSendableUniqueTokens.ts @@ -1,9 +1,10 @@ import { groupBy } from 'lodash'; import { useUserNftsStore } from '@/state/nfts'; +import { UniqueAsset } from '@/entities'; export default function useSendableUniqueTokens() { - const uniqueTokens = useUserNftsStore()(state => (!Array.isArray(state.nfts) ? [] : state.nfts)) || []; - const sendableUniqueTokens = uniqueTokens?.filter((uniqueToken: any) => uniqueToken.isSendable); + const uniqueTokens = useUserNftsStore(state => state.getData()?.nfts || []); + const sendableUniqueTokens = uniqueTokens?.filter((uniqueToken: UniqueAsset) => uniqueToken.isSendable); const grouped = groupBy(sendableUniqueTokens, token => token.familyName); const families = Object.keys(grouped).sort(); const sendableTokens = []; diff --git a/src/hooks/useWalletSectionsData.ts b/src/hooks/useWalletSectionsData.ts index 4304155cd28..ff1ddcc68b7 100644 --- a/src/hooks/useWalletSectionsData.ts +++ b/src/hooks/useWalletSectionsData.ts @@ -63,9 +63,8 @@ export default function useWalletSectionsData({ const { sendableUniqueTokens } = useSendableUniqueTokens(); - const userNftsStore = useUserNftsStore(); - const isFetchingNfts = userNftsStore(state => state.status); - const allUniqueTokens = userNftsStore(state => (Array.isArray(state.nfts) ? state.nfts : [])); + const isFetchingNfts = useUserNftsStore(state => state.status); + const allUniqueTokens = useUserNftsStore(state => (Array.isArray(state.getData()?.nfts) ? state.getData()?.nfts : [])); const { data: positions } = usePositions({ address: accountAddress, currency: nativeCurrency }); const { data: claimables } = useClaimables({ address: accountAddress, currency: nativeCurrency }); diff --git a/src/screens/NFTSingleOfferSheet/index.tsx b/src/screens/NFTSingleOfferSheet/index.tsx index 5956237bd23..6641df60d26 100644 --- a/src/screens/NFTSingleOfferSheet/index.tsx +++ b/src/screens/NFTSingleOfferSheet/index.tsx @@ -103,7 +103,7 @@ export function NFTSingleOfferSheet() { const [isAccepting, setIsAccepting] = useState(false); const txsRef = useRef([]); - const nft = useUserNftsStore()(state => state.getNft(offer.nft.uniqueId)); + const nft = useUserNftsStore(state => state.getNft(offer.nft.uniqueId)); const insufficientEth = isSufficientGas === false && isValidGas; diff --git a/src/screens/mints/PoapSheet.tsx b/src/screens/mints/PoapSheet.tsx index 29173d230ee..fce1e55eb4b 100644 --- a/src/screens/mints/PoapSheet.tsx +++ b/src/screens/mints/PoapSheet.tsx @@ -77,7 +77,7 @@ const PoapSheet = () => { const { isReadOnlyWallet } = useWallets(); const params = useRoute(); - const nfts = useUserNftsStore()(state => state.nfts); + const nfts = useUserNftsStore(state => state.getData()?.nfts); const [claimStatus, setClaimStatus] = useState('none'); const [errorCode, setErrorCode] = useState(undefined); @@ -189,7 +189,7 @@ const PoapSheet = () => { }, [claimPoapByQrHash, claimPoapBySecret, claimStatus, goBack, navigate, nft, poapMintType]); useEffect(() => { - const nft = nfts.find(item => item.image_original_url === poapEvent.imageUrl); + const nft = nfts?.find(item => item.image_original_url === poapEvent.imageUrl); if (nft) { setClaimStatus('claimed'); setNft(nft); diff --git a/src/state/nfts/index.ts b/src/state/nfts/index.ts index da540ed1316..0ffdb25d776 100644 --- a/src/state/nfts/index.ts +++ b/src/state/nfts/index.ts @@ -5,6 +5,7 @@ import { fetchUserNfts } from '@/resources/nfts'; import { time } from '@/utils'; import { NftCollectionSortCriterion, SortDirection } from '@/graphql/__generated__/arc'; import { useAccountSettings } from '@/hooks'; +import reduxStore from '@/redux/store'; type UserNftsStoreType = ReturnType; @@ -43,14 +44,6 @@ export const createUserNftsStore = (config: NftFactoryConfig) => sortBy: $ => $(useNftSortStore, s => s.getNftSort(config.address).sortBy), sortDirection: $ => $(useNftSortStore, s => s.getNftSort(config.address).sortDirection), }, - setData: ({ data, set }) => { - set(() => { - return { - nfts: data.nfts, - nftsMap: data.nftsMap, - }; - }); - }, staleTime: time.minutes(10), }, (_, get) => ({ @@ -66,9 +59,16 @@ export const createUserNftsStore = (config: NftFactoryConfig) => function getOrCreateStore(address: string, internal?: boolean): UserNftsStoreType { const { cachedAddress, cachedStore } = userNftsStoreManager.getState(); - if (cachedAddress && cachedAddress === address && cachedStore) { - return cachedStore; - } + const rawAddress = address?.length ? address : reduxStore.getState().settings.accountAddress; + + /** + * This fallback can be removed once Redux is no longer the source of truth for the current + * accountAddress. It's needed to ensure there's an address available immediately upon app + * launch, which currently is not the case — the initial Redux address is an empty string. + */ + const accountAddress = rawAddress?.length ? rawAddress : cachedAddress ?? rawAddress; + + if (cachedStore && cachedAddress === accountAddress) return cachedStore; const newStore = createUserNftsStore({ address, internal }); userNftsStoreManager.setState({ cachedStore: newStore, cachedAddress: address }); @@ -79,13 +79,11 @@ export function useNftsStore(address: string, internal?: boolean) { return getOrCreateStore(address, internal); } -export function useUserNftsStore() { +export function useUserNftsStore(selector: (state: ReturnType) => T) { const { accountAddress } = useAccountSettings(); - return useNftsStore(accountAddress, true); + return useNftsStore(accountAddress, true)(selector); } -// SORT - export type NftSortAction = `${NftCollectionSortCriterion}|${SortDirection}`; type NftSortByAddress = Record; type NftSort = {