19.05.2026 okkk
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { useConverter, progressPercent } from '@widgets/currency-converter'
|
||||
import { useDebounce } from '@shared/lib/hooks/useDebounce'
|
||||
import { usePaymentQuote, usePaymentConfig, useCreateOrder } from '@features/payment'
|
||||
import { usePaymentQuote, usePaymentQuoteByRub, usePaymentConfig, useCreateOrder } from '@features/payment'
|
||||
import { CommissionPanel } from './CommissionPanel'
|
||||
import { AgreementCheck } from './AgreementCheck'
|
||||
import styles from './ConverterSection.module.css'
|
||||
@@ -8,31 +9,69 @@ import { GAS_PRICE } from '@shared/config/constants'
|
||||
|
||||
export function ConverterSection() {
|
||||
const c = useConverter({ usdtRate: 0 })
|
||||
const [direction, setDirection] = useState<'usdt_to_rub' | 'rub_to_usdt'>('usdt_to_rub')
|
||||
const [rubInputVal, setRubInputVal] = useState('1000')
|
||||
|
||||
const debouncedUsdt = useDebounce(c.numRub, 400)
|
||||
const { data: quote, isError: quoteError } = usePaymentQuote(debouncedUsdt)
|
||||
const { data: config } = usePaymentConfig()
|
||||
|
||||
const configUsdtRate = Number(config?.usdt_exchange_rate) || 0
|
||||
const gasPriceRub = Number(config?.gas_fee) || GAS_PRICE
|
||||
|
||||
const rubTotal = quote?.total_price ?? ''
|
||||
const rubTotalNum = Number(rubTotal) || 0
|
||||
const isUsdtToRub = direction === 'usdt_to_rub'
|
||||
|
||||
const commission = Number(quote?.service_fee) || 0
|
||||
const effectiveRate = c.numRub > 0 ? rubTotalNum / c.numRub : 0
|
||||
const debouncedUsdt = useDebounce(c.numRub, 400)
|
||||
const { data: quoteUsdtToRub, isError: quoteError } = usePaymentQuote(isUsdtToRub ? debouncedUsdt : 0)
|
||||
|
||||
const numRubInput = Number.parseFloat(rubInputVal) || 0
|
||||
const debouncedRub = useDebounce(numRubInput, 400)
|
||||
const { data: quoteRubToUsdt, isError: quoteRubError } = usePaymentQuoteByRub(!isUsdtToRub ? debouncedRub : 0)
|
||||
|
||||
function updateRubInput(raw: string) {
|
||||
setRubInputVal(raw.replace(/[^0-9.]/g, ''))
|
||||
}
|
||||
|
||||
function handleSwap() {
|
||||
setDirection(d => d === 'usdt_to_rub' ? 'rub_to_usdt' : 'usdt_to_rub')
|
||||
}
|
||||
|
||||
const rubTotal = quoteUsdtToRub?.total_price ?? ''
|
||||
const rubTotalNum = Number(rubTotal) || 0
|
||||
const usdtFromRub = quoteRubToUsdt?.usdt_amount ?? ''
|
||||
const usdtFromRubNum = Number(usdtFromRub) || 0
|
||||
|
||||
const commission = isUsdtToRub
|
||||
? Number(quoteUsdtToRub?.service_fee) || 0
|
||||
: Number(quoteRubToUsdt?.service_fee) || 0
|
||||
|
||||
const displayRubAmount = isUsdtToRub ? rubTotalNum : numRubInput
|
||||
const effectiveRate = isUsdtToRub
|
||||
? (c.numRub > 0 ? rubTotalNum / c.numRub : 0)
|
||||
: (usdtFromRubNum > 0 ? numRubInput / usdtFromRubNum : 0)
|
||||
|
||||
const { mutate: submitOrder, isPending } = useCreateOrder()
|
||||
|
||||
function handlePay() {
|
||||
submitOrder({
|
||||
usdt_amount: c.numRub,
|
||||
usdt_exchange_rate: 1,
|
||||
gas_fee: 1,
|
||||
total_price: Number(rubTotal) || 0,
|
||||
})
|
||||
if (isUsdtToRub) {
|
||||
submitOrder({
|
||||
usdt_amount: c.numRub,
|
||||
usdt_exchange_rate: 1,
|
||||
gas_fee: 1,
|
||||
total_price: Number(rubTotal) || 0,
|
||||
})
|
||||
} else {
|
||||
submitOrder({
|
||||
usdt_amount: usdtFromRubNum,
|
||||
usdt_exchange_rate: 1,
|
||||
gas_fee: 1,
|
||||
total_price: numRubInput,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const isPayDisabled = isUsdtToRub
|
||||
? (!rubTotal || isPending || !c.agreed)
|
||||
: (!usdtFromRub || isPending || !c.agreed)
|
||||
|
||||
return (
|
||||
<div className={styles.wrap}>
|
||||
<div className={styles.header}>
|
||||
@@ -63,62 +102,120 @@ export function ConverterSection() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className={styles.field}>
|
||||
<div className={styles.fieldLabel}>Конвертируете</div>
|
||||
<div className={styles.fieldInput}>
|
||||
<input
|
||||
type="text"
|
||||
value={c.rubVal}
|
||||
onChange={(e) => c.updateRub(e.target.value)}
|
||||
placeholder="0"
|
||||
inputMode="decimal"
|
||||
/>
|
||||
<div className={styles.currency}>
|
||||
<span className={`${styles.currencyIcon} ${styles.currencyUsdt}`}>₮</span>
|
||||
USDT
|
||||
{isUsdtToRub ? (
|
||||
<>
|
||||
<div className={styles.field}>
|
||||
<div className={styles.fieldLabel}>Конвертируете</div>
|
||||
<div className={styles.fieldInput}>
|
||||
<input
|
||||
type="text"
|
||||
value={c.rubVal}
|
||||
onChange={(e) => c.updateRub(e.target.value)}
|
||||
placeholder="0"
|
||||
inputMode="decimal"
|
||||
/>
|
||||
<div className={styles.currency}>
|
||||
<span className={`${styles.currencyIcon} ${styles.currencyUsdt}`}>₮</span>
|
||||
USDT
|
||||
</div>
|
||||
</div>
|
||||
{quoteError && (
|
||||
<div className={styles.fieldError}>
|
||||
Сумма слишком большая и превышает 600 000 ₽
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{quoteError && (
|
||||
<div className={styles.fieldError}>
|
||||
Сумма слишком большая и превышает 600 000 ₽
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.swapWrap}>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.swapBtn}
|
||||
onClick={c.toggleMode}
|
||||
aria-label="Поменять направление"
|
||||
>
|
||||
<svg width={16} height={16} viewBox="0 0 16 16" fill="none">
|
||||
<path
|
||||
d="M8 2v12M4 10l4 4 4-4"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className={styles.field}>
|
||||
<div className={styles.fieldLabel}>Платите</div>
|
||||
<div className={styles.fieldInput}>
|
||||
<input type="text" value={rubTotal} readOnly placeholder="0" />
|
||||
<div className={styles.currency}>
|
||||
<span className={`${styles.currencyIcon} ${styles.currencyRub}`}>₽</span>
|
||||
RUB
|
||||
<div className={styles.swapWrap}>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.swapBtn}
|
||||
onClick={handleSwap}
|
||||
aria-label="Поменять направление"
|
||||
>
|
||||
<svg width={16} height={16} viewBox="0 0 16 16" fill="none">
|
||||
<path
|
||||
d="M8 2v12M4 10l4 4 4-4"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.field}>
|
||||
<div className={styles.fieldLabel}>Платите</div>
|
||||
<div className={styles.fieldInput}>
|
||||
<input type="text" value={rubTotal} readOnly placeholder="0" />
|
||||
<div className={styles.currency}>
|
||||
<span className={`${styles.currencyIcon} ${styles.currencyRub}`}>₽</span>
|
||||
RUB
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className={styles.field}>
|
||||
<div className={styles.fieldLabel}>Конвертируете</div>
|
||||
<div className={styles.fieldInput}>
|
||||
<input
|
||||
type="text"
|
||||
value={rubInputVal}
|
||||
onChange={(e) => updateRubInput(e.target.value)}
|
||||
placeholder="0"
|
||||
inputMode="decimal"
|
||||
/>
|
||||
<div className={styles.currency}>
|
||||
<span className={`${styles.currencyIcon} ${styles.currencyRub}`}>₽</span>
|
||||
RUB
|
||||
</div>
|
||||
</div>
|
||||
{quoteRubError && (
|
||||
<div className={styles.fieldError}>
|
||||
Сумма слишком большая и превышает 600 000 ₽
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.swapWrap}>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.swapBtn}
|
||||
onClick={handleSwap}
|
||||
aria-label="Поменять направление"
|
||||
>
|
||||
<svg width={16} height={16} viewBox="0 0 16 16" fill="none">
|
||||
<path
|
||||
d="M8 2v12M4 10l4 4 4-4"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className={styles.field}>
|
||||
<div className={styles.fieldLabel}>Платите</div>
|
||||
<div className={styles.fieldInput}>
|
||||
<input type="text" value={usdtFromRub} readOnly placeholder="0" />
|
||||
<div className={styles.currency}>
|
||||
<span className={`${styles.currencyIcon} ${styles.currencyUsdt}`}>₮</span>
|
||||
USDT
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<CommissionPanel
|
||||
amount={rubTotalNum}
|
||||
progress={progressPercent(rubTotalNum)}
|
||||
amount={displayRubAmount}
|
||||
progress={progressPercent(displayRubAmount)}
|
||||
commission={commission}
|
||||
effectiveRate={effectiveRate}
|
||||
/>
|
||||
@@ -132,7 +229,7 @@ export function ConverterSection() {
|
||||
type="button"
|
||||
className={styles.payBtn}
|
||||
onClick={handlePay}
|
||||
disabled={!rubTotal || isPending || !c.agreed}
|
||||
disabled={isPayDisabled}
|
||||
>
|
||||
{isPending ? 'Обработка...' : 'Оплатить'}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user