# KROW Workforce — redesign demo A complete redesign prototype of the KROW Workforce product with Owliver, the workforce-intelligence panel, built in. Everything is local. There is no backend, API, database, authentication or outbound network call — all figures come from a single typed mock-data module. ## Running it ```bash npm install npm run dev # http://localhost:5173 npm run build # production build npm run typecheck # tsc --noEmit npm run lint # oxlint ``` ## Stack Vite · React 19 · TypeScript · Tailwind CSS v4 · shadcn/ui-style components on Radix · Lucide · Recharts · TanStack Table v9 · React Router. ## Layout One CSS grid (`.app-shell` in `src/index.css`): ``` ┌──────────────────────────────────────────────┐ │ sidebar │ GLOBAL HEADER (64px) │ │ (full ├────────────────────┬─────────────┤ │ height) │ MAIN CONTENT │ OWLIVER │ └───────────┴────────────────────┴─────────────┘ ``` The header spans main + Owliver only; the sidebar owns the full viewport height and all navigation. Owliver sits in its own rail on row 2, so it can never overlap or be clipped by the header. **Breakpoints** — desktop ≥1280: all three columns. Tablet 768–1279: icon rail plus main, Owliver becomes an overlay. Mobile <768: sidebar becomes a drawer (with the complete navigation, nothing removed), Owliver a bottom sheet. ## Structure ``` src/ config/navigation.ts information architecture (mirrors the vendor workspace) data/ types, mockData, selectors, store owliver/ block types, response engine, block renderers components/shell/ AppShell, Sidebar, TopHeader components/owliver/ panel + composer components/shared/ MetricCard, DataTable, Page, Toolbar, StatusBadge components/ui/ Radix-based primitives pages/ the fourteen product pages ``` `src/data/mockData.ts` is the single source of truth and `selectors.ts` derives every computed figure, so a number on a KPI card and the same number quoted by Owliver cannot disagree. ## Home Home is an AI workspace rather than a dashboard. The hierarchy is greeting → central Owliver card → quick actions → compact metrics → Today. Performance content (utilisation, trends, attendance, performance health) deliberately does **not** appear on Home — it lives on the Performance page, which remains complete. ## Owliver **One Owliver per page, never two.** Home shows the central card and no right rail; every other page shows the right rail and no central card. On Home the grid drops to two columns, so main reflows into the space rather than leaving an empty rail behind — and the rail stays hidden on Home even if it was left open elsewhere. That means the central card owns the whole interaction on Home: it holds the conversation, the composer and the suggestions, and an answer appears inside that thread. Replies are typed block lists rendered as real components — text, metric cards, alerts, tables, charts, a staff-allocation flow diagram, recommendations, expandable details and working action buttons. Home's thread starts empty (an invitation to ask). Every other page opens with a greeting, its own brief and one seeded exchange, so the You / Owliver distinction is legible straight away. State lives in `OwliverProvider`, above the panel, which gives two properties the panel could not provide on its own: - **History survives closing.** Collapsing the rail, or the tablet/mobile sheet unmounting, no longer discards the conversation. - **Each page keeps its own thread.** Navigating switches context instead of leaving Home's answers on the Payroll page; returning to a page restores what was asked there. Responses are deterministic and delayed 500–900 ms behind a typing indicator. **Resolve Understaffed Shifts** mutates the shared data, so the greeting, the metrics and the sidebar badges all update behind the panel. ## Shell controls The sidebar collapses to a 72px icon rail (labels become tooltips; active state and badges are preserved) and Owliver closes so main reclaims its column. Both are driven by `data-sidebar` / `data-owliver` attributes on the grid container, so the layout reflows rather than overlaying. ## Notes for future work Two bugs worth remembering, both fixed here: - Passing a fresh `state` / `initialState` object to TanStack Table v9's `useTable` on every render makes its store notify → re-render → notify. Both are memoised in `DataTable.tsx`. - Loading the whole app in one chunk blocked first paint long enough to look like a hang on heavier routes. Pages are lazy-loaded in `App.tsx`.