import React, { useState, useEffect } from 'react'; import { X, Download, CheckCircle2, XCircle, Minus, FileText, User, Home, Calendar } from 'lucide-react'; import { backendApi } from '../../services/apiClient'; interface RegistryItem { id: number; apartment: string; ownerName?: string; area: number; ballotSubmitted: boolean; ballotDate?: string; voteResult?: 'for' | 'against' | 'abstain'; votesByItem?: Record; notes?: string; } interface Props { isOpen: boolean; onClose: () => void; ossId: string; ossAddress: string; } export const OSSRegistryModal: React.FC = ({ isOpen, onClose, ossId, ossAddress }) => { const [registry, setRegistry] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { if (isOpen && ossId) { fetchRegistry(); } }, [isOpen, ossId]); const fetchRegistry = async () => { try { setLoading(true); setError(null); const data = await backendApi.getOSSRegistry(ossId); setRegistry(Array.isArray(data) ? data : []); } catch (err: any) { console.error('Error fetching registry:', err); setError(err?.message || 'Ошибка при загрузке реестра'); setRegistry([]); } finally { setLoading(false); } }; if (!isOpen) return null; // Статистика const totalEntries = registry.length; const submittedCount = registry.filter(r => r.ballotSubmitted).length; const totalArea = registry.reduce((sum, r) => sum + (r.area || 0), 0); const submittedArea = registry.filter(r => r.ballotSubmitted).reduce((sum, r) => sum + (r.area || 0), 0); const votesFor = registry.filter(r => r.voteResult === 'for').length; const votesAgainst = registry.filter(r => r.voteResult === 'against').length; const votesAbstain = registry.filter(r => r.voteResult === 'abstain').length; const getVoteIcon = (voteResult?: string) => { switch (voteResult) { case 'for': return ; case 'against': return ; case 'abstain': return ; default: return
; } }; const getVoteLabel = (voteResult?: string) => { switch (voteResult) { case 'for': return 'За'; case 'against': return 'Против'; case 'abstain': return 'Воздержался'; default: return '—'; } }; const formatVotesByItem = (votesByItem?: Record) => { if (!votesByItem || Object.keys(votesByItem).length === 0) return '—'; const parts = Object.entries(votesByItem) .sort(([a], [b]) => Number(a) - Number(b)) .map(([idx, v]) => `${Number(idx) + 1}: ${getVoteLabel(v)}`); return parts.join('; '); }; const handleExport = () => { // Экспорт в CSV const headers = ['Помещение', 'Собственник', 'Площадь (м²)', 'Бюллетень подан', 'Дата подачи', 'Результат голосования', 'Примечания']; const rows = registry.map(r => [ r.apartment, r.ownerName || '—', r.area.toFixed(2), r.ballotSubmitted ? 'Да' : 'Нет', r.ballotDate || '—', getVoteLabel(r.voteResult), r.notes || '—' ]); const csvContent = [ headers.join(','), ...rows.map(row => row.map(cell => `"${cell}"`).join(',')) ].join('\n'); const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `реестр_ОСС_${ossAddress.replace(/[^a-zA-Zа-яА-Я0-9]/g, '_')}_${new Date().toISOString().split('T')[0]}.csv`; link.click(); }; return (
e.stopPropagation()} > {/* Header */}

Реестр участников ОСС

{ossAddress}

{/* Statistics */}

Всего записей

{totalEntries}

Бюллетеней подано

{submittedCount} / {totalEntries}

Площадь собрана

{submittedArea.toFixed(2)} м²

Общая площадь

{totalArea.toFixed(2)} м²

{/* Vote Statistics */} {(votesFor > 0 || votesAgainst > 0 || votesAbstain > 0) && (
За: {votesFor}
Против: {votesAgainst}
Воздержались: {votesAbstain}
)}
{/* Content */}
{loading ? (

Загрузка реестра...

) : error ? (

{error}

) : registry.length === 0 ? (

Реестр пуст

Бюллетени еще не были внесены

) : (
{registry.map((item, index) => ( ))}
Помещение
Собственник
Площадь (м²) Статус
Дата подачи
Голос По пунктам Примечания
{item.apartment} {item.ownerName || Не указано} {item.area.toFixed(2)} {item.ballotSubmitted ? ( Подано ) : ( Не подано )} {item.ballotDate ? new Date(item.ballotDate).toLocaleDateString('ru-RU') : '—'}
{getVoteIcon(item.voteResult)} {getVoteLabel(item.voteResult)}
{formatVotesByItem(item.votesByItem)} {item.notes || '—'}
)}
{/* Footer */}
Всего записей: {totalEntries} | Подано: {submittedCount} | Площадь: {submittedArea.toFixed(2)} м² из {totalArea.toFixed(2)} м²
); };