diff --git a/src/components/data/invoice-view.tsx b/src/components/data/invoice-view.tsx
index f4ab95f..67bf696 100644
--- a/src/components/data/invoice-view.tsx
+++ b/src/components/data/invoice-view.tsx
@@ -108,10 +108,10 @@ export function InvoiceView({ invoiceId }: InvoiceViewProps) {
}
};
- const formatCurrency = (amount: number) => {
+ const formatCurrency = (amount: number, currency = "USD") => {
return new Intl.NumberFormat("en-US", {
style: "currency",
- currency: "USD",
+ currency,
}).format(amount);
};
@@ -233,7 +233,7 @@ export function InvoiceView({ invoiceId }: InvoiceViewProps) {
onClick={handlePDFExport}
disabled={isExportingPDF}
variant="default"
- className="transform-none flex-shrink-0"
+ className="flex-shrink-0 transform-none"
>
{isExportingPDF ? (
<>
@@ -432,7 +432,10 @@ export function InvoiceView({ invoiceId }: InvoiceViewProps) {
Tax ({((invoice.taxRate ?? 0) * 100).toFixed(1)}%)
- {formatCurrency(invoice.totalAmount * (invoice.taxRate ?? 0), invoice.currency)}
+ {formatCurrency(
+ invoice.totalAmount * (invoice.taxRate ?? 0),
+ invoice.currency,
+ )}
)}
@@ -440,7 +443,10 @@ export function InvoiceView({ invoiceId }: InvoiceViewProps) {
Total
- {formatCurrency(invoice.totalAmount * (1 + (invoice.taxRate ?? 0)), invoice.currency)}
+ {formatCurrency(
+ invoice.totalAmount * (1 + (invoice.taxRate ?? 0)),
+ invoice.currency,
+ )}
diff --git a/src/components/forms/invoice-form.tsx b/src/components/forms/invoice-form.tsx
index 3322291..ab48108 100644
--- a/src/components/forms/invoice-form.tsx
+++ b/src/components/forms/invoice-form.tsx
@@ -21,7 +21,15 @@ import { InvoiceLineItems } from "./invoice-line-items";
import { InvoiceCalendarView } from "./invoice-calendar-view";
import { api } from "~/trpc/react";
import { toast } from "sonner";
-import { Save, Calendar as CalendarIcon, Tag, User, List, FileText, ChevronDown } from "lucide-react";
+import {
+ Save,
+ Calendar as CalendarIcon,
+ Tag,
+ User,
+ List,
+ FileText,
+ ChevronDown,
+} from "lucide-react";
import { SUPPORTED_CURRENCIES } from "~/lib/currency";
import { Textarea } from "~/components/ui/textarea";
import {
@@ -101,7 +109,9 @@ export default function InvoiceForm({ invoiceId }: InvoiceFormProps) {
// Queries (Same as before)
const { data: clients, isLoading: loadingClients } =
api.clients.getAll.useQuery();
- const { data: noteTemplates } = api.invoiceTemplates.getByType.useQuery({ type: "notes" });
+ const { data: noteTemplates } = api.invoiceTemplates.getByType.useQuery({
+ type: "notes",
+ });
const { data: businesses, isLoading: loadingBusinesses } =
api.businesses.getAll.useQuery();
const { data: existingInvoice, isLoading: loadingInvoice } =
@@ -231,32 +241,6 @@ export default function InvoiceForm({ invoiceId }: InvoiceFormProps) {
}),
}));
};
- const moveItemUp = (idx: number) => {
- if (idx === 0) return;
- setFormData((prev) => {
- const newItems = [...prev.items];
- if (newItems[idx] && newItems[idx - 1]) {
- const temp = newItems[idx - 1]!;
- newItems[idx - 1] = newItems[idx];
- newItems[idx] = temp;
- }
- return { ...prev, items: newItems };
- });
- };
- const moveItemDown = (idx: number) => {
- if (idx === formData.items.length - 1) return;
- setFormData((prev) => {
- const newItems = [...prev.items];
- if (newItems[idx] && newItems[idx + 1]) {
- const temp = newItems[idx + 1]!;
- newItems[idx + 1] = newItems[idx];
- newItems[idx] = temp;
- }
- return { ...prev, items: newItems };
- });
- };
- const reorderItems = (newItems: InvoiceItem[]) =>
- setFormData((prev) => ({ ...prev, items: newItems }));
const createInvoice = api.invoices.create.useMutation({
onSuccess: (inv) => {
@@ -453,13 +437,24 @@ export default function InvoiceForm({ invoiceId }: InvoiceFormProps) {
? selectedClient.defaultHourlyRate
: null;
const businessRate =
- currentBusiness && "defaultHourlyRate" in currentBusiness
+ currentBusiness &&
+ "defaultHourlyRate" in currentBusiness
? currentBusiness.defaultHourlyRate
: null;
- updateField("defaultHourlyRate", (clientRate ?? businessRate ?? 0) as number);
+ updateField(
+ "defaultHourlyRate",
+ (clientRate ?? businessRate ?? 0) as number,
+ );
// Auto-fill currency from client
- if (selectedClient && "currency" in selectedClient && selectedClient.currency) {
- updateField("currency", selectedClient.currency as string);
+ if (
+ selectedClient &&
+ "currency" in selectedClient &&
+ selectedClient.currency
+ ) {
+ updateField(
+ "currency",
+ selectedClient.currency as string,
+ );
}
}}
>
@@ -599,7 +594,11 @@ export default function InvoiceForm({ invoiceId }: InvoiceFormProps) {
{noteTemplates && noteTemplates.length > 0 && (
-
@@ -674,9 +673,6 @@ export default function InvoiceForm({ invoiceId }: InvoiceFormProps) {
onAddItem={addItem}
onRemoveItem={removeItem}
onUpdateItem={updateItem}
- onMoveUp={moveItemUp}
- onMoveDown={moveItemDown}
- onReorderItems={reorderItems}
/>
diff --git a/src/components/forms/invoice-line-items.tsx b/src/components/forms/invoice-line-items.tsx
index f77b6ce..98ade02 100644
--- a/src/components/forms/invoice-line-items.tsx
+++ b/src/components/forms/invoice-line-items.tsx
@@ -1,11 +1,6 @@
"use client";
-import {
- ChevronDown,
- ChevronUp,
- Plus,
- Trash2,
-} from "lucide-react";
+import { Plus, Trash2 } from "lucide-react";
import * as React from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Button } from "~/components/ui/button";
@@ -33,9 +28,6 @@ interface InvoiceLineItemsProps {
field: string,
value: string | number | Date,
) => void;
- onMoveUp: (index: number) => void;
- onMoveDown: (index: number) => void;
- onReorderItems: (items: InvoiceItem[]) => void;
className?: string;
}
@@ -49,61 +41,18 @@ interface LineItemRowProps {
field: string,
value: string | number | Date,
) => void;
- onMoveUp: (index: number) => void;
- onMoveDown: (index: number) => void;
- isFirst: boolean;
- isLast: boolean;
}
const LineItemCard = React.forwardRef(
- (
- {
- item,
- index,
- canRemove,
- onRemove,
- onUpdate,
- onMoveUp,
- onMoveDown,
- isFirst,
- isLast,
- },
- ref,
- ) => {
+ ({ item, index, canRemove, onRemove, onUpdate }, ref) => {
return (
- {/* Arrow Controls */}
-
- onMoveUp(index)}
- className="h-6 w-6 p-0"
- disabled={isFirst}
- aria-label="Move up"
- >
-
-
- onMoveDown(index)}
- className="h-6 w-6 p-0"
- disabled={isLast}
- aria-label="Move down"
- >
-
-
-
-
{/* Main Content */}
{/* Description */}
@@ -136,7 +85,7 @@ const LineItemCard = React.forwardRef
(
min={0}
step={0.25}
width="auto"
- className="h-9 flex-1 min-w-[100px] font-mono"
+ className="h-9 min-w-[100px] flex-1 font-mono"
suffix="h"
/>
@@ -148,7 +97,7 @@ const LineItemCard = React.forwardRef(
step={1}
prefix="$"
width="auto"
- className="h-9 flex-1 min-w-[100px] font-mono"
+ className="h-9 min-w-[100px] flex-1 font-mono"
/>
{/* Amount */}
@@ -185,10 +134,6 @@ function MobileLineItem({
canRemove,
onRemove,
onUpdate,
- onMoveUp,
- onMoveDown,
- isFirst,
- isLast,
}: LineItemRowProps) {
return (
-
onMoveUp(index)}
- className="h-8 w-8 p-0"
- disabled={isFirst}
- aria-label="Move up"
- >
-
-
-
onMoveDown(index)}
- className="h-8 w-8 p-0"
- disabled={isLast}
- aria-label="Move down"
- >
-
-
1;
@@ -337,10 +258,6 @@ export function InvoiceLineItems({
canRemove={canRemoveItems}
onRemove={onRemoveItem}
onUpdate={onUpdateItem}
- onMoveUp={onMoveUp}
- onMoveDown={onMoveDown}
- isFirst={index === 0}
- isLast={index === items.length - 1}
/>
@@ -351,10 +268,6 @@ export function InvoiceLineItems({
canRemove={canRemoveItems}
onRemove={onRemoveItem}
onUpdate={onUpdateItem}
- onMoveUp={onMoveUp}
- onMoveDown={onMoveDown}
- isFirst={index === 0}
- isLast={index === items.length - 1}
/>
))}
@@ -368,7 +281,7 @@ export function InvoiceLineItems({
type="button"
variant="outline"
onClick={onAddItem}
- className="w-full border-dashed border-border py-8 text-muted-foreground hover:text-primary hover:bg-accent/50 hover:border-primary/50 transition-all"
+ className="border-border text-muted-foreground hover:text-primary hover:bg-accent/50 hover:border-primary/50 w-full border-dashed py-8 transition-all"
>
Add Line Item
diff --git a/src/components/forms/invoice/invoice-workspace.tsx b/src/components/forms/invoice/invoice-workspace.tsx
index 87da73e..a1b09b4 100644
--- a/src/components/forms/invoice/invoice-workspace.tsx
+++ b/src/components/forms/invoice/invoice-workspace.tsx
@@ -9,98 +9,93 @@ import { InvoiceCalendarView } from "../invoice-calendar-view";
import type { InvoiceFormData } from "./types";
interface InvoiceWorkspaceProps {
- formData: InvoiceFormData;
- viewMode: "list" | "calendar";
- setViewMode: (mode: "list" | "calendar") => void;
- addItem: (date?: Date) => void;
- removeItem: (index: number) => void;
- updateItem: (index: number, field: string, value: string | number | Date) => void;
- moveItemUp: (index: number) => void;
- moveItemDown: (index: number) => void;
- reorderItems: (items: InvoiceFormData['items']) => void;
- className?: string;
+ formData: InvoiceFormData;
+ viewMode: "list" | "calendar";
+ setViewMode: (mode: "list" | "calendar") => void;
+ addItem: (date?: Date) => void;
+ removeItem: (index: number) => void;
+ updateItem: (
+ index: number,
+ field: string,
+ value: string | number | Date,
+ ) => void;
+ className?: string;
}
export function InvoiceWorkspace({
- formData,
- viewMode,
- setViewMode,
- addItem,
- removeItem,
- updateItem,
- moveItemUp,
- moveItemDown,
- reorderItems,
- className,
+ formData,
+ viewMode,
+ setViewMode,
+ addItem,
+ removeItem,
+ updateItem,
+ className,
}: InvoiceWorkspaceProps) {
-
- return (
-
- {/* Workspace Header / View Toggle */}
-
-
-
- {viewMode === 'list' ? 'Line Items' : 'Timesheet'}
-
-
- {formData.items.length} {formData.items.length === 1 ? 'entry' : 'entries'}
-
-
-
-
- setViewMode('list')}
- className="h-8 gap-2 text-xs"
- >
-
- List
-
- setViewMode('calendar')}
- className="h-8 gap-2 text-xs"
- >
-
- Calendar
-
-
-
-
- {/* Workspace Content */}
-
-
- {viewMode === 'list' ? (
-
-
- addItem()}
- onRemoveItem={removeItem}
- onUpdateItem={updateItem}
- onMoveUp={moveItemUp}
- onMoveDown={moveItemDown}
- onReorderItems={reorderItems}
- className="p-4"
- />
-
-
- ) : (
-
-
-
- )}
-
-
+ return (
+
+ {/* Workspace Header / View Toggle */}
+
+
+
+ {viewMode === "list" ? "Line Items" : "Timesheet"}
+
+
+ {formData.items.length}{" "}
+ {formData.items.length === 1 ? "entry" : "entries"}
+
- );
+
+
+ setViewMode("list")}
+ className="h-8 gap-2 text-xs"
+ >
+
+ List
+
+ setViewMode("calendar")}
+ className="h-8 gap-2 text-xs"
+ >
+
+ Calendar
+
+
+
+
+ {/* Workspace Content */}
+
+
+ {viewMode === "list" ? (
+
+
+ addItem()}
+ onRemoveItem={removeItem}
+ onUpdateItem={updateItem}
+ className="p-4"
+ />
+
+
+ ) : (
+
+
+
+ )}
+
+
+
+ );
}