profile refactor

This commit is contained in:
2026-06-29 17:41:56 +03:00
parent 2eaa11f790
commit 237112c302
33 changed files with 7722 additions and 232 deletions

View File

@@ -1 +1,5 @@
export { ProfilePage } from './ui/ProfilePage'
export { ProfileDetailsItem } from './ui/items/ProfileDetailsItem'
export { SecurityItem } from './ui/items/SecurityItem'
export { MnemonicItem } from './ui/items/MnemonicItem'
export { TransactionsItem } from './ui/items/TransactionsItem'

View File

@@ -1,30 +1,29 @@
.page {
min-height: 100vh;
display: flex;
flex-direction: column;
background: var(--bg-deep);
}
.main {
max-width: 1024px;
max-width: 1200px;
width: 100%;
margin: 0 auto;
padding: 40px 32px 60px;
display: flex;
display: grid;
grid-template-columns: 25% 1fr;
gap: 32px;
align-items: start;
}
.sections {
flex: 1;
.menu {
min-width: 0;
}
.content {
min-width: 0;
display: flex;
flex-direction: column;
gap: 16px;
}
/* < 1024px: avatar + sections stack into a single column */
/* < 1024px: menu and content stack into a single column */
@media (max-width: 1023px) {
.main {
flex-direction: column;
.page {
grid-template-columns: 1fr;
padding: 24px 20px 40px;
gap: 24px;
}
@@ -32,7 +31,7 @@
/* < 640px: tighter page padding */
@media (max-width: 639px) {
.main {
.page {
padding: 16px 16px 40px;
}
}

View File

@@ -1,19 +1,19 @@
import { WalletHeader } from '@widgets/wallet-header'
import { KycBanner, ProfileSummary, ProfileDetails, SecuritySection, MnemonicSection } from '@widgets/profile'
import { Outlet } from 'react-router-dom'
import { KycBanner, ProfileMenu } from '@widgets/profile'
import styles from './ProfilePage.module.css'
// Profile dashboard layout. The outer WalletLayout (see RouterProvider) renders
// the header/footer; here we split into a ~25% menu column and a ~75% content
// column. The active item is rendered into the inner <Outlet/>.
export function ProfilePage() {
return (
<div className={styles.page}>
<WalletHeader />
<KycBanner />
<main className={styles.main}>
<ProfileSummary />
<div className={styles.sections}>
<ProfileDetails />
<SecuritySection />
<MnemonicSection />
</div>
<div className={styles.menu}>
<ProfileMenu />
</div>
<main className={styles.content}>
<KycBanner />
<Outlet />
</main>
</div>
)

View File

@@ -0,0 +1,10 @@
import { useMe } from '@features/auth'
import { MnemonicSection } from '@widgets/profile'
import { Spinner } from '@shared/ui'
// «Мнемоническая фраза» dashboard item.
export function MnemonicItem() {
const { isLoading } = useMe()
if (isLoading) return <Spinner fullscreen label="Загрузка" />
return <MnemonicSection />
}

View File

@@ -0,0 +1,11 @@
import { useMe } from '@features/auth'
import { ProfileDetails } from '@widgets/profile'
import { Spinner } from '@shared/ui'
// «Данные профиля» — default dashboard item. Shows a spinner while the profile
// data is still loading, then the details form.
export function ProfileDetailsItem() {
const { isLoading } = useMe()
if (isLoading) return <Spinner fullscreen label="Загрузка" />
return <ProfileDetails />
}

View File

@@ -0,0 +1,10 @@
import { useMe } from '@features/auth'
import { SecuritySection } from '@widgets/profile'
import { Spinner } from '@shared/ui'
// «Безопасность» dashboard item.
export function SecurityItem() {
const { isLoading } = useMe()
if (isLoading) return <Spinner fullscreen label="Загрузка" />
return <SecuritySection />
}

View File

@@ -0,0 +1,7 @@
import { TransactionsPanel } from '@widgets/transactions-panel'
// «Транзакции» dashboard item — the shared transactions panel (list + tabs).
// The panel handles its own loading state.
export function TransactionsItem() {
return <TransactionsPanel />
}

View File

@@ -1,45 +1,15 @@
import { useState } from 'react'
import { useMe } from '@features/auth'
import { TransactionsList } from '@widgets/transactions-list'
import { PurchaseRequestsList } from '@widgets/purchase-requests-list'
import { TransactionsPanel } from '@widgets/transactions-panel'
import styles from './TransactionsPage.module.css'
type Tab = 'transactions' | 'requests'
// The standalone /transactions route now redirects to /profile/transactions
// (see RouterProvider). This page is kept as a thin wrapper around the shared
// TransactionsPanel for any direct/legacy usage.
export function TransactionsPage() {
const { data } = useMe()
const [tab, setTab] = useState<Tab>('transactions')
const isLegal = !!data && data.account_type !== 'individual'
const activeTab: Tab = isLegal ? tab : 'transactions'
return (
<div className={styles.inner}>
<div className={styles.glow} />
<h1 className={styles.title}>Транзакции</h1>
{isLegal && (
<div className={styles.tabs}>
<button
type="button"
className={styles.tab}
data-active={activeTab === 'transactions' || undefined}
onClick={() => setTab('transactions')}
>
Транзакции
</button>
<button
type="button"
className={styles.tab}
data-active={activeTab === 'requests' || undefined}
onClick={() => setTab('requests')}
>
Заявки
</button>
</div>
)}
{activeTab === 'transactions' ? <TransactionsList /> : <PurchaseRequestsList />}
<TransactionsPanel />
</div>
)
}