diff --git a/frontend/src/components/form/Step1Phone.tsx b/frontend/src/components/form/Step1Phone.tsx
new file mode 100644
index 0000000..3659566
--- /dev/null
+++ b/frontend/src/components/form/Step1Phone.tsx
@@ -0,0 +1,172 @@
+import { useState } from 'react';
+import { Form, Input, Button, message, Space } from 'antd';
+import { PhoneOutlined, SafetyOutlined, MailOutlined } from '@ant-design/icons';
+
+interface Props {
+ formData: any;
+ updateFormData: (data: any) => void;
+ onNext: () => void;
+ setIsPhoneVerified: (verified: boolean) => void;
+ addDebugEvent?: (type: string, status: string, message: string, data?: any) => void;
+}
+
+export default function Step1Phone({
+ formData,
+ updateFormData,
+ onNext,
+ setIsPhoneVerified,
+ addDebugEvent
+}: Props) {
+ const [form] = Form.useForm();
+ const [codeSent, setCodeSent] = useState(false);
+ const [loading, setLoading] = useState(false);
+ const [verifyLoading, setVerifyLoading] = useState(false);
+
+ const sendCode = async () => {
+ try {
+ const values = await form.validateFields(['phone', 'email']);
+ const phone = values.phone;
+
+ setLoading(true);
+ addDebugEvent?.('sms', 'pending', `📱 Отправляю SMS на ${phone}...`, { phone });
+
+ const response = await fetch('http://147.45.146.17:8100/api/v1/sms/send', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ phone })
+ });
+
+ const result = await response.json();
+
+ if (response.ok) {
+ addDebugEvent?.('sms', 'success', `✅ SMS отправлен (DEBUG mode)`, {
+ phone,
+ debug_code: result.debug_code,
+ message: result.message
+ });
+ message.success('Код отправлен на ваш телефон');
+ setCodeSent(true);
+ updateFormData({ phone: values.phone, email: values.email });
+ if (result.debug_code) {
+ message.info(`DEBUG: Код ${result.debug_code}`);
+ }
+ } else {
+ addDebugEvent?.('sms', 'error', `❌ Ошибка SMS: ${result.detail}`, { error: result.detail });
+ message.error(result.detail || 'Ошибка отправки кода');
+ }
+ } catch (error) {
+ if ((error as any)?.errorFields) {
+ message.error('Введите телефон и email');
+ } else {
+ message.error('Ошибка соединения с сервером');
+ }
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const verifyCode = async () => {
+ try {
+ const values = await form.validateFields(['phone', 'smsCode']);
+ const phone = values.phone;
+ const code = values.smsCode;
+
+ setVerifyLoading(true);
+ addDebugEvent?.('sms', 'pending', `🔐 Проверяю SMS код...`, { phone, code });
+
+ const response = await fetch('http://147.45.146.17:8100/api/v1/sms/verify', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ phone, code })
+ });
+
+ const result = await response.json();
+
+ if (response.ok) {
+ addDebugEvent?.('sms', 'success', `✅ Телефон подтвержден успешно`, { phone, verified: true });
+ message.success('Телефон подтвержден!');
+ setIsPhoneVerified(true);
+ onNext();
+ } else {
+ addDebugEvent?.('sms', 'error', `❌ Неверный код SMS`, { phone, code, error: result.detail });
+ message.error(result.detail || 'Неверный код');
+ }
+ } catch (error) {
+ if ((error as any)?.errorFields) {
+ message.error('Введите код из SMS');
+ } else {
+ message.error('Ошибка соединения с сервером');
+ }
+ } finally {
+ setVerifyLoading(false);
+ }
+ };
+
+ return (
+
+ }
+ placeholder="+79001234567"
+ maxLength={12}
+ size="large"
+ />
+
+
+
+ }
+ placeholder="example@mail.ru"
+ size="large"
+ type="email"
+ />
+
+
+
+ {!codeSent ? (
+
+ ) : (
+
+ }
+ placeholder="123456"
+ maxLength={6}
+ style={{ width: '70%' }}
+ size="large"
+ name="smsCode"
+ onChange={(e) => form.setFieldValue('smsCode', e.target.value)}
+ />
+
+
+ )}
+
+
+ );
+}
+
+
diff --git a/frontend/src/components/form/Step3Payment.tsx b/frontend/src/components/form/Step3Payment.tsx
index 766147f..1333098 100644
--- a/frontend/src/components/form/Step3Payment.tsx
+++ b/frontend/src/components/form/Step3Payment.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react';
-import { Form, Input, Button, Select, message, Space, Divider } from 'antd';
-import { PhoneOutlined, SafetyOutlined, QrcodeOutlined, MailOutlined } from '@ant-design/icons';
+import { Form, Input, Button, Select, message, Divider } from 'antd';
+import { QrcodeOutlined } from '@ant-design/icons';
const { Option } = Select;
@@ -24,96 +24,12 @@ export default function Step3Payment({
addDebugEvent
}: Props) {
const [form] = Form.useForm();
- const [codeSent, setCodeSent] = useState(false);
- const [loading, setLoading] = useState(false);
- const [verifyLoading, setVerifyLoading] = useState(false);
+ const [codeSent] = useState(false);
+ const [loading] = useState(false);
+ const [verifyLoading] = useState(false);
const [submitting, setSubmitting] = useState(false);
- const sendCode = async () => {
- try {
- const phone = form.getFieldValue('phone');
- if (!phone) {
- message.error('Введите номер телефона');
- return;
- }
-
- setLoading(true);
-
- addDebugEvent?.('sms', 'pending', `📱 Отправляю SMS на ${phone}...`, { phone });
-
- const response = await fetch('http://147.45.146.17:8100/api/v1/sms/send', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ phone }),
- });
-
- const result = await response.json();
-
- if (response.ok) {
- addDebugEvent?.('sms', 'success', `✅ SMS отправлен (DEBUG mode)`, {
- phone,
- debug_code: result.debug_code,
- message: result.message
- });
- message.success('Код отправлен на ваш телефон');
- setCodeSent(true);
- if (result.debug_code) {
- message.info(`DEBUG: Код ${result.debug_code}`);
- }
- } else {
- addDebugEvent?.('sms', 'error', `❌ Ошибка SMS: ${result.detail}`, { error: result.detail });
- message.error(result.detail || 'Ошибка отправки кода');
- }
- } catch (error) {
- message.error('Ошибка соединения с сервером');
- } finally {
- setLoading(false);
- }
- };
-
- const verifyCode = async () => {
- try {
- const phone = form.getFieldValue('phone');
- const code = form.getFieldValue('smsCode');
-
- if (!code) {
- message.error('Введите код из SMS');
- return;
- }
-
- setVerifyLoading(true);
-
- addDebugEvent?.('sms', 'pending', `🔐 Проверяю SMS код...`, { phone, code });
-
- const response = await fetch('http://147.45.146.17:8100/api/v1/sms/verify', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ phone, code }),
- });
-
- const result = await response.json();
-
- if (response.ok) {
- addDebugEvent?.('sms', 'success', `✅ Телефон подтвержден успешно`, {
- phone,
- verified: true
- });
- message.success('Телефон подтвержден!');
- setIsPhoneVerified(true);
- } else {
- addDebugEvent?.('sms', 'error', `❌ Неверный код SMS`, {
- phone,
- code,
- error: result.detail
- });
- message.error(result.detail || 'Неверный код');
- }
- } catch (error) {
- message.error('Ошибка соединения с сервером');
- } finally {
- setVerifyLoading(false);
- }
- };
+ // Верификация телефона перенесена на шаг 1
const handleSubmit = async () => {
try {
@@ -143,106 +59,18 @@ export default function Step3Payment({
- {/* Блок верификации телефона */}
-
+ {/* Блок верификации телефона перенесен на шаг 1 */}
+ {isPhoneVerified && (
+
+ ✅ Телефон подтвержден
+
+ )}
{/* Блок выплаты (показывается только после верификации) */}
{isPhoneVerified && (
diff --git a/frontend/src/pages/ClaimForm.tsx b/frontend/src/pages/ClaimForm.tsx
index 3aaaae2..bfaea4f 100644
--- a/frontend/src/pages/ClaimForm.tsx
+++ b/frontend/src/pages/ClaimForm.tsx
@@ -1,6 +1,7 @@
import { useState, useMemo, useCallback } from 'react';
import { Steps, Card, message, Row, Col } from 'antd';
import Step1Policy from '../components/form/Step1Policy';
+import Step1Phone from '../components/form/Step1Phone';
import Step2EventType from '../components/form/Step2EventType';
import StepDocumentUpload from '../components/form/StepDocumentUpload';
import Step3Payment from '../components/form/Step3Payment';
@@ -165,7 +166,22 @@ export default function ClaimForm() {
const steps = useMemo(() => {
const stepsArray: any[] = [];
- // Шаг 1: Policy (всегда)
+ // Шаг 1: Подтверждение телефона (всегда)
+ stepsArray.push({
+ title: 'Телефон',
+ description: 'Подтверждение по SMS',
+ content: (
+
+ ),
+ });
+
+ // Шаг 2: Policy (всегда)
stepsArray.push({
title: 'Проверка полиса',
description: 'Полис ERV',
@@ -179,7 +195,7 @@ export default function ClaimForm() {
),
});
- // Шаг 2: Event Type Selection (всегда)
+ // Шаг 3: Event Type Selection (всегда)
stepsArray.push({
title: 'Тип события',
description: 'Выбор случая',
@@ -193,7 +209,7 @@ export default function ClaimForm() {
),
});
- // Шаги 3+: Document Upload (динамически, если выбран eventType)
+ // Шаги 4+: Document Upload (динамически, если выбран eventType)
if (formData.eventType && documentConfigs.length > 0) {
documentConfigs.forEach((docConfig, index) => {
stepsArray.push({