feat: похуйу

This commit is contained in:
2026-05-12 23:14:45 +03:00
parent 2bea3f5eea
commit 35e537933e
8 changed files with 115 additions and 29 deletions

View File

@@ -0,0 +1,46 @@
import { getCsrfToken } from '@shared/api/csrf'
const PAYMENT_API_URL = 'https://app.payment.elcsa.ru'
export interface PaymentConfig {
status_code: number
usdt_exchange_rate: string
gas_fee: string
service_fee_rate: string
one_usdt_service_fee: string
one_usdt_total_price: string
created_at: string
}
export interface PaymentQuote {
status_code: number
usdt_amount: string
usdt_exchange_rate: string
gas_fee: string
service_fee: string
total_price: string
service_fee_rate: string
created_at: string
}
export async function getPaymentConfig(): Promise<PaymentConfig> {
const csrf = await getCsrfToken()
const res = await fetch(`${PAYMENT_API_URL}/config`, {
credentials: 'include',
headers: { 'X-CSRF-Token': csrf },
})
const data = await res.json()
if (!res.ok) throw data
return data
}
export async function getPaymentQuote(usdtAmount: number): Promise<PaymentQuote> {
const csrf = await getCsrfToken()
const res = await fetch(`${PAYMENT_API_URL}/payment/quote?usdt_amount=${usdtAmount}`, {
credentials: 'include',
headers: { 'X-CSRF-Token': csrf },
})
const data = await res.json()
if (!res.ok) throw data
return data
}

View File

@@ -0,0 +1,11 @@
import { useQuery } from '@tanstack/react-query'
import { getPaymentConfig } from '../api/paymentApi'
import type { PaymentConfig } from '../api/paymentApi'
export function usePaymentConfig() {
return useQuery<PaymentConfig>({
queryKey: ['payment', 'config'],
queryFn: getPaymentConfig,
staleTime: 60_000,
})
}

View File

@@ -0,0 +1,12 @@
import { useQuery } from '@tanstack/react-query'
import { getPaymentQuote } from '../api/paymentApi'
import type { PaymentQuote } from '../api/paymentApi'
export function usePaymentQuote(usdtAmount: number) {
return useQuery<PaymentQuote>({
queryKey: ['payment', 'quote', usdtAmount],
queryFn: () => getPaymentQuote(usdtAmount),
enabled: usdtAmount > 0,
staleTime: 30_000,
})
}

View File

@@ -0,0 +1,3 @@
export { usePaymentConfig } from './hooks/usePaymentConfig'
export { usePaymentQuote } from './hooks/usePaymentQuote'
export type { PaymentConfig, PaymentQuote } from './api/paymentApi'

View File

@@ -0,0 +1,12 @@
import { useEffect, useState } from 'react'
export function useDebounce<T>(value: T, delay: number): T {
const [debounced, setDebounced] = useState(value)
useEffect(() => {
const id = setTimeout(() => setDebounced(value), delay)
return () => clearTimeout(id)
}, [value, delay])
return debounced
}

View File

@@ -1,6 +1,4 @@
.wrap {
border-radius: 24px;
padding: 32px;
position: relative;
overflow: hidden;
}
@@ -168,12 +166,6 @@
color: var(--text-secondary);
}
.swapBtn:hover {
border-color: var(--highlight);
color: var(--highlight);
transform: rotate(180deg);
}
.bottom {
display: flex;
justify-content: center;

View File

@@ -1,11 +1,23 @@
import { useConverter } from '@widgets/currency-converter'
import { GAS_PRICE, USDT_RATE } from '@shared/config/constants'
import { USDT_RATE, GAS_PRICE } from '@shared/config/constants'
import { useDebounce } from '@shared/lib/hooks/useDebounce'
import { usePaymentConfig, usePaymentQuote } from '@features/payment'
import { CommissionPanel } from './CommissionPanel'
import { AgreementCheck } from './AgreementCheck'
import styles from './ConverterSection.module.css'
export function ConverterSection() {
const c = useConverter({ usdtRate: USDT_RATE })
const { data: config } = usePaymentConfig()
const usdtRate = config ? Number(config.usdt_exchange_rate) || USDT_RATE : USDT_RATE
const gasPrice = config ? Number(config.gas_fee) || GAS_PRICE : GAS_PRICE
const c = useConverter({ usdtRate })
const debouncedRub = useDebounce(c.numRub, 400)
const { data: quote } = usePaymentQuote(debouncedRub)
const usdtVal = quote ? quote.usdt_amount : c.usdtVal
return (
<div className={styles.wrap}>
@@ -16,10 +28,10 @@ export function ConverterSection() {
</div>
<div className={styles.pills}>
<div className={styles.pill}>
Цена газа в RUB <span className={styles.pillValue}>{GAS_PRICE.toFixed(2)} RUB</span>
Цена газа в RUB <span className={styles.pillValue}>{gasPrice.toFixed(2)} RUB</span>
</div>
<div className={styles.pill}>
USDT/RUB <span className={styles.pillValue}>{USDT_RATE.toFixed(2)} </span>
USDT/RUB <span className={styles.pillValue}>{usdtRate.toFixed(2)} </span>
</div>
</div>
</div>
@@ -46,18 +58,12 @@ export function ConverterSection() {
</div>
<div className={styles.field}>
<div className={styles.fieldLabel}>Конвертируете</div>
<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"
/>
<input type="text" value={usdtVal} readOnly />
<div className={styles.currency}>
<span className={`${styles.currencyIcon} ${styles.currencyRub}`}></span>
RUB
<span className={`${styles.currencyIcon} ${styles.currencyUsdt}`}></span>
USDT
</div>
</div>
</div>
@@ -66,8 +72,6 @@ export function ConverterSection() {
<button
type="button"
className={styles.swapBtn}
onClick={c.toggleMode}
aria-label="Поменять направление"
>
<svg width={16} height={16} viewBox="0 0 16 16" fill="none">
<path
@@ -82,12 +86,18 @@ export function ConverterSection() {
</div>
<div className={styles.field}>
<div className={styles.fieldLabel}>Получаете</div>
<div className={styles.fieldLabel}>Платите</div>
<div className={styles.fieldInput}>
<input type="text" value={c.usdtVal} readOnly />
<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
<span className={`${styles.currencyIcon} ${styles.currencyRub}`}></span>
RUB
</div>
</div>
</div>