import React, { useEffect, useState, useMemo } from 'react'; import { CondoService } from '../services/mockDb'; import { CondoExpense, Condo } from '../types'; import { Plus, Search, Filter, Paperclip, X, Save, FileText, Download, Euro, Trash2, Pencil, Briefcase } from 'lucide-react'; export const CondoFinancialsPage: React.FC = () => { const user = CondoService.getCurrentUser(); const isPrivileged = user?.role === 'admin' || user?.role === 'poweruser'; const [expenses, setExpenses] = useState([]); const [loading, setLoading] = useState(true); const [activeCondo, setActiveCondo] = useState(undefined); // Filters const [selectedYear, setSelectedYear] = useState(new Date().getFullYear()); const [availableYears, setAvailableYears] = useState([]); const [searchTerm, setSearchTerm] = useState(''); const [statusFilter, setStatusFilter] = useState<'ALL' | 'PAID' | 'UNPAID' | 'SUSPENDED'>('ALL'); // Modal State const [showModal, setShowModal] = useState(false); const [editingExpense, setEditingExpense] = useState(null); // Form const [formData, setFormData] = useState<{ description: string; supplierName: string; amount: string; paymentDate: string; status: 'PAID' | 'UNPAID' | 'SUSPENDED'; paymentMethod: string; invoiceNumber: string; notes: string; attachments: {fileName: string, fileType: string, data: string}[]; }>({ description: '', supplierName: '', amount: '', paymentDate: '', status: 'UNPAID', paymentMethod: '', invoiceNumber: '', notes: '', attachments: [] }); // Distinct Suppliers for Datalist const suppliers = useMemo(() => { return Array.from(new Set(expenses.map(e => e.supplierName).filter(Boolean))); }, [expenses]); useEffect(() => { loadData(); }, [selectedYear]); const loadData = async () => { setLoading(true); try { const condo = await CondoService.getActiveCondo(); setActiveCondo(condo); const [data, years] = await Promise.all([ CondoService.getCondoExpenses(selectedYear), CondoService.getAvailableYears() ]); setExpenses(data); if (!availableYears.includes(selectedYear) && years.includes(selectedYear)) { setAvailableYears(years); } else if (years.length > 0) { setAvailableYears(prev => Array.from(new Set([...prev, ...years, new Date().getFullYear()])).sort((a,b)=>b-a)); } } catch(e) { console.error(e); } finally { setLoading(false); } }; const handleFileChange = async (e: React.ChangeEvent) => { if (e.target.files && e.target.files.length > 0) { const newAtts = []; for (let i = 0; i < e.target.files.length; i++) { const file = e.target.files[i]; const base64 = await new Promise((resolve) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result as string); reader.readAsDataURL(file); }); newAtts.push({ fileName: file.name, fileType: file.type, data: base64 }); } setFormData(prev => ({ ...prev, attachments: [...prev.attachments, ...newAtts] })); } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { const payload = { id: editingExpense?.id, description: formData.description, supplierName: formData.supplierName, amount: parseFloat(formData.amount), paymentDate: formData.paymentDate || null, status: formData.status, paymentMethod: formData.paymentMethod, invoiceNumber: formData.invoiceNumber, notes: formData.notes, attachments: formData.attachments }; // Fix: Cast payload to any because attachments don't have IDs yet (they are new uploads) await CondoService.saveCondoExpense(payload as any); setShowModal(false); loadData(); } catch(e) { alert("Errore salvataggio spesa"); } }; const handleDelete = async (id: string) => { if (!confirm("Eliminare questa spesa?")) return; try { await CondoService.deleteCondoExpense(id); setExpenses(expenses.filter(e => e.id !== id)); } catch(e) { alert("Errore eliminazione"); } }; const openModal = (exp?: CondoExpense) => { if (exp) { setEditingExpense(exp); setFormData({ description: exp.description, supplierName: exp.supplierName, amount: exp.amount.toString(), paymentDate: exp.paymentDate ? new Date(exp.paymentDate).toISOString().split('T')[0] : '', status: exp.status, paymentMethod: exp.paymentMethod || '', invoiceNumber: exp.invoiceNumber || '', notes: exp.notes || '', attachments: [] // We don't load attachments content back for editing, only new ones }); } else { setEditingExpense(null); setFormData({ description: '', supplierName: '', amount: '', paymentDate: '', status: 'UNPAID', paymentMethod: '', invoiceNumber: '', notes: '', attachments: [] }); } setShowModal(true); }; const openAttachment = async (expId: string, attId: string) => { try { const file = await CondoService.getCondoExpenseAttachment(expId, attId); const win = window.open(); if (win) { if (file.fileType.startsWith('image/') || file.fileType === 'application/pdf') { win.document.write(``); } else { win.document.write(`Download ${file.fileName}`); } } } catch(e) { alert("Errore apertura file"); } }; const filtered = expenses.filter(e => { const matchesSearch = e.description.toLowerCase().includes(searchTerm.toLowerCase()) || e.supplierName.toLowerCase().includes(searchTerm.toLowerCase()); const matchesStatus = statusFilter === 'ALL' || e.status === statusFilter; return matchesSearch && matchesStatus; }); const totalSpent = filtered.reduce((acc, curr) => acc + curr.amount, 0); return (

Spese Condominiali (Uscite)

Registro fatture e pagamenti fornitori per {activeCondo?.name}

{isPrivileged && ( )}
{/* Filters */}
setSearchTerm(e.target.value)} className="w-full border p-2 pl-9 rounded-lg text-slate-700 bg-slate-50" />

Totale

€ {totalSpent.toLocaleString()}

{/* Table */}
{isPrivileged && } {loading ? ( ) : filtered.length === 0 ? ( ) : ( filtered.map(exp => ( {isPrivileged && ( )} )) )}
Data / Scadenza Fornitore & Descrizione Importo Stato DettagliAzioni
Caricamento...
Nessuna spesa registrata.
{exp.paymentDate ? new Date(exp.paymentDate).toLocaleDateString() : '-'}
{exp.supplierName}
{exp.description}
€ {exp.amount.toFixed(2)} {exp.status === 'PAID' ? 'Saldato' : exp.status === 'SUSPENDED' ? 'Sospeso' : 'Insoluto'} {exp.invoiceNumber &&
Fatt. {exp.invoiceNumber}
} {exp.paymentMethod &&
{exp.paymentMethod}
} {exp.attachments && exp.attachments.length > 0 && (
{exp.attachments.map(att => ( ))}
)}
{/* MODAL */} {showModal && (

{editingExpense ? 'Modifica Spesa' : 'Nuova Spesa'}

setFormData({...formData, description: e.target.value})} required placeholder="Es. Pulizia scale Gennaio" />
setFormData({...formData, supplierName: e.target.value})} placeholder="Seleziona o scrivi nuovo..." required /> {suppliers.map((s, i) =>
setFormData({...formData, amount: e.target.value})} required />
setFormData({...formData, invoiceNumber: e.target.value})} />
setFormData({...formData, paymentDate: e.target.value})} />
setFormData({...formData, paymentMethod: e.target.value})} placeholder="Es. Bonifico, RID..." />
{formData.attachments.length > 0 &&

{formData.attachments.length} file pronti per upload

}