Changes
Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
co-authored by
renee-png
parent
a8169fc82a
commit
f75f2d5094
+124
-1
@@ -312,4 +312,127 @@ function TrustLedgerPage() {
|
||||
</Card>
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
function RecordEntryDialog({
|
||||
open, type, clients, onClose, onSaved,
|
||||
}: {
|
||||
open: boolean;
|
||||
type: "deposit" | "withdrawal";
|
||||
clients: ClientLite[];
|
||||
onClose: () => void;
|
||||
onSaved: (entry: Entry) => void;
|
||||
}) {
|
||||
const { user } = useAuth();
|
||||
const [clientId, setClientId] = useState<string>("");
|
||||
const [caseId, setCaseId] = useState<string>("_pool");
|
||||
const [cases, setCases] = useState<{ id: string; case_number: string | null; title: string | null }[]>([]);
|
||||
const [date, setDate] = useState<string>(new Date().toISOString().slice(0, 10));
|
||||
const [amount, setAmount] = useState<string>("");
|
||||
const [note, setNote] = useState<string>("");
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
setClientId(""); setCaseId("_pool"); setCases([]);
|
||||
setAmount(""); setNote(""); setDate(new Date().toISOString().slice(0, 10));
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!clientId) { setCases([]); return; }
|
||||
(async () => {
|
||||
const { data } = await supabase
|
||||
.from("cases")
|
||||
.select("id, case_number, title")
|
||||
.eq("client_id", clientId)
|
||||
.is("archived_at", null)
|
||||
.order("opened_at", { ascending: false });
|
||||
setCases(data ?? []);
|
||||
})();
|
||||
}, [clientId]);
|
||||
|
||||
const sortedClients = useMemo(
|
||||
() => [...clients].filter((c) => !c.archived_at).sort((a, b) => (a.name ?? "").localeCompare(b.name ?? "")),
|
||||
[clients],
|
||||
);
|
||||
|
||||
const save = async () => {
|
||||
if (!clientId) return toast.error("Pick a client");
|
||||
const amt = Number(amount);
|
||||
if (!amt || amt <= 0) return toast.error("Enter a valid amount");
|
||||
setSaving(true);
|
||||
const { data, error } = await supabase
|
||||
.from("trust_ledger_entries")
|
||||
.insert({
|
||||
client_id: clientId,
|
||||
case_id: caseId === "_pool" ? null : caseId,
|
||||
entry_date: date,
|
||||
entry_type: type,
|
||||
amount: amt,
|
||||
note: note || null,
|
||||
created_by: user?.id ?? null,
|
||||
})
|
||||
.select("*")
|
||||
.single();
|
||||
setSaving(false);
|
||||
if (error) return toast.error(error.message);
|
||||
toast.success(`${type === "deposit" ? "Deposit" : "Withdrawal"} recorded`);
|
||||
onSaved(data as Entry);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={(v) => !v && onClose()}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Record {type}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<Label>Client</Label>
|
||||
<Select value={clientId} onValueChange={setClientId}>
|
||||
<SelectTrigger><SelectValue placeholder="Select client…" /></SelectTrigger>
|
||||
<SelectContent>
|
||||
{sortedClients.map((c) => (
|
||||
<SelectItem key={c.id} value={c.id}>{c.name ?? "Unnamed"}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<Label>Case (optional)</Label>
|
||||
<Select value={caseId} onValueChange={setCaseId} disabled={!clientId}>
|
||||
<SelectTrigger><SelectValue placeholder="Client trust pool" /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="_pool">Client trust pool (no case)</SelectItem>
|
||||
{cases.map((c) => (
|
||||
<SelectItem key={c.id} value={c.id}>{c.case_number ?? c.title}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<Label>Date</Label>
|
||||
<Input type="date" value={date} onChange={(e) => setDate(e.target.value)} />
|
||||
</div>
|
||||
<div>
|
||||
<Label>Amount</Label>
|
||||
<Input type="number" step="0.01" placeholder="0.00" value={amount} onChange={(e) => setAmount(e.target.value)} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>Note (optional)</Label>
|
||||
<Textarea rows={2} value={note} onChange={(e) => setNote(e.target.value)} placeholder="Reference, source, purpose…" />
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={onClose}>Cancel</Button>
|
||||
<Button onClick={save} disabled={saving}>
|
||||
{saving ? <Loader2 className="h-4 w-4 mr-2 animate-spin" /> : null}
|
||||
Record {type}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user