This commit is contained in:
2026-06-10 15:27:12 +03:00
parent b3752585ca
commit 493ba4ccef
17 changed files with 898 additions and 4756 deletions

View File

@@ -1,5 +1,6 @@
import { useState } from 'react'
import { FormField, Select } from '@shared/ui'
import { useCreatePurchaseRequest } from '@features/b2b'
import { FormField, Notification, Select } from '@shared/ui'
import styles from './LegalConverterPage.module.css'
const MIN_ORDER = 500_000
@@ -35,6 +36,9 @@ export function LegalConverterPage() {
const [name, setName] = useState('')
const [contact, setContact] = useState('')
const [days, setDays] = useState<number>(TERM_OPTIONS[0].days)
const [notice, setNotice] = useState<'success' | 'error' | null>(null)
const { mutate: submitRequest, isPending } = useCreatePurchaseRequest()
const numAmount = Number(amount.replace(/\D/g, '')) || 0
const belowMin = numAmount > 0 && numAmount < MIN_ORDER
@@ -50,7 +54,31 @@ export function LegalConverterPage() {
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
// Бэкенд пока не подключён — заявка никуда не отправляется.
if (numAmount === 0 || belowMin || isPending) return
// Отдельных полей под имя/контакт/срок/сумму в ₽ у API нет — всё уходит в comment.
const comment = [
name && `Имя: ${name}`,
contact && `Контакт: ${contact}`,
`Срок ожидания: ${dayLabel(days)}`,
`Сумма: ${ru(numAmount)}`,
`Комиссия: ≈${ru(commission)}`,
`Итого: ≈${ru(total)}`,
].filter(Boolean).join('; ')
submitRequest(
{ usdt_amount: numAmount, comment },
{
onSuccess: () => {
setNotice('success')
setAmount('')
setName('')
setContact('')
setDays(TERM_OPTIONS[0].days)
},
onError: () => setNotice('error'),
},
)
}
return (
@@ -145,9 +173,21 @@ export function LegalConverterPage() {
</div>
</div>
<button type="submit" className={styles.submitBtn} disabled={belowMin}>
Оставить заявку
<button
type="submit"
className={styles.submitBtn}
disabled={belowMin || numAmount === 0 || isPending}
>
{isPending ? 'Отправляем...' : 'Оставить заявку'}
</button>
{notice && (
<Notification
status={notice}
message={notice === 'success' ? 'Заявка отправлена' : 'Не удалось отправить заявку'}
onClose={() => setNotice(null)}
/>
)}
</form>
)
}

View File

@@ -27,6 +27,41 @@
z-index: 1;
}
.tabs {
display: flex;
gap: 8px;
margin: 0 0 20px;
position: relative;
z-index: 1;
}
.tab {
display: inline-flex;
align-items: center;
height: 38px;
padding: 0 20px;
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 10px;
color: var(--text-secondary);
font-size: 14px;
font-weight: 600;
font-family: inherit;
cursor: pointer;
transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.tab:hover {
border-color: rgba(74, 109, 255, 0.4);
color: var(--text-primary);
}
.tab[data-active] {
background: rgba(74, 109, 255, 0.12);
border-color: rgba(74, 109, 255, 0.5);
color: var(--interactive, #4a6dff);
}
@media (max-width: 900px) {
.inner {
padding: 20px 16px 32px;

View File

@@ -1,12 +1,45 @@
import { useState } from 'react'
import { useMe } from '@features/auth'
import { TransactionsList } from '@widgets/transactions-list'
import { PurchaseRequestsList } from '@widgets/purchase-requests-list'
import styles from './TransactionsPage.module.css'
type Tab = 'transactions' | 'requests'
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>
<TransactionsList />
{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 />}
</div>
)
}