diff --git a/apps/web/app/(dashboard)/billing/new/page.tsx b/apps/web/app/(dashboard)/billing/new/page.tsx index c583c3e..2c67fb9 100644 --- a/apps/web/app/(dashboard)/billing/new/page.tsx +++ b/apps/web/app/(dashboard)/billing/new/page.tsx @@ -7,6 +7,7 @@ import { trpc } from "@/lib/trpc"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { toast } from "sonner"; +import { formatCurrency } from "@/lib/locale/format"; interface LineItem { id: string; @@ -62,6 +63,7 @@ export default function NewInvoicePage() { ); const servicesQuery = trpc.billing.listServices.useQuery(); + const taxConfigQuery = trpc.billing.getTaxConfig.useQuery(); // Mutation const utils = trpc.useUtils(); @@ -76,19 +78,26 @@ export default function NewInvoicePage() { }, }); - // Calculations + // Calculations — preview only; the server recomputes tax authoritatively + // from the practice's configured (region-aware) rate. + const taxPercent = taxConfigQuery.data?.taxRatePercent ?? "8.00"; + const taxRate = parseFloat(taxPercent) / 100; + const currency = taxConfigQuery.data?.currency ?? "usd"; + const country = taxConfigQuery.data?.country ?? "US"; + const fmt = (v: number | string | null | undefined) => + formatCurrency(v, currency, country); const { subtotal, tax, total } = useMemo(() => { const sub = items.reduce( (sum, item) => sum + item.quantity * parseFloat(item.unitPrice || "0"), 0 ); - const t = Math.round(sub * 0.08 * 100) / 100; + const t = Math.round(sub * taxRate * 100) / 100; return { subtotal: sub, tax: t, total: Math.round((sub + t) * 100) / 100, }; - }, [items]); + }, [items, taxRate]); function handleServiceSelect(serviceId: string) { setSelectedServiceId(serviceId); @@ -355,13 +364,10 @@ export default function NewInvoicePage() { {item.quantity} - ${parseFloat(item.unitPrice).toFixed(2)} + {fmt(item.unitPrice)} - $ - {( - item.quantity * parseFloat(item.unitPrice) - ).toFixed(2)} + {fmt(item.quantity * parseFloat(item.unitPrice))}