- /claims: Databricks claims table through the record-view API, server-side paging and filters (exact on dimensions, ranges on dates); URL is the filter set - finding tiles link to the exact rows: affected set, and the unfiled-inside-window subset behind 'still recoverable'; kind-aware (expiring, slow payer, underpayment) - 'What Ava reviewed' work statement shown under the headline - client: range / multi-value filters Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
125 lines
4.9 KiB
TypeScript
125 lines
4.9 KiB
TypeScript
import { NavLink, Outlet, useNavigate } from 'react-router-dom';
|
|
import { Database, LogOut, Radar } 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 only way a case is born. Nobody asks Ava a question; she
|
|
decides what is worth a person's time. */}
|
|
<Button kind="primary" onClick={() => navigate('/review')}>
|
|
<Radar className="h-4 w-4" />
|
|
Run review
|
|
</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>
|
|
))}
|
|
{/* The data itself, after the pipeline: every claim in the lakehouse. */}
|
|
<li className="shrink-0 lg:mt-3 lg:shrink lg:border-t lg:border-line lg:pt-3">
|
|
<NavLink
|
|
to="/claims"
|
|
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="inline-flex items-center gap-1.5 text-[13px] font-semibold whitespace-nowrap">
|
|
<Database className="h-3.5 w-3.5" /> Claims
|
|
</span>
|
|
<span className={`hidden text-[11px] lg:block ${isActive ? 'text-brand-fg/70' : 'text-faint'}`}>
|
|
The lakehouse, row by row
|
|
</span>
|
|
</>
|
|
)}
|
|
</NavLink>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
|
|
<main className="min-w-0 flex-1 p-4 lg:p-8">
|
|
<Outlet />
|
|
</main>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|