northlake-health/src/layout/Shell.tsx
Yashas b2377b4645 feat: Ava stops waiting to be asked — the daily review
The primary action is now "Run daily review": no form, no question. It
starts the new INIT door dni-act-review, which is the same activity a
scheduler performs at 6am; the button exists so a room does not have to
wait until 6am. Ava sweeps every payer, department and front desk against a
materiality bar and, if nothing clears it, records "nothing to report" and
closes the case herself — it never reaches a desk. "Ask a question" stays,
demoted to a ghost button, for the follow-up path.

A second button replays a quiet morning: the demo data is static, so every
live sweep would flag the same August spike. Anchoring one run on
2026-07-26 lets it genuinely come back empty, and the contrast — one quiet
morning beside one $1.09M morning — is the pitch.

Queue cards and the case page now carry the sweep outcome: what she
reviewed, how many patterns she flagged, and what kind (payer rule change,
front desk, expiring appeals, …). A closed quiet case reads "Nothing to
report" rather than "Closed", because those are different outcomes.

Backend counterpart: sm2/custom-apps/denials-investigator/08_daily_review.sql
and the sweep-first charter in 05_ai_employee.sql.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 13:12:40 +05:30

106 lines
4.1 KiB
TypeScript

import { NavLink, Outlet, useNavigate } from 'react-router-dom';
import { LogOut, Radar, Search } from 'lucide-react';
import { useZino } from '../api/provider';
import { QUEUES, prettyRole } from '../api/config';
import { NorthlakeLockup } from '../components/NorthlakeLogo';
import { ThemeToggle } from '../components/ThemeToggle';
import { Button } from '../components/core';
/**
* The chrome.
*
* The sidebar IS the pipeline: every entry is the record view filtered on
* current_state_name, in the order a case actually moves. A person learns the
* process by using the app. Awaiting Review is first because it is the only
* queue that needs a human, and the one this console exists to serve.
*
* Nothing here is role-gated. Hiding a queue protects nothing — the workflow
* re-checks RBAC on every submission — and hiding one from the person who needs
* it is a worse failure than showing a button that comes back "not permitted".
*/
export function Shell() {
const { user, logout } = useZino();
const navigate = useNavigate();
return (
<div className="flex min-h-full flex-col">
<header className="sticky top-0 z-30 bg-panel">
<div className="flex items-center gap-4 px-4 py-2.5">
<NorthlakeLockup />
<div className="ml-auto flex items-center gap-3">
{/* The sweep is the product; the question is the exception. */}
<Button kind="primary" onClick={() => navigate('/review')}>
<Radar className="h-4 w-4" />
Run daily review
</Button>
<Button kind="ghost" onClick={() => navigate('/new')} title="Ask Ava a specific question">
<Search className="h-4 w-4" />
Ask a question
</Button>
{user && (
<div className="hidden text-right sm:block">
<div className="text-[13px] leading-tight font-semibold text-ink">
{user.name || user.email}
</div>
<div className="text-[11px] leading-tight text-faint">
{(user.roles ?? []).map(prettyRole).join(' · ') || 'No role'}
</div>
</div>
)}
<ThemeToggle />
<button
onClick={logout}
title="Sign out"
aria-label="Sign out"
className="rounded-md p-2 text-muted transition-colors hover:bg-panel2 hover:text-ink focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand"
>
<LogOut className="h-4 w-4" />
</button>
</div>
</div>
<div aria-hidden="true" className="h-[3px] bg-brand" />
</header>
<div className="flex flex-1 flex-col lg:flex-row">
<nav className="shrink-0 border-b border-line bg-panel lg:w-60 lg:border-r lg:border-b-0">
<ul className="flex gap-1 overflow-x-auto p-2 lg:flex-col lg:overflow-visible">
{QUEUES.map((q) => (
<li key={q.path} className="shrink-0 lg:shrink">
<NavLink
to={`/q/${q.path}`}
className={({ isActive }) =>
`block rounded-md px-3 py-2 transition-colors ${
isActive ? 'bg-brand text-brand-fg' : 'text-muted hover:bg-panel2 hover:text-ink'
}`
}
>
{({ isActive }) => (
<>
<span className="block text-[13px] font-semibold whitespace-nowrap">
{q.label}
</span>
<span
className={`hidden text-[11px] lg:block ${isActive ? 'text-brand-fg/70' : 'text-faint'}`}
>
{q.hint}
</span>
</>
)}
</NavLink>
</li>
))}
</ul>
</nav>
<main className="min-w-0 flex-1 p-4 lg:p-6">
<Outlet />
</main>
</div>
</div>
);
}