From fcfdac87b41de3395ad1f03f70360fecc1e3e8b0 Mon Sep 17 00:00:00 2001 From: rassadin11 Date: Thu, 14 May 2026 20:05:35 +0300 Subject: [PATCH] 14.05.2026 rip --- src/features/wallet/index.ts | 2 +- src/features/wallet/model/useWalletData.ts | 8 +++ src/widgets/swap-form/model/useSwapForm.ts | 71 ++++++++++++++++++++ src/widgets/swap-form/ui/SwapCard.module.css | 31 +++++++++ src/widgets/swap-form/ui/SwapCard.tsx | 21 +++++- src/widgets/swap-form/ui/SwapForm.tsx | 22 +++++- 6 files changed, 150 insertions(+), 5 deletions(-) diff --git a/src/features/wallet/index.ts b/src/features/wallet/index.ts index bde6543..ac65156 100644 --- a/src/features/wallet/index.ts +++ b/src/features/wallet/index.ts @@ -1,3 +1,3 @@ -export { useAllWalletBalances, usePrices, useSendWallet, useWalletAddresses } from './model/useWalletData' +export { useAllWalletBalances, usePrices, useSendWallet, useWalletAddresses, useWalletBalance } from './model/useWalletData' export type { Chain, FormattedAmount, WalletBalanceData, PriceEntry, SendWalletPayload, SendWalletResponse, WalletAddress } from './api/walletApi' export { CHAINS } from './api/walletApi' diff --git a/src/features/wallet/model/useWalletData.ts b/src/features/wallet/model/useWalletData.ts index b8f1841..7d82db8 100644 --- a/src/features/wallet/model/useWalletData.ts +++ b/src/features/wallet/model/useWalletData.ts @@ -1,6 +1,14 @@ import { useQuery, useQueries, useMutation } from '@tanstack/react-query' import { getWalletBalance, getPrices, sendWallet, getWalletAddresses, CHAINS, type Chain, type SendWalletPayload } from '../api/walletApi' +export function useWalletBalance(chain: Chain) { + return useQuery({ + queryKey: ['wallet', 'balance', chain], + queryFn: () => getWalletBalance(chain), + staleTime: 30_000, + }) +} + export function useAllWalletBalances() { return useQueries({ queries: CHAINS.map(chain => ({ diff --git a/src/widgets/swap-form/model/useSwapForm.ts b/src/widgets/swap-form/model/useSwapForm.ts index 3ac79df..07c53d2 100644 --- a/src/widgets/swap-form/model/useSwapForm.ts +++ b/src/widgets/swap-form/model/useSwapForm.ts @@ -4,6 +4,7 @@ import eth from '@shared/assets/eth.svg' import sol from '@shared/assets/sol.svg' import trx from '@shared/assets/trx.svg' import arb from '@shared/assets/arb.svg' +import type { WalletBalanceData } from '@features/wallet' export interface Token { symbol: string @@ -27,6 +28,76 @@ const TOKENS: Record = { export const TOKENS_LIST: Token[] = Object.values(TOKENS) +export const TOKEN_META: Record = { + // Native / major + BTC: { letter: '₿', logo: btc, color: '#F7931A' }, + ETH: { letter: 'E', logo: eth, color: '#627EEA' }, + BNB: { letter: 'B', color: '#F3BA2F' }, + SOL: { letter: 'S', logo: sol, color: '#9945FF' }, + TRX: { letter: 'T', logo: trx, color: '#FF060A' }, + ARB: { letter: 'A', logo: arb, color: '#4A6DFF' }, + // Stablecoins + USDC: { letter: '$', color: '#2775CA' }, + USDT: { letter: '$', color: '#26A17B' }, + DAI: { letter: 'D', color: '#F5AC37' }, + BUSD: { letter: 'B', color: '#F0B90B' }, + // ETH tokens + WBTC: { letter: 'W', color: '#F7931A' }, + LINK: { letter: 'L', color: '#2A5ADA' }, + UNI: { letter: 'U', color: '#FF007A' }, + // BSC tokens + WBNB: { letter: 'W', color: '#F3BA2F' }, + DOGE: { letter: 'D', color: '#C2A633' }, + // SOL tokens + JUP: { letter: 'J', color: '#C7A52D' }, + WIF: { letter: 'W', color: '#9333EA' }, + BONK: { letter: 'B', color: '#FF8C00' }, + RAY: { letter: 'R', color: '#5AC4BE' }, + ORCA: { letter: 'O', color: '#1B8EF2' }, + PYTH: { letter: 'P', color: '#8B5CF6' }, + JTO: { letter: 'J', color: '#06B6D4' }, + W: { letter: 'W', color: '#6B7280' }, + PUMP: { letter: 'P', color: '#00D4AA' }, + POPCAT: { letter: 'P', color: '#FF6B6B' }, + TRUMP: { letter: 'T', color: '#E63946' }, + PENGU: { letter: 'P', color: '#60A5FA' }, +} + +const CHAIN_NATIVE: Record = { + ETH: 'ETH', BSC: 'BNB', BTC: 'BTC', TRX: 'TRX', SOL: 'SOL', +} + +export function buildTokensFromBalance(data: WalletBalanceData): Token[] { + const result: Token[] = [] + + const nativeSym = CHAIN_NATIVE[data.chain] ?? data.chain + const nativeMeta = TOKEN_META[nativeSym] + result.push({ + symbol: nativeSym, + letter: nativeMeta?.letter ?? nativeSym[0], + color: nativeMeta?.color ?? '#888', + logo: nativeMeta?.logo, + network: data.chain, + balance: parseFloat(data.native.formatted), + usdRate: data.native.usdPrice, + }) + + for (const [sym, info] of Object.entries(data.tokens)) { + const meta = TOKEN_META[sym] + result.push({ + symbol: sym, + letter: meta?.letter ?? sym[0], + color: meta?.color ?? '#888', + logo: meta?.logo, + network: data.chain, + balance: parseFloat(info.formatted), + usdRate: info.usdPrice, + }) + } + + return result +} + const RATE = 82.2578 export function useSwapForm() { diff --git a/src/widgets/swap-form/ui/SwapCard.module.css b/src/widgets/swap-form/ui/SwapCard.module.css index e63f8de..438c97f 100644 --- a/src/widgets/swap-form/ui/SwapCard.module.css +++ b/src/widgets/swap-form/ui/SwapCard.module.css @@ -50,6 +50,37 @@ font-weight: 500; } +/* ── Network buttons ── */ +.networkPills { + display: flex; + align-items: center; + gap: 5px; +} + +.networkBtn { + background: rgba(255, 255, 255, 0.07); + color: var(--text-secondary); + border: none; + border-radius: 999px; + padding: 4px 10px; + font-size: 11px; + cursor: pointer; + font-family: var(--font-sans); + font-weight: 600; + transition: all 0.2s; + letter-spacing: 0.4px; +} + +.networkBtn:hover { + color: var(--text-primary); + background: rgba(255, 255, 255, 0.13); +} + +.networkBtnActive { + background: rgba(255, 255, 255, 0.18); + color: var(--text-primary); +} + /* ── Pills inside card (desktop only) ── */ .pillsInner { display: flex; diff --git a/src/widgets/swap-form/ui/SwapCard.tsx b/src/widgets/swap-form/ui/SwapCard.tsx index 8035f72..cb04b04 100644 --- a/src/widgets/swap-form/ui/SwapCard.tsx +++ b/src/widgets/swap-form/ui/SwapCard.tsx @@ -12,13 +12,18 @@ interface Props { onTokenChange: (token: Token) => void onAmountChange?: (v: string) => void onSetPercent?: (p: number) => void + selectedNetwork?: string + onNetworkChange?: (network: string) => void } +const NETWORKS = ['BTC', 'ETH', 'BSC', 'TRX', 'SOL'] + const PERCENTS = [25, 50, 100] export function SwapCard({ mode, token, tokenOptions, amount, usd, slippage, onTokenChange, onAmountChange, onSetPercent, + selectedNetwork, onNetworkChange, }: Props) { const [intPart, decPart] = amount.split('.') @@ -42,7 +47,21 @@ export function SwapCard({
- {mode === 'from' ? 'ОТ' : 'К'} + {mode === 'from' ? ( +
+ {NETWORKS.map(n => ( + + ))} +
+ ) : ( + К + )} {token.network}
diff --git a/src/widgets/swap-form/ui/SwapForm.tsx b/src/widgets/swap-form/ui/SwapForm.tsx index d0157b1..af20bd9 100644 --- a/src/widgets/swap-form/ui/SwapForm.tsx +++ b/src/widgets/swap-form/ui/SwapForm.tsx @@ -1,5 +1,7 @@ +import { useState, useEffect } from 'react' import { PrimaryButton } from '@shared/ui' -import { TOKENS_LIST, useSwapForm } from '../model/useSwapForm' +import { useWalletBalance, type Chain } from '@features/wallet' +import { TOKENS_LIST, buildTokensFromBalance, useSwapForm } from '../model/useSwapForm' import { RateRow } from './RateRow' import { SwapCard } from './SwapCard' import { SwapDirectionButton } from './SwapDirectionButton' @@ -17,17 +19,31 @@ export function SwapForm() { setFromToken, setToToken, } = useSwapForm() + const [fromNetwork, setFromNetwork] = useState('ETH') + + const { data: walletData } = useWalletBalance(fromNetwork as Chain) + const tokenOptions = walletData ? buildTokensFromBalance(walletData) : TOKENS_LIST + + useEffect(() => { + if (tokenOptions.length > 0) { + setFromToken(tokenOptions[0]) + setToToken(tokenOptions[1] ?? tokenOptions[0]) + } + }, [fromNetwork]) + return (
@@ -35,7 +51,7 @@ export function SwapForm() {