Files
krow_workforce_owliver/README.md
2026-09-16 20:11:27 +05:30

4.9 KiB
Raw Permalink Blame History

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

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.