2025-10-30 09:50:26 +03:00
|
|
|
|
import { useState } from 'react';
|
|
|
|
|
|
import { Form, Input, Button, message, Space } from 'antd';
|
2025-10-30 09:52:26 +03:00
|
|
|
|
import { PhoneOutlined, SafetyOutlined } from '@ant-design/icons';
|
2025-10-30 09:50:26 +03:00
|
|
|
|
|
|
|
|
|
|
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 {
|
2025-10-30 09:52:26 +03:00
|
|
|
|
const values = await form.validateFields(['phone']);
|
2025-10-30 18:54:05 +03:00
|
|
|
|
const phone = `7${values.phone}`; // БЕЗ +, формат: 79001234567
|
2025-10-30 09:50:26 +03:00
|
|
|
|
|
|
|
|
|
|
setLoading(true);
|
|
|
|
|
|
addDebugEvent?.('sms', 'pending', `📱 Отправляю SMS на ${phone}...`, { phone });
|
|
|
|
|
|
|
2025-10-30 10:00:28 +03:00
|
|
|
|
const response = await fetch('/api/v1/sms/send', {
|
2025-10-30 09:50:26 +03:00
|
|
|
|
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);
|
2025-10-30 09:54:14 +03:00
|
|
|
|
updateFormData({ phone });
|
2025-10-30 09:50:26 +03:00
|
|
|
|
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) {
|
2025-10-30 09:52:26 +03:00
|
|
|
|
message.error('Введите номер телефона');
|
2025-10-30 09:50:26 +03:00
|
|
|
|
} else {
|
|
|
|
|
|
message.error('Ошибка соединения с сервером');
|
|
|
|
|
|
}
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const verifyCode = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const values = await form.validateFields(['phone', 'smsCode']);
|
2025-10-30 18:54:05 +03:00
|
|
|
|
const phone = `7${values.phone}`; // БЕЗ +, формат: 79001234567
|
2025-10-30 09:50:26 +03:00
|
|
|
|
const code = values.smsCode;
|
|
|
|
|
|
|
|
|
|
|
|
setVerifyLoading(true);
|
|
|
|
|
|
addDebugEvent?.('sms', 'pending', `🔐 Проверяю SMS код...`, { phone, code });
|
|
|
|
|
|
|
2025-10-30 10:00:28 +03:00
|
|
|
|
const response = await fetch('/api/v1/sms/verify', {
|
2025-10-30 09:50:26 +03:00
|
|
|
|
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);
|
2025-11-01 13:31:05 +03:00
|
|
|
|
|
|
|
|
|
|
// После верификации создаём контакт в CRM через n8n
|
|
|
|
|
|
try {
|
|
|
|
|
|
addDebugEvent?.('crm', 'info', '📞 Создание контакта в CRM...', { phone });
|
|
|
|
|
|
|
|
|
|
|
|
const crmResponse = await fetch('https://n8n.clientright.pro/webhook/511fde97-88bb-4fb4-bea5-cafdc364be27', {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
|
body: JSON.stringify({ phone })
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const crmResult = await crmResponse.json();
|
|
|
|
|
|
|
|
|
|
|
|
if (crmResponse.ok) {
|
|
|
|
|
|
addDebugEvent?.('crm', 'success', `✅ Контакт создан/найден в CRM`, crmResult);
|
|
|
|
|
|
|
|
|
|
|
|
// Сохраняем данные из CRM в форму
|
|
|
|
|
|
updateFormData({
|
|
|
|
|
|
phone,
|
|
|
|
|
|
contact_id: crmResult.contact_id,
|
|
|
|
|
|
claim_id: crmResult.claim_id,
|
|
|
|
|
|
is_new_contact: crmResult.is_new_contact
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
message.success(crmResult.is_new_contact ? 'Контакт создан!' : 'Контакт найден!');
|
|
|
|
|
|
onNext();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
addDebugEvent?.('crm', 'error', '❌ Ошибка создания контакта в CRM', crmResult);
|
|
|
|
|
|
message.error('Ошибка создания контакта в CRM');
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (crmError) {
|
|
|
|
|
|
addDebugEvent?.('crm', 'error', '❌ Ошибка соединения с CRM', { error: String(crmError) });
|
|
|
|
|
|
message.error('Ошибка соединения с CRM');
|
|
|
|
|
|
}
|
2025-10-30 09:50:26 +03:00
|
|
|
|
} 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 (
|
|
|
|
|
|
<Form
|
|
|
|
|
|
form={form}
|
|
|
|
|
|
layout="vertical"
|
|
|
|
|
|
initialValues={formData}
|
|
|
|
|
|
style={{ marginTop: 24 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<h3 style={{ marginTop: 0 }}>📱 Подтверждение телефона</h3>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label="Номер телефона"
|
|
|
|
|
|
name="phone"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{ required: true, message: 'Введите номер телефона' },
|
2025-10-30 09:54:14 +03:00
|
|
|
|
{ pattern: /^\d{10}$/, message: 'Введите 10 цифр без кода страны' }
|
2025-10-30 09:50:26 +03:00
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input
|
|
|
|
|
|
prefix={<PhoneOutlined />}
|
2025-10-30 09:54:14 +03:00
|
|
|
|
addonBefore="+7"
|
|
|
|
|
|
placeholder="9001234567"
|
|
|
|
|
|
maxLength={10}
|
2025-10-30 09:50:26 +03:00
|
|
|
|
size="large"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item>
|
|
|
|
|
|
{!codeSent ? (
|
|
|
|
|
|
<Button type="primary" onClick={sendCode} loading={loading} block>
|
|
|
|
|
|
Отправить код
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<Space.Compact style={{ width: '100%' }}>
|
|
|
|
|
|
<Input
|
|
|
|
|
|
prefix={<SafetyOutlined />}
|
|
|
|
|
|
placeholder="123456"
|
|
|
|
|
|
maxLength={6}
|
|
|
|
|
|
style={{ width: '70%' }}
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
name="smsCode"
|
|
|
|
|
|
onChange={(e) => form.setFieldValue('smsCode', e.target.value)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<Button type="primary" onClick={verifyCode} loading={verifyLoading} style={{ width: '30%' }} size="large">
|
|
|
|
|
|
Проверить
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</Space.Compact>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</Form.Item>
|
2025-10-30 16:02:02 +03:00
|
|
|
|
|
|
|
|
|
|
{/* 🔧 Технические кнопки для разработки */}
|
|
|
|
|
|
<div style={{
|
|
|
|
|
|
marginTop: 24,
|
|
|
|
|
|
padding: 16,
|
|
|
|
|
|
background: '#f0f0f0',
|
|
|
|
|
|
borderRadius: 8,
|
|
|
|
|
|
border: '2px dashed #999'
|
|
|
|
|
|
}}>
|
|
|
|
|
|
<div style={{ marginBottom: 8, fontSize: 12, color: '#666', fontWeight: 'bold' }}>
|
|
|
|
|
|
🔧 DEV MODE - Быстрая навигация (без валидации)
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div style={{ display: 'flex', gap: 8 }}>
|
|
|
|
|
|
<Button
|
|
|
|
|
|
type="dashed"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
// Автозаполняем телефон и email
|
|
|
|
|
|
const devData = {
|
2025-10-30 18:54:05 +03:00
|
|
|
|
phone: '79001234567', // БЕЗ +
|
2025-10-30 16:02:02 +03:00
|
|
|
|
email: 'test@test.ru',
|
|
|
|
|
|
};
|
|
|
|
|
|
updateFormData(devData);
|
|
|
|
|
|
setIsPhoneVerified(true);
|
|
|
|
|
|
message.success('DEV: Телефон автоматически подтверждён');
|
|
|
|
|
|
onNext();
|
|
|
|
|
|
}}
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
style={{ flex: 1 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
Далее → (Step 2) [пропустить]
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-10-30 09:50:26 +03:00
|
|
|
|
</Form>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|