From 8e87947c5f1b6125f1e36a892b7440db04c6b435 Mon Sep 17 00:00:00 2001 From: dharaneesh-r Date: Sat, 19 Sep 2026 11:43:00 +0530 Subject: [PATCH] updates on the ui changes and more things --- README.md | 2 + src/App.jsx | 22 +- .../assistant/DoormileAI/pageContext.jsx | 4 +- src/components/doormile/BatchEfficiency.jsx | 2 +- src/components/ds/DataTable.jsx | 22 +- src/components/ds/PageHeader.jsx | 54 ++-- src/components/ds/Tabs.jsx | 10 +- src/components/nearle_components/CLAUDE.md | 2 +- src/globalPolish.css | 30 ++ src/layouts/AdminLayout.jsx | 79 +++--- src/lib/PageNotFound.jsx | 8 +- src/lib/assistant/pageContext.js | 8 +- src/pages/Login.jsx | 2 +- src/pages/doormile/ViewProfile.jsx | 2 - src/pages/doormile/appUsers/AppUsers.jsx | 3 - src/pages/doormile/bookings/Bookings.jsx | 5 +- src/pages/doormile/clients/CreateClient.jsx | 3 - src/pages/doormile/clients/CreateCustomer.jsx | 3 - src/pages/doormile/clients/Tenants.jsx | 5 +- .../competitiveIntel/CompetitiveIntel.jsx | 3 - src/pages/doormile/customers/Customers.jsx | 3 - src/pages/doormile/deliveries/Deliveries.jsx | 12 - src/pages/doormile/dispatch/Dispatch.css | 62 ++++- src/pages/doormile/dispatch/Dispatch.jsx | 2 +- .../dispatch/ProfitabilitySection.jsx | 2 +- src/pages/doormile/exceptions/Exceptions.jsx | 3 - src/pages/doormile/home/Home.jsx | 37 +-- src/pages/doormile/hubs/Hubs.jsx | 3 - src/pages/doormile/orders/CreateOrder.jsx | 1 - src/pages/doormile/orders/MultipleOrders.jsx | 1 - src/pages/doormile/orders/Orders.jsx | 7 +- src/pages/doormile/orders/OrdersPreview.jsx | 3 - src/pages/doormile/pricing/Pricing.jsx | 3 - src/pages/doormile/reports/OrdersDetails.jsx | 3 - src/pages/doormile/reports/OrdersSummary.jsx | 3 - src/pages/doormile/reports/Profitability.jsx | 3 - src/pages/doormile/reports/RidersSummary.jsx | 3 - src/pages/doormile/riders/CreateRider.jsx | 3 - src/pages/doormile/riders/EditRider.jsx | 4 - src/pages/doormile/riders/Riders.jsx | 260 +++++++++++++++++- src/pages/doormile/tripsheets/Tripsheets.jsx | 3 - src/pages/doormile/vehicles/Vehicles.jsx | 3 - src/utils/locales/en.json | 2 +- 43 files changed, 511 insertions(+), 184 deletions(-) diff --git a/README.md b/README.md index 22b8d85..53809f4 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,8 @@ Statuses are looked up case-insensitively, and an unmapped value renders as a ne the humanised raw string — so a missing entry is visible rather than silent. Add states there, never in a page-local table. +`PageHeader` renders clean icon, title, and action slots across all console pages without explanatory descriptive subtitles, eliminating vertical clutter for operators who already know the console. + ## Environment | Variable | Purpose | diff --git a/src/App.jsx b/src/App.jsx index b139acb..3f80f5f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -86,8 +86,26 @@ const AuthenticatedApp = () => { } /> } /> - } /> - } /> + {/* Control X — the board formerly routed at /doormile/dispatch. + + The directory, the component and the .dispatch-container CSS + namespace keep their old names on purpose: they are internal, + and renaming a 5,800-line stylesheet's root class is a large + diff with no user-visible benefit and real risk of missing a + selector. Only what an operator sees and types changes. */} + } /> + } /> + + {/* The old paths keep working. + + This board is the page operators sit on all day, so it is the + one most likely to be bookmarked, pinned in a browser tab + group, or pasted into a message. Renaming the route without + this would turn every one of those into a 404 — a support + problem with no upside, avoided by two lines. `replace` so the + dead path does not linger in history behind a Back press. */} + } /> + } /> {/* Static before dynamic, so `orders/create` cannot be read as an order whose id is "create". */} diff --git a/src/components/assistant/DoormileAI/pageContext.jsx b/src/components/assistant/DoormileAI/pageContext.jsx index 45f7e09..7dee9d8 100644 --- a/src/components/assistant/DoormileAI/pageContext.jsx +++ b/src/components/assistant/DoormileAI/pageContext.jsx @@ -154,7 +154,7 @@ const HUBS = { }; const DISPATCH = { - label: 'Dispatch', + label: 'Control X', suggestions: [ { icon: LuLayers, text: 'Morning Batch orders today' }, { icon: LuTimerOff, text: 'Which orders are delayed?' }, @@ -281,7 +281,7 @@ const FOLLOW_UPS = { // Longest-prefix first so 'orders/create' doesn't fall through to 'orders' // with the wrong label. const ROUTES = [ - ['/doormile/dispatch', DISPATCH], + ['/doormile/control-x', DISPATCH], ['/doormile/deliveries', { ...ORDERS, label: 'Deliveries' }], ['/doormile/orders', ORDERS], ['/doormile/milers', RIDERS], diff --git a/src/components/doormile/BatchEfficiency.jsx b/src/components/doormile/BatchEfficiency.jsx index d8d4f0f..dbbc691 100644 --- a/src/components/doormile/BatchEfficiency.jsx +++ b/src/components/doormile/BatchEfficiency.jsx @@ -81,7 +81,7 @@ export function BatchEfficiency({ batch, orders = [], tenantId }) { ) : entries.length === 0 ? ( /* A response that is not a flat object — an array, a scalar, an error envelope. Shown raw rather than dropped. */ -
+        
           {JSON.stringify(result, null, 2)}
         
) : ( diff --git a/src/components/ds/DataTable.jsx b/src/components/ds/DataTable.jsx index e291924..b463d4c 100644 --- a/src/components/ds/DataTable.jsx +++ b/src/components/ds/DataTable.jsx @@ -170,7 +170,7 @@ export function DataTable({ if (loading) { return ( - + ); @@ -178,7 +178,7 @@ export function DataTable({ if (sortedRows.length === 0) { return ( - + {emptyState || ( - + {/* radius="md" (12px), down from "xl". + + Surface's xl resolves to rounded-2xl — calc(var(--radius) + 8px) — + which with --radius at 0.75rem is a 20px corner. On a small chip that + reads as soft; on a full-width table it curves far enough in to cut + visibly across the first and last cells of the header row. + + 12px is `--radius` itself, and matches radiusCard in themes/dt/tokens + — the token meant for a large boxed region, which is what a table is. + A value picked off the scale rather than an arbitrary px, so it stays + in step if the base radius is ever retuned. + + Set on all three branches (loading, empty, populated) so a table does + not change shape as its data arrives. */} + -
+
{caption && } diff --git a/src/components/ds/PageHeader.jsx b/src/components/ds/PageHeader.jsx index 7b673fb..4edccb7 100644 --- a/src/components/ds/PageHeader.jsx +++ b/src/components/ds/PageHeader.jsx @@ -32,32 +32,46 @@ export function PageHeader({ } : {}; + if (!title && !Icon && !subtitle && !actions && !breadcrumb && !children) { + return null; + } + + const hasLeading = Boolean(Icon || title || subtitle); + return ( {breadcrumb} -
-
- {Icon && ( - - - )} -
-

+ {hasLeading && ( +
+ {Icon && ( + + )} - > - {title} -

- {subtitle &&

{subtitle}

} -
-
+ {(title || subtitle) && ( +
+ {title && ( +

+ {title} +

+ )} + {subtitle &&

{subtitle}

} +
+ )} +
+ )} - {actions &&
{actions}
} - + {actions &&
{actions}
} + + )} {children}
diff --git a/src/components/ds/Tabs.jsx b/src/components/ds/Tabs.jsx index 1ac9811..ccc4ec7 100644 --- a/src/components/ds/Tabs.jsx +++ b/src/components/ds/Tabs.jsx @@ -85,7 +85,15 @@ export function Tabs({ // parent — without it a flex item refuses to go below its content width and // overflows the page instead of scrolling inside itself. const track = (children) => ( -
+
{children}
); diff --git a/src/components/nearle_components/CLAUDE.md b/src/components/nearle_components/CLAUDE.md index 8f29d9b..3cf0529 100644 --- a/src/components/nearle_components/CLAUDE.md +++ b/src/components/nearle_components/CLAUDE.md @@ -59,7 +59,7 @@ inconsistent. import { PageShell, KpiGrid, FilterToolbar, DataCard } from 'components/nearle_components/PageLayout'; {/* gap={6} between regions */} - } /> + } /> …… {/* fills the row, no dead gap */} …selectors, date, search…} diff --git a/src/globalPolish.css b/src/globalPolish.css index 68a2ed6..45fc2d7 100644 --- a/src/globalPolish.css +++ b/src/globalPolish.css @@ -55,6 +55,36 @@ body { height: 8px; } +/* The four ::-webkit-scrollbar rules around this comment are DEAD in current + browsers. Measured, not assumed — Chrome 152, this app's own stylesheet + loaded, on an element that scrolls horizontally only: + + inherits `* { scrollbar-width: thin }` -> 10px bar + scrollbar-width: auto -> 15px bar + scrollbar-width: none -> 0px + + Neither the 8px sizing above nor a `::-webkit-scrollbar:horizontal + { height: 0 }` had any effect. Once an element resolves the STANDARD + `scrollbar-width` property — which the `*` rule above hands every element + in the app — Chrome takes the standard path and ignores the legacy + pseudo-elements entirely. So the console's scrollbars are drawn by + `scrollbar-width: thin` + `scrollbar-color`, and the webkit block is inert. + Kept for older WebKit rather than deleted, but do not reach for it to + change anything: it will look like it should work and will not. + + What this means for hiding the SIDEWAYS bar only: the standard property has + no per-axis form, and the webkit `:horizontal` selector that would provide + one is ignored. A bar can therefore only be hidden per-ELEMENT, with + `scrollbar-width: none` — the `.no-scrollbar` utility in index.css. It is + applied to the containers that scroll horizontally ONLY, where there is no + vertical bar for it to take away: every DataTable, every tab strip, the + profitability and batch-efficiency tables, and Dispatch's batch scroller, + strat row and compare timeline. + + One container scrolls on both axes — the bulk-upload preview in + MultipleOrders — and keeps both bars deliberately. Hiding its horizontal + bar is not possible without hiding the vertical one the operator needs. */ + *::-webkit-scrollbar-track { background-color: transparent; } diff --git a/src/layouts/AdminLayout.jsx b/src/layouts/AdminLayout.jsx index 74dd9a5..4ca2d41 100644 --- a/src/layouts/AdminLayout.jsx +++ b/src/layouts/AdminLayout.jsx @@ -47,7 +47,7 @@ const LOGO_FILTER = { /** Destinations that sit directly on the header bar. */ const NAV = [ - { label: 'Dispatch', path: '/doormile/dispatch' }, + { label: 'Control X', path: '/doormile/control-x' }, { label: 'Bookings', path: '/doormile/bookings' }, { label: 'Orders', path: '/doormile/orders' }, { label: 'Deliveries', path: '/doormile/deliveries' }, @@ -60,21 +60,21 @@ const NAV_GROUPS = [ { label: 'Fleet Ops', items: [ - { label: 'Hubs', path: '/doormile/hubs', icon: Warehouse, desc: 'Sortation centers & facilities' }, - { label: 'Vehicles', path: '/doormile/vehicles', icon: Car, desc: 'Fleet register & EV telematics' }, - { label: 'Tripsheets', path: '/doormile/tripsheets', icon: ListTodo, desc: 'Linehaul & middle-mile runs' }, - { label: 'Exceptions', path: '/doormile/exceptions', icon: ShieldAlert, desc: 'Live alerts & delivery blockers' }, - { label: 'Competitive Intel', path: '/doormile/competitive-intel', icon: Activity, desc: 'Benchmarking & market rates' }, - { label: 'App Users', path: '/doormile/app-users', icon: UserCheck, desc: 'System operators & roles' }, + { label: 'Hubs', path: '/doormile/hubs', icon: Warehouse }, + { label: 'Vehicles', path: '/doormile/vehicles', icon: Car }, + { label: 'Tripsheets', path: '/doormile/tripsheets', icon: ListTodo }, + { label: 'Exceptions', path: '/doormile/exceptions', icon: ShieldAlert }, + { label: 'Competitive Intel', path: '/doormile/competitive-intel', icon: Activity }, + { label: 'App Users', path: '/doormile/app-users', icon: UserCheck }, ], }, { label: 'Reports', items: [ - { label: 'Orders Summary', path: '/doormile/reports/orderssummary', icon: FileSpreadsheet, desc: 'Daily volume & status aggregations' }, - { label: 'Orders Details', path: '/doormile/reports/ordersdetails', icon: FileText, desc: 'Granular leg-by-leg breakdown' }, - { label: 'Milers Summary', path: '/doormile/reports/riderssummary', icon: Bike, desc: 'Fleet KPIs & on-duty shifts' }, - { label: 'Profitability', path: '/doormile/reports/profitability', icon: Coins, desc: 'Gross margin & variable costs' }, + { label: 'Orders Summary', path: '/doormile/reports/orderssummary', icon: FileSpreadsheet }, + { label: 'Orders Details', path: '/doormile/reports/ordersdetails', icon: FileText }, + { label: 'Milers Summary', path: '/doormile/reports/riderssummary', icon: Bike }, + { label: 'Profitability', path: '/doormile/reports/profitability', icon: Coins }, ], }, ]; @@ -372,28 +372,31 @@ export default function AdminLayout() { key={item.path} onClick={() => navigate(item.path)} className={cn( - 'flex items-start gap-2.5 p-2 rounded-xl cursor-pointer transition-colors my-0.5', + // items-center, not items-start: with the second + // line gone there is nothing to top-align to, and + // the icon would sit high against a single label. + 'flex items-center gap-2.5 p-2 rounded-xl cursor-pointer transition-colors my-0.5', active ? 'bg-brand-tint/80 text-brand' : 'hover:bg-slate-50 text-ink-1' )} > {ItemIcon && (
)} -
-
{item.label}
- {item.desc && ( -
- {item.desc} -
- )} -
+ {/* Label only. The descriptions under each item + ("Sortation centers & facilities", "Linehaul & + middle-mile runs") were removed: this is a jump + menu for people who already know the console, so a + gloss on every row is read once and then skipped + past forever while still costing the height that + made the menu tall enough to cover the page. */} +
{item.label}
); })} @@ -418,17 +421,25 @@ export default function AdminLayout() { assistantOpen ? 'bg-brand-tint text-brand' : 'text-ink-3 hover:bg-surface-sunken hover:text-ink-1' )} > - {/* 20px inside a 32px button. - Was `h-9 w-9 max-w-none` — a 36px image in a 32px button, - so the mark overflowed its own control by 2px on every - side. Two visible consequences: it stood proud of the - notification bell and avatar beside it, breaking the row's - alignment, and it covered the button's own area completely, - so the `hover:bg-surface-sunken` tint had nowhere to show — - the control looked dead on hover while its neighbours lit - up. Sized to sit inside the button, like the Bell's 16px - icon does. */} - + {/* 24px inside a 32px button. + + Started at `h-9 w-9 max-w-none` — a 36px image in a 32px + button, so the mark overflowed its own control by 2px on + every side. That broke the row's alignment against the + bell and avatar AND covered the button completely, leaving + `hover:bg-surface-sunken` nowhere to render, so the control + looked dead on hover while its neighbours lit up. + + Dropped to 20px to fix both, which read as too faint next + to the bell. 24px is the ceiling that keeps the fix: it + leaves 4px of button on every side, which is what the + hover tint needs to be visible as a ring around the mark. + Anything larger and the tint disappears again. + + Bigger than the Bell's 16px on purpose — this is a brand + mark carrying its own circular frame, so it reads smaller + than its box, where a stroked icon reads full-size. */} + )} @@ -554,10 +565,10 @@ export default function AdminLayout() { {/* `dai-page` is the handshake with the assistant dock: while the panel is open, DoormileAI.css reserves exactly its width of padding here so the page slides open beside it instead of being covered. */} -
+
diff --git a/src/lib/PageNotFound.jsx b/src/lib/PageNotFound.jsx index 253de46..4020438 100644 --- a/src/lib/PageNotFound.jsx +++ b/src/lib/PageNotFound.jsx @@ -21,10 +21,10 @@ export default function PageNotFound() { const quickLinks = [ { - title: 'Live Dispatch', + title: 'Control X', desc: 'Real-time fleet tracking & active runs', icon: Radio, - path: '/doormile/dispatch', + path: '/doormile/control-x', color: 'text-rose-600 bg-rose-50 border-rose-200/70 group-hover:bg-rose-100/70' }, { @@ -98,11 +98,11 @@ export default function PageNotFound() {
{caption}
diff --git a/src/pages/doormile/exceptions/Exceptions.jsx b/src/pages/doormile/exceptions/Exceptions.jsx index 476dbea..e6273f7 100644 --- a/src/pages/doormile/exceptions/Exceptions.jsx +++ b/src/pages/doormile/exceptions/Exceptions.jsx @@ -210,9 +210,6 @@ export default function Exceptions() { return ( Log exception diff --git a/src/pages/doormile/home/Home.jsx b/src/pages/doormile/home/Home.jsx index 5347473..2eeeaac 100644 --- a/src/pages/doormile/home/Home.jsx +++ b/src/pages/doormile/home/Home.jsx @@ -551,7 +551,7 @@ export default function Home() { } }, actions: [ - { label: 'Open Dispatch Board', path: '/doormile/dispatch' }, + { label: 'Open Control X', path: '/doormile/control-x' }, { label: 'View Orders Pipeline', path: '/doormile/orders' } ], timestamp: dayjs().format('hh:mm A') @@ -604,7 +604,7 @@ export default function Home() { }, visualData: deriveVisualData(null, 'create order'), actions: [ - { label: 'Open Dispatch Board', path: '/doormile/dispatch' }, + { label: 'Open Control X', path: '/doormile/control-x' }, { label: 'View Orders Pipeline', path: '/doormile/orders' } ], timestamp: dayjs().format('hh:mm A') @@ -727,7 +727,7 @@ export default function Home() { ? `All ${res.created} orders have been submitted to the dispatch board and scheduled with their designated routes.` : `${res.created} orders were created, ${res.failed} failed.`, actions: [ - { label: 'Open Dispatch Board', path: '/doormile/dispatch' }, + { label: 'Open Control X', path: '/doormile/control-x' }, { label: 'View Orders Pipeline', path: '/doormile/orders' } ], timestamp: dayjs().format('hh:mm A') @@ -754,7 +754,7 @@ export default function Home() { title: `Created order ${res.bookingno || res.id || ''}.`, summary: 'It appears on the Orders page under Pending until a rider is assigned.', actions: [ - { label: 'Open Dispatch Board', path: '/doormile/dispatch' }, + { label: 'Open Control X', path: '/doormile/control-x' }, { label: 'View Orders Pipeline', path: '/doormile/orders' } ], timestamp: dayjs().format('hh:mm A') @@ -925,18 +925,18 @@ export default function Home() { actions.push({ label: 'Upload Bulk Orders', path: '/doormile/orders/multiple' }); } else if (intent.includes('order') || intent.includes('booking')) { actions.push({ label: 'Open Orders Pipeline', path: '/doormile/orders' }); - actions.push({ label: 'View Dispatch Board', path: '/doormile/dispatch' }); + actions.push({ label: 'View Control X', path: '/doormile/control-x' }); } else if (intent.includes('rider') || intent.includes('miler') || intent.includes('workforce') || intent.includes('coverage')) { - actions.push({ label: 'Open Dispatch Board', path: '/doormile/dispatch' }); + actions.push({ label: 'Open Control X', path: '/doormile/control-x' }); actions.push({ label: 'View Milers Directory', path: '/doormile/milers' }); } else if (intent.includes('exception') || intent.includes('attention') || intent.includes('stalled')) { actions.push({ label: 'Inspect Exceptions', path: '/doormile/exceptions' }); - actions.push({ label: 'Open Dispatch Board', path: '/doormile/dispatch' }); + actions.push({ label: 'Open Control X', path: '/doormile/control-x' }); } else if (intent.includes('pricing') || intent.includes('cost') || intent.includes('profit')) { actions.push({ label: 'View Profitability Report', path: '/doormile/reports/profitability' }); actions.push({ label: 'Open Pricing Matrix', path: '/doormile/pricing' }); } else { - actions.push({ label: 'Open Operations Board', path: '/doormile/dispatch' }); + actions.push({ label: 'Open Operations Board', path: '/doormile/control-x' }); actions.push({ label: 'View Orders Pipeline', path: '/doormile/orders' }); } @@ -1000,7 +1000,7 @@ export default function Home() { 'Try naming a date, a status or a client — or open the board below and read it directly.', sourceCalls: [], actions: [ - { label: 'Open Dispatch Board', path: '/doormile/dispatch' }, + { label: 'Open Control X', path: '/doormile/control-x' }, { label: 'View Orders Pipeline', path: '/doormile/orders' } ], visualData: null, @@ -1028,7 +1028,7 @@ export default function Home() { : 'The request did not complete. Nothing was read, so there are no figures to show.', visualData: null, sourceCalls: [], - actions: [{ label: 'Open Dispatch Board', path: '/doormile/dispatch' }], + actions: [{ label: 'Open Control X', path: '/doormile/control-x' }], timestamp: dayjs().format('hh:mm A') }; setActiveResponse(errorPayload); @@ -1216,12 +1216,12 @@ export default function Home() { @@ -1314,7 +1314,7 @@ export default function Home() { @@ -1815,16 +1815,17 @@ export default function Home() { - {/* Dispatch Tile */} + {/* Control X Tile — the launcher rule from the renames above + still holds: the label names the page it opens. */}
- Dispatch + Control X diff --git a/src/pages/doormile/hubs/Hubs.jsx b/src/pages/doormile/hubs/Hubs.jsx index 320b3fb..ab9c636 100644 --- a/src/pages/doormile/hubs/Hubs.jsx +++ b/src/pages/doormile/hubs/Hubs.jsx @@ -199,9 +199,6 @@ export default function Hubs() { return ( New hub diff --git a/src/pages/doormile/orders/CreateOrder.jsx b/src/pages/doormile/orders/CreateOrder.jsx index 07d15cd..6bcf5f1 100644 --- a/src/pages/doormile/orders/CreateOrder.jsx +++ b/src/pages/doormile/orders/CreateOrder.jsx @@ -639,7 +639,6 @@ export default function CreateOrder() { Single Delivery -

Enter pickup, delivery details, and calculate rate

diff --git a/src/pages/doormile/orders/MultipleOrders.jsx b/src/pages/doormile/orders/MultipleOrders.jsx index 5cd79c5..81e7a6c 100644 --- a/src/pages/doormile/orders/MultipleOrders.jsx +++ b/src/pages/doormile/orders/MultipleOrders.jsx @@ -677,7 +677,6 @@ export default function MultipleOrders() { Bulk Upload -

Bulk-create deliveries from CSV/Excel or saved customers

diff --git a/src/pages/doormile/orders/Orders.jsx b/src/pages/doormile/orders/Orders.jsx index ee4c9d9..d94f663 100644 --- a/src/pages/doormile/orders/Orders.jsx +++ b/src/pages/doormile/orders/Orders.jsx @@ -209,7 +209,7 @@ export default function Orders() { OpenToast('Orders optimised', 'success'); refetchOrders(); setSelectedIds([]); - navigate('/doormile/dispatch/preview', { + navigate('/doormile/control-x/preview', { state: { dispatchPreviewData: data, aiMode: 1, @@ -438,9 +438,6 @@ export default function Orders() { return (