feat(frontend): RemitDrawer component with CAS adjustments + parties + claim payments

This commit is contained in:
Tyler
2026-06-20 17:16:23 -06:00
parent 4cd52c3084
commit 25d47a5621
21 changed files with 2899 additions and 0 deletions
@@ -0,0 +1,148 @@
import { fmt } from "@/lib/format";
import type { RemitDetail } from "@/hooks/useRemitDetail";
type FinancialSummaryCardProps = {
remit: RemitDetail;
};
/**
* Single label/value row used inside the financial summary card.
* `mono` opts the value into the project's mono numeric treatment
* (font-mono + tabular-nums + slightly heavier weight) so currency
* figures line up vertically across rows.
*/
function SummaryRow({
testId,
label,
value,
mono = false,
}: {
testId: string;
label: string;
value: React.ReactNode;
mono?: boolean;
}) {
return (
<div
data-testid={testId}
className="flex items-baseline justify-between gap-3 py-2"
>
<span className="text-[11px] font-medium uppercase tracking-[0.14em] text-[color:var(--m-ink-tertiary)]">
{label}
</span>
<span
className={
mono
? "font-mono text-base tabular-nums text-[color:var(--m-ink-primary)]"
: "text-sm text-[color:var(--m-ink-primary)]"
}
style={mono ? { fontFamily: "var(--m-font-mono)" } : undefined}
>
{value}
</span>
</div>
);
}
/**
* Optional value renderer: returns `—` for null/undefined/empty so the
* card never prints "null" or "undefined" in the UI.
*/
function opt(v: string | number | null | undefined, format?: (s: string) => string): React.ReactNode {
if (v === null || v === undefined) return "—";
if (typeof v === "string" && v.trim() === "") return "—";
if (typeof v === "number" && !Number.isFinite(v)) return "—";
return format ? format(String(v)) : v;
}
/**
* Financial summary card for the remittance detail drawer.
*
* Surfaces the headline money figures (paid amount + adjustment amount)
* plus the supporting payment identifiers (method, date, check/trace
* number). Headline amounts are stacked at the top so the eye lands on
* the totals first, then scans the supporting rows below.
*
* All fields gracefully degrade to "—" when absent — the detail
* endpoint doesn't yet populate `paymentMethod`, `paymentDate`, or
* `checkNumber` for every remit, and we'd rather show an em-dash than
* "undefined".
*/
export function FinancialSummaryCard({ remit }: FinancialSummaryCardProps) {
const hasAdjustment = Math.abs(remit.adjustmentAmount) > 0;
return (
<section
className="flex flex-col gap-3 px-6 py-4"
data-testid="financial-summary"
>
<h3
data-testid="section-label"
className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-[color:var(--m-ink-tertiary)]"
>
Financial Summary
</h3>
<div
data-testid="financial-summary-inner"
className="flex flex-col gap-4 rounded-lg border border-[color:var(--m-border-heavy)]/15 bg-[color:var(--m-surface)] p-4"
>
{/* Headline totals — big mono digits, side by side */}
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div
data-testid="summary-paid"
className="flex flex-col gap-1 rounded-md bg-[color:var(--m-surface)]/40 px-3 py-2"
>
<span className="text-[10px] font-medium uppercase tracking-[0.14em] text-[color:var(--m-ink-tertiary)]">
Paid amount
</span>
<span
className="font-mono text-2xl font-semibold tabular-nums text-[color:var(--m-ink-primary)]"
style={{ fontFamily: "var(--m-font-mono)" }}
>
{fmt.usdPrecise(remit.paidAmount)}
</span>
</div>
<div
data-testid="summary-adjustment"
className="flex flex-col gap-1 rounded-md bg-[color:var(--m-surface)]/40 px-3 py-2"
>
<span className="text-[10px] font-medium uppercase tracking-[0.14em] text-[color:var(--m-ink-tertiary)]">
Adjustment amount
</span>
<span
className={
hasAdjustment
? "font-mono text-2xl font-semibold tabular-nums text-[color:var(--m-ink-primary)]"
: "font-mono text-2xl tabular-nums text-[color:var(--m-ink-tertiary)]"
}
style={{ fontFamily: "var(--m-font-mono)" }}
>
{hasAdjustment ? fmt.usdPrecise(remit.adjustmentAmount) : "—"}
</span>
</div>
</div>
{/* Supporting rows: method, payment date, check / trace number */}
<div className="flex flex-col divide-y divide-[color:var(--m-border-heavy)]/10">
<SummaryRow
testId="summary-method"
label="Payment method"
value={opt(remit.paymentMethod)}
/>
<SummaryRow
testId="summary-payment-date"
label="Payment date"
value={opt(remit.paymentDate, fmt.date)}
/>
<SummaryRow
testId="summary-check-number"
label="Check / trace number"
value={opt(remit.checkNumber)}
mono
/>
</div>
</div>
</section>
);
}