Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
gpt-engineer-app[bot]
2026-05-07 18:44:34 +00:00
co-authored by renee-png
parent 46a4ca1089
commit 9d0dc0e202
+12 -10
View File
@@ -141,6 +141,8 @@ function InvoiceDetail() {
const canEdit = isAdmin || invoice.created_by === user?.id;
const isDraft = invoice.status === "draft";
// Line items, notes, and tax can be edited on any non-void invoice (not just drafts).
const canModify = canEdit && invoice.status !== "void";
const balance = Number(invoice.total) - Number(invoice.amount_paid);
const setStatus = async (status: string) => {
@@ -420,7 +422,7 @@ function InvoiceDetail() {
<th className="text-right px-3 py-2 font-medium w-[80px]">Qty</th>
<th className="text-right px-3 py-2 font-medium w-[100px]">Rate</th>
<th className="text-right px-3 py-2 font-medium w-[110px]">Amount</th>
{canEdit && isDraft && <th className="w-[40px]" />}
{canModify && <th className="w-[40px]" />}
</tr>
</thead>
<tbody>
@@ -433,13 +435,13 @@ function InvoiceDetail() {
<td className="px-3 py-1.5 text-right tabular-nums text-xs font-semibold text-muted-foreground">
{sub.billable ? formatCurrency(sub.subtotal) : "—"}
</td>
{canEdit && isDraft && <td />}
{canModify && <td />}
</tr>
{sub.items.map((it) => (
<tr key={it.id} className={`border-t ${!sub.billable ? "text-muted-foreground" : ""}`}>
<td className="px-3 py-2 text-xs">{it.work_date ? formatDate(it.work_date) : "—"}</td>
<td className="px-3 py-2 align-top">
{canEdit && isDraft ? (
{canModify ? (
<Input className="h-8" defaultValue={it.description}
onBlur={(e) => e.target.value !== it.description && updateItem(it.id, { description: e.target.value })} />
) : (
@@ -454,13 +456,13 @@ function InvoiceDetail() {
)}
</td>
<td className="px-3 py-2 text-right tabular-nums">
{canEdit && isDraft ? (
{canModify ? (
<Input className="h-8 text-right tabular-nums" defaultValue={Number(it.quantity)}
onBlur={(e) => Number(e.target.value) !== Number(it.quantity) && updateItem(it.id, { quantity: Number(e.target.value) })} />
) : Number(it.quantity).toFixed(2)}
</td>
<td className="px-3 py-2 text-right tabular-nums">
{canEdit && isDraft ? (
{canModify ? (
<Input className="h-8 text-right tabular-nums" defaultValue={Number(it.rate)}
onBlur={(e) => Number(e.target.value) !== Number(it.rate) && updateItem(it.id, { rate: Number(e.target.value) })} />
) : formatCurrency(it.rate)}
@@ -468,7 +470,7 @@ function InvoiceDetail() {
<td className="px-3 py-2 text-right tabular-nums font-medium">
{sub.billable ? formatCurrency(it.amount) : "—"}
</td>
{canEdit && isDraft && (
{canModify && (
<td className="px-2 py-2 text-right">
<Button variant="ghost" size="icon" className="h-7 w-7 text-muted-foreground hover:text-destructive" onClick={() => removeItem(it.id)}>
<Trash2 className="h-3.5 w-3.5" />
@@ -481,7 +483,7 @@ function InvoiceDetail() {
))}
</tbody>
</table>
{canEdit && isDraft && (
{canModify && (
<div className="border-t px-3 py-2 bg-muted/20">
<Button variant="ghost" size="sm" onClick={() => addManualItem(g.caseRow?.id ?? null)} disabled={savingItem}>
<Plus className="h-3.5 w-3.5 mr-1.5" /> Add line to {g.caseRow?.case_number ?? "this group"}
@@ -492,7 +494,7 @@ function InvoiceDetail() {
</Card>
))}
{canEdit && isDraft && groups.length === 0 && (
{canModify && groups.length === 0 && (
<Button variant="outline" onClick={() => addManualItem(null)}>
<Plus className="h-4 w-4 mr-2" /> Add first line item
</Button>
@@ -501,7 +503,7 @@ function InvoiceDetail() {
<Card className="border-border/60">
<CardContent className="p-4 space-y-2">
<Label className="text-xs uppercase tracking-wider text-muted-foreground">Notes</Label>
{canEdit && isDraft ? (
{canModify ? (
<Textarea defaultValue={invoice.notes ?? ""} rows={3} placeholder="Payment terms, thank-you message…"
onBlur={(e) => updateNotes(e.target.value)} />
) : (
@@ -519,7 +521,7 @@ function InvoiceDetail() {
<Row label="Subtotal" value={formatCurrency(invoice.subtotal)} />
<div className="flex justify-between items-center">
<span className="text-muted-foreground">Tax</span>
{canEdit && isDraft ? (
{canModify ? (
<div className="flex items-center gap-1">
<Input className="h-7 w-16 text-right tabular-nums" type="number" step="0.01"
defaultValue={invoice.subtotal > 0 ? ((Number(invoice.tax) / Number(invoice.subtotal)) * 100).toFixed(2) : "0"}