Files
solace-bg-dubai/frontend/components/dashboard/BalanceDisplay.tsx
defiQUG a03417be98
All checks were successful
CI / lint-and-test (push) Successful in 9m52s
chore: consolidate local WIP (repo cleanup 20260707)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 09:41:38 -07:00

127 lines
5.0 KiB
TypeScript

"use client";
import { useEffect, useRef } from "react";
import { gsap } from "gsap";
import { CONTRACT_ADDRESSES } from "@/lib/web3/contracts";
import { CHAIN138_TOKENS, formatTokenAmount } from "@/lib/tokens";
import { useTokenBalances } from "@/lib/hooks/useTokenBalances";
import { formatUsd, tokenUsdValue, useUsdPrices } from "@/lib/prices";
import { formatAddress } from "@/lib/utils";
import { CHAIN138_ID } from "@/lib/constants/chain138";
export function BalanceDisplay() {
const treasuryAddress = CONTRACT_ADDRESSES.TreasuryWallet as `0x${string}` | undefined;
const displayRef = useRef<HTMLDivElement>(null);
const { ethUsd, isLoading: pricesLoading } = useUsdPrices();
const {
nativeBalance,
cusdtRaw,
cusdcRaw,
erc20Tokens,
isLoading: balancesLoading,
} = useTokenBalances(treasuryAddress);
const loading = balancesLoading || pricesLoading;
useEffect(() => {
if (displayRef.current && nativeBalance) {
gsap.from(displayRef.current, {
opacity: 0,
y: 20,
duration: 0.8,
ease: "power3.out",
});
}
}, [nativeBalance]);
if (loading && !nativeBalance && cusdtRaw === undefined) {
return (
<div className="bg-gray-900 rounded-xl p-8 h-64 flex items-center justify-center">
<p className="text-gray-400">Loading treasury balance</p>
</div>
);
}
if (!treasuryAddress) {
return (
<div className="bg-gray-900 rounded-xl p-8 h-64 flex items-center justify-center">
<p className="text-gray-400">Treasury wallet not configured</p>
</div>
);
}
const ethRaw = nativeBalance?.value;
const ethUsdVal = tokenUsdValue(ethRaw, 18, "ETH", ethUsd);
const cusdtUsd = tokenUsdValue(cusdtRaw, erc20Tokens[0].decimals, "cUSDT", ethUsd);
const cusdcUsd = tokenUsdValue(cusdcRaw, erc20Tokens[1].decimals, "cUSDC", ethUsd);
const totalUsd =
[ethUsdVal, cusdtUsd, cusdcUsd].reduce<number | null>((sum, v) => {
if (v == null) return sum;
return (sum ?? 0) + v;
}, null) ?? 0;
const formattedNative = nativeBalance?.formatted ?? "0";
return (
<div ref={displayRef} className="relative bg-gray-900 rounded-xl p-8 overflow-hidden border border-gray-800">
<div className="absolute inset-0 bg-gradient-to-br from-blue-500/10 to-purple-500/10" />
<div className="absolute inset-0 bg-[radial-gradient(circle_at_50%_50%,rgba(59,130,246,0.1),transparent_50%)]" />
<div className="relative z-10">
<div className="flex flex-wrap items-start justify-between gap-3 mb-4">
<div>
<h2 className="text-2xl font-semibold bg-gradient-to-r from-blue-400 to-purple-400 bg-clip-text text-transparent">
Treasury Balance
</h2>
<p className="text-xs text-gray-500 mt-1 font-mono">
Multisig · {formatAddress(treasuryAddress)} · Chain {CHAIN138_ID}
</p>
</div>
<div className="text-right">
<p className="text-xs text-gray-500">Estimated total</p>
<p className="text-xl font-bold text-white tabular-nums">{formatUsd(totalUsd)}</p>
</div>
</div>
<div className="flex items-center gap-8">
<div className="flex-1 space-y-4">
<div className="flex items-end justify-between gap-4">
<div>
<p className="text-5xl font-bold mb-1 bg-gradient-to-r from-white to-gray-300 bg-clip-text text-transparent">
{formattedNative}
</p>
<p className="text-gray-400">{nativeBalance?.symbol ?? "ETH"}</p>
</div>
<p className="text-lg text-emerald-400 tabular-nums pb-1">{formatUsd(ethUsdVal)}</p>
</div>
{cusdtRaw !== undefined && (
<div className="flex items-center justify-between gap-4 text-sm">
<span className="text-gray-400">
{formatTokenAmount(cusdtRaw.toString(), erc20Tokens[0])}
</span>
<span className="text-emerald-400 tabular-nums">{formatUsd(cusdtUsd)}</span>
</div>
)}
{cusdcRaw !== undefined && (
<div className="flex items-center justify-between gap-4 text-sm">
<span className="text-gray-400">
{formatTokenAmount(cusdcRaw.toString(), erc20Tokens[1])}
</span>
<span className="text-emerald-400 tabular-nums">{formatUsd(cusdcUsd)}</span>
</div>
)}
</div>
<div className="w-64 h-64 hidden sm:flex items-center justify-center">
<div
className="relative w-40 h-40 rounded-full border-2 border-blue-500/40 shadow-[0_0_40px_rgba(59,130,246,0.25)] animate-[spin_24s_linear_infinite]"
aria-hidden
>
<div className="absolute inset-3 rounded-full border border-purple-500/30" />
<div className="absolute inset-8 rounded-full bg-gradient-to-br from-blue-500/20 to-purple-500/20" />
</div>
</div>
</div>
</div>
</div>
);
}