feat(sp6): InboxHeader + CandidateBreakdown

This commit is contained in:
Tyler
2026-06-20 18:41:07 -06:00
parent 5f3339ac1f
commit 610e580844
4 changed files with 143 additions and 0 deletions
@@ -0,0 +1,23 @@
// @vitest-environment happy-dom
import { afterEach, describe, expect, it } from "vitest";
import { cleanup, render } from "@testing-library/react";
import { CandidateBreakdown } from "./CandidateBreakdown";
afterEach(() => cleanup());
describe("CandidateBreakdown", () => {
it("renders per-field scores", () => {
const { container } = render(
<CandidateBreakdown
score={92}
breakdown={{ patient: 1, date: 1, amount: 1, provider: 1 }}
tier="strong"
/>,
);
expect(container.textContent).toMatch(/patient/i);
expect(container.textContent).toMatch(/date/i);
expect(container.textContent).toMatch(/amount/i);
expect(container.textContent).toMatch(/provider/i);
expect(container.textContent).toContain("92");
});
});
@@ -0,0 +1,56 @@
import type { ScoreBreakdown, ScoreTier } from "@/lib/inbox-api";
const FIELDS: Array<{ key: keyof ScoreBreakdown; label: string; weight: number }> = [
{ key: "patient", label: "Patient", weight: 40 },
{ key: "date", label: "Date", weight: 25 },
{ key: "amount", label: "Amount", weight: 20 },
{ key: "provider", label: "Provider", weight: 15 },
];
export function CandidateBreakdown({
score,
breakdown,
tier,
}: {
score: number;
breakdown: ScoreBreakdown;
tier: ScoreTier;
}) {
return (
<div className="font-mono" style={{ fontSize: 11 }}>
<div className="flex items-baseline justify-between mb-2">
<span
className="uppercase"
style={{ color: "var(--tt-ink-dim)", letterSpacing: "0.12em" }}
>
Score
</span>
<span
className="tabular-nums"
style={{ color: "var(--tt-amber)", fontSize: 24 }}
>
{score}
</span>
</div>
<ul className="space-y-1">
{FIELDS.map((f) => (
<li key={f.key} className="flex justify-between">
<span style={{ color: "var(--tt-ink)" }}>{f.label}</span>
<span
className="tabular-nums"
style={{ color: "var(--tt-ink-dim)" }}
>
{Math.round(breakdown[f.key] * f.weight)} / {f.weight}
</span>
</li>
))}
</ul>
<p
className="mt-3 uppercase"
style={{ color: "var(--tt-ink-dim)", letterSpacing: "0.12em", fontSize: 10 }}
>
{tier}
</p>
</div>
);
}
+14
View File
@@ -0,0 +1,14 @@
// @vitest-environment happy-dom
import { afterEach, describe, expect, it } from "vitest";
import { cleanup, render } from "@testing-library/react";
import { InboxHeader } from "./InboxHeader";
afterEach(() => cleanup());
describe("InboxHeader", () => {
it("renders the date and counts", () => {
const { container } = render(<InboxHeader needEyesCount={6} doneTodayCount={23} />);
expect(container.textContent).toMatch(/6.*items need eyes/);
expect(container.textContent).toMatch(/23.*done today/);
});
});
+50
View File
@@ -0,0 +1,50 @@
export function InboxHeader({
needEyesCount,
doneTodayCount,
}: {
needEyesCount: number;
doneTodayCount: number;
}) {
const now = new Date();
const day = now.toLocaleDateString("en-US", { weekday: "short" }).toUpperCase();
const time = now.toLocaleTimeString("en-US", {
hour: "2-digit",
minute: "2-digit",
hour12: false,
});
return (
<header
className="sticky top-0 z-10 px-6 py-4"
style={{
background: "var(--tt-bg)",
borderBottom: "1px solid var(--tt-bg-elev)",
}}
>
<h1
className="tracking-tight"
style={{
color: "var(--tt-ink)",
fontFamily: "'Inter Tight', system-ui, sans-serif",
fontWeight: 700,
fontSize: 22,
}}
>
INBOX{" "}
<span
className="font-mono"
style={{ color: "var(--tt-amber)", fontSize: 16 }}
>
· {day} {time}
</span>
</h1>
<p
className="font-mono mt-1"
style={{ color: "var(--tt-ink-dim)", fontSize: 11, letterSpacing: "0.05em" }}
>
<span style={{ color: "var(--tt-amber)" }}>{needEyesCount}</span> items need eyes ·{" "}
<span style={{ color: "var(--tt-ink)" }}>{doneTodayCount}</span> done today
</p>
</header>
);
}