add the invoices ui over the invoiceshelf sidecar

a /invoices workspace screen replicating the parts of the invoiceshelf web ui
that are actually used: dashboard, invoices, estimates, recurring invoices,
payments, expenses, customers, items and reports.

one document editor serves invoices, estimates and recurring invoices — they
share the line-item table, the discounts, the taxes and the totals, and differ
only in a header strip. the arithmetic is a port of upstream's
use-document-calculations, rounding points included, because the server
re-validates the totals it is sent. money is integer minor units throughout and
is converted to major units at the edges only.

selection and editor state live in the url (`/invoices/:section`, `?selected=`,
`?edit=`), so the nav highlight is derived rather than held, back closes an
editor instead of leaving the screen, and a half-written form survives a reload.

sending a document is behind an explicit confirmation — it emails the customer.

built against the running 2.4.2 instance rather than the 3.0 checkout in
_references; the two differ materially. typechecked, not yet exercised in a
browser.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-31 06:44:02 +00:00
co-authored by Claude Opus 5
parent b6dc73915d
commit 5ee56e736b
32 changed files with 6365 additions and 0 deletions
@@ -136,6 +136,7 @@ import {
Radio,
Network,
ArrowDownUp,
Receipt,
} from 'lucide-react';
export const ALL_DOCK_ITEMS: DockItem[] = [
@@ -147,6 +148,7 @@ export const ALL_DOCK_ITEMS: DockItem[] = [
{ label: 'Soulseek', to: '/soulseek', image: '/slskd.png', color: '#ffffff' },
{ label: 'Headscale', to: '/headscale', icon: Network, color: '#818cf8' },
{ label: 'Transmission', to: '/transmission', icon: ArrowDownUp, color: '#e11d48' },
{ label: 'Invoices', to: '/invoices', icon: Receipt, color: '#0891b2' },
{ label: 'Editor', to: '/code-editor', icon: Code, color: '#a78bfa' },
{ label: 'Plans', to: '/plans', icon: FileText, color: '#f472b6' },
{ label: 'Jobs', to: '/jobs', icon: Workflow, color: '#14b8a6' },