diff --git a/frontend/src/pages/ClaimForm.tsx b/frontend/src/pages/ClaimForm.tsx index ecc03a8..220863b 100644 --- a/frontend/src/pages/ClaimForm.tsx +++ b/frontend/src/pages/ClaimForm.tsx @@ -230,19 +230,6 @@ export default function ClaimForm() { } }, [formData.showClaimConfirmation, formData.claimPlanData]); - // Cleanup: закрываем SSE соединение при размонтировании - useEffect(() => { - return () => { - if (claimPlanEventSourceRef.current) { - claimPlanEventSourceRef.current.close(); - claimPlanEventSourceRef.current = null; - } - if (claimPlanTimeoutRef.current) { - clearTimeout(claimPlanTimeoutRef.current); - claimPlanTimeoutRef.current = null; - } - }; - }, []); // Динамически определяем список шагов на основе выбранного eventType const documentConfigs = formData.eventType ? getDocumentsForEventType(formData.eventType) : []; @@ -284,97 +271,116 @@ export default function ClaimForm() { }); }, []); - // Подписка на канал claim:plan для получения данных заявления (для черновиков) - const subscribeToClaimPlanForDraft = useCallback((sessionToken: string, claimId: string) => { - console.log('📡 Подписка на канал claim:plan для черновика:', { sessionToken, claimId }); + // Преобразование данных черновика в формат propertyName для формы подтверждения + const transformDraftToClaimPlanFormat = useCallback((data: { + claim: any; + payload: any; + body: any; + isTelegramFormat: boolean; + finalClaimId: string; + actualSessionId: string; + currentFormData: FormData; + }) => { + const { claim, payload, body, finalClaimId, actualSessionId, currentFormData } = data; - // Закрываем предыдущее соединение, если есть - if (claimPlanEventSourceRef.current) { - claimPlanEventSourceRef.current.close(); - claimPlanEventSourceRef.current = null; - } + // Извлекаем данные из body (telegram) или напрямую из payload (web_form) + const applicantData = body.applicant || payload.applicant || {}; + const caseData = body.case || payload.case || {}; + const contractData = body.contract_or_service || payload.contract_or_service || {}; + const offendersData = body.offenders || payload.offenders || []; + const claimData = body.claim || payload.claim || {}; + const metaData = body.meta || payload.meta || {}; + const documentsMeta = body.documents_meta || payload.documents_meta || []; - // Очищаем предыдущий таймаут - if (claimPlanTimeoutRef.current) { - clearTimeout(claimPlanTimeoutRef.current); - claimPlanTimeoutRef.current = null; - } - - // Создаём новое SSE соединение - const eventSource = new EventSource(`/api/v1/claim-plan/${sessionToken}`); - claimPlanEventSourceRef.current = eventSource; - - eventSource.onopen = () => { - console.log('✅ Подключено к каналу claim:plan для черновика'); - addDebugEvent('claim-plan', 'info', '📡 Ожидание данных заявления для черновика...'); - message.loading('Загрузка данных заявления...', 0); - }; - - eventSource.onmessage = (event) => { + // Извлекаем ответы на вопросы из wizard_answers + const wizardAnswers = body.answers || payload.answers || {}; + let answersParsed = wizardAnswers; + if (typeof wizardAnswers === 'string') { try { - const data = JSON.parse(event.data); - console.log('📥 Получены данные из claim:plan для черновика:', data); - - if (data.event_type === 'claim_plan_ready' && data.status === 'ready') { - // Данные заявления получены! - message.destroy(); // Убираем loading сообщение - message.success('Данные заявления загружены!'); - - // Сохраняем данные заявления в formData - updateFormData({ - claimPlanData: data.data, // Данные от n8n - showClaimConfirmation: true, // Флаг для показа формы подтверждения - }); - - // Закрываем SSE соединение - eventSource.close(); - claimPlanEventSourceRef.current = null; - - // Переход к шагу подтверждения произойдёт автоматически через useEffect - } else if (data.event_type === 'claim_plan_error' || data.status === 'error') { - message.destroy(); - message.error(data.message || 'Ошибка получения данных заявления'); - eventSource.close(); - claimPlanEventSourceRef.current = null; - // Переходим к визарду вместо подтверждения - setCurrentStep(2); - } else if (data.event_type === 'claim_plan_timeout' || data.status === 'timeout') { - message.destroy(); - message.warning('Данные заявления ещё обрабатываются. Вы можете продолжить редактирование.'); - eventSource.close(); - claimPlanEventSourceRef.current = null; - // Переходим к визарду вместо подтверждения - setCurrentStep(2); - } - } catch (error) { - console.error('❌ Ошибка парсинга данных из claim:plan:', error); - message.destroy(); - message.error('Ошибка обработки данных заявления'); - eventSource.close(); - claimPlanEventSourceRef.current = null; - setCurrentStep(2); + answersParsed = JSON.parse(wizardAnswers); + } catch (e) { + console.warn('⚠️ Не удалось распарсить answers:', e); + answersParsed = {}; } + } + + // Формируем attachments_names из documents_meta + const attachmentsNames = documentsMeta.map((doc: any) => { + return doc.original_file_name || doc.file_name || doc.field_name || 'Документ'; + }); + + // Формируем attachments с полной информацией + const attachments = documentsMeta.map((doc: any) => ({ + label: doc.original_file_name || doc.file_name || doc.field_name || 'Документ', + url: doc.file_id ? `https://s3.twcstorage.ru${doc.file_id}` : '', + file_id: doc.file_id || '', + stored_file_name: doc.file_name || '', + original_file_name: doc.original_file_name || doc.file_name || '', + field_name: doc.field_name || '', + uploaded_at: doc.uploaded_at || new Date().toISOString(), + })); + + // Формируем propertyName в нужном формате + const propertyName = { + applicant: { + first_name: applicantData.first_name || null, + middle_name: applicantData.middle_name || null, + last_name: applicantData.last_name || null, + full_name: applicantData.full_name || null, + birth_date: applicantData.birth_date || null, + birth_date_fmt: applicantData.birth_date_fmt || null, + birth_place: applicantData.birth_place || null, + inn: applicantData.inn || null, + address: applicantData.address || null, + phone: claim.phone || payload.phone || body.phone || currentFormData.phone || null, + email: claim.email || payload.email || body.email || currentFormData.email || null, + }, + case: { + category: caseData.category || payload.case_type || 'consumer', + direction: caseData.direction || 'web_form', + country: caseData.country || null, + }, + contract_or_service: { + agreement_date: contractData.agreement_date || null, + agreement_date_fmt: contractData.agreement_date_fmt || null, + amount_paid: contractData.amount_paid || null, + amount_paid_fmt: contractData.amount_paid_fmt || null, + subject: contractData.subject || payload.problem_description || body.problem_description || null, + period_start: contractData.period_start || null, + period_start_fmt: contractData.period_start_fmt || null, + period_end: contractData.period_end || null, + period_end_fmt: contractData.period_end_fmt || null, + period_text: contractData.period_text || null, + }, + offenders: offendersData.length > 0 ? offendersData : [], + claim: { + reason: claimData.reason || caseData.category || 'consumer', + description: claimData.description || payload.problem_description || body.problem_description || null, + }, + meta: { + claim_id: finalClaimId, + unified_id: claim.unified_id || currentFormData.unified_id || null, + status: claim.status_code || 'draft', + created_at: claim.created_at || new Date().toISOString(), + updated_at: claim.updated_at || new Date().toISOString(), + user_id: metaData.user_id || null, + }, + attachments: attachments, + attachments_count: attachments.length, + attachments_names: attachmentsNames, }; - eventSource.onerror = (error) => { - console.error('❌ Ошибка SSE соединения claim:plan:', error); - message.destroy(); - message.warning('Не удалось получить данные заявления. Вы можете продолжить редактирование.'); - eventSource.close(); - claimPlanEventSourceRef.current = null; - setCurrentStep(2); // Переходим к визарду вместо подтверждения - }; - - // Таймаут на 5 минут - claimPlanTimeoutRef.current = setTimeout(() => { - console.warn('⏰ Таймаут ожидания данных заявления для черновика'); - message.destroy(); - message.warning('Превышено время ожидания данных заявления. Вы можете продолжить редактирование.'); - eventSource.close(); - claimPlanEventSourceRef.current = null; - setCurrentStep(2); - }, 300000); // 5 минут - }, [updateFormData, addDebugEvent]); + // Возвращаем данные в формате массива (как ожидает форма подтверждения) + return [{ + propertyName: propertyName, + session_token: actualSessionId, + prefix: '', + telegram_id: null, + claim_id: finalClaimId, + unified_id: claim.unified_id || currentFormData.unified_id || null, + user_id: metaData.user_id || null, + }]; + }, []); // Загрузка черновика const loadDraft = useCallback(async (claimId: string) => { @@ -505,16 +511,29 @@ export default function ClaimForm() { // ✅ Если все шаги заполнены и статус = draft → переходим к форме подтверждения if (isReadyForConfirmation) { - console.log('✅ Все шаги заполнены, переходим к форме подтверждения'); + console.log('✅ Все шаги заполнены, преобразуем данные для формы подтверждения'); setIsPhoneVerified(true); - // Подписываемся на канал claim:plan для получения данных заявления - subscribeToClaimPlanForDraft(actualSessionId, finalClaimId); + // Преобразуем данные из БД в формат propertyName для формы подтверждения + const claimPlanData = transformDraftToClaimPlanFormat({ + claim, + payload, + body, + isTelegramFormat, + finalClaimId, + actualSessionId, + currentFormData: formData, + }); - // Пока устанавливаем шаг визарда, переход к подтверждению произойдёт автоматически - // когда данные будут получены через SSE - setCurrentStep(2); // StepWizardPlan + // Сохраняем данные заявления в formData + updateFormData({ + claimPlanData: claimPlanData, + showClaimConfirmation: true, + }); + + // Переход к шагу подтверждения произойдёт автоматически через useEffect + setCurrentStep(2); // StepWizardPlan (временно, useEffect переключит на подтверждение) return; }