diff --git a/src/routes/cases.$caseId.tsx b/src/routes/cases.$caseId.tsx index ab4299a..8d98ed8 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); @@ -275,7 +292,11 @@ function CaseDetail() { />
- + {canManage ? ( + + ) : ( + + )} @@ -331,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 + +
+ ) : ( + + )} +
+ ); +} 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}
}
)}