diff --git a/pages/ExtraordinaryAdmin.tsx b/pages/ExtraordinaryAdmin.tsx index 1f3c9cf..7a18aff 100644 --- a/pages/ExtraordinaryAdmin.tsx +++ b/pages/ExtraordinaryAdmin.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'; import { CondoService } from '../services/mockDb'; import { ExtraordinaryExpense, Family, ExpenseItem, ExpenseShare } from '../types'; -import { Plus, Calendar, FileText, CheckCircle2, Clock, Users, X, Save, Paperclip, Euro, Trash2, Eye, Briefcase, Pencil, Banknote } from 'lucide-react'; +import { Plus, Calendar, FileText, CheckCircle2, Clock, Users, X, Save, Paperclip, Euro, Trash2, Eye, Briefcase, Pencil, Banknote, History } from 'lucide-react'; export const ExtraordinaryAdmin: React.FC = () => { const [expenses, setExpenses] = useState([]); @@ -32,6 +32,8 @@ export const ExtraordinaryAdmin: React.FC = () => { const [payAmount, setPayAmount] = useState(0); const [payNotes, setPayNotes] = useState(''); const [isPaying, setIsPaying] = useState(false); + const [paymentHistory, setPaymentHistory] = useState([]); + const [loadingHistory, setLoadingHistory] = useState(false); useEffect(() => { loadData(); @@ -67,9 +69,6 @@ export const ExtraordinaryAdmin: React.FC = () => { // Preserve existing data if available const existing = formShares.find(s => s.familyId === fid); if (existing) { - // If editing and we just toggled someone else, re-calc percentages evenly? - // Or keep manual adjustments? - // For simplicity: auto-recalc resets percentages evenly. return { ...existing, percentage: parseFloat(percentage.toFixed(2)), @@ -120,14 +119,11 @@ export const ExtraordinaryAdmin: React.FC = () => { setFormItems(newItems); }; - // Trigger share recalc when total changes (if not manual) - // We only trigger auto-recalc if not editing existing complex shares, - // OR if editing but user hasn't manually messed with them yet (simplification: always recalc on total change for now) useEffect(() => { if (selectedFamilyIds.length > 0) { recalculateShares(selectedFamilyIds); } - }, [totalAmount]); // eslint-disable-line react-hooks/exhaustive-deps + }, [totalAmount]); const handleFileChange = async (e: React.ChangeEvent) => { if (e.target.files && e.target.files.length > 0) { @@ -154,7 +150,6 @@ export const ExtraordinaryAdmin: React.FC = () => { }; const openEditModal = async (exp: ExtraordinaryExpense) => { - // Fetch full details first to get items and shares try { const detail = await CondoService.getExpenseDetails(exp.id); setIsEditing(true); @@ -166,12 +161,10 @@ export const ExtraordinaryAdmin: React.FC = () => { setFormContractor(detail.contractorName); setFormItems(detail.items || []); - // Populate shares for editing const currentShares = detail.shares || []; setFormShares(currentShares); setSelectedFamilyIds(currentShares.map(s => s.familyId)); - // Attachments (Cannot edit attachments in this simple view for now, cleared) setFormAttachments([]); setShowModal(true); @@ -197,7 +190,7 @@ export const ExtraordinaryAdmin: React.FC = () => { endDate: formEnd, contractorName: formContractor, items: formItems, - shares: formShares // Now we send shares to sync + shares: formShares }); } else { await CondoService.createExpense({ @@ -237,12 +230,25 @@ export const ExtraordinaryAdmin: React.FC = () => { }; // MANUAL PAYMENT HANDLERS - const openPayModal = (share: ExpenseShare) => { + const openPayModal = async (share: ExpenseShare) => { + if (!selectedExpense) return; const remaining = Math.max(0, share.amountDue - share.amountPaid); setPayShare(share); setPayAmount(remaining); setPayNotes('Saldo manuale'); setShowPayModal(true); + + // Fetch History + setLoadingHistory(true); + try { + const history = await CondoService.getExpensePayments(selectedExpense.id, share.familyId); + setPaymentHistory(history); + } catch (e) { + console.error(e); + setPaymentHistory([]); + } finally { + setLoadingHistory(false); + } }; const handleManualPayment = async (e: React.FormEvent) => { @@ -251,21 +257,48 @@ export const ExtraordinaryAdmin: React.FC = () => { setIsPaying(true); try { - // Updated API allows Admins to pass familyId to pay on their behalf await CondoService.payExpense(selectedExpense.id, payAmount, payShare.familyId); - - // Refresh Details - const updated = await CondoService.getExpenseDetails(selectedExpense.id); - setSelectedExpense(updated); - setShowPayModal(false); + await refreshShareData(); + // Reset input + setPayAmount(0); + setPayNotes(''); } catch (e: any) { - console.error(e); alert("Errore registrazione pagamento: " + (e.message || "Errore sconosciuto")); } finally { setIsPaying(false); } }; + const handleDeletePayment = async (paymentId: string) => { + if (!confirm("Annullare questo pagamento? L'importo verrà stornato dal saldo versato.")) return; + + try { + await CondoService.deleteExpensePayment(paymentId); + await refreshShareData(); + } catch(e) { + alert("Errore annullamento pagamento"); + } + }; + + const refreshShareData = async () => { + if (!selectedExpense || !payShare) return; + + // Refresh Expense Details to update the table in background + const updatedExpense = await CondoService.getExpenseDetails(selectedExpense.id); + setSelectedExpense(updatedExpense); + + // Refresh Payment History inside modal + const history = await CondoService.getExpensePayments(selectedExpense.id, payShare.familyId); + setPaymentHistory(history); + + // Update local PayShare reference for amount calculation + const updatedShare = updatedExpense.shares?.find(s => s.familyId === payShare.familyId); + if (updatedShare) { + setPayShare(updatedShare); + setPayAmount(Math.max(0, updatedShare.amountDue - updatedShare.amountPaid)); + } + }; + return (
@@ -497,15 +530,13 @@ export const ExtraordinaryAdmin: React.FC = () => { - {share.status !== 'PAID' && ( - - )} + ))} @@ -528,53 +559,111 @@ export const ExtraordinaryAdmin: React.FC = () => {
)} - {/* MANUAL PAYMENT MODAL */} + {/* MANUAL PAYMENT / MANAGEMENT MODAL */} {showPayModal && payShare && (
-
-
-

Registra Pagamento

+
+
+
+

Gestione Pagamenti

+

{payShare.familyName}

+
-
-
-

Famiglia: {payShare.familyName}

-

Restante da pagare: € {(payShare.amountDue - payShare.amountPaid).toFixed(2)}

-
- -
- -
- - setPayAmount(parseFloat(e.target.value))} - required - /> +
+ {/* Summary Card */} +
+
+

Quota Totale

+

€ {payShare.amountDue.toFixed(2)}

+
+
+

Restante

+

€ {(payShare.amountDue - payShare.amountPaid).toFixed(2)}

-
- - setPayNotes(e.target.value)} - /> + {/* History Section */} +
+

+ Storico Versamenti +

+ {loadingHistory ? ( +
Caricamento...
+ ) : paymentHistory.length === 0 ? ( +
+ Nessun pagamento registrato. +
+ ) : ( +
+ + + + + + + + + + + {paymentHistory.map(ph => ( + + + + + + + ))} + +
DataNoteImporto
{new Date(ph.datePaid).toLocaleDateString()}{ph.notes}€ {ph.amount.toFixed(2)} + +
+
+ )}
-
- - + {/* Add New Section */} +
+

Registra Nuovo Incasso

+ +
+ +
+ + setPayAmount(parseFloat(e.target.value))} + required + /> +
+
+ +
+ + setPayNotes(e.target.value)} + /> +
+ + +
- +
)}