14.05.2026 rip
This commit is contained in:
@@ -192,3 +192,12 @@ export async function getTokensList(): Promise<TokenInfo[]> {
|
|||||||
export async function getRelayQuote(payload: RelayQuotePayload): Promise<RelayQuoteResponse> {
|
export async function getRelayQuote(payload: RelayQuotePayload): Promise<RelayQuoteResponse> {
|
||||||
return walletPost<RelayQuoteResponse>('/api/relay/quote', payload)
|
return walletPost<RelayQuoteResponse>('/api/relay/quote', payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function createWallet(): Promise<void> {
|
||||||
|
await walletPost<unknown>('/wallet/create', {})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function revealMnemonic(): Promise<string> {
|
||||||
|
const res = await walletPost<{ success: boolean; data: { mnemonic: string } }>('/wallets/mnemonic/reveal', {})
|
||||||
|
return res.data.mnemonic
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export { useAllWalletBalances, usePrices, useSendWallet, useWalletAddresses, useWalletBalance, usePortfolio, useTokensList, useRelayQuote } from './model/useWalletData'
|
export { useAllWalletBalances, usePrices, useSendWallet, useWalletAddresses, useWalletBalance, usePortfolio, useTokensList, useRelayQuote, useCreateWallet, useRevealMnemonic } from './model/useWalletData'
|
||||||
export type { Chain, FormattedAmount, WalletBalanceData, PriceEntry, SendWalletPayload, SendWalletResponse, WalletAddress, PortfolioData, PortfolioChain, PortfolioNative, PortfolioToken, TokenInfo, RelayQuotePayload, RelayQuoteResponse } from './api/walletApi'
|
export type { Chain, FormattedAmount, WalletBalanceData, PriceEntry, SendWalletPayload, SendWalletResponse, WalletAddress, PortfolioData, PortfolioChain, PortfolioNative, PortfolioToken, TokenInfo, RelayQuotePayload, RelayQuoteResponse } from './api/walletApi'
|
||||||
export { CHAINS } from './api/walletApi'
|
export { CHAINS } from './api/walletApi'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useQuery, useQueries, useMutation } from '@tanstack/react-query'
|
import { useQuery, useQueries, useMutation } from '@tanstack/react-query'
|
||||||
import { getWalletBalance, getPrices, sendWallet, getWalletAddresses, getPortfolio, getTokensList, getRelayQuote, CHAINS, type Chain, type SendWalletPayload, type RelayQuotePayload } from '../api/walletApi'
|
import { getWalletBalance, getPrices, sendWallet, getWalletAddresses, getPortfolio, getTokensList, getRelayQuote, createWallet, revealMnemonic, CHAINS, type Chain, type SendWalletPayload, type RelayQuotePayload } from '../api/walletApi'
|
||||||
|
|
||||||
export function useWalletBalance(chain: Chain) {
|
export function useWalletBalance(chain: Chain) {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
@@ -58,6 +58,19 @@ export function useTokensList() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useCreateWallet() {
|
||||||
|
return useMutation({ mutationFn: createWallet })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useRevealMnemonic() {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['wallet', 'mnemonic'],
|
||||||
|
queryFn: revealMnemonic,
|
||||||
|
staleTime: Infinity,
|
||||||
|
retry: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function useRelayQuote(payload: RelayQuotePayload | null) {
|
export function useRelayQuote(payload: RelayQuotePayload | null) {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['relay', 'quote',
|
queryKey: ['relay', 'quote',
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import { WalletHeader } from '@widgets/wallet-header'
|
import { WalletHeader } from '@widgets/wallet-header'
|
||||||
import { SeedPhraseWidget } from '@widgets/seed-phrase'
|
import { SeedPhraseWidget } from '@widgets/seed-phrase'
|
||||||
|
import { useRevealMnemonic } from '@features/wallet'
|
||||||
import styles from './SeedPhrasePage.module.css'
|
import styles from './SeedPhrasePage.module.css'
|
||||||
|
|
||||||
const MOCK_WORDS = ['egg', 'phone', 'long', 'vibe', 'potato', 'soup', 'skirt', 'black', 'phase', 'word', 'num', 'cucumber']
|
|
||||||
|
|
||||||
export function SeedPhrasePage() {
|
export function SeedPhrasePage() {
|
||||||
|
const { data: mnemonic, isLoading } = useRevealMnemonic()
|
||||||
|
const words = mnemonic ? mnemonic.split(' ') : []
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.page}>
|
<div className={styles.page}>
|
||||||
<WalletHeader />
|
<WalletHeader />
|
||||||
<main className={styles.main}>
|
<main className={styles.main}>
|
||||||
<div className={styles.glow} />
|
<div className={styles.glow} />
|
||||||
<SeedPhraseWidget words={MOCK_WORDS} />
|
{!isLoading && <SeedPhraseWidget words={words} />}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -35,6 +35,20 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.noWallet {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 24px;
|
||||||
|
min-height: 300px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
.glow {
|
.glow {
|
||||||
width: auto;
|
width: auto;
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
import { Navigate } from 'react-router-dom'
|
import { Navigate, useNavigate } from 'react-router-dom'
|
||||||
import { useMe } from '@features/auth'
|
import { useMe } from '@features/auth'
|
||||||
import { ROUTES } from '@shared/config/routes'
|
import { ROUTES } from '@shared/config/routes'
|
||||||
|
import { usePortfolio, useCreateWallet } from '@features/wallet'
|
||||||
import { BalanceCard } from '@widgets/balance-card'
|
import { BalanceCard } from '@widgets/balance-card'
|
||||||
import { TokenTable } from '@widgets/token-table'
|
import { TokenTable } from '@widgets/token-table'
|
||||||
import { WalletHeader } from '@widgets/wallet-header'
|
import { WalletHeader } from '@widgets/wallet-header'
|
||||||
|
import { Button } from '@shared/ui'
|
||||||
import styles from './WalletPage.module.css'
|
import styles from './WalletPage.module.css'
|
||||||
|
|
||||||
export function WalletPage() {
|
export function WalletPage() {
|
||||||
const { data, isLoading, isError } = useMe()
|
const { data, isLoading, isError } = useMe()
|
||||||
|
const { error: portfolioError } = usePortfolio()
|
||||||
|
const { mutate: createWallet, isPending } = useCreateWallet()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
const noWallet = (portfolioError as any)?.error?.includes('No wallets')
|
||||||
|
|
||||||
if (isLoading) return null
|
if (isLoading) return null
|
||||||
if (isError) return <div className={styles.error}>Произошла ошибка. Попробуйте обновить страницу.</div>
|
if (isError) return <div className={styles.error}>Произошла ошибка. Попробуйте обновить страницу.</div>
|
||||||
@@ -18,8 +25,23 @@ export function WalletPage() {
|
|||||||
<WalletHeader />
|
<WalletHeader />
|
||||||
<main className={styles.main}>
|
<main className={styles.main}>
|
||||||
<div className={styles.glow} />
|
<div className={styles.glow} />
|
||||||
|
{noWallet ? (
|
||||||
|
<div className={styles.noWallet}>
|
||||||
|
<p>У вас пока нет кошелька. Создайте его, чтобы начать.</p>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => createWallet(undefined, { onSuccess: () => navigate(ROUTES.SEED_PHRASE) })}
|
||||||
|
disabled={isPending}
|
||||||
|
>
|
||||||
|
{isPending ? 'Создание...' : 'Создать кошелёк'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
<BalanceCard />
|
<BalanceCard />
|
||||||
<TokenTable />
|
<TokenTable />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,13 +3,11 @@ import { PrimaryButton } from '@shared/ui'
|
|||||||
import { useWalletBalance, useWalletAddresses, useTokensList, useRelayQuote, type Chain } from '@features/wallet'
|
import { useWalletBalance, useWalletAddresses, useTokensList, useRelayQuote, type Chain } from '@features/wallet'
|
||||||
import { useDebounce } from '@shared/lib/hooks/useDebounce'
|
import { useDebounce } from '@shared/lib/hooks/useDebounce'
|
||||||
import { TOKENS_LIST, buildTokensFromBalance, useSwapForm } from '../model/useSwapForm'
|
import { TOKENS_LIST, buildTokensFromBalance, useSwapForm } from '../model/useSwapForm'
|
||||||
import { RateRow } from './RateRow'
|
|
||||||
import { SwapCard } from './SwapCard'
|
import { SwapCard } from './SwapCard'
|
||||||
import { SwapDirectionButton } from './SwapDirectionButton'
|
import { SwapDirectionButton } from './SwapDirectionButton'
|
||||||
import { SwapInfoPanel } from './SwapInfoPanel'
|
import { SwapInfoPanel } from './SwapInfoPanel'
|
||||||
import styles from './SwapForm.module.css'
|
import styles from './SwapForm.module.css'
|
||||||
|
|
||||||
const RATE = 82.2578
|
|
||||||
|
|
||||||
const CHAIN_ID: Record<string, number> = { ETH: 1, BSC: 56, SOL: 792703809 }
|
const CHAIN_ID: Record<string, number> = { ETH: 1, BSC: 56, SOL: 792703809 }
|
||||||
const NATIVE_ADDR: Record<string, string> = {
|
const NATIVE_ADDR: Record<string, string> = {
|
||||||
@@ -24,8 +22,7 @@ export function SwapForm() {
|
|||||||
const {
|
const {
|
||||||
fromAmount, fromUsd,
|
fromAmount, fromUsd,
|
||||||
fromToken, toToken,
|
fromToken, toToken,
|
||||||
isRefreshing,
|
setFromAmount, setPercent, swapTokens,
|
||||||
setFromAmount, setPercent, swapTokens, refreshRate,
|
|
||||||
setFromToken, setToToken,
|
setFromToken, setToToken,
|
||||||
} = useSwapForm()
|
} = useSwapForm()
|
||||||
|
|
||||||
@@ -95,14 +92,6 @@ export function SwapForm() {
|
|||||||
onTokenChange={setToToken}
|
onTokenChange={setToToken}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<RateRow
|
|
||||||
fromSymbol={fromToken.symbol}
|
|
||||||
toSymbol={toToken.symbol}
|
|
||||||
rate={RATE}
|
|
||||||
isRefreshing={isRefreshing}
|
|
||||||
onRefresh={refreshRate}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SwapInfoPanel gasFee={gasFee} />
|
<SwapInfoPanel gasFee={gasFee} />
|
||||||
|
|
||||||
<PrimaryButton />
|
<PrimaryButton />
|
||||||
|
|||||||
Reference in New Issue
Block a user