🚀 MVP: FastAPI + React форма с SMS верификацией
✅ Инфраструктура: PostgreSQL, Redis, RabbitMQ, S3 ✅ Backend: SMS сервис + API endpoints ✅ Frontend: React форма (3 шага) + SMS верификация
This commit is contained in:
122
frontend/src/components/form/Step2Details.tsx
Normal file
122
frontend/src/components/form/Step2Details.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
import { Form, Input, DatePicker, Select, Button, Upload, message } from 'antd';
|
||||
import { UploadOutlined } from '@ant-design/icons';
|
||||
import type { UploadFile } from 'antd/es/upload/interface';
|
||||
import { useState } from 'react';
|
||||
|
||||
const { TextArea } = Input;
|
||||
const { Option } = Select;
|
||||
|
||||
interface Props {
|
||||
formData: any;
|
||||
updateFormData: (data: any) => void;
|
||||
onNext: () => void;
|
||||
onPrev: () => void;
|
||||
}
|
||||
|
||||
export default function Step2Details({ formData, updateFormData, onNext, onPrev }: Props) {
|
||||
const [form] = Form.useForm();
|
||||
const [fileList, setFileList] = useState<UploadFile[]>([]);
|
||||
|
||||
const handleNext = async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
updateFormData({
|
||||
...values,
|
||||
incidentDate: values.incidentDate?.format('YYYY-MM-DD'),
|
||||
uploadedFiles: fileList.map(f => f.uid),
|
||||
});
|
||||
onNext();
|
||||
} catch (error) {
|
||||
message.error('Заполните все обязательные поля');
|
||||
}
|
||||
};
|
||||
|
||||
const uploadProps = {
|
||||
fileList,
|
||||
beforeUpload: (file: File) => {
|
||||
const isImage = file.type.startsWith('image/');
|
||||
const isPDF = file.type === 'application/pdf';
|
||||
if (!isImage && !isPDF) {
|
||||
message.error('Можно загружать только изображения и PDF');
|
||||
return false;
|
||||
}
|
||||
const isLt10M = file.size / 1024 / 1024 < 10;
|
||||
if (!isLt10M) {
|
||||
message.error('Файл должен быть меньше 10MB');
|
||||
return false;
|
||||
}
|
||||
|
||||
setFileList([...fileList, {
|
||||
uid: Math.random().toString(),
|
||||
name: file.name,
|
||||
status: 'done',
|
||||
url: URL.createObjectURL(file),
|
||||
} as UploadFile]);
|
||||
|
||||
return false; // Отключаем автозагрузку
|
||||
},
|
||||
onRemove: (file: UploadFile) => {
|
||||
setFileList(fileList.filter(f => f.uid !== file.uid));
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={formData}
|
||||
style={{ marginTop: 24 }}
|
||||
>
|
||||
<Form.Item
|
||||
label="Дата происшествия"
|
||||
name="incidentDate"
|
||||
>
|
||||
<DatePicker style={{ width: '100%' }} format="DD.MM.YYYY" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Тип транспорта"
|
||||
name="transportType"
|
||||
>
|
||||
<Select placeholder="Выберите тип транспорта">
|
||||
<Option value="air">Авиа</Option>
|
||||
<Option value="train">Поезд</Option>
|
||||
<Option value="bus">Автобус</Option>
|
||||
<Option value="ship">Водный транспорт</Option>
|
||||
<Option value="other">Другое</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Описание происшествия"
|
||||
name="incidentDescription"
|
||||
>
|
||||
<TextArea
|
||||
rows={4}
|
||||
placeholder="Опишите что произошло..."
|
||||
maxLength={1000}
|
||||
showCount
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Документы (билеты, справки, чеки)">
|
||||
<Upload {...uploadProps} listType="picture">
|
||||
<Button icon={<UploadOutlined />}>Загрузить файлы</Button>
|
||||
</Upload>
|
||||
<div style={{ marginTop: 8, color: '#999', fontSize: 12 }}>
|
||||
Максимум 10 MB на файл. Форматы: JPG, PNG, PDF, HEIC
|
||||
</div>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
<Button onClick={onPrev}>Назад</Button>
|
||||
<Button type="primary" onClick={handleNext} style={{ flex: 1 }}>
|
||||
Далее
|
||||
</Button>
|
||||
</div>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user