diff --git a/src/features/payment/api/paymentApi.ts b/src/features/payment/api/paymentApi.ts index 5c3e266..ff91ab0 100644 --- a/src/features/payment/api/paymentApi.ts +++ b/src/features/payment/api/paymentApi.ts @@ -25,7 +25,7 @@ export interface PaymentQuote { export async function getPaymentConfig(): Promise { const csrf = await getCsrfToken() - const res = await fetch(`${PAYMENT_API_URL}/config`, { + const res = await fetch(`${PAYMENT_API_URL}/payment/config`, { credentials: 'include', headers: { 'X-CSRF-Token': csrf }, }) @@ -44,3 +44,53 @@ export async function getPaymentQuote(usdtAmount: number): Promise if (!res.ok) throw data return data } + +export interface CreateOrderPayload { + usdt_amount: number + usdt_exchange_rate: number + gas_fee: number + total_price: number +} + +export interface OrderResult { + status_code: number + order: { + id: string + created_at: string + updated_at: string + user_id: string + usdt_amount: string + usdt_exchange_rate: string + gas_fee: string + total_price: string + service_fee: string + status: string + client_payment_id: string + itpay_payment_qr_url_desktop: string + itpay_payment_qr_url_android: string + itpay_payment_qr_url_ios: string + itpay_payment_qr_image_desktop: string + itpay_payment_qr_image_android: string + itpay_payment_qr_image_ios: string + itpay_id: string + itpay_qr_id: string + itpay_amount: string + itpay_created_at: string + } +} + +export async function createOrder(payload: CreateOrderPayload): Promise { + const csrf = await getCsrfToken() + const res = await fetch(`${PAYMENT_API_URL}/order/create`, { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': csrf, + }, + body: JSON.stringify(payload), + }) + const data = await res.json() + if (!res.ok) throw data + return data +} diff --git a/src/features/payment/hooks/useCreateOrder.ts b/src/features/payment/hooks/useCreateOrder.ts new file mode 100644 index 0000000..2d85e91 --- /dev/null +++ b/src/features/payment/hooks/useCreateOrder.ts @@ -0,0 +1,12 @@ +import { useMutation } from '@tanstack/react-query' +import { createOrder } from '../api/paymentApi' + +export function useCreateOrder() { + return useMutation({ + mutationFn: createOrder, + onSuccess: (data) => { + const url = data.order.itpay_payment_qr_url_desktop + if (url) window.location.href = url + }, + }) +} diff --git a/src/features/payment/index.ts b/src/features/payment/index.ts index 81f5fb9..5481ea6 100644 --- a/src/features/payment/index.ts +++ b/src/features/payment/index.ts @@ -1,3 +1,4 @@ export { usePaymentConfig } from './hooks/usePaymentConfig' export { usePaymentQuote } from './hooks/usePaymentQuote' -export type { PaymentConfig, PaymentQuote } from './api/paymentApi' +export { useCreateOrder } from './hooks/useCreateOrder' +export type { PaymentConfig, PaymentQuote, CreateOrderPayload, OrderResult } from './api/paymentApi' diff --git a/src/widgets/converter-page/ui/ConverterSection.module.css b/src/widgets/converter-page/ui/ConverterSection.module.css index 47cc094..0da6452 100644 --- a/src/widgets/converter-page/ui/ConverterSection.module.css +++ b/src/widgets/converter-page/ui/ConverterSection.module.css @@ -174,6 +174,24 @@ border-top: 1px solid var(--glass-border); } +.payBtn { + width: 100%; + margin-top: 24px; + padding: 18px; + border-radius: 12px; + background: var(--grad-center); + color: var(--text-primary); + font-size: 16px; + font-weight: 600; + letter-spacing: 1px; + transition: opacity 0.2s; +} + +.payBtn:disabled { + opacity: 0.4; + cursor: not-allowed; +} + @media (max-width: 1024px) { .body { grid-template-columns: 1fr; diff --git a/src/widgets/converter-page/ui/ConverterSection.tsx b/src/widgets/converter-page/ui/ConverterSection.tsx index 62459c4..b43df33 100644 --- a/src/widgets/converter-page/ui/ConverterSection.tsx +++ b/src/widgets/converter-page/ui/ConverterSection.tsx @@ -1,7 +1,7 @@ import { useConverter } from '@widgets/currency-converter' import { USDT_RATE, GAS_PRICE } from '@shared/config/constants' import { useDebounce } from '@shared/lib/hooks/useDebounce' -import { usePaymentConfig, usePaymentQuote } from '@features/payment' +import { usePaymentConfig, usePaymentQuote, useCreateOrder } from '@features/payment' import { CommissionPanel } from './CommissionPanel' import { AgreementCheck } from './AgreementCheck' import styles from './ConverterSection.module.css' @@ -19,6 +19,17 @@ export function ConverterSection() { const rubTotal = quote?.total_price ?? '' + const { mutate: submitOrder, isPending } = useCreateOrder() + + function handlePay() { + submitOrder({ + usdt_amount: c.numRub, + usdt_exchange_rate: 1, + gas_fee: 1, + total_price: Number(rubTotal) || 0, + }) + } + return (
@@ -49,6 +60,7 @@ export function ConverterSection() {
) } diff --git a/src/widgets/currency-converter/ui/Converter.tsx b/src/widgets/currency-converter/ui/Converter.tsx index 5419f9c..680ef79 100644 --- a/src/widgets/currency-converter/ui/Converter.tsx +++ b/src/widgets/currency-converter/ui/Converter.tsx @@ -42,6 +42,7 @@ export function Converter() { className={styles.tab} data-active={c.mode === 'sell' || undefined} onClick={() => c.setMode('sell')} + disabled > ПРОДАТЬ diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo index 14ee701..ed380af 100644 --- a/tsconfig.tsbuildinfo +++ b/tsconfig.tsbuildinfo @@ -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/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"} \ No newline at end of file +{"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/usecreateorder.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"} \ No newline at end of file