# Invoice generator dashboard

A shadcn/ui block from the [@watermelon](https://ui.watermelon.sh) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/watermelon/invoice-generator-dashboard).

- Page, with a live preview: https://shadcn.exchange/r/watermelon/invoice-generator-dashboard
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/watermelon/invoice-generator-dashboard-light-079a28aee45cc524.png
- Registry item: https://registry.watermelon.sh/r/invoice-generator-dashboard.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://registry.watermelon.sh/r/invoice-generator-dashboard.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `@radix-ui/react-dialog`, `@radix-ui/react-dropdown-menu`, `@radix-ui/react-label`, `@radix-ui/react-select`, `@radix-ui/react-separator`, `@radix-ui/react-slot`, `@radix-ui/react-tooltip`, `class-variance-authority`, `lucide-react`, `next-themes`
- Registry items: `breadcrumb`, `button`, `dialog`, `dropdown-menu`, `input`, `label`, `popover`, `select`, `separator`, `sheet`, `sidebar`, `skeleton`, `textarea`, `tooltip`, `utils`

## Files

### `src/components/dashboards/invoice-generator-dashboard/components/app-sidebar.tsx`

```tsx
"use client";
import * as React from "react";
import {
  Plus,
  Send,
  X
} from "lucide-react";

import { SearchForm } from "./search-form";
import {
  Sidebar,
  SidebarContent,
  SidebarGroup,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarHeader,
  SidebarMenu,
  SidebarMenuButton,
  SidebarMenuItem,
  SidebarRail,
} from "@/components/ui/sidebar";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";

import { sidebarData } from "../data";

interface AppSidebarProps extends React.ComponentProps<typeof Sidebar> {
  onNavigate?: (view: string) => void;
  currentView?: string;
}

export function AppSidebar({ onNavigate, currentView, ...props }: AppSidebarProps) {
  return (
    <Sidebar {...props} className="px-4 md:px-2">
      <SidebarHeader className="border-b px-2 md:px-0 border-border">
        <Dialog>
          <DialogTrigger asChild>
            <SidebarMenuButton
              className="
                flex items-center justify-center gap-2 px-8 py-3 font-sans text-base font-medium text-white/90 hover:text-white tracking-tight rounded-xl h-12 bg-linear-to-b from-[#279596] to-[#318A8B] shadow-[inset_0_4px_6px_rgba(255,255,255,0.4),inset_0_-4px_6px_rgba(255,255,255,0.2),inset_0_0_0_1px_rgba(255,255,255,0.1)] transition-colors duration-300 ease-in-out cursor-pointer active:text-white
              "
            >
              <Plus className="size-6" strokeWidth={2.5} />
              <span>Compose Email</span>
            </SidebarMenuButton>
          </DialogTrigger>
          <DialogContent className="sm:max-w-[525px] p-0 overflow-hidden bg-background border-border shadow-xl">
            <DialogHeader className="px-6 py-4 border-b border-border bg-muted/30">
              <DialogTitle className="text-lg font-semibold tracking-tight text-foreground">New Message</DialogTitle>
            </DialogHeader>
            <div className="flex flex-col">
              <div className="flex items-center border-b border-border px-4 py-2 hover:bg-muted/10 transition-colors">
                <span className="text-sm font-medium text-muted-foreground w-12 shrink-0">To:</span>
                <Input 
                  className="border-0 focus-visible:ring-0 focus-visible:ring-offset-0 shadow-none h-8 px-2 text-sm text-foreground placeholder:text-muted-foreground/50 rounded-none bg-transparent" 
                  placeholder="recipient@example.com"
                  autoFocus
                />
              </div>
              <div className="flex items-center border-b border-border px-4 py-2 hover:bg-muted/10 transition-colors">
                <span className="text-sm font-medium text-muted-foreground w-12 shrink-0">Subject:</span>
                <Input 
                  className="border-0 focus-visible:ring-0 focus-visible:ring-offset-0 shadow-none h-8 px-4 text-sm text-foreground placeholder:text-muted-foreground/50 rounded-none bg-transparent" 
                  placeholder="Enter subject" 
                />
              </div>
              <div className="p-4">
                <Textarea 
                  className="min-h-[250px] border-0 focus-visible:ring-0 focus-visible:ring-offset-0 shadow-none resize-none px-2 text-sm text-foreground placeholder:text-muted-foreground/50 rounded-none bg-transparent" 
                  placeholder="Write your message here..."
                />
              </div>
              <div className="flex items-center justify-between border-t border-border px-6 py-4 bg-muted/10">
                <Button variant="ghost" className="h-9 px-4 text-muted-foreground hover:text-foreground">
                  <X className="size-4 " />
                  Discard
                </Button>
                <div className="flex gap-2">
                  <DialogTrigger asChild>
                    <Button variant="outline" className="h-9 px-4">Save Draft</Button>
                  </DialogTrigger>
                  <Button className="h-9 px-5 bg-[#279596] hover:bg-[#207e7f] text-white tracking-tight font-medium shadow-sm transition-colors">
                    <Send className="size-4" />
                    Send
                  </Button>
                </div>
              </div>
            </div>
          </DialogContent>
        </Dialog>
      </SidebarHeader>
      <SidebarContent className="pt-2 px-2 md:px-0">
        <SearchForm />
        {sidebarData.navMain.map((item) => (
          <SidebarGroup key={item.title} className="px-2 md:px-0 border-b-[1.5px] border-border">
            <SidebarGroupLabel className="text-[15px] -ml-1.5 text-muted-foreground tracking-tight">{item.title}</SidebarGroupLabel>
            <SidebarGroupContent>
              <SidebarMenu>
                {item.items.map((subItem) => (
                  <SidebarMenuItem key={subItem.title}>
                    <SidebarMenuButton
                      asChild
                      isActive={currentView === subItem.title}
                      disabled={subItem.isDisabled}
                      className="h-10 text-[15px] text-muted-foreground/90 data-[active=true]:bg-accent data-[active=true]:text-teal-800 dark:data-[active=true]:text-teal-400 rounded-lg data-[active=true]:border-[1.5px] data-[active=true]:border-border tracking-tight hover:text-teal-800 dark:hover:text-teal-400 disabled:opacity-50 disabled:cursor-not-allowed pl-3"
                    >
                      <a
                        href={subItem.url}
                        onClick={(e) => {
                          if (subItem.isDisabled) {
                            e.preventDefault();
                            return;
                          }
                          if (onNavigate) {
                            e.preventDefault();
                            onNavigate(subItem.title);
                            return;
                          }
                        }}
                      >
                        {subItem.icon && (
                          <subItem.icon className="size-5" strokeWidth={2.5} />
                        )}
                        <span className="font-medium ">{subItem.title}</span>
                      </a>
                    </SidebarMenuButton>
                  </SidebarMenuItem>
                ))}
              </SidebarMenu>
            </SidebarGroupContent>
          </SidebarGroup>
        ))}
      </SidebarContent>
      <SidebarRail />
    </Sidebar>
  );
}
```

### `src/components/dashboards/invoice-generator-dashboard/components/mode-toggle.tsx`

```tsx
"use client";

import { Moon, Sun } from "lucide-react";
import { useTheme } from "next-themes";
import { Button } from "@/components/ui/button";

export function ModeToggle() {
    const { theme, setTheme } = useTheme();

    return (
        <Button
            variant="ghost"
            size="icon"
            className="size-9 rounded-lg border border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900 hover:bg-neutral-100 dark:hover:bg-neutral-800 transition-colors"
            onClick={() => setTheme(theme === "light" ? "dark" : "light")}
        >
            <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
            <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
            <span className="sr-only">Toggle theme</span>
        </Button>
    );
}
```

### `src/components/dashboards/invoice-generator-dashboard/components/search-form.tsx`

```tsx
import { Search } from "lucide-react"

import { Label } from "@/components/ui/label"
import {
  SidebarGroup,
  SidebarGroupContent,
  SidebarInput,
} from "@/components/ui/sidebar"

export function SearchForm({ ...props }: React.ComponentProps<"form">) {
  return (
    <form {...props}>
      <SidebarGroup className="py-0 px-0">
        <SidebarGroupContent className="relative ">
          <Label htmlFor="search" className="sr-only">
            Search
          </Label>
          <SidebarInput
            id="search"
            placeholder="Search Anything"
            className="pl-10 h-12 placeholder:text-muted-foreground text-foreground tracking-tight placeholder:text-[15px] bg-secondary/50 rounded-xl border-border focus-visible:ring-0!"
          />
          <Search className="pointer-events-none absolute top-1/2 left-3 size-5 -translate-y-1/2 opacity-50 select-none" />
        </SidebarGroupContent>
      </SidebarGroup>
    </form>
  )
}
```

### `src/components/dashboards/invoice-generator-dashboard/components/site-header.tsx`

```tsx
"use client";

import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
} from "@/components/ui/breadcrumb";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import { SidebarTrigger } from "@/components/ui/sidebar";
import { Eye, EyeOff, Save, Send } from "lucide-react";
import { ModeToggle } from "./mode-toggle";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";

export const SiteHeader = ({
  currentView,
  onTogglePreview,
  isPreviewHidden
}: {
  currentView?: string;
  onTogglePreview?: () => void;
  isPreviewHidden?: boolean;
}) => {
  return (
    <header className="flex h-16 shrink-0 items-center justify-between gap-2 border-b px-4">
      <div className="flex items-center gap-2">
        <SidebarTrigger className="-ml-1" />
        <Separator orientation="vertical" className="mr-2 h-4" />
        <Breadcrumb>
          <BreadcrumbList>
            <BreadcrumbItem className="hidden md:block">
              <BreadcrumbLink
                href="#"
                className="text-xl text-foreground font-semibold"
              >
                {currentView}
              </BreadcrumbLink>
            </BreadcrumbItem>
          </BreadcrumbList>
        </Breadcrumb>
      </div>
      <div className="flex items-center gap-2 py-5">
        <ModeToggle />
        <Button
          className="group h-9 rounded-lg text-muted-foreground tracking-tight border-border shadow-none bg-background hidden lg:flex transition-colors duration-300 hover:shadow-sm"
          variant="outline"
          onClick={onTogglePreview}
        >
          {isPreviewHidden ? (
            <>
              <Eye className="size-4 transition-transform duration-300 group-hover:scale-110" />
              Show preview
            </>
          ) : (
            <>
              <EyeOff className="size-4 transition-transform duration-300 group-hover:scale-110" />
              Hide preview
            </>
          )}
        </Button>
        <Popover>
          <PopoverTrigger asChild>
            <Button
              className="group h-9 rounded-lg text-muted-foreground tracking-tight border-border shadow-none bg-background hidden sm:flex transition-colors duration-300 hover:shadow-sm"
              variant="outline"
            >
              <Save className="size-4 transition-transform duration-300 group-hover:scale-110" />
              Save as Draft
            </Button>
          </PopoverTrigger>
          <PopoverContent className="w-56 p-4">
            <div className="flex flex-col gap-2">
              <h4 className="font-medium leading-none tracking-tight">Draft Saved</h4>
              <p className="text-sm text-muted-foreground">
                Your invoice has been saved as a draft locally.
              </p>
            </div>
          </PopoverContent>
        </Popover>

        <Dialog>
          <DialogTrigger asChild>
            <Button className="group h-9 rounded-lg px-3 sm:px-4 tracking-tight border-[1.5px] bg-neutral-900 text-white/90 font-medium text-sm shadow-[inset_0_4px_6px_rgba(255,255,255,0.4),inset_0_-4px_6px_rgba(255,255,255,0.2),inset_0_0_0_1px_rgba(255,255,255,0.1)] border-none dark:bg-neutral-800 hover:bg-neutral-800 dark:hover:bg-neutral-700 transition-colors duration-300 hover:shadow-lg">
              <Send className="size-4 transition-transform duration-300 group-hover:translate-x-0.5 group-hover:-translate-y-0.5" />
              <span className="hidden sm:inline">Send Invoice</span>
            </Button>
          </DialogTrigger>
          <DialogContent
            className="sm:max-w-[425px]"
            onOpenAutoFocus={(e) => e.preventDefault()}
          >
            <DialogHeader>
              <DialogTitle>Send Invoice</DialogTitle>
              <DialogDescription>
                Review the details below before sending this invoice to the client.
              </DialogDescription>
            </DialogHeader>
            <div className="grid gap-4 py-4">
              <div className="grid gap-2">
                <Label htmlFor="email">Client Email</Label>
                <Input id="email" defaultValue="client@email.com" />
              </div>
              <div className="grid gap-2">
                <Label htmlFor="subject">Subject Line</Label>
                <Input id="subject" defaultValue="Invoice INV-0001 from Your Company" />
              </div>
            </div>
            <div className="flex justify-end">
              <Button type="submit" className="bg-neutral-900 border-none dark:bg-neutral-800 hover:bg-neutral-800 dark:hover:bg-neutral-700 text-white">Confirm & Send</Button>
            </div>
          </DialogContent>
        </Dialog>
      </div>
    </header>
  );
};
```

### `src/components/dashboards/invoice-generator-dashboard/components/version-switcher.tsx`

```tsx
"use client"

import * as React from "react"
import { Check, ChevronsUpDown, GalleryVerticalEnd } from "lucide-react"

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
  SidebarMenu,
  SidebarMenuButton,
  SidebarMenuItem,
} from "@/components/ui/sidebar"

export function VersionSwitcher({
  versions,
  defaultVersion,
}: {
  versions: string[]
  defaultVersion: string
}) {
  const [selectedVersion, setSelectedVersion] = React.useState(defaultVersion)

  return (
    <SidebarMenu>
      <SidebarMenuItem>
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <SidebarMenuButton
              size="lg"
              className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
            >
              <div className="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg">
                <GalleryVerticalEnd className="size-4" />
              </div>
              <div className="flex flex-col gap-0.5 leading-none">
                <span className="font-medium">Documentation</span>
                <span className="">v{selectedVersion}</span>
              </div>
              <ChevronsUpDown className="ml-auto" />
            </SidebarMenuButton>
          </DropdownMenuTrigger>
          <DropdownMenuContent
            className="w-(--radix-dropdown-menu-trigger-width)"
            align="start"
          >
            {versions.map((version) => (
              <DropdownMenuItem
                key={version}
                onSelect={() => setSelectedVersion(version)}
              >
                v{version}{" "}
                {version === selectedVersion && <Check className="ml-auto" />}
              </DropdownMenuItem>
            ))}
          </DropdownMenuContent>
        </DropdownMenu>
      </SidebarMenuItem>
    </SidebarMenu>
  )
}
```

### `src/components/dashboards/invoice-generator-dashboard/dashboardLayout.tsx`

```tsx
import { AppSidebar } from "./components/app-sidebar";
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
import { SiteHeader } from "./components/site-header";

export const DashboardLayout = ({
  children,
  onNavigate,
  currentView,
  onTogglePreview,
  isPreviewHidden
}: {
  children: React.ReactNode;
  onNavigate?: (view: string) => void;
  currentView?: string;
  onTogglePreview?: () => void;
  isPreviewHidden?: boolean;
}) => {
  return (
    <SidebarProvider>
      <AppSidebar onNavigate={onNavigate} currentView={currentView} />
      <SidebarInset>
        <SiteHeader
          currentView={currentView}
          onTogglePreview={onTogglePreview}
          isPreviewHidden={isPreviewHidden}
        />
        <main className="flex-1">
          {children}
        </main>
      </SidebarInset>
    </SidebarProvider>
  );
};
```

### `src/components/dashboards/invoice-generator-dashboard/data.ts`

```ts
import {
  ReceiptText,
  Inbox,
  Star,
  Send,
  FileText,
  Calendar,
  Archive,
  AlertCircle,
  Trash,
  Tag,
} from "lucide-react";

export const initialInvoice = {
  invoiceNumber: "INV-0231",
  billedByName: "John Jacobs",
  billedByEmail: "hijacob@gmail.com",
  billedByAddress: "123 Maple Street, Springfield",
  billedToCompany: "Acme Corp.",
  billedToEmail: "hi@acmecorp.com",
  billedToAddress: "321 Apple Street, Autumfield",
  dateIssued: "Jul 28, 2025",
  dueDate: "Jul 31, 2025",
  items: [{ description: "Website Design", qty: 1, cost: 49.0, total: 49.0 }],
  currency: "USD",
};

export const sidebarData = {
  navMain: [
    {
      title: "General",
      items: [
        {
          title: "Invoice",
          icon: ReceiptText,
          url: "/invoice",
          isActive: true,
        },
        {
          title: "Inbox",
          icon: Inbox,
          url: "#",
          isDisabled: true,
        },
        {
          title: "Starred",
          icon: Star,
          url: "#",
          isDisabled: true,
        },
        {
          title: "Sent",
          icon: Send,
          url: "#",
          isDisabled: true,
        },
        {
          title: "Drafts",
          icon: FileText,
          url: "#",
          isDisabled: true,
        },
        {
          title: "Scheduled",
          icon: Calendar,
          url: "#",
          isDisabled: true,
        },
        {
          title: "Archive",
          icon: Archive,
          url: "#",
          isDisabled: true,
        },
        {
          title: "Spam",
          icon: AlertCircle,
          url: "#",
          isDisabled: true,
        },
        {
          title: "Trash",
          icon: Trash,
          url: "#",
          isDisabled: true,
        },
      ],
    },
    {
      title: "Labels",
      items: [
        {
          title: "Marketing",
          icon: Tag,
          url: "#",
          isDisabled: true,
        },
        {
          title: "Sales",
          icon: Tag,
          url: "#",
          isDisabled: true,
        },
      ],
    },
  ],
};
```

### `src/components/dashboards/invoice-generator-dashboard/demo.tsx`

```tsx
"use client";

import { useState } from "react";
import { DashboardLayout } from "./dashboardLayout";
import { InvoiceView } from "./invoicePageView";

export default function InvoiceGeneratorDashboardDemo() {
    const [currentView, setCurrentView] = useState("Invoice");
    const [isPreviewHidden, setIsPreviewHidden] = useState(false);

    const renderContent = () => {
        switch (currentView) {
            case "Invoice":
                return <InvoiceView isPreviewHidden={isPreviewHidden} />;
            default:
                return <InvoiceView isPreviewHidden={isPreviewHidden} />;
        }
    };

    return (
        <DashboardLayout
            onNavigate={setCurrentView}
            currentView={currentView}
            onTogglePreview={() => setIsPreviewHidden(!isPreviewHidden)}
            isPreviewHidden={isPreviewHidden}
        >
            {renderContent()}
        </DashboardLayout>
    );
}
```

### `src/components/dashboards/invoice-generator-dashboard/invoicePageView.tsx`

```tsx
"use client";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { cn } from "@/lib/utils";
import { useState } from "react";
import { initialInvoice } from "./data";

export const InvoiceView = ({ isPreviewHidden }: { isPreviewHidden?: boolean }) => {
  const [view, setView] = useState("form");
  const [invoice, setInvoice] = useState(initialInvoice);

  interface InvoiceItem {
    description: string;
    qty: number;
    cost: number;
    total: number;
  }

  interface Invoice {
    invoiceNumber: string;
    billedByName: string;
    billedByEmail: string;
    billedByAddress: string;
    billedToCompany: string;
    billedToEmail: string;
    billedToAddress: string;
    dateIssued: string;
    dueDate: string;
    items: InvoiceItem[];
    currency: string;
  }

  const handleInputChange = (field: keyof Invoice, value: string): void => {
    setInvoice((prev: Invoice) => ({
      ...prev,
      [field]: value,
    }));
  };

  const handleItemChange = (
    index: number,
    field: keyof InvoiceItem,
    value: string
  ): void => {
    const updatedItems = [...invoice.items];
    updatedItems[index] = {
      ...updatedItems[index],
      [field]: field === "description" ? value : parseFloat(value) || 0,
    };
    // Auto-calculate total
    if (field === "qty" || field === "cost") {
      updatedItems[index].total =
        updatedItems[index].qty * updatedItems[index].cost;
    }
    setInvoice((prev: Invoice) => ({
      ...prev,
      items: updatedItems,
    }));
  };

  const addItem = () => {
    setInvoice((prev) => ({
      ...prev,
      items: [...prev.items, { description: "", qty: 1, cost: 0, total: 0 }],
    }));
  };

  const subtotal = invoice.items.reduce((sum, item) => sum + item.total, 0);

  return (
    <div className="flex flex-col lg:h-[calc(100vh-4rem)] w-full px-2 py-4 lg:overflow-hidden">
      {/* View Switcher for Mobile/Tablet */}
      <div className="lg:hidden mb-4">
        <Select value={view} onValueChange={setView}>
          <SelectTrigger className="w-full h-10 bg-background dark:bg-card shadow-none font-medium border-border hover:border-neutral-300 dark:hover:border-neutral-700 transition-colors">
            <SelectValue placeholder="Select View" />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="form">Edit Invoice Form</SelectItem>
            <SelectItem value="preview">Live Invoice Preview</SelectItem>
          </SelectContent>
        </Select>
      </div>

      <div className="flex flex-col lg:flex-row gap-6 h-full w-full lg:overflow-hidden">
        {/* Left Side - Form */}
        <div
          className={cn(
            "p-4 border-[1.5px] rounded-lg lg:overflow-y-auto scrollbar-hide bg-card border-border",
            // On mobile (lg:hidden), if view isn't 'form', hide this. 
            // On desktop (lg:block), if isPreviewHidden is true, center and set width. Otherwise fill available space.
            view !== "form" && "hidden lg:block",
            view === "form" && "block lg:flex-1",
            isPreviewHidden ? "lg:w-[60%] lg:mx-auto lg:block" : "lg:flex-1"
          )}
        >
          <div className="space-y-6">
            {/* Header Section */}
            <div>
              <h3 className="font-semibold mb-3 text-foreground/90 tracking-tight">
                Invoice Number
              </h3>
              <Input
                value={invoice.invoiceNumber}
                onChange={(e) =>
                  handleInputChange("invoiceNumber", e.target.value)
                }
                placeholder="INV-0001"
                className="h-10 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none"
              />
            </div>


            {/* Client Details */}
            <div>
              <h3 className="font-semibold mb-3 text-foreground/90 tracking-tight">
                Billed By
              </h3>
              <div className="space-y-3 p-3 rounded-xl border border-border bg-background/30 px-4 py-4 hover:border-neutral-300 dark:hover:border-neutral-700 transition-colors duration-300 shadow-none">
                <div>
                  <label className="text-xs text-muted-foreground mb-1 block font-medium">
                    Name
                  </label>
                  <Input
                    value={invoice.billedByName}
                    onChange={(e) =>
                      handleInputChange("billedByName", e.target.value)
                    }
                    placeholder="Your Name"
                    className="h-9 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none text-foreground"
                  />
                </div>
                <div>
                  <label className="text-xs text-muted-foreground mb-1 block font-medium">
                    Email
                  </label>
                  <Input
                    value={invoice.billedByEmail}
                    onChange={(e) =>
                      handleInputChange("billedByEmail", e.target.value)
                    }
                    placeholder="email@email.com"
                    className="h-9 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none text-foreground"
                  />
                </div>
                <div>
                  <label className="text-xs text-muted-foreground mb-1 block font-medium">
                    Address
                  </label>
                  <Input
                    value={invoice.billedByAddress}
                    onChange={(e) =>
                      handleInputChange("billedByAddress", e.target.value)
                    }
                    placeholder="Street Address"
                    className="h-9 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none text-foreground"
                  />
                </div>
              </div>
            </div>

            {/* Billed To */}
            <div>
              <h3 className="font-semibold mb-3 text-foreground/90 tracking-tight">
                Billed To
              </h3>
              <div className="space-y-3 p-3 rounded-xl border border-border bg-background/30 px-4 py-4 hover:border-neutral-300 dark:hover:border-neutral-700 transition-colors duration-300 shadow-none">
                <div>
                  <label className="text-xs text-muted-foreground mb-1 block font-medium">
                    Company
                  </label>
                  <Input
                    value={invoice.billedToCompany}
                    onChange={(e) =>
                      handleInputChange("billedToCompany", e.target.value)
                    }
                    placeholder="Client Company"
                    className="h-9 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none text-foreground"
                  />
                </div>
                <div>
                  <label className="text-xs text-muted-foreground mb-1 block font-medium">
                    Email
                  </label>
                  <Input
                    value={invoice.billedToEmail}
                    onChange={(e) =>
                      handleInputChange("billedToEmail", e.target.value)
                    }
                    placeholder="client@email.com"
                    className="h-9 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none text-foreground"
                  />
                </div>
                <div>
                  <label className="text-xs text-muted-foreground mb-1 block font-medium">
                    Address
                  </label>
                  <Input
                    value={invoice.billedToAddress}
                    onChange={(e) =>
                      handleInputChange("billedToAddress", e.target.value)
                    }
                    placeholder="Street Address"
                    className="h-9 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none text-foreground"
                  />
                </div>
              </div>
            </div>

            {/* Dates */}
            <div>
              <h3 className="font-semibold mb-3 text-foreground/90 tracking-tight">
                Dates
              </h3>
              <div className="grid grid-cols-2 gap-3">
                <div className="bg-background/30 rounded-xl border border-border p-3 hover:border-neutral-300 dark:hover:border-neutral-700 transition-colors duration-300 shadow-none">
                  <label className="text-xs text-muted-foreground mb-1 block font-medium">
                    Date Issued
                  </label>
                  <Input
                    value={invoice.dateIssued}
                    onChange={(e) =>
                      handleInputChange("dateIssued", e.target.value)
                    }
                    placeholder="Date"
                    className="h-9 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none text-foreground"
                  />
                </div>
                <div className="bg-background/30 rounded-xl border border-border p-3 hover:border-neutral-300 dark:hover:border-neutral-700 transition-colors duration-300 shadow-none">
                  <label className="text-xs text-muted-foreground mb-1 block font-medium">
                    Due Date
                  </label>
                  <Input
                    value={invoice.dueDate}
                    onChange={(e) =>
                      handleInputChange("dueDate", e.target.value)
                    }
                    placeholder="Date"
                    className="h-9 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none text-foreground"
                  />
                </div>
              </div>
            </div>

            {/* Items */}
            <div>
              <h3 className="font-semibold mb-3 text-foreground/90 tracking-tight">
                Invoice Items
              </h3>
              <div className="space-y-3">
                {invoice.items.map((item, index) => (
                  <div key={index} className="border border-border bg-background/30 rounded-xl p-4 space-y-3 hover:border-neutral-300 dark:hover:border-neutral-700 transition-colors duration-300 shadow-none">
                    <div className="space-y-1">
                      <label className="text-xs text-muted-foreground block font-medium">Description</label>
                      <Input
                        value={item.description}
                        onChange={(e) =>
                          handleItemChange(index, "description", e.target.value)
                        }
                        placeholder="Item description"
                        className="h-9 text-sm focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none text-foreground"
                      />
                    </div>
                    <div className="grid grid-cols-3 gap-3">
                      <div>
                        <label className="text-xs text-muted-foreground mb-1 block font-medium">
                          Qty
                        </label>
                        <Input
                          type="number"
                          value={item.qty}
                          onChange={(e) =>
                            handleItemChange(index, "qty", e.target.value)
                          }
                          className="h-9 text-sm focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none text-foreground"
                        />
                      </div>
                      <div>
                        <label className="text-xs text-muted-foreground mb-1 block font-medium">
                          Cost
                        </label>
                        <Input
                          type="number"
                          value={item.cost}
                          onChange={(e) =>
                            handleItemChange(index, "cost", e.target.value)
                          }
                          className="h-9 text-sm focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none text-foreground"
                        />
                      </div>
                      <div>
                        <label className="text-xs text-muted-foreground mb-1 block font-medium">
                          Total
                        </label>
                        <Input
                          type="number"
                          value={item.total.toFixed(2)}
                          readOnly
                          className="h-9 text-sm bg-muted/50 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-neutral-400 dark:focus-visible:border-neutral-600 outline-none shadow-none text-foreground"
                        />
                      </div>
                    </div>
                  </div>
                ))}
                <Button
                  onClick={addItem}
                  variant="outline"
                  className="w-full h-10 text-sm rounded-xl border-dashed border-[1.5px] border-border bg-background/50 hover:bg-muted/50 hover:border-neutral-300 dark:hover:border-neutral-700 hover:shadow-sm transition-colors duration-300 cursor-pointer"
                >
                  + Add Item
                </Button>
              </div>
            </div>
          </div>
        </div>

        <div
          className={cn(
            "h-fit lg:h-full bg-muted/50 dark:bg-neutral-950/40 rounded-xl border-[1.5px] border-border lg:overflow-y-auto custom-scrollbar",
            // Mobile toggle logic
            view !== "preview" && "hidden lg:block",
            // Desktop hide logic
            isPreviewHidden ? "lg:hidden" : "lg:flex-1"
          )}
        >
          <div className="w-full min-h-full h-fit flex justify-center p-4 sm:p-8 lg:p-10">
            <div
              className="relative bg-white dark:bg-neutral-900 rounded-lg p-6 lg:p-10 border-[1.5px] border-border w-full lg:max-w-4xl h-fit shadow-2xl shadow-neutral-200/50 dark:shadow-neutral-950/50 flex flex-col justify-between lg:origin-top lg:scale-[0.95] 2xl:scale-100 transform transition-transform duration-300"
              style={{
                clipPath:
                  "polygon(0 0, calc(100% - 40px) 0, 100% 40px, 100% 100%, 0 100%)",
              }}
            >
              <div
                className="absolute top-0 right-0 w-[40px] h-[40px] rounded-bl-xl bg-neutral-50 dark:bg-neutral-800 border-border border-l-[1.5px] border-b-[1.5px]"
              ></div>
              <div>
                <div className="mb-6 sm:mb-8">
                  <h1 className="text-2xl lg:text-4xl font-semibold text-foreground mb-1 tracking-tight">
                    Invoice
                  </h1>
                  <div className="grid grid-cols-2 gap-4 sm:gap-8 my-4 font-semibold">
                    <span className="text-muted-foreground tracking-tight text-xs lg:text-sm">
                      Invoice Number
                    </span>
                    <span className="text-xs lg:text-sm font-bold text-foreground">
                      {invoice.invoiceNumber}
                    </span>
                  </div>
                </div>

                <div className="grid grid-cols-2 gap-4 sm:gap-8 mb-6 sm:mb-8">
                  <div>
                    <h3 className="text-xs lg:text-sm font-semibold text-muted-foreground mb-2 sm:mb-3">
                      Billed by:
                    </h3>
                    <div className="text-[10px] lg:text-sm leading-relaxed">
                      <p className="font-semibold text-foreground">
                        {invoice.billedByName}
                      </p>
                      <p className="text-muted-foreground">{invoice.billedByEmail}</p>
                      <p className="text-muted-foreground">
                        {invoice.billedByAddress}
                      </p>
                    </div>
                  </div>
                  <div>
                    <h3 className="text-xs lg:text-sm font-semibold text-muted-foreground mb-2 sm:mb-3">
                      Billed to:
                    </h3>
                    <div className="text-[10px] lg:text-sm leading-relaxed">
                      <p className="font-semibold text-foreground">
                        {invoice.billedToCompany}
                      </p>
                      <p className="text-muted-foreground">{invoice.billedToEmail}</p>
                      <p className="text-muted-foreground">
                        {invoice.billedToAddress}
                      </p>
                    </div>
                  </div>
                </div>

                <div className="grid grid-cols-2 gap-4 sm:gap-8 mb-6 sm:mb-8">
                  <div>
                    <h3 className="text-xs lg:text-sm font-semibold text-muted-foreground mb-1 sm:mb-2">
                      Date Issued:
                    </h3>
                    <p className="text-foreground font-medium text-[10px] lg:text-sm">
                      {invoice.dateIssued}
                    </p>
                  </div>
                  <div>
                    <h3 className="text-xs lg:text-sm font-semibold text-muted-foreground mb-1 sm:mb-2">
                      Due Date:
                    </h3>
                    <p className="text-foreground font-medium text-[10px] lg:text-sm">
                      {invoice.dueDate}
                    </p>
                  </div>
                </div>

                {/* Items Table */}
                <div className="mb-6 sm:mb-8">
                  <table className="w-full">
                    <thead>
                      <tr className="border-b border-border">
                        <th className="text-left text-[10px] lg:text-sm font-semibold text-muted-foreground pb-2">
                          Item
                        </th>
                        <th className="text-center text-[10px] lg:text-sm font-semibold text-muted-foreground pb-2">
                          QTY
                        </th>
                        <th className="text-right text-[10px] lg:text-sm font-semibold text-muted-foreground pb-2">
                          Cost
                        </th>
                        <th className="text-right text-[10px] lg:text-sm font-semibold text-muted-foreground pb-2">
                          Total
                        </th>
                      </tr>
                    </thead>
                    <tbody>
                      {invoice.items.map((item, index) => (
                        <tr key={index} className="border-b border-border/50 hover:bg-muted/30 transition-colors">
                          <td className="py-2 sm:py-3 text-[10px] lg:text-sm text-muted-foreground font-medium">
                            {item.description}
                          </td>
                          <td className="py-2 sm:py-3 text-[10px] lg:text-sm text-center text-muted-foreground font-medium">
                            {item.qty}
                          </td>
                          <td className="py-2 sm:py-3 text-[10px] lg:text-sm text-right text-muted-foreground font-medium">
                            ${item.cost.toFixed(2)}
                          </td>
                          <td className="py-2 sm:py-3 text-[10px] lg:text-sm text-right text-muted-foreground font-medium">
                            ${item.total.toFixed(2)}
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              </div>

              {/* Summary */}
              <div className="flex justify-end mt-auto">
                <div className="w-48 lg:w-64">
                  <div className="flex justify-between py-2 border-b-2 border-border">
                    <span className="text-[10px] lg:text-sm text-muted-foreground">Subtotal</span>
                    <span className="text-[10px] lg:text-sm text-foreground font-medium">
                      ${subtotal.toFixed(2)}
                    </span>
                  </div>
                  <div className="flex justify-between py-2 sm:py-3">
                    <span className="text-xs lg:text-base font-semibold text-foreground">Total</span>
                    <span className="text-xs lg:text-base font-semibold text-foreground">
                      ${subtotal.toFixed(2)}
                    </span>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
```
