import React, { useState, useEffect } from 'react'; import { LegalCourtCase } from '../../types'; import { FileText, History, MessageSquare, User, X, Edit, Save, ExternalLink } from 'lucide-react'; import { authFetch } from '../../services/apiClient'; function getCourtCaseExternalUrl(type: string, caseNumber: string): { url: string; label: string } { const encoded = encodeURIComponent(caseNumber.trim()); if (type === 'arbitration') { return { url: `https://kad.arbitr.ru/?q=${encoded}`, label: 'КАД' }; } return { url: 'https://sudrf.ru/', label: 'СОЮ' }; } export interface CaseDetailsModalProps { courtCase: LegalCourtCase; onClose: () => void; onUpdate: (updatedCase: LegalCourtCase) => void; } const DOC_TYPE_LABELS: Record = { pretenzia: 'Претензия', isk: 'Исковое заявление', reshenie: 'Решение суда', ispolnitelny_list: 'Исполнительный лист', postanovlenie_ip: 'Постановление об ИП', other: 'Прочее' }; export const CaseDetailsModal: React.FC = ({ courtCase, onUpdate, onClose }) => { const [activeTab, setActiveTab] = useState<'info' | 'history' | 'comments' | 'documents'>('info'); const [loading, setLoading] = useState(false); const [history, setHistory] = useState([]); const [comments, setComments] = useState([]); const [documents, setDocuments] = useState([]); const [newComment, setNewComment] = useState(''); const [commentAuthor, setCommentAuthor] = useState(''); const [isEditing, setIsEditing] = useState(false); const [newDoc, setNewDoc] = useState({ docType: 'isk', fileUrl: '', docDate: '', title: '' }); const [docLoading, setDocLoading] = useState(false); const [formData, setFormData] = useState({ amount: courtCase.amount, recoveredAmount: courtCase.recoveredAmount || 0, status: courtCase.status, nextHearingDate: courtCase.nextHearingDate || '', judge: courtCase.judge || '', courtName: courtCase.courtName ?? '', notes: courtCase.notes ?? '', penaltyAmount: courtCase.penaltyAmount ?? 0, overdueSince: courtCase.overdueSince ?? '' }); useEffect(() => { loadHistory(); loadComments(); loadDocuments(); }, [courtCase.id]); const loadHistory = async () => { try { const response = await authFetch(`/api/legal/court-cases/${courtCase.id}/history`); if (response.ok) { const data = await response.json(); setHistory(data || []); } } catch (error) { console.error('Error loading history:', error); } }; const loadComments = async () => { try { const response = await authFetch(`/api/legal/court-cases/${courtCase.id}/comments`); if (response.ok) { const data = await response.json(); setComments(data || []); } } catch (error) { console.error('Error loading comments:', error); } }; const loadDocuments = async () => { try { const response = await authFetch(`/api/legal/court-cases/${courtCase.id}/documents`); if (response.ok) { const data = await response.json(); setDocuments(Array.isArray(data) ? data : []); } } catch (error) { console.error('Error loading documents:', error); } }; const handleAddDocument = async () => { if (!newDoc.fileUrl.trim()) { alert('Укажите ссылку на документ'); return; } setDocLoading(true); try { const response = await authFetch(`/api/legal/court-cases/${courtCase.id}/documents`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ docType: newDoc.docType, fileUrl: newDoc.fileUrl.trim(), docDate: newDoc.docDate || null, title: newDoc.title.trim() || null }) }); if (response.ok) { setNewDoc({ docType: 'isk', fileUrl: '', docDate: '', title: '' }); await loadDocuments(); } else { alert('Ошибка при добавлении документа'); } } catch (error) { console.error('Error adding document:', error); alert('Ошибка при добавлении документа'); } finally { setDocLoading(false); } }; const handleDeleteDocument = async (docId: number) => { if (!confirm('Удалить документ?')) return; try { const response = await authFetch(`/api/legal/court-cases/${courtCase.id}/documents/${docId}`, { method: 'DELETE' }); if (response.ok) await loadDocuments(); } catch (error) { console.error('Error deleting document:', error); } }; const handleSave = async () => { setLoading(true); try { const response = await authFetch(`/api/legal/court-cases/${courtCase.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...formData, changedBy: commentAuthor || 'System' }) }); if (response.ok) { const updated = await response.json(); onUpdate(updated); setIsEditing(false); await loadHistory(); } else { alert('Ошибка при сохранении'); } } catch (error) { console.error('Error saving case:', error); alert('Ошибка при сохранении'); } finally { setLoading(false); } }; const handleAddComment = async () => { if (!newComment.trim() || !commentAuthor.trim()) { alert('Заполните автора и комментарий'); return; } setLoading(true); try { const response = await authFetch(`/api/legal/court-cases/${courtCase.id}/comments`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ author: commentAuthor, comment: newComment }) }); if (response.ok) { setNewComment(''); await loadComments(); } else { alert('Ошибка при добавлении комментария'); } } catch (error) { console.error('Error adding comment:', error); alert('Ошибка при добавлении комментария'); } finally { setLoading(false); } }; const getStatusLabel = (status: string) => { const labels: Record = { 'pre_trial': 'Досудебное', 'litigation': 'Судебный процесс', 'decision_received': 'Решение получено', 'enforcement': 'ФССП', 'closed': 'Завершено' }; return labels[status] || status; }; return (

Карточка дела

{courtCase.caseNumber}

{(() => { const { url, label } = getCourtCaseExternalUrl(courtCase.type, courtCase.caseNumber); return ( {label} ); })()}
{[ { id: 'info', label: 'Основная информация', icon: FileText }, { id: 'history', label: 'История', icon: History }, { id: 'comments', label: 'Комментарии', icon: MessageSquare }, { id: 'documents', label: 'Документы', icon: FileText } ].map(tab => ( ))}
{activeTab === 'info' && (
{!isEditing ? ( <>

{courtCase.subject}

{getStatusLabel(courtCase.status)}

{courtCase.debtorName || 'Не указан'}

{courtCase.address || 'Не указан'}

{courtCase.amount.toLocaleString()} ₽

{(courtCase.penaltyAmount ?? 0) > 0 && (

в т.ч. пени {(courtCase.penaltyAmount || 0).toLocaleString()} ₽

)}

{(courtCase.recoveredAmount || 0).toLocaleString()} ₽

{(courtCase.amountAtBailiffs || 0).toLocaleString()} ₽

{(courtCase.overdueSince || (courtCase.penaltyAmount ?? 0) > 0) && (
{courtCase.overdueSince && (

{courtCase.overdueSince}

)} {(courtCase.penaltyAmount ?? 0) > 0 && (

{(courtCase.penaltyAmount || 0).toLocaleString()} ₽

)}
)}

{courtCase.courtName || 'Не указан'}

{courtCase.judge || 'Не указан'}

{courtCase.nextHearingDate || 'Не назначено'}

{courtCase.notes && (

{courtCase.notes}

)} ) : (
setFormData({ ...formData, amount: parseFloat(e.target.value) || 0 })} className="w-full px-4 py-2 border border-slate-200 rounded-xl text-sm outline-none focus:ring-2 focus:ring-primary-500" required />
setFormData({ ...formData, recoveredAmount: parseFloat(e.target.value) || 0 })} className="w-full px-4 py-2 border border-slate-200 rounded-xl text-sm outline-none focus:ring-2 focus:ring-primary-500" />
setFormData({ ...formData, nextHearingDate: e.target.value })} className="w-full px-4 py-2 border border-slate-200 rounded-xl text-sm outline-none focus:ring-2 focus:ring-primary-500" />
setFormData({ ...formData, courtName: e.target.value })} className="w-full px-4 py-2 border border-slate-200 rounded-xl text-sm outline-none focus:ring-2 focus:ring-primary-500" />
setFormData({ ...formData, judge: e.target.value })} className="w-full px-4 py-2 border border-slate-200 rounded-xl text-sm outline-none focus:ring-2 focus:ring-primary-500" />
setFormData({ ...formData, penaltyAmount: parseFloat(e.target.value) || 0 })} className="w-full px-4 py-2 border border-slate-200 rounded-xl text-sm outline-none focus:ring-2 focus:ring-primary-500" />
setFormData({ ...formData, overdueSince: e.target.value })} className="w-full px-4 py-2 border border-slate-200 rounded-xl text-sm outline-none focus:ring-2 focus:ring-primary-500" />