+
+ {/* Description */}
+
onUpdateItem(index, "description", e.target.value)}
- placeholder="What did you work on?"
- className="bg-muted/30 border-transparent focus:border-input focus:bg-background transition-all font-medium"
+ placeholder="Describe the work performed..."
+ className="w-full text-sm font-medium"
/>
-
-
-
-
+
+ {/* Controls Row */}
+
+ {/* Hours */}
onUpdateItem(index, "hours", v)}
step={0.25}
min={0}
- className="bg-muted/30"
+ width="auto"
+ className="h-9 flex-1 min-w-[100px] font-mono"
+ suffix="h"
/>
-
-
-
+
+ {/* Rate */}
onUpdateItem(index, "rate", v)}
prefix="$"
min={0}
- className="bg-muted/30"
+ step={1}
+ width="auto"
+ className="h-9 flex-1 min-w-[100px] font-mono"
/>
+
+ {/* Amount */}
+
+
+ ${(item.hours * item.rate).toFixed(2)}
+
+
+
+ {/* Actions */}
+
-
-
- ${(item.hours * item.rate).toFixed(2)}
-
-
-
))}
diff --git a/src/components/forms/invoice-form.tsx b/src/components/forms/invoice-form.tsx
index a57de08..2906667 100644
--- a/src/components/forms/invoice-form.tsx
+++ b/src/components/forms/invoice-form.tsx
@@ -105,7 +105,7 @@ export default function InvoiceForm({ invoiceId }: InvoiceFormProps) {
hours: item.hours,
rate: item.rate,
amount: item.amount,
- })) || [];
+ })).sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) || [];
setFormData({
invoiceNumber: existingInvoice.invoiceNumber,
businessId: existingInvoice.businessId ?? "",
@@ -134,10 +134,11 @@ export default function InvoiceForm({ invoiceId }: InvoiceFormProps) {
}, [formData.items, formData.taxRate]);
// Handlers (addItem, updateItem etc. - same as before)
- const addItem = (date?: Date) => {
+ const addItem = (date?: Date | unknown) => {
+ const validDate = date instanceof Date ? date : new Date();
setFormData((prev) => ({
...prev,
- items: [...prev.items, { id: crypto.randomUUID(), date: date ?? new Date(), description: "", hours: 1, rate: prev.defaultHourlyRate ?? 0, amount: prev.defaultHourlyRate ?? 0 }],
+ items: [...prev.items, { id: crypto.randomUUID(), date: validDate, description: "", hours: 1, rate: prev.defaultHourlyRate ?? 0, amount: prev.defaultHourlyRate ?? 0 }],
}));
};
const removeItem = (idx: number) => { if (formData.items.length > 1) setFormData((prev) => ({ ...prev, items: prev.items.filter((_, i) => i !== idx) })); };
@@ -232,7 +233,9 @@ export default function InvoiceForm({ invoiceId }: InvoiceFormProps) {
status: formData.status,
notes: formData.notes,
taxRate: formData.taxRate,
- items: formData.items.map(i => ({ date: i.date, description: i.description, hours: i.hours, rate: i.rate, amount: i.hours * i.rate })),
+ items: formData.items
+ .sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime())
+ .map(i => ({ date: i.date, description: i.description, hours: i.hours, rate: i.rate, amount: i.hours * i.rate })),
};
if (invoiceId && invoiceId !== "new" && invoiceId !== undefined) await updateInvoice.mutateAsync({ id: invoiceId, ...payload });
else await createInvoice.mutateAsync(payload);
diff --git a/src/components/forms/invoice-line-items.tsx b/src/components/forms/invoice-line-items.tsx
index e266317..28862e9 100644
--- a/src/components/forms/invoice-line-items.tsx
+++ b/src/components/forms/invoice-line-items.tsx
@@ -174,7 +174,7 @@ function SortableLineItem({
value={item.description}
onChange={(e) => onUpdate(index, "description", e.target.value)}
placeholder="Describe the work performed..."
- className="w-full text-sm font-medium border-transparent bg-transparent hover:bg-muted/50 focus:bg-background focus:ring-1 focus:ring-ring transition-all rounded-md px-2 -ml-2"
+ className="w-full text-sm font-medium"
/>
@@ -187,7 +187,8 @@ function SortableLineItem({
onUpdate(index, "date", date ?? new Date())
}
size="sm"
- className="h-9 w-36"
+ className="w-full sm:w-[180px]"
+ inputClassName="h-9"
/>
{/* Hours */}
@@ -197,7 +198,8 @@ function SortableLineItem({
min={0}
step={0.25}
width="auto"
- className="h-9 w-32"
+ className="h-9 flex-1 min-w-[100px] font-mono"
+ suffix="h"
/>
{/* Rate */}
@@ -208,7 +210,7 @@ function SortableLineItem({
step={1}
prefix="$"
width="auto"
- className="h-9 w-32"
+ className="h-9 flex-1 min-w-[100px] font-mono"
/>
{/* Amount */}
@@ -281,6 +283,7 @@ function MobileLineItem({
date={item.date}
onDateChange={(date) => onUpdate(index, "date", date ?? new Date())}
size="sm"
+ inputClassName="h-9"
/>