feat: polish invoice editor and viewer UI with custom NumberInput
component - Create custom NumberInput component with increment/decrement buttons - Add 0.25 step increments for hours and rates in invoice forms - Implement emerald-themed styling with hover states and accessibility - Add keyboard navigation (arrow keys) and proper ARIA support - Condense invoice editor tax/totals section into efficient grid layout - Update client dropdown to single-line format (name + email) - Add fixed footer with floating action bar pattern matching business forms - Redesign invoice viewer with better space utilization and visual hierarchy - Maintain professional appearance and consistent design system - Fix Next.js 15 params Promise handling across all invoice pages - Resolve TypeScript compilation errors and type-only imports
This commit is contained in:
@@ -1,28 +1,28 @@
|
||||
"use client"
|
||||
"use client";
|
||||
|
||||
import { format } from "date-fns"
|
||||
import { Calendar as CalendarIcon } from "lucide-react"
|
||||
import * as React from "react"
|
||||
import { format } from "date-fns";
|
||||
import { Calendar as CalendarIcon } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { Button } from "~/components/ui/button"
|
||||
import { Calendar } from "~/components/ui/calendar"
|
||||
import { Label } from "~/components/ui/label"
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Calendar } from "~/components/ui/calendar";
|
||||
import { Label } from "~/components/ui/label";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "~/components/ui/popover"
|
||||
import { cn } from "~/lib/utils"
|
||||
} from "~/components/ui/popover";
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
interface DatePickerProps {
|
||||
date?: Date
|
||||
onDateChange: (date: Date | undefined) => void
|
||||
label?: string
|
||||
placeholder?: string
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
required?: boolean
|
||||
id?: string
|
||||
date?: Date;
|
||||
onDateChange: (date: Date | undefined) => void;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
required?: boolean;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
export function DatePicker({
|
||||
@@ -33,16 +33,16 @@ export function DatePicker({
|
||||
className,
|
||||
disabled = false,
|
||||
required = false,
|
||||
id
|
||||
id,
|
||||
}: DatePickerProps) {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
return (
|
||||
<div className={cn("flex flex-col gap-2", className)}>
|
||||
{label && (
|
||||
<Label htmlFor={id} className="text-sm font-medium text-gray-700">
|
||||
<Label htmlFor={id} className="text-sm font-medium">
|
||||
{label}
|
||||
{required && <span className="text-red-500 ml-1">*</span>}
|
||||
{required && <span className="text-destructive ml-1">*</span>}
|
||||
</Label>
|
||||
)}
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
@@ -52,12 +52,12 @@ export function DatePicker({
|
||||
id={id}
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
"w-full justify-between font-normal h-10 border-gray-200 focus:border-emerald-500 focus:ring-emerald-500 text-sm",
|
||||
!date && "text-gray-500"
|
||||
"h-10 w-full justify-between text-sm font-normal",
|
||||
!date && "text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
{date ? format(date, "PPP") : placeholder}
|
||||
<CalendarIcon className="h-4 w-4 text-gray-400" />
|
||||
<CalendarIcon className="text-muted-foreground h-4 w-4" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
|
||||
@@ -66,12 +66,12 @@ export function DatePicker({
|
||||
selected={date}
|
||||
captionLayout="dropdown"
|
||||
onSelect={(selectedDate: Date | undefined) => {
|
||||
onDateChange(selectedDate)
|
||||
setOpen(false)
|
||||
onDateChange(selectedDate);
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user