From 180f14dfb0266e819c0a7838c31ff320494b7a6c Mon Sep 17 00:00:00 2001 From: Sean O'Connor Date: Sun, 14 Dec 2025 22:02:04 -0500 Subject: [PATCH] feat: improve invoice calendar item display and date picker icon button styling --- bun.lock | 3 + package.json | 1 + .../forms/invoice-calendar-view.tsx | 87 +++-- src/components/forms/invoice-form.tsx | 2 +- src/components/forms/invoice-line-items.tsx | 356 +++++++----------- src/components/ui/calendar.tsx | 7 +- src/components/ui/date-picker.tsx | 6 +- 7 files changed, 195 insertions(+), 267 deletions(-) diff --git a/bun.lock b/bun.lock index e366b9e..a3dec39 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "name": "beenvoice", "dependencies": { "@dnd-kit/core": "^6.3.1", + "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@radix-ui/react-alert-dialog": "^1.1.15", @@ -145,6 +146,8 @@ "@dnd-kit/core": ["@dnd-kit/core@6.3.1", "", { "dependencies": { "@dnd-kit/accessibility": "^3.1.1", "@dnd-kit/utilities": "^3.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ=="], + "@dnd-kit/modifiers": ["@dnd-kit/modifiers@9.0.0", "", { "dependencies": { "@dnd-kit/utilities": "^3.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@dnd-kit/core": "^6.3.0", "react": ">=16.8.0" } }, "sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw=="], + "@dnd-kit/sortable": ["@dnd-kit/sortable@10.0.0", "", { "dependencies": { "@dnd-kit/utilities": "^3.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@dnd-kit/core": "^6.3.0", "react": ">=16.8.0" } }, "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg=="], "@dnd-kit/utilities": ["@dnd-kit/utilities@3.2.2", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg=="], diff --git a/package.json b/package.json index e9694c2..83d6ce7 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ }, "dependencies": { "@dnd-kit/core": "^6.3.1", + "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@radix-ui/react-alert-dialog": "^1.1.15", diff --git a/src/components/forms/invoice-calendar-view.tsx b/src/components/forms/invoice-calendar-view.tsx index 94e7697..b819248 100644 --- a/src/components/forms/invoice-calendar-view.tsx +++ b/src/components/forms/invoice-calendar-view.tsx @@ -255,8 +255,8 @@ export function InvoiceCalendarView({ {dayItems.length > 0 ? ( dayItems.map(({ item }, i) => (
-
{item.description || "No description"}
-
{item.hours}h
+
{item.description || "No description"}
+
{item.hours}h
)) ) : ( @@ -285,11 +285,11 @@ export function InvoiceCalendarView({ > - -
+ +
- {date ? format(date, "EEEE, MMMM do") : "Details"} + {date ? format(date, "EEEE, MMMM do") : "Details"}
@@ -312,50 +312,48 @@ export function InvoiceCalendarView({ ) : (
{selectedDateItems.map(({ item, index }) => ( -
-
+
+
{/* Description */} -
+
+ onUpdateItem(index, "description", e.target.value)} placeholder="Describe the work performed..." - className="w-full text-sm font-medium" + className="pl-3 text-sm" />
- {/* Controls Row */} -
- {/* Hours */} - onUpdateItem(index, "hours", v)} - step={0.25} - min={0} - width="auto" - className="h-9 flex-1 min-w-[100px] font-mono" - suffix="h" - /> - - {/* Rate */} - onUpdateItem(index, "rate", v)} - prefix="$" - min={0} - step={1} - width="auto" - className="h-9 flex-1 min-w-[100px] font-mono" - /> - - {/* Amount */} -
- - ${(item.hours * item.rate).toFixed(2)} - + {/* Hours and Rate in a row */} +
+
+ + onUpdateItem(index, "hours", v)} + step={0.25} + min={0} + width="full" + />
+
+ + onUpdateItem(index, "rate", v)} + prefix="$" + min={0} + step={1} + width="full" + /> +
+
+
- {/* Actions */} + {/* Bottom section with controls, item name, and total */} +
+
+
+ + Item #{index + 1} + +
+
+ Total + + ${(item.hours * item.rate).toFixed(2)} + +
))} diff --git a/src/components/forms/invoice-form.tsx b/src/components/forms/invoice-form.tsx index 2906667..2f68a3b 100644 --- a/src/components/forms/invoice-form.tsx +++ b/src/components/forms/invoice-form.tsx @@ -134,7 +134,7 @@ export default function InvoiceForm({ invoiceId }: InvoiceFormProps) { }, [formData.items, formData.taxRate]); // Handlers (addItem, updateItem etc. - same as before) - const addItem = (date?: Date | unknown) => { + const addItem = (date?: unknown) => { const validDate = date instanceof Date ? date : new Date(); setFormData((prev) => ({ ...prev, diff --git a/src/components/forms/invoice-line-items.tsx b/src/components/forms/invoice-line-items.tsx index 28862e9..f77b6ce 100644 --- a/src/components/forms/invoice-line-items.tsx +++ b/src/components/forms/invoice-line-items.tsx @@ -1,26 +1,8 @@ "use client"; -import { - closestCenter, - DndContext, - KeyboardSensor, - PointerSensor, - useSensor, - useSensors, - type DragEndEvent, -} from "@dnd-kit/core"; -import { - arrayMove, - SortableContext, - sortableKeyboardCoordinates, - useSortable, - verticalListSortingStrategy, -} from "@dnd-kit/sortable"; -import { CSS } from "@dnd-kit/utilities"; import { ChevronDown, ChevronUp, - GripVertical, Plus, Trash2, } from "lucide-react"; @@ -73,73 +55,30 @@ interface LineItemRowProps { isLast: boolean; } -interface SortableLineItemProps { - item: InvoiceItem; - index: number; - canRemove: boolean; - onRemove: (index: number) => void; - onUpdate: ( - index: number, - field: string, - value: string | number | Date, - ) => void; - onMoveUp: (index: number) => void; - onMoveDown: (index: number) => void; - isFirst: boolean; - isLast: boolean; -} - -function SortableLineItem({ - item, - index, - canRemove, - onRemove, - onUpdate, - onMoveUp, - onMoveDown, - isFirst, - isLast, -}: SortableLineItemProps) { - const { - attributes, - listeners, - setNodeRef, - transform, - transition, - isDragging, - } = useSortable({ id: item.id }); - - const style = { - transform: CSS.Transform.toString(transform), - transition, - }; - - return ( -