fix: update UI to 7-state display framework

- WorklistTable: consolidate 9 filter tabs to 8 matching 7-state labels
  (Docs Required, Escalate, Confirm Appt., Begin Outreach, Clear to Ship,
  New Patient, On Track) + add combined "escalate" filter key for
  RENEWAL_CRITICAL + VISIT_REQUIRED
- Sidebar: fix broken filter keys (REFILL_WINDOW/VISIT_DUE/OUT_OF_COVERAGE
  never matched any r.flag value) - replace with SUPPLY_LAPSED, escalate,
  RESUPPLY_READY; update labels to 7-state names
- App: rename Sidebar props to match new framework; update stat cards to
  Needs Attention / Outreach in Progress / Clear to Ship

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Kisa 2026-06-07 16:27:25 -04:00
parent e57f803f26
commit 77a1cdb2c0
3 changed files with 41 additions and 38 deletions

View file

@ -21,15 +21,16 @@ function AppInner() {
const [importLabel, setImportLabel] = useState("No data imported");
const csvImportRef = useRef(null);
// New flag names from backend v0.2
const supplyLapsed = records.filter((r) => r.flag === "SUPPLY_LAPSED").length;
const visitRequired = records.filter((r) => r.flag === "VISIT_REQUIRED").length;
const renewalCritical = records.filter((r) => r.flag === "RENEWAL_CRITICAL").length;
const renewalElevated = records.filter((r) => r.flag === "RENEWAL_ELEVATED").length;
const renewalSoon = records.filter((r) => r.flag === "RENEWAL_SOON").length;
const transferPending = records.filter((r) => r.flag === "TRANSFER_PENDING").length;
const refill = records.filter((r) => r.flag === "RESUPPLY_READY").length;
const okCount = records.filter((r) => r.flag === "ACTIVE").length;
const urgent = supplyLapsed + visitRequired + renewalCritical + renewalElevated + transferPending;
const escalateCount = visitRequired + renewalCritical;
const outreachCount = renewalSoon + renewalElevated;
const handleResults = useCallback(async (file) => {
const label = new Date().toLocaleDateString("en-US", {
@ -71,9 +72,9 @@ function AppInner() {
<div className="flex w-full min-h-screen bg-[var(--bg-page)] text-[var(--text-primary)] transition-colors">
{/* Sidebar */}
<Sidebar
oocCount={supplyLapsed}
visitDueCount={visitRequired + renewalCritical + renewalElevated}
refillCount={refill}
supplyLapsedCount={supplyLapsed}
escalateCount={escalateCount}
clearToShipCount={refill}
activeFilter={activeFilter}
onFilterChange={setActiveFilter}
onImportClick={() => csvImportRef.current?.trigger()}
@ -111,19 +112,19 @@ function AppInner() {
<div className="grid grid-cols-3 gap-4 mb-6">
<StatCard
priority
label="Prescriber Action"
value={urgent}
sub={`${supplyLapsed} supply lapsed · ${visitRequired + renewalCritical + renewalElevated} renewal/visit action · ${transferPending} transfer`}
label="Needs Attention"
value={supplyLapsed + escalateCount + transferPending}
sub={`${supplyLapsed} docs required · ${escalateCount} escalate · ${transferPending} new patient`}
/>
<StatCard
label="⚠ Resupply Ready"
label="Outreach in Progress"
value={outreachCount}
sub={`${renewalElevated} confirm appt. · ${renewalSoon} begin outreach`}
/>
<StatCard
label="Clear to Ship"
value={refill}
sub="patients within resupply window — initiate now"
/>
<StatCard
label="✓ Active"
value={okCount}
sub="patients with supply on track — no action needed"
sub={`${refill} patients in resupply window · ${okCount} on track`}
/>
</div>

View file

@ -1,7 +1,7 @@
export default function Sidebar({
oocCount,
visitDueCount,
refillCount,
supplyLapsedCount,
escalateCount,
clearToShipCount,
activeFilter,
onFilterChange,
onImportClick,
@ -14,23 +14,24 @@ export default function Sidebar({
badge: null,
},
{
label: "Resupply Ready",
key: "REFILL_WINDOW",
icon: "",
badge: refillCount,
label: "Docs Required",
key: "SUPPLY_LAPSED",
icon: "!",
badge: supplyLapsedCount,
badgeWarn: true,
},
{
label: "Renewal Due",
key: "VISIT_DUE",
icon: "⚡",
badge: visitDueCount,
label: "Escalate",
key: "escalate",
icon: "!",
badge: escalateCount,
badgeWarn: true,
},
{
label: "Supply Lapsed",
key: "OUT_OF_COVERAGE",
icon: "",
badge: oocCount,
label: "Clear to Ship",
key: "RESUPPLY_READY",
icon: "",
badge: clearToShipCount,
},
];

View file

@ -24,14 +24,13 @@ function scoreClass(priority) {
const FILTERS = [
{ key: "all", label: "All" },
{ key: "SUPPLY_LAPSED", label: "Supply Lapsed" },
{ key: "VISIT_REQUIRED", label: "Visit Required" },
{ key: "RENEWAL_CRITICAL", label: "Renewal Critical" },
{ key: "RENEWAL_ELEVATED", label: "Renewal Elevated" },
{ key: "RENEWAL_SOON", label: "Renewal Due" },
{ key: "RESUPPLY_READY", label: "Resupply Ready" },
{ key: "ACTIVE", label: "Active" },
{ key: "TRANSFER_PENDING", label: "Transfer" },
{ key: "SUPPLY_LAPSED", label: "Docs Required" },
{ key: "escalate", label: "Escalate" },
{ key: "RENEWAL_ELEVATED", label: "Confirm Appt." },
{ key: "RENEWAL_SOON", label: "Begin Outreach" },
{ key: "RESUPPLY_READY", label: "Clear to Ship" },
{ key: "TRANSFER_PENDING", label: "New Patient" },
{ key: "ACTIVE", label: "On Track" },
];
const HIGH_PRIORITY_FLAGS = ["SUPPLY_LAPSED", "VISIT_REQUIRED", "RENEWAL_CRITICAL", "TRANSFER_PENDING"];
@ -55,6 +54,8 @@ export default function WorklistTable({ records, activeFilter, onFilterChange })
const filtered =
activeFilter === "all"
? localRecords
: activeFilter === "escalate"
? localRecords.filter((r) => r.flag === "RENEWAL_CRITICAL" || r.flag === "VISIT_REQUIRED")
: localRecords.filter((r) => r.flag === activeFilter);
const todayStr = new Date().toLocaleDateString("en-US", {