From 49b6df7a80f8de5cf4e3a097db066ee4f3610b3d Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 01:58:25 +0000 Subject: [PATCH] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/components/cases/collections-tab.tsx | 65 ++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/components/cases/collections-tab.tsx b/src/components/cases/collections-tab.tsx index 21c3eba..54883bd 100644 --- a/src/components/cases/collections-tab.tsx +++ b/src/components/cases/collections-tab.tsx @@ -365,12 +365,77 @@ export function CollectionDetail({ .from("collection_ledger_entries") .select("*") .eq("collection_id", collection.id) + .order("sort_order", { ascending: true }) .order("entry_date", { ascending: true }) .order("created_at", { ascending: true }); setEntries(data ?? []); setLoading(false); }; + // Inline-edit a single field (optimistic) + const patchEntry = async (id: string, patch: Record) => { + setEntries((prev) => prev.map((e) => (e.id === id ? { ...e, ...patch } : e))); + const { error } = await (supabase.from("collection_ledger_entries") as any) + .update(patch) + .eq("id", id); + if (error) { + toast.error("Could not save", { description: error.message }); + load(); + } else { + onChange(); + } + }; + + // Insert a blank row at the end (sort_order = max+10) + const addBlankRow = async () => { + const maxSort = entries.reduce((m: number, e: any) => Math.max(m, Number(e.sort_order) || 0), 0); + const today = new Date().toISOString().slice(0, 10); + const { data, error } = await supabase + .from("collection_ledger_entries") + .insert({ + collection_id: collection.id, + entry_date: today, + transaction_type: "adjustment", + sort_order: maxSort + 10, + created_by: user?.id, + }) + .select() + .single(); + if (error) { toast.error(error.message); return; } + setEntries((prev) => [...prev, data]); + }; + + // Drag-and-drop reorder + const sensors = useSensors( + useSensor(PointerSensor, { activationConstraint: { distance: 4 } }), + useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }), + ); + const handleDragEnd = async (e: DragEndEvent) => { + const { active, over } = e; + if (!over || active.id === over.id) return; + const oldIdx = entries.findIndex((x: any) => x.id === active.id); + const newIdx = entries.findIndex((x: any) => x.id === over.id); + if (oldIdx < 0 || newIdx < 0) return; + const reordered = arrayMove(entries, oldIdx, newIdx).map((x: any, i: number) => ({ + ...x, + sort_order: (i + 1) * 10, + })); + setEntries(reordered); + // Persist new sort orders + const updates = reordered.map((x: any) => + (supabase.from("collection_ledger_entries") as any) + .update({ sort_order: x.sort_order }) + .eq("id", x.id), + ); + const results = await Promise.all(updates); + const failed = results.find((r: any) => r.error); + if (failed) { + toast.error("Reorder failed", { description: failed.error.message }); + load(); + } + }; + + useEffect(() => { load(); // eslint-disable-next-line react-hooks/exhaustive-deps