diff --git a/src/pages/accounting/AccountingDepositsPage.tsx b/src/pages/accounting/AccountingDepositsPage.tsx index 2ccd900..d2728bd 100644 --- a/src/pages/accounting/AccountingDepositsPage.tsx +++ b/src/pages/accounting/AccountingDepositsPage.tsx @@ -9,9 +9,10 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Textarea } from "@/components/ui/textarea"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; import { toast } from "sonner"; import { money, fmtDate } from "./lib/format"; -import { Landmark, Loader2, Plus, Trash2 } from "lucide-react"; +import { Landmark, Loader2, Plus, Trash2, Pencil } from "lucide-react"; import { EmptyState } from "./components/EmptyState"; import { ensureUndepositedFunds } from "./lib/undeposited"; @@ -32,6 +33,13 @@ export default function AccountingDepositsPage() { const [lines, setLines] = useState([]); const [saving, setSaving] = useState(false); + // Edit-existing-deposit state + const [editDep, setEditDep] = useState(null); + const [editDate, setEditDate] = useState(""); + const [editBankId, setEditBankId] = useState(""); + const [editMemo, setEditMemo] = useState(""); + const [savingEdit, setSavingEdit] = useState(false); + useEffect(() => { if (!cid) return; ensureUndepositedFunds(cid).then((id) => setUndepositedId(id)).catch(() => {}); @@ -53,6 +61,13 @@ export default function AccountingDepositsPage() { (await accounting.from("accounts").select("id,name,code,type,balance").eq("company_id", cid).order("type").order("code")).data ?? [], }); + const { data: recentDeposits = [] } = useQuery({ + queryKey: ["recent-deposits", cid], + enabled: !!cid, + queryFn: async () => + (await accounting.from("deposits").select("id,date,amount,memo,bank_account_id").eq("company_id", cid).order("date", { ascending: false }).limit(50)).data ?? [], + }); + // Two sources of "awaiting deposit": transactions parked on the Undeposited // Funds account (banking flow) and payments_received not yet deposited (incl. // payments synced from the main app's owner ledger). Both are unified below. @@ -206,6 +221,53 @@ export default function AccountingDepositsPage() { } }; + const bankName = (id: string) => (bankAccounts as any[]).find((a) => a.id === id)?.name ?? "—"; + + const refreshDeposits = () => { + ["undeposited-tx", "undeposited-pmt", "bank-accounts", "all-accounts", "accounts", "transactions", "recent-deposits"] + .forEach((k) => qc.invalidateQueries({ queryKey: [k, cid] })); + }; + + const openEditDeposit = (d: any) => { + setEditDep(d); setEditDate(d.date); setEditBankId(d.bank_account_id); setEditMemo(d.memo ?? ""); + }; + + const saveEditDeposit = async () => { + if (!editDep) return; + setSavingEdit(true); + try { + const { error } = await accounting.from("deposits") + .update({ date: editDate, bank_account_id: editBankId, memo: editMemo || null }) + .eq("id", editDep.id); + if (error) throw new Error(error.message); + // keep linked payments' bank account in sync (the deposit GL re-posts via trigger) + await accounting.from("payments_received").update({ bank_account_id: editBankId }).eq("deposit_id", editDep.id); + toast.success("Deposit updated"); + setEditDep(null); + refreshDeposits(); + } catch (e: any) { + toast.error(e?.message ?? "Failed to update deposit"); + } finally { + setSavingEdit(false); + } + }; + + const deleteDeposit = async (d: any) => { + if (!confirm(`Delete the deposit of ${money(Number(d.amount), cur)} on ${fmtDate(d.date)}? Its items return to "awaiting deposit".`)) return; + try { + // Release the deposited items so they return to the queue, then remove the deposit. + await accounting.from("transactions").update({ deposit_id: null }).eq("deposit_id", d.id); + await accounting.from("payments_received").update({ deposited: false, deposit_id: null }).eq("deposit_id", d.id); + await accounting.from("deposit_lines").delete().eq("deposit_id", d.id); + const { error } = await accounting.from("deposits").delete().eq("id", d.id); + if (error) throw new Error(error.message); + toast.success("Deposit deleted"); + refreshDeposits(); + } catch (e: any) { + toast.error(e?.message ?? "Failed to delete deposit"); + } + }; + if (!associationId) return

Select an association.

; if (companyLoading) return
; if (companyError || !companyId) return

{companyError || "Accounting setup is not ready."}

; @@ -360,6 +422,72 @@ export default function AccountingDepositsPage() { {saving ? "Recording…" : `Deposit ${money(grandTotal, cur)}`} + + {/* Recent deposits — edit / delete */} + + Recent deposits + + {(recentDeposits as any[]).length === 0 ? ( +

No deposits recorded yet.

+ ) : ( + + + + Date + Deposited to + Amount + Memo + + + + + {(recentDeposits as any[]).map((d) => ( + + {fmtDate(d.date)} + {bankName(d.bank_account_id)} + {money(Number(d.amount), cur)} + {d.memo ?? "—"} + +
+ + +
+
+
+ ))} +
+
+ )} +
+
+ + { if (!o) setEditDep(null); }}> + + Edit deposit +
+

+ Changing the date, bank account, or memo re-posts this deposit's GL entry. To change which items are included, delete it and re-create the deposit. +

+
+ + +
+
setEditDate(e.target.value)} />
+