Update ExtraordinaryAdmin.tsx
This commit is contained in:
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user