diff --git a/src/components/settlement/SettlementReceipt.test.tsx b/src/components/settlement/SettlementReceipt.test.tsx new file mode 100644 index 00000000..d1f6c92f --- /dev/null +++ b/src/components/settlement/SettlementReceipt.test.tsx @@ -0,0 +1,32 @@ +/** @vitest-environment happy-dom */ + +import { describe, expect, it, vi } from 'vitest'; +import { fireEvent, render, screen } from '@testing-library/react'; +import { buildReceiptFilename, SettlementReceipt } from './SettlementReceipt'; + +const data = { + commitmentId: 'commitment/1', + finalValue: '$100', + fees: '$2', + transactionHash: '0xabc', + settledAt: '2026-07-30T10:00:00.000Z', +}; + +describe('SettlementReceipt', () => { + it('sanitizes the printable filename', () => { + expect(buildReceiptFilename(data.commitmentId, data.settledAt)).toBe( + 'settlement-receipt-commitment-1-2026-07-30', + ); + }); + + it('renders only after success and prints from the accessible action', () => { + const print = vi.spyOn(window, 'print').mockImplementation(() => undefined); + const { rerender } = render(); + expect(screen.queryByRole('region', { name: 'Settlement receipt' })).not.toBeInTheDocument(); + + rerender(); + fireEvent.click(screen.getByRole('button', { name: 'Download receipt' })); + expect(print).toHaveBeenCalledOnce(); + print.mockRestore(); + }); +}); diff --git a/src/components/settlement/SettlementReceipt.tsx b/src/components/settlement/SettlementReceipt.tsx new file mode 100644 index 00000000..a94c4286 --- /dev/null +++ b/src/components/settlement/SettlementReceipt.tsx @@ -0,0 +1,54 @@ +'use client'; + +export interface SettlementReceiptData { + commitmentId: string; + finalValue: string; + fees: string; + transactionHash: string; + settledAt: string; +} + +export function buildReceiptFilename(commitmentId: string, settledAt: string): string { + const safeId = commitmentId.replace(/[^a-z0-9_-]/gi, '-').slice(0, 80) || 'commitment'; + const date = new Date(settledAt).toISOString().slice(0, 10); + return `settlement-receipt-${safeId}-${date}`; +} + +export function printSettlementReceipt(data: SettlementReceiptData): void { + const previousTitle = document.title; + document.title = buildReceiptFilename(data.commitmentId, data.settledAt); + window.print(); + window.setTimeout(() => { + document.title = previousTitle; + }, 0); +} + +export function SettlementReceipt({ + status, + data, +}: { + status: 'pending' | 'success'; + data: SettlementReceiptData; +}) { + if (status !== 'success') return null; + + return ( +
+

Settlement receipt

+
+
Commitment
{data.commitmentId}
+
Final value
{data.finalValue}
+
Fees / penalty
{data.fees}
+
Transaction
{data.transactionHash}
+
Settled
{data.settledAt}
+
+ +
+ ); +}