@@ -151,7 +191,7 @@ export default function PaymentExport({ invoiceId, payments }: Props) {
)}
{/* Column Selection */}
- {payments.length > 0 && (
+ {payments.length > 0 && exportFormat === 'csv' && (
Columns to include
@@ -183,7 +223,9 @@ export default function PaymentExport({ invoiceId, payments }: Props) {
{/* Export Info */}
{payments.length > 0 && !showFilters && (
- CSV will include payer address, amount (USDC), timestamp, and transaction hash for all payments.
+ {exportFormat === 'pdf'
+ ? 'PDF will include the invoice number, payer addresses, amounts, timestamps, and transaction hashes.'
+ : 'CSV will include payer address, amount (USDC), timestamp, and transaction hash for all payments.'}
)}
diff --git a/src/lib/paymentExportPdf.ts b/src/lib/paymentExportPdf.ts
new file mode 100644
index 00000000..5a81def9
--- /dev/null
+++ b/src/lib/paymentExportPdf.ts
@@ -0,0 +1,143 @@
+/**
+ * paymentExportPdf.ts — Renders a printable PDF payment summary.
+ *
+ * Follows the same "print to PDF" flow used by `ReceiptPDF` / `InvoicePDF`:
+ * the summary is rendered as a self-contained HTML document in a new window
+ * and the browser's print dialog produces the PDF. Colour tokens come from
+ * `src/lib/pdfTheme.ts` so the export stays consistent with the rest of the
+ * PDF pipeline.
+ */
+
+import type { Payment } from "@stellar-split/sdk";
+import { formatAmount } from "@stellar-split/sdk";
+import { getPdfTheme } from "@/lib/pdfTheme";
+
+type PaymentWithMeta = Payment & { timestamp?: number; txHash?: string };
+
+/** Escape untrusted text before interpolating it into the HTML document. */
+function escapeHtml(value: string): string {
+ return value
+ .replace(/&/g, "&")
+ .replace(//g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'");
+}
+
+/** Format a payment timestamp (seconds or milliseconds) as an ISO-8601 date. */
+function formatTimestamp(timestamp: number | undefined): string {
+ if (!timestamp) return "";
+ const ms = timestamp < 10000000000 ? timestamp * 1000 : timestamp;
+ return new Date(ms).toISOString();
+}
+
+/** Sum payment amounts when the SDK exposes them as bigints. */
+function sumAmounts(payments: PaymentWithMeta[]): bigint {
+ return payments.reduce
((sum, payment) => {
+ return sum + (typeof payment.amount === "bigint" ? payment.amount : 0n);
+ }, 0n);
+}
+
+/**
+ * Build a printable payment-summary HTML document for an invoice.
+ * Includes the invoice number, per-payment amounts, payer addresses and
+ * transaction hashes, plus a totals row.
+ */
+export function buildPaymentSummaryHtml(
+ invoiceId: string,
+ payments: PaymentWithMeta[],
+ preferDark = false,
+): string {
+ const theme = getPdfTheme(preferDark);
+ const total = sumAmounts(payments);
+
+ const rows = payments
+ .map((payment) => {
+ const hash = payment.txHash ? escapeHtml(payment.txHash) : "—";
+ return `
+ | ${escapeHtml(payment.payer)} |
+ ${escapeHtml(formatAmount(payment.amount))} USDC |
+ ${escapeHtml(formatTimestamp(payment.timestamp)) || "—"} |
+ ${hash} |
+
`;
+ })
+ .join("\n");
+
+ const totalRow =
+ total > 0n
+ ? `
+ | Total (${payments.length} payment${payments.length === 1 ? "" : "s"}) |
+ ${escapeHtml(formatAmount(total))} USDC |
+
`
+ : "";
+
+ const emptyRow = ` | No payments to export. |
`;
+
+ return `
+
+
+
+ StellarSplit Payment Summary — Invoice ${escapeHtml(invoiceId)}
+
+
+
+ ✦ StellarSplit
+ Payment Summary — Invoice #${escapeHtml(invoiceId)}
+
+
+
+ | Recipient Address |
+ Amount |
+ Timestamp |
+ Transaction Hash |
+
+
+
+${payments.length > 0 ? rows : emptyRow}
+${totalRow}
+
+
+
+