From e59b1f22e455a464dbde05d862709b22e2a33faa Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:07:01 +0000 Subject: [PATCH 1/4] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/cases.$caseId.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/routes/cases.$caseId.tsx b/src/routes/cases.$caseId.tsx index ab4299a..17dc95e 100644 --- a/src/routes/cases.$caseId.tsx +++ b/src/routes/cases.$caseId.tsx @@ -89,6 +89,23 @@ function CaseDetail() { else { toast.success("Assignee updated"); load(); } }; + const updateRate = async (rateInput: string) => { + const trimmed = rateInput.trim(); + const next = trimmed === "" ? null : Number(trimmed); + if (next !== null && (!Number.isFinite(next) || next < 0)) { + toast.error("Enter a valid rate (0 or higher)"); + return false; + } + const { error } = await supabase + .from("cases") + .update({ default_hourly_rate: next }) + .eq("id", caseId); + if (error) { toast.error(error.message); return false; } + toast.success(next === null ? "Case rate cleared" : `Case rate set to $${next.toFixed(2)}/hr`); + load(); + return true; + }; + const filteredClients = useMemo(() => { const q = clientSearch.trim().toLowerCase(); if (!q) return clients.slice(0, 50); From 810170abb7fe43d4865c8c384d431e473dcce8c7 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:07:15 +0000 Subject: [PATCH 2/4] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/cases.$caseId.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/routes/cases.$caseId.tsx b/src/routes/cases.$caseId.tsx index 17dc95e..b743be3 100644 --- a/src/routes/cases.$caseId.tsx +++ b/src/routes/cases.$caseId.tsx @@ -292,7 +292,11 @@ function CaseDetail() { />
- + {canManage ? ( + + ) : ( + + )} From 2cb2ed77668f05e83baec09a724685c2e6a9e936 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:07:41 +0000 Subject: [PATCH 3/4] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/cases.$caseId.tsx | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/routes/cases.$caseId.tsx b/src/routes/cases.$caseId.tsx index b743be3..8d98ed8 100644 --- a/src/routes/cases.$caseId.tsx +++ b/src/routes/cases.$caseId.tsx @@ -352,3 +352,62 @@ function SmallStat({ label, value }: { label: string; value: string }) {
); } + +function EditableRateStat({ + value, + onSave, +}: { + value: number | null; + onSave: (raw: string) => Promise; +}) { + const [editing, setEditing] = useState(false); + const [raw, setRaw] = useState(value != null ? String(value) : ""); + const [saving, setSaving] = useState(false); + + useEffect(() => { + setRaw(value != null ? String(value) : ""); + }, [value]); + + const commit = async () => { + setSaving(true); + const ok = await onSave(raw); + setSaving(false); + if (ok) setEditing(false); + }; + + return ( +
+
Case rate
+ {editing ? ( +
+ $ + setRaw(e.target.value)} + onKeyDown={(e) => { + if (e.key === "Enter") commit(); + if (e.key === "Escape") { setRaw(value != null ? String(value) : ""); setEditing(false); } + }} + autoFocus + className="h-7 px-2 text-sm" + /> + /hr + +
+ ) : ( + + )} +
+ ); +} From b0aebc27acf485714b3cabda230d73fe62530dd9 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:07:53 +0000 Subject: [PATCH 4/4] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/invoices.$invoiceId.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/invoices.$invoiceId.tsx b/src/routes/invoices.$invoiceId.tsx index 7241cd9..535eaae 100644 --- a/src/routes/invoices.$invoiceId.tsx +++ b/src/routes/invoices.$invoiceId.tsx @@ -425,13 +425,13 @@ function InvoiceDetail() { {sub.items.map((it) => ( {it.work_date ? formatDate(it.work_date) : "—"} - + {canEdit && isDraft ? ( e.target.value !== it.description && updateItem(it.id, { description: e.target.value })} /> ) : ( -
-
{it.description}
+
+
{it.description}
{it.user?.full_name &&
{it.user.full_name}
}
)}