import { fmt } from "@/lib/format"; import type { ClaimDetail } from "@/types"; type StateHistoryTimelineProps = { history: ClaimDetail["stateHistory"]; }; /** * Event-kind → dot background color. The dot is the only colored element * per row; the rest of the row uses the standard ink tokens so the * timeline reads as a calm list of facts, with the dot color doing the * signal work. * * claim_submitted → ink-secondary (neutral, in-flight) * claim_accepted → success (payer accepted) * claim_paid → success (funds received) * claim_denied → error (needs attention) * manual_match → warning (operator action) * manual_unmatch → warning (operator action) * remit_received → accent (ERA arrived) * anything else → muted (forward-compat with new kinds) */ const DOT_BG: Record = { claim_submitted: "bg-[color:var(--m-ink-secondary)]", claim_accepted: "bg-[color:var(--m-success)]", claim_paid: "bg-[color:var(--m-success)]", claim_denied: "bg-[color:var(--m-error)]", manual_match: "bg-[color:var(--m-warning)]", manual_unmatch: "bg-[color:var(--m-warning)]", remit_received: "bg-[color:var(--m-accent)]", }; function dotColorFor(kind: string): string { return DOT_BG[kind] ?? "bg-[color:var(--m-ink-tertiary)]"; } /** * Display label for the event kind. The raw kind is a snake-case machine * value (e.g. ``claim_paid``); replacing underscores with spaces gives a * friendlier visual label without losing the original token (it's still * on the ``
  • `` attribute for tests/inspection). The * CSS ``uppercase`` transform handles visual casing. */ function kindLabel(kind: string): string { return kind.replace(/_/g, " "); } /** * State-history timeline for the claim detail drawer (SP4). * * Vertical timeline: a 2px left rule on the outer
      with a colored * dot on each
    1. centered on the rule (negative offset). Events * render in input order — the backend already returns them * most-recent-first per the type comment, so the visual order matches * the audit order without resorting. Each row shows the kind eyebrow, * a mono ts (date + time), and an optional remittance id underneath * when the event was triggered by an ERA. */ export function StateHistoryTimeline({ history }: StateHistoryTimelineProps) { return (

      State History ({history.length})

      {history.length === 0 ? (

      No history events

      ) : (
        {history.map((event, i) => (
      1. {kindLabel(event.kind)} {fmt.date(event.ts)} · {fmt.time(event.ts)}
        {event.remittanceId ? ( ↳ Remit {event.remittanceId} ) : null}
      2. ))}
      )}
      ); }