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} }
)}
|