feat: похуйу
This commit is contained in:
46
src/features/payment/api/paymentApi.ts
Normal file
46
src/features/payment/api/paymentApi.ts
Normal 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
|
||||
}
|
||||
11
src/features/payment/hooks/usePaymentConfig.ts
Normal file
11
src/features/payment/hooks/usePaymentConfig.ts
Normal 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,
|
||||
})
|
||||
}
|
||||
12
src/features/payment/hooks/usePaymentQuote.ts
Normal file
12
src/features/payment/hooks/usePaymentQuote.ts
Normal 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,
|
||||
})
|
||||
}
|
||||
3
src/features/payment/index.ts
Normal file
3
src/features/payment/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export { usePaymentConfig } from './hooks/usePaymentConfig'
|
||||
export { usePaymentQuote } from './hooks/usePaymentQuote'
|
||||
export type { PaymentConfig, PaymentQuote } from './api/paymentApi'
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"root":["./src/main.tsx","./src/vite-env.d.ts","./src/app/app.tsx","./src/app/providers/guestroute.tsx","./src/app/providers/protectedroute.tsx","./src/app/providers/queryprovider.tsx","./src/app/providers/routerprovider.tsx","./src/app/providers/scrolltotop.tsx","./src/app/providers/index.ts","./src/features/auth/index.ts","./src/features/auth/api/registrationapi.ts","./src/features/auth/hooks/useauth.ts","./src/features/auth/hooks/useisauthenticated.ts","./src/features/kyc/api/kycapi.ts","./src/pages/converter/index.ts","./src/pages/converter/ui/converterpage.tsx","./src/pages/home/index.ts","./src/pages/home/ui/homepage.tsx","./src/pages/kyc/index.ts","./src/pages/kyc/ui/kycpage.tsx","./src/pages/login/index.ts","./src/pages/login/ui/loginpage.tsx","./src/pages/profile/index.ts","./src/pages/profile/ui/profilepage.tsx","./src/pages/register/index.ts","./src/pages/register/ui/registerpage.tsx","./src/pages/seed-phrase/index.ts","./src/pages/seed-phrase/ui/seedphrasepage.tsx","./src/pages/swap/index.ts","./src/pages/swap/ui/swappage.tsx","./src/pages/wallet/index.ts","./src/pages/wallet/ui/walletpage.tsx","./src/shared/api/base.ts","./src/shared/api/csrf.ts","./src/shared/api/tokenstore.ts","./src/shared/api/types.ts","./src/shared/config/constants.ts","./src/shared/config/env.ts","./src/shared/config/routes.ts","./src/shared/lib/hooks/usedebounce.ts","./src/shared/lib/hooks/uselocalstorage.ts","./src/shared/lib/utils/cn.ts","./src/shared/types/index.ts","./src/shared/ui/index.ts","./src/shared/ui/button/button.tsx","./src/shared/ui/button/index.ts","./src/shared/ui/formfield/formfield.tsx","./src/shared/ui/formfield/index.ts","./src/shared/ui/notification/notification.tsx","./src/shared/ui/notification/index.ts","./src/shared/ui/pill/pill.tsx","./src/shared/ui/pill/index.ts","./src/shared/ui/primarybutton/primarybutton.tsx","./src/shared/ui/primarybutton/index.ts","./src/shared/ui/title/title.tsx","./src/shared/ui/tokenicon/tokenicon.tsx","./src/shared/ui/tokenicon/index.ts","./src/widgets/about/index.ts","./src/widgets/about/ui/about.tsx","./src/widgets/balance-card/index.ts","./src/widgets/balance-card/ui/balancecard.tsx","./src/widgets/converter-page/index.ts","./src/widgets/converter-page/ui/agreementcheck.tsx","./src/widgets/converter-page/ui/commissionpanel.tsx","./src/widgets/converter-page/ui/convertersection.tsx","./src/widgets/currency-converter/index.ts","./src/widgets/currency-converter/model/tiers.ts","./src/widgets/currency-converter/model/useconverter.ts","./src/widgets/currency-converter/ui/agreementcheckbox.tsx","./src/widgets/currency-converter/ui/commissiontable.tsx","./src/widgets/currency-converter/ui/converter.tsx","./src/widgets/currency-converter/ui/tiers.tsx","./src/widgets/footer/index.ts","./src/widgets/footer/ui/footer.tsx","./src/widgets/header/index.ts","./src/widgets/header/ui/header.tsx","./src/widgets/hero/index.ts","./src/widgets/hero/lib/usecountdown.ts","./src/widgets/hero/ui/conversionflow.tsx","./src/widgets/hero/ui/countdown.tsx","./src/widgets/hero/ui/exchangecard.tsx","./src/widgets/hero/ui/hero.tsx","./src/widgets/kyc-verification/index.ts","./src/widgets/kyc-verification/model/usekyc.ts","./src/widgets/kyc-verification/ui/kycmodal.tsx","./src/widgets/kyc-verification/ui/kycwidget.tsx","./src/widgets/login-form/index.ts","./src/widgets/login-form/model/useloginform.ts","./src/widgets/login-form/ui/loginform.tsx","./src/widgets/networks-table/index.ts","./src/widgets/networks-table/model/networks.ts","./src/widgets/networks-table/ui/networkstable.tsx","./src/widgets/profile/index.ts","./src/widgets/profile/ui/profileavatar.tsx","./src/widgets/profile/ui/profilesection.tsx","./src/widgets/register-form/index.ts","./src/widgets/register-form/model/useregisterform.ts","./src/widgets/register-form/ui/registerform.tsx","./src/widgets/seed-phrase/index.ts","./src/widgets/seed-phrase/model/useseedphrase.ts","./src/widgets/seed-phrase/ui/seedphrasewidget.tsx","./src/widgets/swap-form/index.ts","./src/widgets/swap-form/model/useswapform.ts","./src/widgets/swap-form/ui/raterow.tsx","./src/widgets/swap-form/ui/swapcard.tsx","./src/widgets/swap-form/ui/swapdirectionbutton.tsx","./src/widgets/swap-form/ui/swapform.tsx","./src/widgets/swap-form/ui/swapinfopanel.tsx","./src/widgets/swap-form/ui/tokenselect.tsx","./src/widgets/token-table/index.ts","./src/widgets/token-table/model/tokens.ts","./src/widgets/token-table/ui/tokentable.tsx","./src/widgets/wallet-header/index.ts","./src/widgets/wallet-header/ui/walletheader.tsx"],"version":"5.6.3"}
|
||||
{"root":["./src/main.tsx","./src/vite-env.d.ts","./src/app/app.tsx","./src/app/providers/guestroute.tsx","./src/app/providers/protectedroute.tsx","./src/app/providers/queryprovider.tsx","./src/app/providers/routerprovider.tsx","./src/app/providers/scrolltotop.tsx","./src/app/providers/index.ts","./src/features/auth/index.ts","./src/features/auth/api/profileapi.ts","./src/features/auth/api/registrationapi.ts","./src/features/auth/hooks/useauth.ts","./src/features/auth/hooks/useisauthenticated.ts","./src/features/auth/hooks/useme.ts","./src/features/kyc/api/kycapi.ts","./src/features/payment/index.ts","./src/features/payment/api/paymentapi.ts","./src/features/payment/hooks/usepaymentconfig.ts","./src/features/payment/hooks/usepaymentquote.ts","./src/pages/converter/index.ts","./src/pages/converter/ui/converterpage.tsx","./src/pages/home/index.ts","./src/pages/home/ui/homepage.tsx","./src/pages/kyc/index.ts","./src/pages/kyc/ui/kycpage.tsx","./src/pages/login/index.ts","./src/pages/login/ui/loginpage.tsx","./src/pages/profile/index.ts","./src/pages/profile/ui/profilepage.tsx","./src/pages/register/index.ts","./src/pages/register/ui/registerpage.tsx","./src/pages/seed-phrase/index.ts","./src/pages/seed-phrase/ui/seedphrasepage.tsx","./src/pages/swap/index.ts","./src/pages/swap/ui/swappage.tsx","./src/pages/wallet/index.ts","./src/pages/wallet/ui/walletpage.tsx","./src/shared/api/base.ts","./src/shared/api/csrf.ts","./src/shared/api/tokenstore.ts","./src/shared/api/types.ts","./src/shared/config/constants.ts","./src/shared/config/env.ts","./src/shared/config/routes.ts","./src/shared/lib/hooks/usedebounce.ts","./src/shared/lib/hooks/uselocalstorage.ts","./src/shared/lib/utils/cn.ts","./src/shared/types/index.ts","./src/shared/ui/index.ts","./src/shared/ui/button/button.tsx","./src/shared/ui/button/index.ts","./src/shared/ui/formfield/formfield.tsx","./src/shared/ui/formfield/index.ts","./src/shared/ui/notification/notification.tsx","./src/shared/ui/notification/index.ts","./src/shared/ui/pill/pill.tsx","./src/shared/ui/pill/index.ts","./src/shared/ui/primarybutton/primarybutton.tsx","./src/shared/ui/primarybutton/index.ts","./src/shared/ui/title/title.tsx","./src/shared/ui/tokenicon/tokenicon.tsx","./src/shared/ui/tokenicon/index.ts","./src/widgets/about/index.ts","./src/widgets/about/ui/about.tsx","./src/widgets/balance-card/index.ts","./src/widgets/balance-card/ui/balancecard.tsx","./src/widgets/converter-page/index.ts","./src/widgets/converter-page/ui/agreementcheck.tsx","./src/widgets/converter-page/ui/commissionpanel.tsx","./src/widgets/converter-page/ui/convertersection.tsx","./src/widgets/currency-converter/index.ts","./src/widgets/currency-converter/model/tiers.ts","./src/widgets/currency-converter/model/useconverter.ts","./src/widgets/currency-converter/ui/agreementcheckbox.tsx","./src/widgets/currency-converter/ui/commissiontable.tsx","./src/widgets/currency-converter/ui/converter.tsx","./src/widgets/currency-converter/ui/tiers.tsx","./src/widgets/footer/index.ts","./src/widgets/footer/ui/footer.tsx","./src/widgets/header/index.ts","./src/widgets/header/ui/header.tsx","./src/widgets/hero/index.ts","./src/widgets/hero/lib/usecountdown.ts","./src/widgets/hero/ui/conversionflow.tsx","./src/widgets/hero/ui/countdown.tsx","./src/widgets/hero/ui/exchangecard.tsx","./src/widgets/hero/ui/hero.tsx","./src/widgets/kyc-verification/index.ts","./src/widgets/kyc-verification/model/usekyc.ts","./src/widgets/kyc-verification/ui/kycmodal.tsx","./src/widgets/kyc-verification/ui/kycwidget.tsx","./src/widgets/login-form/index.ts","./src/widgets/login-form/model/useloginform.ts","./src/widgets/login-form/ui/loginform.tsx","./src/widgets/networks-table/index.ts","./src/widgets/networks-table/model/networks.ts","./src/widgets/networks-table/ui/networkstable.tsx","./src/widgets/profile/index.ts","./src/widgets/profile/ui/profileavatar.tsx","./src/widgets/profile/ui/profilesection.tsx","./src/widgets/register-form/index.ts","./src/widgets/register-form/model/useregisterform.ts","./src/widgets/register-form/ui/registerform.tsx","./src/widgets/seed-phrase/index.ts","./src/widgets/seed-phrase/model/useseedphrase.ts","./src/widgets/seed-phrase/ui/seedphrasewidget.tsx","./src/widgets/swap-form/index.ts","./src/widgets/swap-form/model/useswapform.ts","./src/widgets/swap-form/ui/raterow.tsx","./src/widgets/swap-form/ui/swapcard.tsx","./src/widgets/swap-form/ui/swapdirectionbutton.tsx","./src/widgets/swap-form/ui/swapform.tsx","./src/widgets/swap-form/ui/swapinfopanel.tsx","./src/widgets/swap-form/ui/tokenselect.tsx","./src/widgets/token-table/index.ts","./src/widgets/token-table/model/tokens.ts","./src/widgets/token-table/ui/tokentable.tsx","./src/widgets/wallet-header/index.ts","./src/widgets/wallet-header/ui/walletheader.tsx"],"version":"5.6.3"}
|
||||
Reference in New Issue
Block a user