14.05.2026 rip
This commit is contained in:
69
src/widgets/token-table/model/useTokenRows.ts
Normal file
69
src/widgets/token-table/model/useTokenRows.ts
Normal 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 }
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 : ''}`}
|
||||
|
||||
Reference in New Issue
Block a user