diff --git a/src/features/wallet/components/AssetBalanceGrid.tsx b/src/features/wallet/components/AssetBalanceGrid.tsx new file mode 100644 index 0000000..e9f6556 --- /dev/null +++ b/src/features/wallet/components/AssetBalanceGrid.tsx @@ -0,0 +1,72 @@ +'use client'; + +import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/components/ui/card'; +import { Wallet } from 'lucide-react'; +import { formatCurrency, formatRelativeTime } from '@/lib/format'; +import { AssetCard } from './AssetCard'; +import type { WalletSummary } from '../types'; + +interface AssetBalanceGridProps { + summary: WalletSummary | null; + isLoading?: boolean; +} + +export function AssetBalanceGrid({ summary, isLoading }: AssetBalanceGridProps) { + if (isLoading) { + return ( + +
+
+
+
+
+ + ); + } + + if (!summary || summary.assets.length === 0) { + return ( + +
+ +

No assets found

+

+ Your wallet does not hold any Stellar assets yet. Once you receive tokens, they will appear here. +

+
+
+ ); + } + + return ( +
+ + +
+
+ Asset Balances + + Multi-asset overview across your Stellar wallet + +
+
+

+ {formatCurrency(summary.totalUsdValue, 'USD')} +

+

+ Total Value · {formatRelativeTime(summary.lastUpdated)} +

+
+
+
+ +
+ {summary.assets.map((asset) => ( + + ))} +
+
+
+
+ ); +} diff --git a/src/features/wallet/components/AssetCard.tsx b/src/features/wallet/components/AssetCard.tsx new file mode 100644 index 0000000..8404ebf --- /dev/null +++ b/src/features/wallet/components/AssetCard.tsx @@ -0,0 +1,56 @@ +'use client'; + +import { Card, CardContent } from '@/components/ui/card'; +import { Badge } from '@/components/ui/badge'; +import { formatCurrency } from '@/lib/format'; +import type { AssetBalance } from '../types'; + +interface AssetCardProps { + asset: AssetBalance; +} + +const ASSET_COLORS: Record = { + XLM: 'bg-info-soft text-info', + USDC: 'bg-success-soft text-success', + EURC: 'bg-gold-soft text-gold-strong', + ASTRO: 'bg-warning-soft text-warning', +}; + +export function AssetCard({ asset }: AssetCardProps) { + const usdValue = asset.balance * asset.usdPrice; + const colorClass = ASSET_COLORS[asset.code] ?? 'bg-surface-secondary text-foreground-secondary'; + + return ( + + +
+
+
+ {asset.code} +
+
+

{asset.name}

+

{asset.code}

+
+
+ + ${asset.usdPrice.toFixed(2)} + +
+ +
+
+ + {formatCurrency(asset.balance, asset.code)} + +
+

+ {formatCurrency(usdValue, 'USD')} equivalent +

+
+
+
+ ); +} diff --git a/src/features/wallet/index.ts b/src/features/wallet/index.ts new file mode 100644 index 0000000..5236035 --- /dev/null +++ b/src/features/wallet/index.ts @@ -0,0 +1,4 @@ +export { AssetBalanceGrid } from './components/AssetBalanceGrid'; +export { AssetCard } from './components/AssetCard'; +export type { AssetBalance, AssetCode, WalletSummary } from './types'; +export { MOCK_WALLET_SUMMARY, MOCK_ASSET_BALANCES } from './mock-data'; diff --git a/src/features/wallet/mock-data.ts b/src/features/wallet/mock-data.ts index 024fc8c..cacf2c4 100644 --- a/src/features/wallet/mock-data.ts +++ b/src/features/wallet/mock-data.ts @@ -1,57 +1,47 @@ -import type { StellarAsset } from './types'; +import type { AssetBalance, WalletSummary } from './types'; -/** - * Preset list of well-known Stellar assets. - * Issuer keys are real Stellar mainnet addresses for these tokens. - */ -export const presetAssets: StellarAsset[] = [ +export const MOCK_ASSET_BALANCES: AssetBalance[] = [ { + id: 'ast-xlm', + code: 'XLM', + name: 'Stellar Lumens', + balance: 12450.75, + usdPrice: 0.12, + decimals: 7, + }, + { + id: 'ast-usdc', code: 'USDC', - issuer: 'GA5ZSEJYB37JTH5UA4GHHQTUWQZ3XMY4Y2S3VHLW7A7I73ZMIFR67LMZ', name: 'USD Coin', - verification: 'verified', - trustline: 'trusted', + balance: 8420.5, + usdPrice: 1.0, + issuer: 'GA5ZSEJ6B3AE8RGX3C古城L4PBRPSNY7HO6AZGEBTXOZMOI57DPMGBGI', + decimals: 7, }, { + id: 'ast-eurc', code: 'EURC', - issuer: 'GDQOE23C4MMKFZ25LZ5SE6Y56NYCJ7NKVP6YSO7HA7KJLJ7T6S5YEUU', name: 'Euro Coin', - verification: 'verified', - trustline: 'untrusted', - }, - { - code: 'yXLM', - issuer: 'GALPCCUINT6MUDRN6PMKG6CLTEL3TE3KDEFSAU5T2RUEETE5Z5EMX25VP', - name: 'yXLM (Superfluid)', - verification: 'verified', - trustline: 'untrusted', - }, - { - code: 'ARST', - issuer: 'GBSTZN5OZTUIJ5ZG4N6XZSOPCJ5T765B5N7L4YELLGLO2ZBEDJWN7B1A', - name: 'Arst', - verification: 'verified', - trustline: 'untrusted', + balance: 3200.0, + usdPrice: 1.09, + issuer: 'GAXLKZUT5RRPOOMN6HEB3TTSX5IREHBWMFT76Y2G4Q377E3VZE5BN2EQ', + decimals: 7, }, { - code: 'BTC', - issuer: 'GAUTUYYRTHMLUOVG7VZ7S5S7N3H3RE7V6Y3S3Z4J5Z2YX4QH4ZXXXX', - name: 'Bitcoin on Stellar', - verification: 'unverified', - trustline: 'untrusted', - }, - { - code: 'ETH', - issuer: 'GBVOLZ7F7Y7EVJZXEWZ3F6V3EODV4YU4GIOFAPJFHTJL4R7PKM3KJP7F', - name: 'Ethereum on Stellar', - verification: 'unverified', - trustline: 'untrusted', - }, - { - code: 'SRT', - issuer: 'GSSPDVH3SS66RCPPLJDCNLD4PC6S5KSJVYAJI7GPXGCQ7ESKC3STHT4A', - name: 'Soroban token', - verification: 'unverified', - trustline: 'untrusted', + id: 'ast-astro', + code: 'ASTRO', + name: 'Astroid Token', + balance: 45000.0, + usdPrice: 0.05, + decimals: 7, }, ]; + +export const MOCK_WALLET_SUMMARY: WalletSummary = { + totalUsdValue: MOCK_ASSET_BALANCES.reduce( + (sum, asset) => sum + asset.balance * asset.usdPrice, + 0, + ), + assets: MOCK_ASSET_BALANCES, + lastUpdated: new Date().toISOString(), +}; diff --git a/src/features/wallet/types.ts b/src/features/wallet/types.ts index 19917ee..dbc20f3 100644 --- a/src/features/wallet/types.ts +++ b/src/features/wallet/types.ts @@ -1,23 +1,18 @@ -/** An asset entry in the Stellar Asset Directory. */ +export type AssetCode = 'XLM' | 'USDC' | 'EURC' | 'ASTRO'; -export type AssetVerificationStatus = 'verified' | 'unverified'; - -export type AssetTrustlineStatus = 'trusted' | 'untrusted'; - -export interface StellarAsset { - /** Short code, e.g. "USDC", "EURC", "yXLM". Max 12 alphanumeric chars. */ - code: string; - /** Stellar issuer public key (starts with 'G', 56 characters). */ - issuer: string; - /** Human-readable name, e.g. "USD Coin". */ +export interface AssetBalance { + id: string; + code: AssetCode; name: string; - /** Whether the issuer has been verified by the directory. */ - verification: AssetVerificationStatus; - /** Whether the current wallet holds a trustline for this asset. */ - trustline: AssetTrustlineStatus; + balance: number; + usdPrice: number; + iconUrl?: string; + issuer?: string; + decimals: number; } -export interface AddAssetFormValues { - code: string; - issuer: string; +export interface WalletSummary { + totalUsdValue: number; + assets: AssetBalance[]; + lastUpdated: string; }