feat: remove old manual payment dialog and api method
This commit is contained in:
@@ -73,20 +73,6 @@ export async function postOrderMessage(id: string, text: string): Promise<void>
|
||||
await apiClient.post(`me/orders/${id}/messages`, { text })
|
||||
}
|
||||
|
||||
/** Подтверждение оплаты переводом: multipart detail + необязательный файл receipt (хотя бы одно нужно на сервере). */
|
||||
export async function submitOrderPayment(
|
||||
orderId: string,
|
||||
payload: { detail: string; receiptFile: File | null },
|
||||
): Promise<{ ok: boolean; status: string }> {
|
||||
const formData = new FormData()
|
||||
formData.append('detail', payload.detail)
|
||||
if (payload.receiptFile) {
|
||||
formData.append('receipt', payload.receiptFile)
|
||||
}
|
||||
const { data } = await apiClient.post<{ ok: boolean; status: string }>(`me/orders/${orderId}/pay`, formData)
|
||||
return data
|
||||
}
|
||||
|
||||
export async function confirmOrderReceived(id: string): Promise<{ ok: boolean; status: string }> {
|
||||
const { data } = await apiClient.post<{ ok: boolean; status: string }>(`me/orders/${id}/confirm-received`)
|
||||
return data
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export { OrderPaymentSection } from './ui/OrderPaymentSection'
|
||||
export { PaymentDialog } from './ui/PaymentDialog'
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import Alert from '@mui/material/Alert'
|
||||
import Box from '@mui/material/Box'
|
||||
import Button from '@mui/material/Button'
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogActions from '@mui/material/DialogActions'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import Stack from '@mui/material/Stack'
|
||||
import TextField from '@mui/material/TextField'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import axios from 'axios'
|
||||
import { PAYMENT_TRANSFER_INSTRUCTIONS_PLAIN } from '@/shared/constants/payment-instructions'
|
||||
|
||||
type Props = {
|
||||
open: boolean
|
||||
isPending: boolean
|
||||
error: unknown
|
||||
onClose: () => void
|
||||
onSubmit: (params: { detail: string; receiptFile: File | null }) => void
|
||||
}
|
||||
|
||||
function paySubmitErrorMessage(err: unknown): string {
|
||||
if (axios.isAxiosError(err)) {
|
||||
const raw = err.response?.data
|
||||
const apiMsg =
|
||||
raw && typeof raw === 'object' && 'error' in raw && typeof (raw as { error: unknown }).error === 'string'
|
||||
? (raw as { error: string }).error
|
||||
: null
|
||||
return apiMsg || err.message || 'Не удалось отправить данные оплаты'
|
||||
}
|
||||
if (err instanceof Error) return err.message
|
||||
return 'Не удалось отправить данные оплаты'
|
||||
}
|
||||
|
||||
export function PaymentDialog({ open, isPending, error, onClose, onSubmit }: Props) {
|
||||
const [detail, setDetail] = useState('')
|
||||
const [receiptFile, setReceiptFile] = useState<File | null>(null)
|
||||
const [clientError, setClientError] = useState<string | null>(null)
|
||||
|
||||
const receiptPreviewUrl = useMemo(() => {
|
||||
if (!receiptFile) return null
|
||||
return URL.createObjectURL(receiptFile)
|
||||
}, [receiptFile])
|
||||
|
||||
useEffect(() => {
|
||||
if (!receiptPreviewUrl) return
|
||||
return () => URL.revokeObjectURL(receiptPreviewUrl)
|
||||
}, [receiptPreviewUrl])
|
||||
|
||||
const reset = () => {
|
||||
setDetail('')
|
||||
setReceiptFile(null)
|
||||
setClientError(null)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
if (isPending) return
|
||||
reset()
|
||||
onClose()
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
const hasText = detail.trim().length > 0
|
||||
const hasFile = Boolean(receiptFile)
|
||||
if (!hasText && !hasFile) {
|
||||
setClientError('Укажите комментарий и/или прикрепите чек.')
|
||||
return
|
||||
}
|
||||
setClientError(null)
|
||||
onSubmit({ detail: detail.trim(), receiptFile })
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={handleClose} fullWidth maxWidth="sm">
|
||||
<DialogTitle>Подтверждение оплаты</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography variant="body2" sx={{ whiteSpace: 'pre-wrap', mb: 2 }}>
|
||||
{PAYMENT_TRANSFER_INSTRUCTIONS_PLAIN}
|
||||
</Typography>
|
||||
<TextField
|
||||
label="Комментарий об оплате (сумма, время перевода и т.д.)"
|
||||
value={detail}
|
||||
onChange={(e) => {
|
||||
setDetail(e.target.value)
|
||||
setClientError(null)
|
||||
}}
|
||||
fullWidth
|
||||
multiline
|
||||
minRows={3}
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={1.5} sx={{ mb: 1, alignItems: { sm: 'center' } }}>
|
||||
<Button component="label" variant="outlined">
|
||||
Прикрепить чек (png, jpg, webp)
|
||||
<input
|
||||
hidden
|
||||
type="file"
|
||||
accept="image/png,image/jpeg,image/webp"
|
||||
onChange={(e) => {
|
||||
const file = e.target.files?.[0]
|
||||
setReceiptFile(file ?? null)
|
||||
setClientError(null)
|
||||
e.currentTarget.value = ''
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
{receiptFile && (
|
||||
<Button color="error" variant="text" onClick={() => setReceiptFile(null)}>
|
||||
Убрать файл
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ mb: 1, display: 'block' }}>
|
||||
Нужен текст комментария и/или изображение чека.
|
||||
</Typography>
|
||||
{receiptPreviewUrl && (
|
||||
<Box
|
||||
component="img"
|
||||
src={receiptPreviewUrl}
|
||||
alt="Предпросмотр чека"
|
||||
sx={{ maxWidth: '100%', maxHeight: 200, borderRadius: 1, border: 1, borderColor: 'divider', mb: 1 }}
|
||||
/>
|
||||
)}
|
||||
{clientError && (
|
||||
<Alert severity="warning" sx={{ mb: 1 }}>
|
||||
{clientError}
|
||||
</Alert>
|
||||
)}
|
||||
{error ? (
|
||||
<Alert severity="error" sx={{ mt: 1 }}>
|
||||
{paySubmitErrorMessage(error)}
|
||||
</Alert>
|
||||
) : null}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleClose} disabled={isPending}>
|
||||
Отмена
|
||||
</Button>
|
||||
<Button variant="contained" disabled={isPending} onClick={handleSubmit}>
|
||||
Подтвердить оплату
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/** Текст модалки оплаты (можно переопределить через VITE_PAYMENT_INSTRUCTIONS — многострочная строка \n). */
|
||||
const fromEnv =
|
||||
typeof import.meta.env.VITE_PAYMENT_INSTRUCTIONS === 'string' ? import.meta.env.VITE_PAYMENT_INSTRUCTIONS.trim() : ''
|
||||
|
||||
export const PAYMENT_TRANSFER_INSTRUCTIONS_PLAIN =
|
||||
fromEnv ||
|
||||
[
|
||||
'Временно оплата доступна только переводом на ВТБ / Сбербанк.',
|
||||
'',
|
||||
'По номеру +79524181624',
|
||||
'Получатель: Лариса К',
|
||||
].join('\n')
|
||||
Reference in New Issue
Block a user