154 lines
5.4 KiB
TypeScript
154 lines
5.4 KiB
TypeScript
import { useState } from 'react'
|
||
import { FormField, Select } from '@shared/ui'
|
||
import styles from './LegalConverterPage.module.css'
|
||
|
||
const MIN_ORDER = 500_000
|
||
|
||
// Чем дольше пользователь готов ждать, тем ниже комиссия сервиса.
|
||
const TERM_OPTIONS = [
|
||
{ days: 3, rate: 0.05 },
|
||
{ days: 4, rate: 0.04636 },
|
||
{ days: 5, rate: 0.04273 },
|
||
{ days: 6, rate: 0.03909 },
|
||
{ days: 7, rate: 0.03545 },
|
||
{ days: 8, rate: 0.03182 },
|
||
{ days: 9, rate: 0.02818 },
|
||
{ days: 10, rate: 0.02455 },
|
||
{ days: 11, rate: 0.02091 },
|
||
{ days: 12, rate: 0.01727 },
|
||
{ days: 13, rate: 0.01364 },
|
||
{ days: 14, rate: 0.01 },
|
||
] as const
|
||
|
||
const ru = (n: number) => n.toLocaleString('ru-RU', { maximumFractionDigits: 0 })
|
||
|
||
const dayLabel = (days: number) => {
|
||
const mod10 = days % 10
|
||
const mod100 = days % 100
|
||
if (mod10 === 1 && mod100 !== 11) return `${days} день`
|
||
if (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)) return `${days} дня`
|
||
return `${days} дней`
|
||
}
|
||
|
||
export function LegalConverterPage() {
|
||
const [amount, setAmount] = useState('')
|
||
const [name, setName] = useState('')
|
||
const [contact, setContact] = useState('')
|
||
const [days, setDays] = useState<number>(TERM_OPTIONS[0].days)
|
||
|
||
const numAmount = Number(amount.replace(/\D/g, '')) || 0
|
||
const belowMin = numAmount > 0 && numAmount < MIN_ORDER
|
||
|
||
const rate = TERM_OPTIONS.find((o) => o.days === days)?.rate ?? TERM_OPTIONS[0].rate
|
||
const commission = numAmount * rate
|
||
const total = numAmount + commission
|
||
|
||
const handleAmountChange = (value: string) => {
|
||
const digits = value.replace(/\D/g, '')
|
||
setAmount(digits ? ru(Number(digits)) : '')
|
||
}
|
||
|
||
const handleSubmit = (e: React.FormEvent) => {
|
||
e.preventDefault()
|
||
// Бэкенд пока не подключён — заявка никуда не отправляется.
|
||
}
|
||
|
||
return (
|
||
<form className={styles.wrap} onSubmit={handleSubmit}>
|
||
<div className={styles.header}>
|
||
<h1 className={styles.title}>Оставить заявку</h1>
|
||
<p className={styles.subtitle}>
|
||
Конвертация крупных объёмов по индивидуальному курсу. Оставьте заявку —
|
||
менеджер свяжется с вами, подтвердит актуальный курс и сопроводит сделку.
|
||
</p>
|
||
</div>
|
||
|
||
<div className={styles.body}>
|
||
<div className={styles.formCol}>
|
||
<FormField
|
||
label="Объём заявки, ₽"
|
||
type="text"
|
||
value={amount}
|
||
onChange={handleAmountChange}
|
||
placeholder="от 500 000"
|
||
/>
|
||
{belowMin && (
|
||
<p className={styles.hint}>
|
||
Минимальный объём заявки — {ru(MIN_ORDER)} ₽
|
||
</p>
|
||
)}
|
||
|
||
<Select
|
||
id="term"
|
||
label="Срок ожидания операции"
|
||
value={days}
|
||
onChange={setDays}
|
||
options={TERM_OPTIONS.map((o) => ({
|
||
value: o.days,
|
||
label: `${dayLabel(o.days)} — комиссия ${(o.rate * 100).toFixed(3)} %`,
|
||
}))}
|
||
/>
|
||
|
||
<FormField
|
||
label="Как к вам обращаться"
|
||
type="text"
|
||
value={name}
|
||
onChange={setName}
|
||
placeholder="Имя"
|
||
/>
|
||
|
||
<FormField
|
||
label="Email или телефон для связи"
|
||
type="text"
|
||
value={contact}
|
||
onChange={setContact}
|
||
placeholder="example@mail.ru / +7 900 000-00-00"
|
||
/>
|
||
</div>
|
||
|
||
<div className={styles.infoCol}>
|
||
<div className={styles.infoTitle}>УСЛОВИЯ</div>
|
||
|
||
<div className={styles.infoRow}>
|
||
<span className={styles.infoLabel}>Минимальный объём</span>
|
||
<span className={styles.infoValue}>{ru(MIN_ORDER)} ₽</span>
|
||
</div>
|
||
|
||
<div className={styles.infoRow}>
|
||
<span className={styles.infoLabel}>Срок ожидания</span>
|
||
<span className={styles.infoValue}>{dayLabel(days)}</span>
|
||
</div>
|
||
|
||
<div className={styles.infoRow}>
|
||
<span className={styles.infoLabel}>Ставка комиссии</span>
|
||
<span className={styles.infoValue}>{(rate * 100).toFixed(3)} %</span>
|
||
</div>
|
||
|
||
<div className={styles.infoRow}>
|
||
<span className={styles.infoLabel}>Сумма комиссии</span>
|
||
<span className={styles.infoValue}>
|
||
{numAmount > 0 ? `≈ ${ru(commission)} ₽` : '—'}
|
||
</span>
|
||
</div>
|
||
|
||
<div className={styles.infoRow} data-accent>
|
||
<span className={styles.infoLabel}>Итого к оплате</span>
|
||
<span className={styles.infoValue}>
|
||
{numAmount > 0 ? `≈ ${ru(total)} ₽` : '—'}
|
||
</span>
|
||
</div>
|
||
|
||
<p className={styles.note}>
|
||
Итоговая комиссия рассчитывается индивидуально и зависит от объёма,
|
||
валюты и направления сделки.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<button type="submit" className={styles.submitBtn} disabled={belowMin}>
|
||
Оставить заявку
|
||
</button>
|
||
</form>
|
||
)
|
||
}
|