feat: похуйу
This commit is contained in:
@@ -25,7 +25,7 @@ export interface PaymentQuote {
|
||||
|
||||
export async function getPaymentConfig(): Promise<PaymentConfig> {
|
||||
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<PaymentQuote>
|
||||
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<OrderResult> {
|
||||
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
|
||||
}
|
||||
|
||||
12
src/features/payment/hooks/useCreateOrder.ts
Normal file
12
src/features/payment/hooks/useCreateOrder.ts
Normal file
@@ -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
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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'
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 (
|
||||
<div className={styles.wrap}>
|
||||
<div className={styles.header}>
|
||||
@@ -49,6 +60,7 @@ export function ConverterSection() {
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
disabled
|
||||
className={styles.tab}
|
||||
data-active={c.mode === 'sell' || undefined}
|
||||
onClick={() => c.setMode('sell')}
|
||||
@@ -116,6 +128,15 @@ export function ConverterSection() {
|
||||
<div className={styles.bottom}>
|
||||
<AgreementCheck checked={c.agreed} onToggle={() => c.setAgreed(!c.agreed)} />
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className={styles.payBtn}
|
||||
onClick={handlePay}
|
||||
disabled={!rubTotal || isPending}
|
||||
>
|
||||
{isPending ? 'Обработка...' : 'Оплатить'}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ export function Converter() {
|
||||
className={styles.tab}
|
||||
data-active={c.mode === 'sell' || undefined}
|
||||
onClick={() => c.setMode('sell')}
|
||||
disabled
|
||||
>
|
||||
ПРОДАТЬ
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user