diff --git a/playground/nextjs-app-router/components/demo/IdentityCard.tsx b/playground/nextjs-app-router/components/demo/IdentityCard.tsx index 128d504391..455b0e4d85 100644 --- a/playground/nextjs-app-router/components/demo/IdentityCard.tsx +++ b/playground/nextjs-app-router/components/demo/IdentityCard.tsx @@ -3,31 +3,32 @@ import { IdentityCard } from '@coinbase/onchainkit/identity'; import { base, mainnet } from 'viem/chains'; import { useAccount } from 'wagmi'; -import { useName, getName, useAvatar, getAvatar } from '@coinbase/onchainkit/identity'; +import { useNames, getNames, useAvatars, getAvatars } from '@coinbase/onchainkit/identity'; import { useState, useEffect } from 'react'; import { useOnchainKit, setOnchainKitConfig } from '@coinbase/onchainkit'; -// Component for useName resolution - only shows name/address text -function NameItem({ address }: { address: `0x${string}` }) { - const { data: name, isLoading } = useName({ address }); +// Component for useNames resolution - only shows name/address text +function NameItem({ address, nameIndex, names }: { address: `0x${string}`, nameIndex: number, names: (string | null)[] | undefined }) { return (
  • - {isLoading ? 'Loading...' : name || `${address.substring(0, 6)}...${address.substring(38)}`} + {!names ? 'Loading...' : (names[nameIndex] || `${address.substring(0, 6)}...${address.substring(38)}`)}
  • ); } -// Component for useAvatar resolution - shows avatar image + address -function AvatarItem({ address }: { address: `0x${string}` }) { - // Get name first, then use it for avatar if available - const { data: name } = useName({ address }); - const { data: avatar, isLoading } = useAvatar({ - ensName: name || undefined - }); +// Component for useAvatars resolution - shows avatar image + address +function AvatarItem({ address, nameIndex, names, avatars }: { + address: `0x${string}`, + nameIndex: number, + names: (string | null)[] | undefined, + avatars: (string | null)[] | undefined +}) { + const name = names ? names[nameIndex] : null; + const avatar = avatars && name ? avatars[nameIndex] : null; return (
  • - {isLoading ? ( + {!names || !avatars ? ( 'Loading...' ) : ( <> @@ -39,108 +40,36 @@ function AvatarItem({ address }: { address: `0x${string}` }) { ); } -// Component for getName resolution - only shows name/address text -function GetNameItem({ address }: { address: `0x${string}` }) { - const [name, setName] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const { apiKey, chain } = useOnchainKit(); - - useEffect(() => { - const fetchName = async () => { - try { - console.log(`Fetching name for address: ${address}, with API key: ${apiKey ? 'Available' : 'Not available'}`); - - // Set the OnchainKit config before making the call - if (apiKey) { - setOnchainKitConfig({ - apiKey, - chain, - }); - } - - // Explicitly specify the chain parameter (mainnet by default) - const result = await getName({ address, chain: mainnet }); - console.log(`Name result for ${address}: ${result}`); - setName(result); - } catch (error) { - console.error(`Error fetching name for ${address}:`, error); - } finally { - setIsLoading(false); - } - }; - - if (apiKey) { - fetchName(); - } else { - console.error('API key not available for getName'); - setIsLoading(false); - } - }, [address, apiKey, chain]); - +// Component for getNames resolution - only shows name/address text +function GetNameItem({ address, nameIndex, names, isLoading }: { + address: `0x${string}`, + nameIndex: number, + names: (string | null)[], + isLoading: boolean +}) { return (
  • - {isLoading ? 'Loading...' : name || `${address.substring(0, 6)}...${address.substring(38)}`} + {isLoading ? 'Loading...' : names[nameIndex] || `${address.substring(0, 6)}...${address.substring(38)}`}
  • ); } -// Component for getAvatar resolution - shows avatar image + address -function GetAvatarItem({ address }: { address: `0x${string}` }) { - const [avatar, setAvatar] = useState(null); - const [name, setName] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const { apiKey, chain } = useOnchainKit(); - - useEffect(() => { - const fetchData = async () => { - try { - console.log(`Fetching data for address: ${address}, with API key: ${apiKey ? 'Available' : 'Not available'}`); - - // Set the OnchainKit config before making the call - if (apiKey) { - setOnchainKitConfig({ - apiKey, - chain, - }); - } - - // First get the name with explicit chain parameter - const nameResult = await getName({ address, chain: mainnet }); - console.log(`Name result for ${address}: ${nameResult}`); - setName(nameResult); - - // Then use the name to get the avatar if available, with explicit chain parameter - if (nameResult) { - console.log(`Fetching avatar for name: ${nameResult}`); - const avatarResult = await getAvatar({ ensName: nameResult, chain: mainnet }); - console.log(`Avatar result for ${nameResult}: ${avatarResult ? 'Found' : 'Not found'}`); - setAvatar(avatarResult); - } else { - console.log(`No name found for ${address}, skipping avatar fetch`); - } - } catch (error) { - console.error(`Error fetching data for ${address}:`, error); - } finally { - setIsLoading(false); - } - }; - - if (apiKey) { - fetchData(); - } else { - console.error('API key not available for getAvatar'); - setIsLoading(false); - } - }, [address, apiKey, chain]); - +// Component for getAvatars resolution - shows avatar image + address +function GetAvatarItem({ address, nameIndex, names, avatars, isLoading }: { + address: `0x${string}`, + nameIndex: number, + names: (string | null)[], + avatars: (string | null)[], + isLoading: boolean +}) { return (
  • {isLoading ? ( 'Loading...' ) : ( <> - {avatar && Avatar} - {name || `${address.substring(0, 6)}...${address.substring(38)}`} + {avatars[nameIndex] && Avatar} + {names[nameIndex] || `${address.substring(0, 6)}...${address.substring(38)}`} )}
  • @@ -151,6 +80,25 @@ export function IdentityCardDemo() { const { address } = useAccount(); const [addresses, setAddresses] = useState([]); + // For getNames and getAvatars + const [batchNames, setBatchNames] = useState<(string | null)[]>([]); + const [batchAvatars, setBatchAvatars] = useState<(string | null)[]>([]); + const [isLoadingNames, setIsLoadingNames] = useState(true); + const [isLoadingAvatars, setIsLoadingAvatars] = useState(true); + + const { apiKey, chain } = useOnchainKit(); + + // For useNames and useAvatars + const { data: hookNames, isLoading: isLoadingHookNames } = useNames({ + addresses: addresses as `0x${string}`[], + chain: mainnet + }); + + const { data: hookAvatars, isLoading: isLoadingHookAvatars } = useAvatars({ + ensNames: hookNames?.filter(Boolean) as string[] || [], + chain: mainnet + }); + // Generate addresses with the first one fixed and the rest random useEffect(() => { const generateAddresses = () => { @@ -171,6 +119,62 @@ export function IdentityCardDemo() { generateAddresses(); }, []); + + // Fetch names and avatars using getNames and getAvatars + useEffect(() => { + const fetchData = async () => { + if (!addresses.length || !apiKey) return; + + try { + setIsLoadingNames(true); + + // Set the OnchainKit config before making the call + setOnchainKitConfig({ + apiKey, + chain, + }); + + // Get names for all addresses in a batch + const nameResults = await getNames({ + addresses: addresses as `0x${string}`[], + chain: mainnet + }); + + setBatchNames(nameResults); + setIsLoadingNames(false); + + // Get avatars for all names in a batch + setIsLoadingAvatars(true); + const validNames = nameResults.filter(Boolean) as string[]; + + if (validNames.length > 0) { + const avatarResults = await getAvatars({ + ensNames: validNames, + chain: mainnet + }); + + // Create a mapping of names to avatars + const avatarMap = new Map(); + validNames.forEach((name, idx) => { + avatarMap.set(name, avatarResults[idx]); + }); + + // Map avatars back to the original address order + const mappedAvatars = nameResults.map(name => + name ? avatarMap.get(name) || null : null + ); + + setBatchAvatars(mappedAvatars); + } + } catch (error) { + console.error('Error fetching data:', error); + } finally { + setIsLoadingAvatars(false); + } + }; + + fetchData(); + }, [addresses, apiKey, chain]); if (!address) { return null; @@ -180,49 +184,73 @@ export function IdentityCardDemo() {
    - {/* useName List */} + {/* useNames List */}
    -

    useName

    +

    useNames

      {addresses.map((addr, index) => ( - + ))}
    - {/* getName List */} + {/* getNames List */}
    -

    getName

    +

    getNames

      {addresses.map((addr, index) => ( - + ))}
    - {/* useAvatar List */} + {/* useAvatars List */}
    -

    useAvatar

    +

    useAvatars

      {addresses.map((addr, index) => ( - + ))}
    - {/* getAvatar List */} + {/* getAvatars List */}
    -

    getAvatar

    +

    getAvatars

      {addresses.map((addr, index) => ( - + ))}