Files
beenvoice/src/lib/currency.ts
T
Claude e6b79ce2c2 Add bulk actions, multi-currency, expenses, templates, and reports
Schema (migration 0001):
- clients: add currency column (default USD)
- invoices: add currency column (default USD)
- New expenses table: amount, currency, category, billable, reimbursable,
  client/invoice/business relations, notes
- New invoice_templates table: name, type (notes|terms), content, isDefault

API:
- invoices: add bulkUpdateStatus and bulkDelete procedures (ownership-safe)
- invoices: currency field threaded through create/update schemas
- clients: currency field added to create/update schemas
- New expenses router: full CRUD with authorization
- New invoiceTemplates router: full CRUD, isDefault management per type
- Root router: wire in expenses and invoiceTemplates

Currency (src/lib/currency.ts):
- Shared formatCurrency(amount, currency) utility replacing hardcoded USD
- SUPPORTED_CURRENCIES list (17 currencies)
- Invoice form: currency selector in Config card, auto-fills from client
- Client form: currency selector in Billing Information card

Bulk actions (invoices list):
- Checkbox column with select-all support
- Selection toolbar: Mark as Sent/Paid/Draft dropdown, Delete (N) button
- DataTable: new selectionActions prop renders toolbar when rows selected

Notes templates:
- Invoice form: Notes card with textarea in Details tab
- Template dropdown button appears when templates exist
- /dashboard/invoices/templates: full CRUD page for notes and terms templates

New pages:
- /dashboard/expenses: expense list with summary cards, add/edit dialog
- /dashboard/reports: KPI cards, 12-month revenue area chart, top clients
  bar chart, status breakdown, recent activity
- Navigation: Expenses and Reports added to Main section

https://claude.ai/code/session_012sqEgNQpx676isepeoX4Mi
2026-04-05 02:34:06 +00:00

31 lines
1.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export const SUPPORTED_CURRENCIES = [
{ code: "USD", label: "USD US Dollar" },
{ code: "EUR", label: "EUR Euro" },
{ code: "GBP", label: "GBP British Pound" },
{ code: "CAD", label: "CAD Canadian Dollar" },
{ code: "AUD", label: "AUD Australian Dollar" },
{ code: "NZD", label: "NZD New Zealand Dollar" },
{ code: "CHF", label: "CHF Swiss Franc" },
{ code: "JPY", label: "JPY Japanese Yen" },
{ code: "SGD", label: "SGD Singapore Dollar" },
{ code: "HKD", label: "HKD Hong Kong Dollar" },
{ code: "SEK", label: "SEK Swedish Krona" },
{ code: "NOK", label: "NOK Norwegian Krone" },
{ code: "DKK", label: "DKK Danish Krone" },
{ code: "MXN", label: "MXN Mexican Peso" },
{ code: "BRL", label: "BRL Brazilian Real" },
{ code: "INR", label: "INR Indian Rupee" },
{ code: "ZAR", label: "ZAR South African Rand" },
] as const;
export type CurrencyCode = (typeof SUPPORTED_CURRENCIES)[number]["code"];
export function formatCurrency(amount: number, currency = "USD"): string {
return new Intl.NumberFormat("en-US", {
style: "currency",
currency,
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(amount);
}