Files
solace-bg-dubai/frontend/components/web3/WalletBalancePanel.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

133 lines
3.8 KiB
TypeScript

"use client";
import { useTokenBalances } from "@/lib/hooks/useTokenBalances";
import {
formatUsd,
tokenUsdValue,
useUsdPrices,
} from "@/lib/prices";
import { formatTokenAmount } from "@/lib/tokens";
import { formatAddress } from "@/lib/utils";
import { CHAIN138_ID } from "@/lib/constants/chain138";
interface WalletBalancePanelProps {
address: `0x${string}`;
onDisconnect?: () => void;
}
function BalanceRow({
label,
amount,
usd,
loading,
}: {
label: string;
amount: string;
usd: number | null;
loading?: boolean;
}) {
return (
<div className="flex items-center justify-between gap-3 py-2 border-b border-gray-800 last:border-b-0">
<div>
<p className="text-sm font-medium text-gray-200">{label}</p>
<p className="text-xs text-gray-500 font-mono">
{loading ? "Loading…" : amount}
</p>
</div>
<p className="text-sm font-semibold text-emerald-400 tabular-nums">
{loading ? "…" : formatUsd(usd)}
</p>
</div>
);
}
export function WalletBalancePanel({ address, onDisconnect }: WalletBalancePanelProps) {
const { ethUsd, isLoading: pricesLoading } = useUsdPrices();
const {
nativeBalance,
cusdtRaw,
cusdcRaw,
erc20Tokens,
isLoading: balancesLoading,
refetch,
} = useTokenBalances(address);
const loading = balancesLoading || pricesLoading;
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);
return (
<div className="p-4 w-full sm:w-80">
<div className="mb-3">
<p className="text-xs uppercase tracking-wide text-gray-500">Connected wallet</p>
<p className="font-mono text-sm text-white mt-0.5">{formatAddress(address)}</p>
<p className="text-xs text-gray-500 mt-1">Chain {CHAIN138_ID} balances</p>
</div>
<div className="rounded-lg bg-gray-950/80 border border-gray-800 px-3">
<BalanceRow
label="ETH"
amount={ethRaw !== undefined ? `${nativeBalance?.formatted ?? "0"} ETH` : "0 ETH"}
usd={ethUsdVal}
loading={loading}
/>
<BalanceRow
label="cUSDT"
amount={
cusdtRaw !== undefined
? formatTokenAmount(cusdtRaw.toString(), erc20Tokens[0])
: "0 cUSDT"
}
usd={cusdtUsd}
loading={loading}
/>
<BalanceRow
label="cUSDC"
amount={
cusdcRaw !== undefined
? formatTokenAmount(cusdcRaw.toString(), erc20Tokens[1])
: "0 cUSDC"
}
usd={cusdcUsd}
loading={loading}
/>
</div>
<div className="flex items-center justify-between mt-3 pt-3 border-t border-gray-800">
<span className="text-xs text-gray-500">Estimated total</span>
<span className="text-base font-bold text-white tabular-nums">
{loading ? "…" : formatUsd(totalUsd)}
</span>
</div>
<div className="flex gap-2 mt-4">
<button
type="button"
onClick={() => refetch()}
className="flex-1 px-3 py-2 text-xs bg-gray-800 hover:bg-gray-700 rounded-lg transition-colors"
>
Refresh
</button>
{onDisconnect && (
<button
type="button"
onClick={onDisconnect}
className="flex-1 px-3 py-2 text-xs bg-red-600/90 hover:bg-red-600 rounded-lg transition-colors"
>
Disconnect
</button>
)}
</div>
</div>
);
}