Now our users have NFTS and SFTs, we need a way to for them to see whats in their wallet... Lets start with the NFTs making use of the Asset Register.
Create src/providers/AssetRegisterProvider.tsx with the following content
import { AssetRegisterClientProvider } from '@futureverse/asset-register-react/v2';
import { useFutureverseSigner } from '@futureverse/auth-react';
import { type ReactNode, useEffect, useMemo, useState } from 'react';
import { type Address } from 'viem';
const url = 'https://ar-api.futureverse.cloud/graphql';
const ASSET_REGISTRY_DOMAIN =
typeof window === 'undefined' ? '' : window.location.host;
const ASSET_REGISTRY_ORIGIN =
typeof window === 'undefined' ? '' : window.origin;
type Props = {
children: ReactNode;
};
export const AssetRegisterProvider: React.FC<Props> = ({ children }) => {
const signer = useFutureverseSigner();
const [address, setAddress] = useState<Address>();
useEffect(() => {
void (async () => {
if (signer) {
setAddress((await signer.getAddress()) as Address);
}
})();
}, [signer]);
const auth = useMemo(() => {
if (!address || !signer) {
return undefined;
}
return {
origin: ASSET_REGISTRY_ORIGIN,
domain: ASSET_REGISTRY_DOMAIN,
chainId: 1,
sign: (message: string) => signer.signMessage(message),
walletAddress: address,
storage: {
get: (key: string) => localStorage.getItem(key),
set: (key: string, value: string) => localStorage.setItem(key, value),
},
};
}, [address, signer]);
return (
<AssetRegisterClientProvider url={url} auth={auth}>
{children}
</AssetRegisterClientProvider>
);
};Open src/providers/FvProvider.tsx and add the following import at the top of the file
import { AssetRegisterProvider } from './AssetRegisterProvider';Add the AssetRegisterProvider inside of <AuthUiProvider ../> tags and around {children} to look like this
<AuthUiProvider themeConfig={customTheme} authClient={authClient}>
<AssetRegisterProvider>
{children}
</AssetRegisterProvider>
</AuthUiProvider>Create src/components/MyCollection.tsx with the following content
import { useAssets } from '@futureverse/asset-register-react/v2';
import { useAuth } from '@futureverse/auth-react';
import type { AssetModel } from '@futureverse/asset-register/models';
import React from 'react';
import { COLLECTION_ID } from '@/lib/utils';
import { Skeleton } from '@/components/ui/skeleton';
import NftToken from '@/components/NftToken';
import { useQueryClient } from '@tanstack/react-query';
export default function MyCollection() {
const { userSession } = useAuth();
const queryClient = useQueryClient();
const assetQueryParams = React.useMemo(
() => ({
first: 11,
addresses: [userSession?.eoa, userSession?.futurepass],
collectionIds: [`7672:root:${COLLECTION_ID}`],
}),
[userSession]
);
const {
assets,
reactQuery: { hasNextPage, fetchNextPage, isFetching, isLoading, error },
} = useAssets(assetQueryParams, {
enabled: true,
initialPageParam: undefined,
getNextPageParam: lastPage => lastPage?.nextCursor,
});
return (
<>
<main className="flex min-h-[calc(100dvh-6rem-1rem)] flex-col items-center text-white">
<div className="container grid grid-cols-1 gap-4 pb-8 mt-4">
<div className="w-full col-span-full flex flex-row gap-4 items-baseline">
<h1 className="text-3xl font-black text-start leading-6">
Your Collection
</h1>
<span
className="text-xs text-start cursor-pointer inline-flex leading-none"
onClick={() => {
void queryClient.invalidateQueries({ queryKey: ['assets'] });
void queryClient.invalidateQueries({ queryKey: ['GetAsset'] });
void queryClient.invalidateQueries({ queryKey: ['slots'] });
}}
>
[ <span className="underline">REFRESH</span>
]
</span>
</div>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-10 ">
{isLoading && (
<>
<Skeleton className="aspect-square" />
<Skeleton className="aspect-square" />
<Skeleton className="aspect-square" />
<Skeleton className="aspect-square" />
<Skeleton className="aspect-square" />
</>
)}
{assets
?.sort((a, b) => {
return Number(a?.tokenId) > Number(b?.tokenId) ? 1 : -1;
})
?.map((asset: AssetModel, i: number) => (
<NftToken key={`nft-${i}`} asset={asset} />
))}
{!isLoading && isFetching && (
<Skeleton className="aspect-square flex flex-col justify-center items-center text-center">
Fetching...
</Skeleton>
)}
</div>
{error && (
<div className="bg-red-500 text-white p-2 rounded-md col-span-full">
{error.message}
</div>
)}
{hasNextPage && (
<button
type="button"
onClick={() => fetchNextPage()}
className="bg-slate-400 text-white p-2 rounded-md col-span-full"
>
Load More
</button>
)}
</div>
</main>
</>
);
}Create src/components/NftToken.tsx with the following content
import type { AssetModel } from '@futureverse/asset-register/models';
import { Skeleton } from './ui/skeleton';
type NftTokenProps = {
asset: AssetModel;
};
export default function NftToken({ asset }: NftTokenProps) {
return (
<>
<div className="cursor-pointer">
<div className="aspect-square relative cursor-pointer">
{asset?.metadata?.properties?.image ? (
<img
src={asset?.metadata?.properties?.image}
alt="alt"
className="aspect-square relative pointer-events-none cursor-pointer rounded-md overflow-hidden"
/>
) : (
<Skeleton className="aspect-square animate-pulse w-full" />
)}
<div className="absolute top-2 left-0 text-left text-sm md:text-base lg:text-lg leading-none font-semibold p-2 bg-slate-400 bg-opacity-50 backdrop-blur-sm">
{/* @ts-expect-error - Error will be fixed in SDK */}
Token {asset?.rawData?.tokenId}
</div>
</div>
</div>
</>
);
}Remove the comments in the following code blocks in src/components/Navigation.tsx
{
/*
<NavigationMenuItem>
<NavigationMenuLink
asChild
onClick={() => closeHandler && closeHandler(false)}
className={`${navigationMenuTriggerStyle()} bg-transparent hover:bg-transparent text-white hover:text-orange-500 duration-300 transition-colors text-lg`}
>
<Link to="/my-collection">My Collection</Link>
</NavigationMenuLink>
</NavigationMenuItem>
*/
}so it looks like
<NavigationMenuItem>
<NavigationMenuLink
asChild
onClick={() => closeHandler && closeHandler(false)}
className={`${navigationMenuTriggerStyle()} bg-transparent hover:bg-transparent text-white hover:text-orange-500 duration-300 transition-colors text-lg`}
>
<Link to="/my-collection">My Collection</Link>
</NavigationMenuLink>
</NavigationMenuItem>Remove the following comments from src/App.tsx
// import MyCollection from '@/components/MyCollection';and
{
/* <Route
path="/my-collection"
element={
<ProtectedRoute>
<MyCollection />
</ProtectedRoute>
}
/> */
}so it looks like
<Route
path="/my-collection"
element={
<ProtectedRoute>
<MyCollection />
</ProtectedRoute>
}
/>