Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions src/components/address/address-breadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
AlertCircleIcon,
ChevronRightIcon,
FilterIcon,
HomeIcon,
Expand All @@ -25,13 +26,17 @@ const AddressBreadcrumb = ({
showAddAddress,
setShowAddAddress,
blocks,
loading,
hasError,
}: {
resolvedAddresses: ResolvedAddress[];
showFilters: boolean;
setShowFilters: (show: boolean) => void;
showAddAddress: boolean;
setShowAddAddress: (show: boolean) => void;
blocks: MinimalBlock[];
loading: boolean;
hasError: boolean;
}) => {
const { theme } = useTheme();

Expand All @@ -55,14 +60,28 @@ const AddressBreadcrumb = ({
>
<ol role="list" className="flex items-center space-x-4">
<li>
<div>
<div className="relative">
<a
href={theme ? `/?theme=${theme}` : "/"}
className="text-gray-400 hover:text-gray-300 dark:text-gray-500 dark:hover:text-gray-400"
>
<HomeIcon aria-hidden="true" className="size-5 shrink-0" />
<span className="sr-only">Home</span>
</a>
{/* Error indicator badge next to home icon */}
{hasError && (
<Tooltip>
<TooltipTrigger asChild>
<AlertCircleIcon
className="absolute -top-1 -right-1 size-3 text-red-600 dark:text-red-400"
aria-label="Error loading address"
/>
</TooltipTrigger>
<TooltipContent>
<p>Error loading address</p>
</TooltipContent>
</Tooltip>
)}
</div>
</li>
<li>
Expand All @@ -76,25 +95,36 @@ const AddressBreadcrumb = ({
aria-current={"page"}
className="ml-4 hidden text-sm font-medium text-gray-500 hover:text-gray-700 md:block dark:text-gray-400 dark:hover:text-gray-300"
>
{resolvedAddresses.length === 0 && (
{loading && resolvedAddresses.length === 0 && (
<Skeleton className="h-4 w-32" />
)}
{resolvedAddresses.length === 1 &&
{!loading && hasError && resolvedAddresses.length === 0 && (
<span className="text-red-600 dark:text-red-400">
Error loading address
</span>
)}
{!loading &&
resolvedAddresses.length === 1 &&
getDisplayName(resolvedAddresses[0].address)}
{resolvedAddresses.length > 1 &&
{!loading &&
resolvedAddresses.length > 1 &&
`Multiple addresses (${resolvedAddresses.length})`}
</a>
<a
href={""}
aria-current={"page"}
className="ml-4 text-sm font-medium text-gray-500 hover:text-gray-700 md:hidden dark:text-gray-400 dark:hover:text-gray-300"
>
{resolvedAddresses.length === 0 && (
{loading && resolvedAddresses.length === 0 && (
<Skeleton className="h-4 w-24" />
)}
{resolvedAddresses.length === 1 &&
{!loading && hasError && resolvedAddresses.length === 0 && (
<span className="text-red-600 dark:text-red-400">Error</span>
)}
{!loading &&
resolvedAddresses.length === 1 &&
getDisplayName(resolvedAddresses[0].address, true)}
{resolvedAddresses.length > 1 && "Multiple addresses"}
{!loading && resolvedAddresses.length > 1 && "Multiple addresses"}
</a>

<div className={"ml-3 flex items-center gap-2"}>
Expand Down
14 changes: 10 additions & 4 deletions src/components/address/address-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,11 @@ export default function AddressView({ addresses }: { addresses: string }) {
() => addresses.split(",").filter(Boolean),
[addresses],
);
const { resolvedAddresses } = useAlgorandAddresses(addressesArray);
const {
resolvedAddresses,
loading: addressLoading,
hasError: addressError,
} = useAlgorandAddresses(addressesArray);

// Function to update addresses in both state and URL
const handleAddAddresses = (newAddresses: string[]) => {
Expand Down Expand Up @@ -215,6 +219,8 @@ export default function AddressView({ addresses }: { addresses: string }) {
showFilters={showFilters}
setShowFilters={setShowFilters}
blocks={filteredBlocks}
loading={addressLoading}
hasError={addressError}
/>
<AddAddress
showAddAddress={showAddAddress}
Expand All @@ -227,14 +233,14 @@ export default function AddressView({ addresses }: { addresses: string }) {
selectedAddresses={selectedAddresses}
setSelectedAddresses={setSelectedAddresses}
/>
{resolvedAddresses.length === 1 && (
{resolvedAddresses.length === 1 && resolvedAddresses[0] && (
<div>
<div className={"flex flex-wrap items-center gap-2"}>
<h2 className="block text-xl/7 text-gray-700 sm:hidden sm:truncate sm:text-lg sm:tracking-tight">
{displayAlgoAddress(resolvedAddresses[0].address)}
{displayAlgoAddress(resolvedAddresses[0]?.address)}
</h2>
<h2 className="hidden text-xl/7 text-gray-700 sm:block sm:truncate sm:text-lg sm:tracking-tight">
{resolvedAddresses[0].address}
{resolvedAddresses[0]?.address}
</h2>
<CopyButton address={resolvedAddresses[0].address} />
</div>
Expand Down
22 changes: 20 additions & 2 deletions src/hooks/useAlgorandAddress.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { resolveNFD } from "@/hooks/queries/useNFD";
import * as React from "react";
import { ResolvedAddress } from "@/components/heatmap/types.ts";
import { toast } from "sonner";

export const useAlgorandAddresses = (addresses: string[]) => {
const [resolvedAddresses, setResolvedAddresses] = React.useState<
Expand All @@ -16,13 +17,30 @@ export const useAlgorandAddresses = (addresses: string[]) => {
const resolved = await Promise.all(
addresses.map(async (address) => {
if (address.toLowerCase().endsWith(".algo")) {
return { address: await resolveNFD(address), nfd: address };
const resolvedAddr = await resolveNFD(address);
// If NFD resolution fails (expired, not found, etc.), skip it
if (!resolvedAddr || resolvedAddr.length !== 58) {
toast.error(
`NFD "${address}" could not be resolved. It may be expired or not found.`,
);
return null;
}
return { address: resolvedAddr, nfd: address };
}
return { address, nfd: null };
}),
);

setResolvedAddresses(resolved);
// Filter out any null values from failed NFD resolutions
const validAddresses = resolved.filter(
(addr): addr is ResolvedAddress => addr !== null,
);
setResolvedAddresses(validAddresses);

// If we had addresses but none resolved successfully, that's an error state
if (addresses.length > 0 && validAddresses.length === 0) {
setError(true);
}
} catch (err) {
console.error(err);
setError(true);
Expand Down
Loading