Update ExtraordinaryAdmin.tsx

This commit is contained in:
2025-12-11 00:01:39 +01:00
committed by GitHub
parent f9291f2db8
commit 899aaa90d1

View File

@@ -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 } from 'lucide-react';
import { Plus, Calendar, FileText, CheckCircle2, Clock, Users, X, Save, Paperclip, Euro, Trash2, Eye, Briefcase, Pencil, Banknote } from 'lucide-react';
export const ExtraordinaryAdmin: React.FC = () => {
const [expenses, setExpenses] = useState<ExtraordinaryExpense[]>([]);
@@ -26,6 +26,13 @@ export const ExtraordinaryAdmin: React.FC = () => {
const [formAttachments, setFormAttachments] = useState<{fileName: string, fileType: string, data: string}[]>([]);
const [selectedFamilyIds, setSelectedFamilyIds] = useState<string[]>([]); // Helper to track checkboxes
// Manual Payment Modal State
const [showPayModal, setShowPayModal] = useState(false);
const [payShare, setPayShare] = useState<ExpenseShare | null>(null);
const [payAmount, setPayAmount] = useState<number>(0);
const [payNotes, setPayNotes] = useState('');
const [isPaying, setIsPaying] = useState(false);
useEffect(() => {
loadData();
}, []);
@@ -229,6 +236,36 @@ export const ExtraordinaryAdmin: React.FC = () => {
} catch(e) { alert("Errore file"); }
};
// MANUAL PAYMENT HANDLERS
const openPayModal = (share: ExpenseShare) => {
const remaining = Math.max(0, share.amountDue - share.amountPaid);
setPayShare(share);
setPayAmount(remaining);
setPayNotes('Saldo manuale');
setShowPayModal(true);
};
const handleManualPayment = async (e: React.FormEvent) => {
e.preventDefault();
if (!selectedExpense || !payShare) return;
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);
} catch (e: any) {
console.error(e);
alert("Errore registrazione pagamento: " + (e.message || "Errore sconosciuto"));
} finally {
setIsPaying(false);
}
};
return (
<div className="space-y-6 pb-20 animate-fade-in">
<div className="flex justify-between items-center">
@@ -440,6 +477,7 @@ export const ExtraordinaryAdmin: React.FC = () => {
<th className="p-3 text-right">Da Pagare</th>
<th className="p-3 text-right">Versato</th>
<th className="p-3 text-center">Stato</th>
<th className="p-3 text-center">Azioni</th>
</tr>
</thead>
<tbody className="divide-y">
@@ -458,6 +496,17 @@ export const ExtraordinaryAdmin: React.FC = () => {
{share.status === 'PAID' ? 'Saldato' : share.status === 'PARTIAL' ? 'Parziale' : 'Insoluto'}
</span>
</td>
<td className="p-3 text-center">
{share.status !== 'PAID' && (
<button
onClick={() => openPayModal(share)}
className="text-xs bg-blue-50 text-blue-600 hover:bg-blue-100 px-2 py-1 rounded border border-blue-200 font-medium"
title="Registra Pagamento Manuale"
>
Paga
</button>
)}
</td>
</tr>
))}
</tbody>
@@ -468,7 +517,7 @@ export const ExtraordinaryAdmin: React.FC = () => {
<td className="p-3 text-right text-blue-600">
{selectedExpense.shares?.reduce((a,b) => a + b.amountPaid, 0).toLocaleString()}
</td>
<td></td>
<td colSpan={2}></td>
</tr>
</tfoot>
</table>
@@ -478,6 +527,57 @@ export const ExtraordinaryAdmin: React.FC = () => {
</div>
</div>
)}
{/* MANUAL PAYMENT MODAL */}
{showPayModal && payShare && (
<div className="fixed inset-0 bg-black/50 z-[60] flex items-center justify-center p-4 backdrop-blur-sm">
<div className="bg-white rounded-xl shadow-xl w-full max-w-sm p-6 animate-in fade-in zoom-in duration-200">
<div className="flex justify-between items-center mb-4 border-b pb-2">
<h3 className="font-bold text-lg text-slate-800">Registra Pagamento</h3>
<button onClick={() => setShowPayModal(false)}><X className="w-5 h-5 text-slate-400"/></button>
</div>
<form onSubmit={handleManualPayment} className="space-y-4">
<div className="bg-blue-50 p-3 rounded-lg border border-blue-100 text-sm">
<p className="text-slate-500">Famiglia: <span className="font-bold text-slate-800">{payShare.familyName}</span></p>
<p className="text-slate-500">Restante da pagare: <span className="font-bold text-red-600"> {(payShare.amountDue - payShare.amountPaid).toFixed(2)}</span></p>
</div>
<div>
<label className="block text-xs font-bold text-slate-500 uppercase mb-1">Importo Incassato ()</label>
<div className="relative">
<Banknote className="absolute left-3 top-2.5 w-4 h-4 text-slate-400"/>
<input
type="number"
step="0.01"
className="w-full border p-2 pl-9 rounded-lg text-slate-700 font-bold"
value={payAmount}
onChange={e => setPayAmount(parseFloat(e.target.value))}
required
/>
</div>
</div>
<div>
<label className="block text-xs font-bold text-slate-500 uppercase mb-1">Note (Opzionale)</label>
<input
className="w-full border p-2 rounded-lg text-slate-700 text-sm"
placeholder="Es. Bonifico, Contanti..."
value={payNotes}
onChange={e => setPayNotes(e.target.value)}
/>
</div>
<div className="flex gap-2 pt-2">
<button type="button" onClick={() => setShowPayModal(false)} className="flex-1 border p-2 rounded-lg text-slate-600 hover:bg-slate-50">Annulla</button>
<button type="submit" disabled={isPaying} className="flex-1 bg-green-600 text-white p-2 rounded-lg hover:bg-green-700 font-bold disabled:opacity-50">
{isPaying ? '...' : 'Conferma'}
</button>
</div>
</form>
</div>
</div>
)}
</div>
);
};