// src/pages/DashboardPage/BillingPage/PrintableInvoice.tsx // The formal, print-only rendering of one invoice (letterhead + meta + bill-to + line table + totals), // assembled by invoicePrintModel and revealed only under @media print (see index.css.printable-invoice). // Kept plain semantic HTML (a real for the lines) so the browser's print output is clean and // black-on-white. The org logo resolves through usePhotoUrl (org thumbnails are base64, so synchronous). import { createPortal } from 'react-dom'; import type { Invoice } from 'fhir/r4'; import { useAuthServiceContext } from '../../../services'; import { usePhotoUrl } from '../../../hooks/usePhotoUrl'; import { buildInvoicePrintModel, type InvoiceLedger } from './invoicePrintModel'; /** `ledger` is the payment ledger read for THIS invoice; without one the bill says payments are not shown. */ const PrintableInvoice = ({ invoice, ledger }: { invoice: Invoice; ledger?: InvoiceLedger }) => { const { currentOrganization } = useAuthServiceContext(); const model = buildInvoicePrintModel(invoice, currentOrganization, ledger); const { url: logoUrl } = usePhotoUrl(model.logo, 'organization'); const showLogo = Boolean(model.logo); // Portal to so the absolute-positioned print block isn't anchored inside the Radix dialog's // transformed container (which would offset it on the printed page). The print CSS is intentionally // unscoped (.printable-invoice), so it applies here just the same. return createPortal(
{model.lines.map((line, i) => ( ))}
DescriptionQtyUnitAmount
{line.description} {line.quantity} {line.unitPrice} {line.amount}
{model.tax !== undefined && ( <>
Subtotal{model.subtotal}
Tax{model.tax}
)}
Total{model.total}
{/* What was paid, from the ledger, never from the status; an unread ledger says so. */}
Payments
{model.ledger.kind === 'unread' ? (

{model.ledger.note}

) : ( <> {model.ledger.rows.length ? ( {model.ledger.rows.map((row, i) => ( ))}
Paid onAmount
{row.date}{row.amount}
) : (

No payments recorded.

)}
Total paid{model.ledger.paid}
Balance due{model.ledger.balance}
)}
, document.body, ); }; export default PrintableInvoice;