🚀 MVP: FastAPI + React форма с SMS верификацией

 Инфраструктура: PostgreSQL, Redis, RabbitMQ, S3
 Backend: SMS сервис + API endpoints
 Frontend: React форма (3 шага) + SMS верификация
This commit is contained in:
AI Assistant
2025-10-24 16:19:58 +03:00
parent 8af23e90fa
commit 0f82eef08d
42 changed files with 2902 additions and 241 deletions

View File

@@ -0,0 +1,131 @@
import { Form, Input, Radio, Button, Select, message } from 'antd';
import { BankOutlined, CreditCardOutlined, QrcodeOutlined } from '@ant-design/icons';
import { useState } from 'react';
const { Option } = Select;
interface Props {
formData: any;
updateFormData: (data: any) => void;
onPrev: () => void;
onSubmit: () => void;
}
export default function Step3Payment({ formData, updateFormData, onPrev, onSubmit }: Props) {
const [form] = Form.useForm();
const [paymentMethod, setPaymentMethod] = useState(formData.paymentMethod || 'sbp');
const [submitting, setSubmitting] = useState(false);
const handleSubmit = async () => {
try {
const values = await form.validateFields();
updateFormData(values);
setSubmitting(true);
await onSubmit();
} catch (error) {
message.error('Заполните все обязательные поля');
} finally {
setSubmitting(false);
}
};
return (
<Form
form={form}
layout="vertical"
initialValues={formData}
style={{ marginTop: 24 }}
>
<Form.Item
label="Способ выплаты"
name="paymentMethod"
rules={[{ required: true, message: 'Выберите способ выплаты' }]}
>
<Radio.Group onChange={(e) => setPaymentMethod(e.target.value)}>
<Radio.Button value="sbp">
<QrcodeOutlined /> СБП (Быстрые платежи)
</Radio.Button>
<Radio.Button value="card">
<CreditCardOutlined /> Карта
</Radio.Button>
<Radio.Button value="bank_transfer">
<BankOutlined /> Банковский счет
</Radio.Button>
</Radio.Group>
</Form.Item>
{paymentMethod === 'sbp' && (
<Form.Item
label="Банк для СБП"
name="bankName"
rules={[{ required: true, message: 'Выберите банк' }]}
>
<Select placeholder="Выберите ваш банк">
<Option value="sberbank">Сбербанк</Option>
<Option value="tinkoff">Тинькофф</Option>
<Option value="vtb">ВТБ</Option>
<Option value="alfabank">Альфа-Банк</Option>
<Option value="raiffeisen">Райффайзенбанк</Option>
<Option value="other">Другой</Option>
</Select>
</Form.Item>
)}
{paymentMethod === 'card' && (
<Form.Item
label="Номер карты"
name="cardNumber"
rules={[
{ required: true, message: 'Введите номер карты' },
{ pattern: /^\d{16}$/, message: '16 цифр без пробелов' }
]}
>
<Input
prefix={<CreditCardOutlined />}
placeholder="1234567890123456"
maxLength={16}
/>
</Form.Item>
)}
{paymentMethod === 'bank_transfer' && (
<>
<Form.Item
label="Название банка"
name="bankName"
rules={[{ required: true, message: 'Введите название банка' }]}
>
<Input prefix={<BankOutlined />} placeholder="Сбербанк" />
</Form.Item>
<Form.Item
label="Номер счета"
name="accountNumber"
rules={[
{ required: true, message: 'Введите номер счета' },
{ pattern: /^\d{20}$/, message: '20 цифр' }
]}
>
<Input placeholder="12345678901234567890" maxLength={20} />
</Form.Item>
</>
)}
<Form.Item>
<div style={{ display: 'flex', gap: 8, marginTop: 32 }}>
<Button onClick={onPrev}>Назад</Button>
<Button
type="primary"
onClick={handleSubmit}
loading={submitting}
style={{ flex: 1 }}
size="large"
>
Отправить заявку
</Button>
</div>
</Form.Item>
</Form>
);
}