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