import { useState } from 'react' import { useDebounce } from '@shared/lib/hooks/useDebounce' import { progressPercent } from '@entities/commission' import { GAS_PRICE, MIN_RUB_AMOUNT } from '@shared/config/constants' import type { ConvertFieldData } from '@shared/ui' import { usePaymentConfig } from '../hooks/usePaymentConfig' import { usePaymentQuote } from '../hooks/usePaymentQuote' import { usePaymentQuoteByRub } from '../hooks/usePaymentQuoteByRub' const TOO_LARGE_ERROR = 'Сумма слишком большая и превышает 600 000 ₽' const sanitize = (raw: string) => raw.replace(/[^0-9.]/g, '') interface Options { /** Значение курса USDT/RUB до загрузки конфига (пилюля). */ rateFallback?: number } export function useCurrencyConversion({ rateFallback = 0 }: Options = {}) { const [direction, setDirection] = useState<'usdt_to_rub' | 'rub_to_usdt'>('usdt_to_rub') const [usdtInput, setUsdtInput] = useState('1000') const [rubInput, setRubInput] = useState(String(MIN_RUB_AMOUNT)) const { data: config } = usePaymentConfig() const configUsdtRate = Number(config?.usdt_exchange_rate) || rateFallback const gasPriceRub = Number(config?.gas_fee) || GAS_PRICE const isUsdtToRub = direction === 'usdt_to_rub' const numUsdt = Number.parseFloat(usdtInput) || 0 const debouncedUsdt = useDebounce(numUsdt, 400) const { data: quoteUsdtToRub, isError: quoteError } = usePaymentQuote(isUsdtToRub ? debouncedUsdt : 0) const numRubInput = Number.parseFloat(rubInput) || 0 const debouncedRub = useDebounce(numRubInput, 400) const { data: quoteRubToUsdt, isError: quoteRubError } = usePaymentQuoteByRub(!isUsdtToRub ? debouncedRub : 0) const rubBelowMin = !isUsdtToRub && numRubInput > 0 && numRubInput < MIN_RUB_AMOUNT 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 ? (numUsdt > 0 ? rubTotalNum / numUsdt : 0) : (usdtFromRubNum > 0 ? numRubInput / usdtFromRubNum : 0) function onSwap() { setDirection(d => (d === 'usdt_to_rub' ? 'rub_to_usdt' : 'usdt_to_rub')) } const convert: ConvertFieldData = isUsdtToRub ? { value: usdtInput, currency: 'USDT', onChange: (raw) => setUsdtInput(sanitize(raw)), error: quoteError ? TOO_LARGE_ERROR : undefined, } : { value: rubInput, currency: 'RUB', onChange: (raw) => setRubInput(sanitize(raw)), error: rubBelowMin ? `Минимальная сумма: ${MIN_RUB_AMOUNT.toLocaleString('ru-RU')} ₽` : quoteRubError ? TOO_LARGE_ERROR : undefined, } const pay: ConvertFieldData = isUsdtToRub ? { value: rubTotal, currency: 'RUB' } : { value: usdtFromRub, currency: 'USDT' } return { isUsdtToRub, gasPriceRub, configUsdtRate, convert, pay, onSwap, commission: { amount: displayRubAmount, progress: progressPercent(displayRubAmount), commission, effectiveRate, }, // сырые значения для создания ордера и валидации в обёртках numUsdt, usdtFromRubNum, rubTotal, rubTotalNum, numRubInput, usdtFromRub, rubBelowMin, } }