Three problems, and the first one is the reason the other two were hard to see. THERE WAS NO DASHBOARD. "/" redirected to the underwriting queue — one stage, usually empty, and belonging to somebody else. Every screen in the app answered "show me this queue"; none answered "how is the book doing, and is anything waiting on me?", which is the only question a person has before they have picked a queue. So: a Today page. Three blocks, in the order somebody cares about them. What is waiting on a person, as three cards that colour only when they have something in them. Renewals running out, worst first, capped at 30 days because a renewal six months away is not a thing to look at today. Then every stage with its count, zeroes included — a stage quietly receiving nothing is only visible if its zero is on screen. It is one list call, counted in the browser. That is honest at this size and it is the same call the queues already make. If the book outgrows it the answer is a counts endpoint, not a bigger page. THE WORDS WERE WRITTEN FOR WHOEVER BUILT THE WORKFLOW. "What happens next" was followed by "these are the only activities this state allows — but the workflow decides, server-side, whether you may". A failed list said "this queue has no record view yet". Panels were called "Flow details". A closed lead read "nothing runs from here". None of that is wrong; all of it is addressed to the wrong reader. Now: "What you can do", "Lead details", "History", "This queue could not be loaded". Queue names say what they want — "Documents needed", "Underwriter to review", "Payment to confirm". The sidebar group called "Not yet" says "Not due yet", and "Running by itself" says "The agents have it", which is the actual claim being made. THE QUEUE HAD NINE COLUMNS AND LED WITH THE WRONG ONE. Two were internal vocabulary: attribution status renders "clear" or "contested" and means nothing to an operator, and the channel is background rather than something anyone scans a queue for. Both fold into a subtitle under the customer. That leaves six columns and puts the renewal countdown — the number that decides whether to act today — second instead of fifth. Also: the timeline printed a raw slug when a step came back without a name. It is the screen this product is demonstrated on, so a "zk-act-doc-reminder" in the middle of an otherwise readable story is expensive. It now reads as English.
83 lines
2.9 KiB
JavaScript
83 lines
2.9 KiB
JavaScript
import { NavLink, Outlet } from 'react-router-dom'
|
|
import { NAV_GROUPS, STAGES } from '../api/config.js'
|
|
import UserMenu from './UserMenu.jsx'
|
|
import logo from '../assets/brand/zurich_logo.webp'
|
|
import './Shell.css'
|
|
|
|
/**
|
|
* The sidebar groups the pipeline by WHO IS HOLDING each lead, not by where it
|
|
* sits in the process. Fourteen flat stages answer "what is the process?", which
|
|
* is not the question anyone signing in has; these answer "is anything waiting
|
|
* on me?". Queues that need a person are named by what they want done.
|
|
*
|
|
* It deliberately carries no counts. A tally here can only come from fetching
|
|
* every lead on a timer and counting client-side, which is a second full list
|
|
* call per open tab that disagrees with the queue's own total the moment either
|
|
* one is paged. The count belongs on the queue, which already has it from the
|
|
* server.
|
|
*/
|
|
export default function Shell() {
|
|
return (
|
|
<div className="shell">
|
|
<header className="shell__top">
|
|
<div className="shell__brand">
|
|
<img src={logo} alt="Zurich Kotak General Insurance" />
|
|
<div className="shell__brandtext">
|
|
<strong>Lead Desk</strong>
|
|
<span>Lead to Policy</span>
|
|
</div>
|
|
</div>
|
|
<UserMenu />
|
|
</header>
|
|
|
|
<div className="shell__body">
|
|
<nav className="shell__nav" aria-label="Pipeline">
|
|
<NavLink
|
|
to="/"
|
|
end
|
|
className={({ isActive }) => 'shell__today' + (isActive ? ' is-active' : '')}
|
|
>
|
|
Today
|
|
</NavLink>
|
|
|
|
<NavLink to="/add" className="shell__add">
|
|
<svg viewBox="0 0 16 16" aria-hidden="true">
|
|
<path d="M8 3.2v9.6M3.2 8h9.6" fill="none" stroke="currentColor" strokeWidth="1.7"
|
|
strokeLinecap="round" />
|
|
</svg>
|
|
Add a lead
|
|
</NavLink>
|
|
|
|
{NAV_GROUPS.map((group) => {
|
|
const stages = STAGES.filter((s) => s.kind === group.kind)
|
|
if (!stages.length) return null
|
|
return (
|
|
<div className="shell__group" key={group.kind}>
|
|
<p className="shell__navlabel">{group.label}</p>
|
|
<div className="shell__stages">
|
|
{stages.map((s) => (
|
|
<NavLink
|
|
key={s.uid}
|
|
to={`/stage/${s.uid}`}
|
|
title={s.need ? s.name : undefined}
|
|
className={({ isActive }) =>
|
|
'shell__stage' + (isActive ? ' is-active' : '') + (s.kind === 'needs' ? ' is-needed' : '')
|
|
}
|
|
>
|
|
<span className="shell__stagename">{s.need ?? s.name}</span>
|
|
</NavLink>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
})}
|
|
</nav>
|
|
|
|
<main className="shell__main">
|
|
<Outlet />
|
|
</main>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|