refactor(converter): shared page layout + reusable conversion logic/UI
Pages: - add WalletLayout route (WalletHeader + main + Footer via <Outlet/>), wrap converter/swap/bridge/transactions; thin pages, drop duplicated shell CSS - extract SwapBridgeTabs shared between swap/bridge pages Converter reuse (FSD layers, no widget->widget imports): - move commission tiers to entities/commission (+ CommissionTable ui) - shared calc hook features/payment/model/useCurrencyConversion; useConverterSection becomes thin wrapper; HomePage Converter reuses it - move ConvertField/DirectionSwapButton to shared/ui; delete dead useConverter Tooling: - add eslint.config.js (ESLint 9 flat config); fix no-explicit-any in WalletPage Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,52 +1,12 @@
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
background: var(--bg-deep);
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 24px 28px 0;
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding: 10px 24px;
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
font-family: var(--font-sans);
|
||||
letter-spacing: 0.5px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.active {
|
||||
background: linear-gradient(135deg, var(--grad-edge), var(--grad-center));
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.inactive {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.inactive:hover {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 32px 20px 48px;
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 32px 20px 48px;
|
||||
}
|
||||
|
||||
@media (max-width: 650px) {
|
||||
.main {
|
||||
padding: 32px 20px;
|
||||
}
|
||||
.content {
|
||||
padding: 32px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,14 @@
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Footer } from '@widgets/footer'
|
||||
import { BridgeForm } from '@widgets/bridge-form'
|
||||
import { WalletHeader } from '@widgets/wallet-header'
|
||||
import { ROUTES } from '@shared/config/routes'
|
||||
import { SwapBridgeTabs } from '@widgets/swap-bridge-tabs'
|
||||
import styles from './BridgePage.module.css'
|
||||
|
||||
export function BridgePage() {
|
||||
const navigate = useNavigate()
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<WalletHeader />
|
||||
|
||||
<div className={styles.tabs}>
|
||||
<button
|
||||
className={`${styles.tab} ${styles.inactive}`}
|
||||
onClick={() => navigate(ROUTES.SWAP)}
|
||||
>
|
||||
СВОП
|
||||
</button>
|
||||
<button
|
||||
className={`${styles.tab} ${styles.active}`}
|
||||
onClick={() => navigate(ROUTES.BRIDGE)}
|
||||
>
|
||||
БРИДЖ
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<main className={styles.main}>
|
||||
<>
|
||||
<SwapBridgeTabs active="bridge" />
|
||||
<div className={styles.content}>
|
||||
<BridgeForm />
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--bg-deep);
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
padding: 28px 32px 40px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.main {
|
||||
padding: 20px 16px 32px;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,5 @@
|
||||
import { ConverterSection } from '@widgets/converter-page'
|
||||
import { Footer } from '@widgets/footer'
|
||||
import { WalletHeader } from '@widgets/wallet-header'
|
||||
import styles from './ConverterPage.module.css'
|
||||
|
||||
export function ConverterPage() {
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<WalletHeader />
|
||||
<main className={styles.main}>
|
||||
<ConverterSection />
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
)
|
||||
return <ConverterSection />
|
||||
}
|
||||
|
||||
@@ -1,52 +1,12 @@
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
background: var(--bg-deep);
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 24px 28px 0;
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding: 10px 24px;
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
font-family: var(--font-sans);
|
||||
letter-spacing: 0.5px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.active {
|
||||
background: linear-gradient(135deg, var(--grad-edge), var(--grad-center));
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.inactive {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.inactive:hover {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 32px 20px 48px;
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 32px 20px 48px;
|
||||
}
|
||||
|
||||
@media (max-width: 650px) {
|
||||
.main {
|
||||
padding: 32px 20px;
|
||||
}
|
||||
}
|
||||
.content {
|
||||
padding: 32px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,14 @@
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Footer } from '@widgets/footer'
|
||||
import { SwapForm } from '@widgets/swap-form'
|
||||
import { WalletHeader } from '@widgets/wallet-header'
|
||||
import { ROUTES } from '@shared/config/routes'
|
||||
import { SwapBridgeTabs } from '@widgets/swap-bridge-tabs'
|
||||
import styles from './SwapPage.module.css'
|
||||
|
||||
export function SwapPage() {
|
||||
const navigate = useNavigate()
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<WalletHeader />
|
||||
|
||||
<div className={styles.tabs}>
|
||||
<button
|
||||
className={`${styles.tab} ${styles.active}`}
|
||||
onClick={() => navigate(ROUTES.SWAP)}
|
||||
>
|
||||
СВОП
|
||||
</button>
|
||||
<button
|
||||
className={`${styles.tab} ${styles.inactive}`}
|
||||
onClick={() => navigate(ROUTES.BRIDGE)}
|
||||
>
|
||||
БРИДЖ
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<main className={styles.main}>
|
||||
<>
|
||||
<SwapBridgeTabs active="swap" />
|
||||
<div className={styles.content}>
|
||||
<SwapForm />
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--bg-deep);
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
.inner {
|
||||
padding: 28px 32px 40px;
|
||||
max-width: 1200px;
|
||||
width: 100%;
|
||||
@@ -36,7 +28,7 @@
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.main {
|
||||
.inner {
|
||||
padding: 20px 16px 32px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
import { WalletHeader } from '@widgets/wallet-header'
|
||||
import { Footer } from '@widgets/footer'
|
||||
import { TransactionsList } from '@widgets/transactions-list'
|
||||
import styles from './TransactionsPage.module.css'
|
||||
|
||||
export function TransactionsPage() {
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<WalletHeader />
|
||||
<main className={styles.main}>
|
||||
<div className={styles.glow} />
|
||||
<h1 className={styles.title}>Транзакции</h1>
|
||||
<TransactionsList />
|
||||
</main>
|
||||
<Footer />
|
||||
<div className={styles.inner}>
|
||||
<div className={styles.glow} />
|
||||
<h1 className={styles.title}>Транзакции</h1>
|
||||
<TransactionsList />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export function WalletPage() {
|
||||
const navigate = useNavigate()
|
||||
const { chain: chainParam } = useParams<{ chain?: string }>()
|
||||
|
||||
const noWallet = (portfolioError as any)?.error?.includes('No wallets')
|
||||
const noWallet = (portfolioError as { error?: string } | null)?.error?.includes('No wallets')
|
||||
|
||||
if (isLoading) return null
|
||||
if (isError) return <div className={styles.error}>Произошла ошибка. Попробуйте обновить страницу.</div>
|
||||
|
||||
Reference in New Issue
Block a user