import React, { useState, useEffect } from 'react'; import { PaymentInvoice, PaymentInvoiceStatus, PaymentInvoicePurposeType, PaymentInvoiceFormat } from '../../types'; import { apiClient } from '../../services/apiClient'; import { FileText, Search, Filter, Eye, Edit2, CheckCircle2, XCircle, Clock, Calendar } from 'lucide-react'; interface PaymentInvoiceListProps { onInvoiceClick: (invoice: PaymentInvoice) => void; onCreateNew: () => void; currentUserId: string; /** Можно ли создавать/редактировать (по умолчанию true) */ canEdit?: boolean; /** Показывать только счета на своё имя / от своего имени */ scopeOwn?: boolean; } const StatusBadge: React.FC<{ status: PaymentInvoiceStatus }> = ({ status }) => { const config: Record = { draft: { label: 'Черновик', color: 'text-slate-500', bg: 'bg-slate-100' }, pending_manager_approval: { label: 'На согл. руков.', color: 'text-amber-600', bg: 'bg-amber-50' }, pending_finance_manager_approval: { label: 'На согл. фин. руков.', color: 'text-blue-600', bg: 'bg-blue-50' }, approved: { label: 'Согласован', color: 'text-indigo-600', bg: 'bg-indigo-50' }, scheduled: { label: 'В графике', color: 'text-purple-600', bg: 'bg-purple-50' }, paid: { label: 'Оплачен', color: 'text-emerald-600', bg: 'bg-emerald-50' }, postponed: { label: 'Отложен', color: 'text-orange-600', bg: 'bg-orange-50' }, cancelled: { label: 'Отменен', color: 'text-red-600', bg: 'bg-red-50' }, rejected: { label: 'Отклонен', color: 'text-red-600', bg: 'bg-red-50' }, completed: { label: 'Выполнено', color: 'text-green-600', bg: 'bg-green-50' } }; const s = config[status] || config.draft; return ( {s.label} ); }; const PurposeTypeLabel: Record = { building: 'Дом', district: 'Участок', legal: 'Юристы', office: 'Офис', hr: 'HR', event: 'Мероприятие', other: 'Другое' }; const PaymentFormatLabel: Record = { prepayment: 'Предоплата', postpayment: 'Постоплата', advance: 'Аванс' }; export const PaymentInvoiceList: React.FC = ({ onInvoiceClick, onCreateNew, currentUserId, canEdit = true, scopeOwn = false, }) => { const [invoices, setInvoices] = useState([]); const [loading, setLoading] = useState(true); const [search, setSearch] = useState(''); const [statusFilter, setStatusFilter] = useState('all'); const [purposeTypeFilter, setPurposeTypeFilter] = useState('all'); const [paymentFormatFilter, setPaymentFormatFilter] = useState('all'); const [page, setPage] = useState(1); const [totalPages, setTotalPages] = useState(1); useEffect(() => { fetchInvoices(); }, [statusFilter, purposeTypeFilter, paymentFormatFilter, search, page, scopeOwn]); const fetchInvoices = async () => { try { setLoading(true); const params = new URLSearchParams(); if (statusFilter !== 'all') params.append('status', statusFilter); if (purposeTypeFilter !== 'all') params.append('purposeType', purposeTypeFilter); if (paymentFormatFilter !== 'all') params.append('paymentFormat', paymentFormatFilter); if (search) params.append('search', search); if (scopeOwn) params.append('scope', 'own'); params.append('page', page.toString()); params.append('limit', '20'); const response = await apiClient.get<{ invoices: PaymentInvoice[]; pagination: any }>( `/finance/payment-invoices?${params.toString()}` ); setInvoices(response.invoices); setTotalPages(response.pagination.totalPages); } catch (err) { console.error('Error fetching invoices:', err); } finally { setLoading(false); } }; const getPurposeLabel = (invoice: PaymentInvoice): string => { if (invoice.purposeType === 'building' && invoice.purposeBuildingIds.length > 0) { return `Дом (${invoice.purposeBuildingIds.length})`; } if (invoice.purposeType === 'district' && invoice.purposeDistrictIds.length > 0) { return `Участок (${invoice.purposeDistrictIds.length})`; } if (invoice.purposeType === 'event') { return invoice.purposeDescription || PurposeTypeLabel.event || 'Мероприятие'; } return PurposeTypeLabel[invoice.purposeType] || invoice.purposeDescription || 'Не указано'; }; if (loading) { return (

Загрузка счетов...

); } return (
{/* Фильтры и поиск */}
{/* Поиск */}
{ setSearch(e.target.value); setPage(1); }} placeholder="Поиск по номеру, подрядчику, услуге..." className="w-full pl-10 pr-4 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500" />
{/* Фильтры */}
{/* Список счетов */}

Счета на оплату ({invoices.length})

{canEdit && ( )}
{invoices.length === 0 ? (
Счетов не найдено
) : ( invoices.map(invoice => (
onInvoiceClick(invoice)} className="p-4 flex flex-col md:flex-row md:items-center justify-between hover:bg-slate-50 transition-colors cursor-pointer group gap-4" >
{invoice.invoiceNumber}

{invoice.contractorName}

{getPurposeLabel(invoice)} • {PaymentFormatLabel[invoice.paymentFormat]} • {invoice.itemType === 'materials' ? 'ТМЦ' : 'Услуга'} • {invoice.serviceDescription}

{invoice.totalAmount.toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ₽

{new Date(invoice.createdAt).toLocaleDateString('ru-RU')}

{invoice.scheduledDate && (

{new Date(invoice.scheduledDate).toLocaleDateString('ru-RU')}

)}
)) )}
{/* Пагинация */} {totalPages > 1 && (
Страница {page} из {totalPages}
)}
); };