import * as React from "react" interface InvoiceAddress { name: string address: string[] phone: string email: string } interface InvoicePaymentRow { label: string amount: number } interface InvoicePayment { subtotal: number /** * Empty when the plan is not split into installments. * If populated, split-payment rows will be shown. */ payments: InvoicePaymentRow[] totalPaid: number balanceDue: number } interface GymInvoiceProps { invoiceNo: string invoiceDate: string dueDate: string /** Retained for API compatibility; the invoice no longer renders a logo. */ logoSrc?: string logoAlt?: string from: InvoiceAddress billTo: InvoiceAddress plan: { gymPlanName: string type: string memberName: string validityPeriod: string } payment: InvoicePayment paymentMethod: string preparedBy: string notes: string[] footerItems: string[] className?: string formatAmount: (amount: number) => string /** * This ref now captures the full A4 invoice page. * The PDF download uses this exact node. */ bodyRef?: React.Ref /** * Kept for compatibility with existing caller. * The footer is still inside the same invoice page. */ footerRef?: React.Ref } function GymInvoice({ invoiceNo, invoiceDate, dueDate, from, billTo, plan, payment, paymentMethod, preparedBy, notes, footerItems, formatAmount, bodyRef, footerRef, className = "", }: GymInvoiceProps) { return (
{/* Header */}

Invoice

{/* Invoice meta */}
{/* From / Bill To */}
{/* Membership / Service Details */}
Gym Plan Name Type Name of Member(s) Expiry Date / Validity Period
{plan.gymPlanName} {plan.type} {plan.memberName} {plan.validityPeriod}
{/* Notes / Terms + Payment Summary */}
{notes.map((note, i) => (

{note}

))}
{/* Payment Method / Prepared By */}

{paymentMethod || "-"}

{preparedBy || "-"}

{/* Footer stays inside the same one-page A4 receipt */}
{footerItems.map((item, i) => ( {i > 0 && |} {item} ))}
) } function Divider({ className = "" }: { className?: string }) { return (
) } function MetaRow({ label, value }: { label: string; value: string }) { return (
{label} :

{value}

) } function SectionTitle({ title }: { title: string }) { return (

{title}

) } function InfoBlock({ title, data }: { title: string; data: InvoiceAddress }) { return (

{data.name}

{data.address.map((line, i) => (

{line}

))}

{data.phone}

{data.email}

) } function TableHeadCell({ children }: { children: React.ReactNode }) { return (
{children}
) } function TableCell({ children }: { children: React.ReactNode }) { return (
{children}
) } function PaymentSummary({ payment, formatAmount, }: { payment: InvoicePayment formatAmount: (amount: number) => string }) { const hasBreakdown = payment.payments.length > 0 return (
{hasBreakdown ? ( <> {payment.payments.map((row, i) => ( ))} ) : ( )}
) } function SummaryRow({ label, amount, highlight = false, }: { label: string amount: string highlight?: boolean }) { return (
{label} {amount}
) } export { GymInvoice } export type { GymInvoiceProps, InvoiceAddress, InvoicePayment, InvoicePaymentRow, }