Skip to content

Commit

Permalink
feat: add retryable loader for token page
Browse files Browse the repository at this point in the history
  • Loading branch information
MartianGreed committed Oct 31, 2024
1 parent c920f42 commit 3b03ef3
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 62 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { useSuspenseLoadingTokens } from "~/hooks/useTokenLoading";
import TokenSummary from "./token-summary";
import TokenStats from "./token-stats";
import TokenActions from "./token-actions";
import TokenOffers from "./token-offers";
import TokenTraits from "./token-traits";
import TokenAbout from "./token-about";
import TokenActivity from "./token-activity";
import { notFound } from "next/navigation";

interface TokenPageDetailsProps {
contractAddress: string;
tokenId: string;
}

export function TokenPageDetails({ contractAddress, tokenId }: TokenPageDetailsProps) {
const { token, tokenMarketData } = useSuspenseLoadingTokens({ contractAddress, tokenId });

if (null === token || null === tokenMarketData) {
return notFound()
}

return (
<main className="mx-auto max-w-[120rem] p-5 pt-0 lg:p-8">
<div className="grid grid-cols-1 gap-5 lg:grid-cols-[minmax(0,1fr)_minmax(0,2fr)] lg:gap-8">
<TokenSummary
className="top-[calc(var(--site-header-height)+2rem)] h-fit lg:sticky"
token={token}
/>
<div className="flex flex-col lg:gap-8">
<div className="flex flex-col-reverse gap-5 lg:flex-col lg:gap-8">
<TokenStats
token={token}
tokenMarketData={tokenMarketData}
className="mb-5 lg:mb-0"
/>
<TokenActions
token={token}
tokenMarketData={tokenMarketData}
className="-mx-5 lg:mx-0"
/>
</div>
<TokenOffers
token={token}
tokenMarketData={tokenMarketData}
className="-mx-5 lg:mx-0"
/>
<TokenTraits
className="-mx-5 lg:mx-0"
contractAddress={contractAddress}
tokenAttributes={token.metadata?.attributes ?? []}
/>
<TokenAbout
className="-mx-5 lg:mx-0"
contractAddress={contractAddress}
token={token}
tokenId={tokenId}
/>
</div>
</div>
<TokenActivity
className="mt-6 lg:mt-20"
contractAddress={contractAddress}
tokenId={tokenId}
/>
</main>
)
}

export function TokenPageDetailsSkeleton() {
return (
<main className="max-w-[120rem] p-5 pt-0 lg:p-8">
<div className="grid grid-cols-1 gap-5 lg:grid-cols-[minmax(0,1fr)_minmax(0,2fr)] lg:gap-8">
<div className="top-[calc(var(--site-header-height)+2rem)] h-fit lg:sticky">
<div className="h-[400px] animate-pulse rounded-lg bg-gray-200"></div>
</div>
<div className="flex flex-col lg:gap-8">
<div className="flex flex-col-reverse gap-5 lg:flex-col lg:gap-8">
<div className="mb-5 lg:mb-0">
<div className="h-[200px] animate-pulse rounded-lg bg-gray-200"></div>
</div>
<div className="-mx-5 lg:mx-0">
<div className="h-[150px] animate-pulse rounded-lg bg-gray-200"></div>
</div>
</div>
<div className="-mx-5 lg:mx-0">
<div className="h-[200px] animate-pulse rounded-lg bg-gray-200"></div>
</div>
<div className="-mx-5 lg:mx-0">
<div className="h-[180px] animate-pulse rounded-lg bg-gray-200"></div>
</div>
<div className="-mx-5 lg:mx-0">
<div className="h-[250px] animate-pulse rounded-lg bg-gray-200"></div>
</div>
</div>
</div>
<div className="mt-6 lg:mt-20">
<div className="h-[300px] animate-pulse rounded-lg bg-gray-200"></div>
</div>
</main>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ export default function TokenStats({
? starkProfile.name
: data.owner
? ownerOrShortAddress({
ownerAddress: data.owner,
address,
})
ownerAddress: data.owner,
address,
})
: "";

const floor = data.floor ? formatEther(BigInt(data.floor)) : "_";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default function TokenSummary({
className,
token,
}: PropsWithClassName<TokenSummaryProps>) {

return (
<div
className={cn(
Expand Down
64 changes: 9 additions & 55 deletions apps/arkmarket/src/app/token/[contractAddress]/[tokenId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@

import { notFound } from "next/navigation";

import TokenAbout from "./components/token-about";
import TokenActions from "./components/token-actions";
import TokenActivity from "./components/token-activity";
import TokenOffers from "./components/token-offers";
import TokenStats from "./components/token-stats";
import TokenSummary from "./components/token-summary";
import TokenTraits from "./components/token-traits";
import { useTokenLoading } from "~/hooks/useTokenLoading";
import { Suspense } from "react";
import { TokenPageDetails, TokenPageDetailsSkeleton } from "./components/token-page-details";
import { CollectionDescription } from "~/config/homepage";

interface TokenPageProps {
params: {
Expand All @@ -21,16 +17,11 @@ interface TokenPageProps {
export default async function TokenPage({
params: { contractAddress, tokenId },
}: TokenPageProps) {
const { token, tokenMarketData, isRealmsCollection, isLoading } = await useTokenLoading({ contractAddress, tokenId });

const isRealmsCollection = CollectionDescription[contractAddress];
if (!isRealmsCollection) {
return notFound();
}

if (!token?.owner || !tokenMarketData) {
return notFound();
}

return (
<>
<head>
Expand All @@ -39,49 +30,12 @@ export default async function TokenPage({
content={`https://ark-market-unframed.vercel.app/api/og/token?collection_address=${contractAddress}&token_id=${tokenId}`}
/>
</head>
<main className="mx-auto max-w-[120rem] p-5 pt-0 lg:p-8">
<div className="grid grid-cols-1 gap-5 lg:grid-cols-[minmax(0,1fr)_minmax(0,2fr)] lg:gap-8">
<TokenSummary
className="top-[calc(var(--site-header-height)+2rem)] h-fit lg:sticky"
token={token}
<Suspense fallback={<TokenPageDetailsSkeleton />}>
<TokenPageDetails
contractAddress={contractAddress}
tokenId={tokenId}
/>
<div className="flex flex-col lg:gap-8">
<div className="flex flex-col-reverse gap-5 lg:flex-col lg:gap-8">
<TokenStats
token={token}
tokenMarketData={tokenMarketData}
className="mb-5 lg:mb-0"
/>
<TokenActions
token={token}
tokenMarketData={tokenMarketData}
className="-mx-5 lg:mx-0"
/>
</div>
<TokenOffers
token={token}
tokenMarketData={tokenMarketData}
className="-mx-5 lg:mx-0"
/>
<TokenTraits
className="-mx-5 lg:mx-0"
contractAddress={contractAddress}
tokenAttributes={token.metadata?.attributes ?? []}
/>
<TokenAbout
className="-mx-5 lg:mx-0"
contractAddress={contractAddress}
token={token}
tokenId={tokenId}
/>
</div>
</div>
<TokenActivity
className="mt-6 lg:mt-20"
contractAddress={contractAddress}
tokenId={tokenId}
/>
</main>
</Suspense>
</>
);
}
29 changes: 25 additions & 4 deletions apps/arkmarket/src/hooks/useTokenLoading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,31 @@ interface UseTokenLoadingResponse {
token: Token | null;
tokenMarketData: TokenMarketData | null;
isRealmsCollection: boolean;
isLoading: boolean;
}
const timeout = async (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const withRetry = async (fn, params) => {
let value
let counter = 0;
while (!value) {
++counter;
try {
value = await fn(params);
} catch (err) {
if (counter >= 30) {
return null;
}
await timeout(3000);
console.error(`Retrying ${fn} to fetch data ${err}`);
}
}
return value;

}

export function useSuspenseLoadingTokens({ contractAddress, tokenId }: UseTokenLoadingParams) {
const token = use(withRetry(getToken, { contractAddress, tokenId }));
const tokenMarketData = use(withRetry(getTokenMarketData, { contractAddress, tokenId }));
return { token, tokenMarketData };
}

export async function useTokenLoading({ contractAddress, tokenId }: UseTokenLoadingParams): Promise<UseTokenLoadingResponse> {
Expand All @@ -23,14 +47,12 @@ export async function useTokenLoading({ contractAddress, tokenId }: UseTokenLoad
contractAddress,
tokenId,
});

} catch (err) {
console.error(err)
return {
token: null,
tokenMarketData: null,
isRealmsCollection: false,
isLoading: false,
};
}

Expand All @@ -45,7 +67,6 @@ export async function useTokenLoading({ contractAddress, tokenId }: UseTokenLoad
token,
tokenMarketData,
isRealmsCollection: !!collection,
isLoading: false,
};
}

0 comments on commit 3b03ef3

Please sign in to comment.