From 386fd21bb3735e74d5dc2c153630218e1e314373 Mon Sep 17 00:00:00 2001 From: Jason Schwarz Date: Thu, 12 Feb 2026 20:38:27 -0400 Subject: [PATCH 1/2] refactor: adjust claim page --- src/app/claim/loading.tsx | 63 +++++++++++++++++++++++++++ src/lib/analytics-server.ts | 86 ++++++++++++++----------------------- 2 files changed, 95 insertions(+), 54 deletions(-) create mode 100644 src/app/claim/loading.tsx diff --git a/src/app/claim/loading.tsx b/src/app/claim/loading.tsx new file mode 100644 index 0000000..f748166 --- /dev/null +++ b/src/app/claim/loading.tsx @@ -0,0 +1,63 @@ +import { Skeleton } from "@/components/ui/skeleton" +import { Card } from "@/components/ui/card" + +export default function ClaimLoading() { + return ( +
+
+ {/* Header skeleton */} +
+
+ +
+
+ + {/* Hero + content skeleton */} +
+
+ {/* Hero skeleton */} +
+
+ +
+
+ + +
+ +
+ + {/* CTA button skeleton */} +
+ +
+ + {/* Feature cards skeleton */} +
+ {[1, 2, 3].map((i) => ( + +
+ + + + +
+
+ ))} +
+ + {/* Stats row skeleton */} +
+ {[1, 2, 3].map((i) => ( +
+ + +
+ ))} +
+
+
+
+
+ ) +} diff --git a/src/lib/analytics-server.ts b/src/lib/analytics-server.ts index 681de58..56ff4ff 100644 --- a/src/lib/analytics-server.ts +++ b/src/lib/analytics-server.ts @@ -1,32 +1,24 @@ import { env } from "@/env/server" import { getLeaderboard } from "@/lib/analytics/services/leaderboard.service" import { transformLeaderboardRows } from "@/lib/analytics/services/leaderboard-transform" -import { getActiveTraders as getActiveTradersService } from "@/lib/analytics/services/transactions.service" +import { + getActiveTraders as getActiveTradersService, + getCumulativeSuccessfulTransactions as getCumulativeSuccessfulTransactionsService, + getSwapVolume as getSwapVolumeService, +} from "@/lib/analytics/services/transactions.service" + +const FUUL_PAYOUTS_SUMMARY_URL = "https://api.fuul.xyz/api/v1/payouts/summary" /** - * Server-side function to fetch cumulative successful transactions from analytics API - * Calls the internal API route which handles the external API call + * Server-side function to fetch cumulative successful transactions. + * Calls the analytics service directly to avoid self-referencing HTTP on Vercel. */ export async function getCumulativeTransactions(): Promise { try { - // Call the internal API route - const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000" - const response = await fetch(`${baseUrl}/api/analytics/transactions`, { - cache: "no-store", + const cumulativeTxs = await getCumulativeSuccessfulTransactionsService({ + catalog: "fastrpc", }) - - if (!response.ok) { - console.error("Failed to fetch transactions:", response.statusText) - return null - } - - const data = await response.json() - - if (data.success && data.cumulativeSuccessfulTxs !== null) { - return Number(data.cumulativeSuccessfulTxs) - } - - return null + return cumulativeTxs } catch (error) { console.error("Error fetching cumulative transactions:", error) return null @@ -65,30 +57,15 @@ export async function getEthPrice(): Promise { } /** - * Server-side function to fetch cumulative swap volume from analytics API - * Calls the internal API route which handles the external API call + * Server-side function to fetch cumulative swap volume. + * Calls the analytics service directly to avoid self-referencing HTTP on Vercel. */ export async function getCumulativeSwapVolume(): Promise<{ eth: number | null usd: number | null }> { try { - const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000" - const response = await fetch(`${baseUrl}/api/analytics/volume/swap`, { - cache: "no-store", - }) - - if (!response.ok) { - console.error("Failed to fetch swap volume:", response.statusText) - return { eth: null, usd: null } - } - - const data = await response.json() - if (!data.success) return { eth: null, usd: null } - - const eth = data.cumulativeSwapVolEth != null ? Number(data.cumulativeSwapVolEth) : null - const usd = data.cumulativeSwapVolUsd != null ? Number(data.cumulativeSwapVolUsd) : null - return { eth, usd } + return await getSwapVolumeService() } catch (error) { console.error("Error fetching cumulative swap volume:", error) return { eth: null, usd: null } @@ -126,33 +103,34 @@ export async function getSwapTransactionCount(): Promise { } /** - * Server-side function to fetch total points earned from Fuul payout summary - * Calls the internal API route which handles the external API call + * Server-side function to fetch total points earned from Fuul payout summary. + * Calls Fuul API directly to avoid self-referencing HTTP on Vercel. */ export async function getTotalPointsEarned(): Promise { try { - // Call the internal API route - const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000" - const response = await fetch(`${baseUrl}/api/fuul/payouts-summary?currency=point`, { + const fuulApiKey = env.FUUL_API_KEY + if (!fuulApiKey) { + console.error("FUUL_API_KEY not configured") + return null + } + const url = new URL(FUUL_PAYOUTS_SUMMARY_URL) + url.searchParams.set("currency", "point") + const response = await fetch(url.toString(), { + method: "GET", + headers: { + accept: "application/json", + Authorization: `Bearer ${fuulApiKey}`, + }, cache: "no-store", }) - if (!response.ok) { - console.error("Failed to fetch payout summary:", response.statusText) + console.error("Failed to fetch payout summary:", response.status, await response.text()) return null } - const data = await response.json() - - if ( - data.success && - data.data && - data.data.total_payouts !== null && - data.data.total_payouts !== undefined - ) { + if (data.data && data.data.total_payouts !== null && data.data.total_payouts !== undefined) { return Number(data.data.total_payouts) } - return null } catch (error) { console.error("Error fetching total points earned:", error) From d769ba7726885a1ec638d94709534cf221f69304 Mon Sep 17 00:00:00 2001 From: Jason Schwarz Date: Thu, 12 Feb 2026 20:43:58 -0400 Subject: [PATCH 2/2] refactor: adjust referral page --- src/app/referral/loading.tsx | 5 +++ src/app/referral/page.tsx | 9 +---- .../referral/ReferralPageSkeleton.tsx | 39 +++++++++++++++++++ 3 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 src/app/referral/loading.tsx create mode 100644 src/components/referral/ReferralPageSkeleton.tsx diff --git a/src/app/referral/loading.tsx b/src/app/referral/loading.tsx new file mode 100644 index 0000000..89eab77 --- /dev/null +++ b/src/app/referral/loading.tsx @@ -0,0 +1,5 @@ +import { ReferralPageSkeleton } from "@/components/referral/ReferralPageSkeleton" + +export default function ReferralLoading() { + return +} diff --git a/src/app/referral/page.tsx b/src/app/referral/page.tsx index 311b9f0..03fbcdf 100644 --- a/src/app/referral/page.tsx +++ b/src/app/referral/page.tsx @@ -9,6 +9,7 @@ import { ArrowRight } from "lucide-react" import { Fuul } from "@fuul/sdk" import { isAddress } from "viem" import "@/lib/fuul" +import { ReferralPageSkeleton } from "@/components/referral/ReferralPageSkeleton" function ReferralPageContent() { const router = useRouter() @@ -166,13 +167,7 @@ function ReferralPageContent() { export default function ReferralPage() { return ( - -
Loading...
- - } - > + }> ) diff --git a/src/components/referral/ReferralPageSkeleton.tsx b/src/components/referral/ReferralPageSkeleton.tsx new file mode 100644 index 0000000..e13a99d --- /dev/null +++ b/src/components/referral/ReferralPageSkeleton.tsx @@ -0,0 +1,39 @@ +import { Skeleton } from "@/components/ui/skeleton" + +/** + * Shared skeleton for the referral page layout. + * Used by src/app/referral/loading.tsx and the Suspense fallback in page.tsx + * so LCP is fast and CLS is minimal when real content loads. + */ +export function ReferralPageSkeleton() { + return ( +
+ {/* Background effects - match referral page */} +
+
+ +
+ {/* Header - logo area + Referral title */} +
+
+ + +
+
+ + {/* Main - hero + CTA skeleton */} +
+
+
+ + +
+
+ +
+
+
+
+
+ ) +}