14.05.2026 rip

This commit is contained in:
2026-05-14 15:50:22 +03:00
parent 0f88a68c59
commit 79f1ee371b
8 changed files with 142 additions and 7 deletions

View File

@@ -0,0 +1,69 @@
import { useAllWalletBalances, usePrices } from '@features/wallet'
import { CHAINS } from '@features/wallet'
import { TOKENS } from './tokens'
import type { WalletBalanceData } from '@features/wallet'
const PRICE_SYMBOLS = ['BTC', 'ETH', 'SOL', 'TRX', 'ARB']
type ChainSource =
| { chain: 'BTC' | 'ETH' | 'SOL' | 'TRX'; type: 'native' }
| { chain: 'ETH'; type: 'token'; symbol: string }
const CHAIN_MAP: Record<string, ChainSource> = {
BTC: { chain: 'BTC', type: 'native' },
ETH: { chain: 'ETH', type: 'native' },
SOL: { chain: 'SOL', type: 'native' },
TRX: { chain: 'TRX', type: 'native' },
ARB: { chain: 'ETH', type: 'token', symbol: 'ARB' },
}
function formatUsd(value: number): string {
return `$${value.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
}
function formatPrice(value: number): string {
if (value >= 1) {
return `$${value.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
}
return `$${value.toLocaleString('en-US', { minimumFractionDigits: 4, maximumFractionDigits: 6 })}`
}
export function useTokenRows() {
const balanceResults = useAllWalletBalances()
const pricesQuery = usePrices(PRICE_SYMBOLS)
const isLoading = balanceResults.some(r => r.isLoading) || pricesQuery.isLoading
const balanceByChain: Record<string, WalletBalanceData> = {}
CHAINS.forEach((chain, i) => {
const data = balanceResults[i].data
if (data) balanceByChain[chain] = data
})
const rows = TOKENS.map(t => {
const src = CHAIN_MAP[t.ticker]
const chainData = src ? balanceByChain[src.chain] : undefined
let bal = t.bal
let usd = t.usd
if (chainData) {
const amount =
src.type === 'native'
? chainData.native
: chainData.tokens[src.type === 'token' ? src.symbol : t.ticker]
if (amount) {
bal = amount.formatted
usd = formatUsd(amount.usdValue)
}
}
const priceEntry = pricesQuery.data?.[t.ticker]
const price = priceEntry ? formatPrice(priceEntry.usd) : t.price
return { ...t, price, bal, usd }
})
return { rows, isLoading }
}

View File

@@ -3,6 +3,12 @@
border: 1px solid var(--glass-border);
border-radius: 20px;
overflow: hidden;
transition: opacity 0.2s;
}
.loading {
opacity: 0.6;
pointer-events: none;
}
.table {

View File

@@ -1,9 +1,10 @@
import { useState } from 'react'
import { TOKENS } from '../model/tokens'
import { useTokenRows } from '../model/useTokenRows'
import styles from './TokenTable.module.css'
export function TokenTable() {
const [favs, setFavs] = useState<boolean[]>(TOKENS.map((t) => t.fav))
const { rows, isLoading } = useTokenRows()
const [favs, setFavs] = useState<boolean[]>(() => rows.map((t) => t.fav))
function toggleFav(i: number) {
setFavs((prev) => prev.map((v, idx) => (idx === i ? !v : v)))
@@ -17,7 +18,7 @@ export function TokenTable() {
return (
<>
<div className={styles.wrap}>
<div className={`${styles.wrap} ${isLoading ? styles.loading : ''}`}>
{/* Desktop table */}
<table className={styles.table}>
<thead>
@@ -31,7 +32,7 @@ export function TokenTable() {
</tr>
</thead>
<tbody>
{TOKENS.map((t, i) => (
{rows.map((t, i) => (
<tr key={t.ticker}>
<td>
<button
@@ -81,7 +82,7 @@ export function TokenTable() {
{/* Mobile card list */}
<div className={styles.mobileList}>
{TOKENS.map((t, i) => (
{rows.map((t, i) => (
<div key={t.ticker} className={styles.card}>
<button
className={`${styles.star} ${favs[i] ? styles.starOn : ''}`}