ui/ux improvement

This commit is contained in:
2026-09-18 16:57:24 +05:30
parent 115a06a02c
commit 041dc37861
43 changed files with 1697 additions and 746 deletions

View File

@@ -21,6 +21,7 @@ import {
} from 'lucide-react';
import type { DeliveryRow, OrderRow, TenantLocation } from '@/api/types';
import { KpiCard } from '@/components/KpiCard';
import { Tab, TabBar } from '@/components/TabBar';
import { useSelection, type Selection } from '@/components/useSelection';
import { Panel } from '@/components/Panel';
import { TablePager } from '@/components/TablePager';
@@ -231,80 +232,69 @@ export function DispatchBoard({ scope }: { scope: DispatchScope }) {
return (
<div className="dispatch-container">
{/* ── Unified Strategy & Operations Toolbar (xpressconsole #strat-row style) ── */}
<div id="strat-row" className="strat-row">
<div className="strat-tabs">
<button
type="button"
className={`sbt ${mode === 'riders' ? 'active' : ''}`}
onClick={() => changeMode('riders')}
>
<span className="sbt-icon"><Bike size={15} /></span>
<span>By Rider</span>
<span className="sbt-badge">{totals.riders}</span>
</button>
{/* The view switcher, on the console's own segmented control.
These six were `.sbt` — a seventh treatment of "tab" in this app:
bordered when idle, a solid brand fill with a purple glow when
selected. They now read exactly like the view tabs on Sales, Users,
Inventory and the rest.
The `.strat-row` card around them is gone too. It was a bordered,
shadowed toolbar whose only remaining child was this strip — the
operations cluster beside it was removed earlier — and a card holding
nothing but a tab track is a box drawn round a box. Every other page
stands its switcher directly on the page. */}
<TabBar aria-label="Dispatch views">
<Tab
label="By rider"
icon={<Bike size={14} />}
count={totals.riders || undefined}
isActive={mode === 'riders'}
onClick={() => changeMode('riders')}
/>
<Tab
label="By store"
icon={<Store size={14} />}
count={branches.length || undefined}
isActive={mode === 'stores'}
onClick={() => changeMode('stores')}
/>
{/* A shop's customer book is its own. Grouping a partner's rounds by
customer would mean reading every merchant's book to put a name to
a phone number, so the tab is not offered on a partner board. */}
{scope.kind === 'tenant' ? (
<Tab
label="By customer"
icon={<Users size={14} />}
isActive={mode === 'customers'}
onClick={() => changeMode('customers')}
/>
) : null}
<button
type="button"
className={`sbt ${mode === 'stores' ? 'active' : ''}`}
onClick={() => changeMode('stores')}
>
<span className="sbt-icon"><Store size={15} /></span>
<span>By Store</span>
<span className="sbt-badge">{branches.length}</span>
</button>
{/* A shop's customer book is its own. Grouping a partner's rounds by
customer would mean reading every merchant's book to put a name to
a phone number, so the tab is not offered on a partner board. */}
{scope.kind === 'tenant' ? (
<button
type="button"
className={`sbt ${mode === 'customers' ? 'active' : ''}`}
onClick={() => changeMode('customers')}
>
<span className="sbt-icon"><Users size={15} /></span>
<span>By Customer</span>
</button>
) : null}
<button
type="button"
className={`sbt ${mode === 'active' ? 'active' : ''}`}
onClick={() => changeMode('active')}
>
<span className="sbt-icon"><Radio size={15} /></span>
<span>Active Fleet</span>
<span className="sbt-dot-live" />
</button>
<button
type="button"
className={`sbt ${mode === 'timing' ? 'active' : ''}`}
onClick={() => changeMode('timing')}
>
<span className="sbt-icon"><Timer size={15} /></span>
<span>Plan vs Actual</span>
</button>
<button
type="button"
className={`sbt ${mode === 'profit' ? 'active' : ''}`}
onClick={() => changeMode('profit')}
>
<span className="sbt-icon"><IndianRupee size={15} /></span>
<span>Unit Economics</span>
</button>
</div>
{/* No operations cluster.
What stood here was a hub picker with one hard-coded hub, a demo /
live toggle, a rider count read off the mock fleet, and a profit
chip computed as `value * 0.28` labelled "(84%)" — a number with no
source. All four described the page rather than the day's work, and
three of them were not true. The KPI row below carries the figures
that come from the data. */}
</div>
{/* The three below group the day differently from the three above:
those slice the same stops by whose they are, these report on how
the day went. The rule in the track says so. */}
<Tab
label="Active fleet"
icon={<Radio size={14} />}
isActive={mode === 'active'}
onClick={() => changeMode('active')}
isGroupStart
isLive
/>
<Tab
label="Plan vs actual"
icon={<Timer size={14} />}
isActive={mode === 'timing'}
onClick={() => changeMode('timing')}
/>
<Tab
label="Unit economics"
icon={<IndianRupee size={14} />}
isActive={mode === 'profit'}
onClick={() => changeMode('profit')}
/>
</TabBar>
{/* The same four-card row every other page uses — same `kpi-grid`, same