diff --git a/docs/Doormile-Hub-Console-API-Reference.md b/docs/Doormile-Hub-Console-API-Reference.md deleted file mode 100644 index 593a061..0000000 --- a/docs/Doormile-Hub-Console-API-Reference.md +++ /dev/null @@ -1,889 +0,0 @@ -# Doormile Hub Console — Frontend Integration Guide - -**Base URL:** `https://api.doormile.com` -**Auth:** Bearer token in `Authorization` header on every authenticated request -**Content-Type:** `application/json` on all POST / PATCH calls - -## How the flow works - -1. Staff opens the console → Login page -2. `POST /api/v1/hub/login` → receives JWT + hub context -3. Store token + hub context in localStorage -4. Every page reads hub name/city from stored context (no extra call) -5. Every API call sends `Authorization: Bearer ` -6. On 401 → clear localStorage → redirect to `/login` - ---- - -## 1. Authentication - -### POST /api/v1/hub/login -No auth header needed. - -Request body: - -```json -{ - "email": "hub.coimbatore@doormile.in", - "password": "password123" -} -``` - -Response: - -```json -{ - "success": true, - "token": "eyJhbGci...", - "hub": { - "hubid": 1, - "hubname": "Coimbatore Jupiter Hub", - "hubtype": "sorting_center", - "city": "Coimbatore", - "capacity": 50 - }, - "staff": { - "displayname": "Coimbatore Hub Staff", - "email": "hub.coimbatore@doormile.in", - "role": 6 - }, - "is_doormile_staff": true -} -``` - -What to store in localStorage after login: - -```js -localStorage.setItem('hub_token', data.token) -localStorage.setItem('hub_context', JSON.stringify(data.hub)) -localStorage.setItem('hub_staff', JSON.stringify(data.staff)) -localStorage.setItem('hub_is_doormile', String(data.is_doormile_staff)) -``` - -Test accounts: - -| Email | Password | Hub | Access | -|---|---|---|---| -| hub.coimbatore@doormile.in | password123 | Coimbatore Jupiter Hub | Full (Doormile staff) | -| hub.hyderabad@doormile.in | password123 | Hyderabad hub | Full (Doormile staff) | -| hub.bangalore@doormile.in | password123 | Bangalore hub | Full (Doormile staff) | -| hub.chennai@doormile.in | password123 | Chennai hub | Full (Doormile staff) | -| hub@kpmtravels.in | password123 | Hub 1 | Restricted (partner — no hub management) | - ---- - -## 2. Dashboard - -### GET /api/v1/hub/dashboard -Returns live KPI stats for the logged-in staff's hub. - -Response: - -```json -{ - "success": true, - "data": { - "parcels_received_today": 142, - "milers_available": 6, - "milers_on_duty": 12, - "pending_pickups": 8, - "batches_sent_today": 3, - "exceptions": 2 - } -} -``` - -Which UI element uses which field: - -| Dashboard card | Field | -|---|---| -| Total Parcels Received | `parcels_received_today` | -| Available Milers | `milers_available` | -| Milers on Duty | `milers_on_duty` | -| Pending Pickups | `pending_pickups` | -| Batches Sent Today | `batches_sent_today` | -| Needs Checking | `exceptions` | - -**Note:** Hub name shown in the header/title comes from localStorage (`hub_context.hubname`) — not from this endpoint. No extra call needed. - ---- - -## 3. Inbound — Receive Parcels - -### GET /api/v1/hub/inbound/today -Returns all parcels inbounded at this hub today. Now returns `sendername`, `originname`, `destinationname`, `temperature` (readable names instead of raw IDs and pincodes). - -Response: - -```json -{ - "success": true, - "data": [ - { - "bookingid": 15, - "trackingnumber": "DM-882201", - "sendername": "Acme Corp", - "originname": "Mumbai Hub", - "destinationname": "Dwarka Sec 12, Coimbatore", - "weight": "2.4 kg", - "condition": "Good", - "temperature": "N/A", - "shelf": "Zone A (Shelf 1)", - "inboundedat": "2026-07-04T09:15:00Z" - } - ], - "total": 1 -} -``` - -### POST /api/v1/hub/bookings/:id/inbound -Scan a parcel in. `:id` is the booking/consignment ID. - -Request body: - -```json -{ - "tracking_id": "DM-882201", - "condition": "Good", - "temperature": "N/A", - "shelf": "Zone A (Shelf 1)", - "weight": "2.4 kg" -} -``` - -Condition values: `Good` · `Damaged Box` · `Wet / Crushed` · `Missing Label` -Temperature: Free text — "4.1°C" for cold chain items, "N/A" for dry goods - -Response: - -```json -{ - "success": true, - "data": { - "bookingid": 15, - "trackingnumber": "DM-882201", - "recommended_shelf": "Zone A (Shelf 1)", - "status": "At_Hub" - } -} -``` - -Shelf recommendation logic (backend handles this automatically): - -- Condition contains Damaged / Wet / Missing → Exception Area -- Temperature is not N/A → Zone C (Cold Room) -- Otherwise → Zone A or Zone B based on destination - -Error — tracking ID not found: - -```json -{ - "success": false, - "message": "booking not found" -} -``` - -HTTP 404. - ---- - -## 4. Order Assignment — Pickup Requests - -### GET /api/v1/hub/bookings/unassigned -Returns all pending pickup requests for this hub's city. - -Response: - -```json -{ - "success": true, - "data": [ - { - "bookingid": 21, - "customerName": "Ramesh K.", - "pickupaddress": "Gandhipuram, Coimbatore", - "deliveryaddress": "Hitech City, Hyderabad", - "packagedescription": "Small Box, 2kg", - "createdat": "2026-07-04T08:45:00Z", - "status": "Pending_Pickup" - } - ], - "total": 3 -} -``` - -For assigning a miler to these bookings, see **Section 14 — Hub Assignment Override**. - ---- - -## 5. Dispatch & Batches - -### GET /api/v1/hub/batches -Returns all outgoing batches for this hub. - -Response: - -```json -{ - "success": true, - "data": [ - { - "tripsheetid": 1, - "batchlabel": "BATCH-9281", - "batchkind": "transfer", - "destinationlabel": "Mumbai Hub (BOM-02)", - "vehicle": "Truck DL-01-BZ-8055", - "itemcount": 154, - "status": "Draft", - "createdat": "2026-07-04T08:00:00Z", - "dispatchtime": null - } - ], - "total": 1 -} -``` - -Status values: `Draft` → `Ready` → `Dispatched` -Batchkind values: `local` · `transfer` - -### POST /api/v1/hub/batches -Create a new outgoing batch. - -Request body: - -```json -{ - "route": "Transfer to Mumbai Hub", - "destination": "Mumbai Hub (BOM-02)", - "vehicle": "Truck DL-01-BZ-8055", - "parcels_count": 154, - "kind": "transfer" -} -``` - -Response: - -```json -{ - "success": true, - "data": { - "tripsheetid": 2, - "batchlabel": "BATCH-9282", - "status": "Draft" - } -} -``` - -### PATCH /api/v1/hub/batches/:id/status -Move a batch through its status flow. - -Request body — mark as ready: - -```json -{ "status": "Ready" } -``` - -Request body — dispatch (send out): - -```json -{ "status": "Dispatched" } -``` - -Response: - -```json -{ - "success": true, - "data": { - "tripsheetid": 1, - "status": "Ready", - "dispatchtime": null - } -} -``` - -Invalid status transition → 400: - -```json -{ - "success": false, - "message": "invalid status" -} -``` - ---- - -## 6. Milers - -### GET /api/v1/hub/milers -Returns all milers assigned to this hub, now with operational stats per miler. - -Response: - -```json -{ - "success": true, - "data": [ - { - "userid": 4, - "displayname": "Rajesh Kumar", - "phone": "+91 98765 43210", - "vehicleid": 1, - "hubid": 1, - "availabilitystatus": "Available", - "rating": 4.8, - "completedorders": 45, - "cancelledorders": 2, - "currentlat": 11.0168, - "currentlon": 76.9558, - "device_token": "fcm_token_here", - "zones": ["641001", "641012"], - "assignedload": 2, - "capacity": 30, - "pickupspending": 1, - "codcollected": 4500.00, - "codpending": 1200.00, - "checkinat": "2026-07-04T08:12:00Z", - "hoursactive": 6.4, - "isverified": true - } - ], - "total": 6 -} -``` - -Availability status values: `Available` · `Assigned` · `On_Break` · `Offline` - -The `zones`, `assignedload`, `capacity`, `pickupspending`, `codcollected`, `codpending`, `checkinat`, `hoursactive`, `isverified` fields were the empty fields the Milers page was trying to show. Now populated from real data. - -### POST /api/v1/admin/milers -Create (onboard) a new miler. Hub JWT is accepted here. - -Request body: - -```json -{ - "displayname": "Muthu Kumar", - "phone": "+91 90011 22334", - "hubid": 1, - "vehicleid": 2, - "availabilitystatus": "Available" -} -``` - -Response: - -```json -{ - "success": true, - "data": { - "userid": 10, - "displayname": "Muthu Kumar" - } -} -``` - -### PATCH /api/v1/admin/milers/:id -Update a miler's details or status. - -Request body (any subset of fields): - -```json -{ - "availabilitystatus": "On_Break", - "hubid": 2 -} -``` - -### DELETE /api/v1/admin/milers/:id -Remove a miler from the roster. - -Response: - -```json -{ - "success": true, - "message": "miler removed" -} -``` - ---- - -## 7. Routing — Where Does It Go? - -### GET /api/v1/hub/routing/:trackingno -Scan a parcel and get its sort destination. `:trackingno` is the tracking number scanned at the sort station. - -Response: - -```json -{ - "success": true, - "data": { - "trackingno": "DM-TRK-0015", - "destination": "Peelamedu, 641004", - "recommendedshelf": "Zone B", - "nexthop": "Local delivery", - "condition": "Good", - "iscoldchain": false, - "weight": "2.4 kg", - "customername": "Ramesh K.", - "bookingid": 15 - } -} -``` - -`nexthop` values: `Local delivery` · `Transfer to Mumbai Hub` (or whichever destination hub). -Use `recommendedshelf` to show the big shelf indicator UI. - -Error — tracking number not found → 404. Show a "Parcel not found" error state. - -```json -{ - "success": false, - "message": "parcel not found" -} -``` - ---- - -## 8. Rider Routes - -### GET /api/v1/hub/rider-routes -Returns all milers at this hub with their planned stops today. - -### GET /api/v1/hub/milers/:id/route -Returns the planned stops for a single miler. `:id` is the miler user ID. - -Response (same `data[]` shape for both; the single-miler endpoint returns one entry): - -```json -{ - "success": true, - "data": [ - { - "mileruserid": 4, - "milername": "Rajesh Kumar", - "mode": "pickup", - "totalstops": 5, - "completedstops": 2, - "totaldistance_km": 12.4, - "stops": [ - { "seq": 1, "address": "Gandhipuram, Coimbatore", "lat": 11.0168, "lon": 76.9558, "items": 1, "bookingid": 20, "status": "completed", "eta_minutes": 0 }, - { "seq": 2, "address": "RS Puram, Coimbatore", "lat": 11.001, "lon": 76.951, "items": 2, "bookingid": 21, "status": "pending", "eta_minutes": 12 } - ] - } - ] -} -``` - -`mode` values: `pickup` · `delivery` -Stop status values: `pending` · `in_progress` · `completed` - -Pass `stops[].lat/lon` to OSRM to draw the route line — the OSRM call stays client-side. - ---- - -## 9. Live Trucks - -### GET /api/v1/hub/tripsheets/in-transit -Returns transfer trucks currently in transit, with interpolated live positions. -Poll this every 5 seconds alongside miler locations. - -Response: - -```json -{ - "success": true, - "data": [ - { - "tripsheetid": 3, - "tripsheetno": "DM-TS-0003", - "label": "Chennai Jupiter Hub → Coimbatore Jupiter Hub", - "originlat": 13.0827, "originlon": 80.2707, - "destlat": 11.0168, "destlon": 76.9558, - "currentlat": 12.1, "currentlon": 78.9, - "status": "In_Transit", - "progresspct": 40, - "vehicleno": "TN-04-AX-8822", - "itemcount": 154, - "eta_minutes": 180 - } - ] -} -``` - -`currentlat/lon` gives the truck's position on the map. Replace the fake animated truck with these real coordinates. - ---- - -## 10. Arriving Vehicles - -### GET /api/v1/hub/inbound/vehicles -Returns trucks arriving at this hub (Dashboard → "Trucks Arriving" table). - -Response: - -```json -{ - "success": true, - "data": [ - { - "vehicleno": "TN-04-AX-8822", - "origin": "Chennai Jupiter Hub", - "tripsheetid": 3, - "status": "On the way", - "eta": "2 hrs 30 min", - "unloadedpct": 0, - "itemcount": 154 - } - ] -} -``` - -Status values: `On the way` · `Unloading` -(Dispatched maps to `On the way`, Arrived maps to `Unloading`.) - ---- - -## 11. Activity Feed - -### GET /api/v1/hub/activity?limit=10 -Returns a real event feed for this hub (UNION across 4 sources: inbound, dispatch, exceptions, sorting). - -Response: - -```json -{ - "success": true, - "data": [ - { "time": "2026-07-04T11:24:00Z", "type": "exception", "text": "Exception raised: Damaged on DM-TRK-999999" }, - { "time": "2026-07-04T11:22:00Z", "type": "inbound", "text": "Received parcel DM-TRK-999999 from Coimbatore Jupiter Hub" }, - { "time": "2026-07-04T11:20:00Z", "type": "dispatch", "text": "Dispatched batch DM-TS-0003 to Mumbai Hub" } - ], - "total": 3 -} -``` - -Type values: `inbound` · `dispatch` · `exception` · `sorting` -Use `type` to pick the icon color — same color scheme as the existing mock. - ---- - -## 12. Zones - -### GET /api/v1/hub/zones -Returns the delivery zone breakdown for this hub (Dashboard → "Delivery Areas"). - -Response: - -```json -{ - "success": true, - "data": [ - { "zone": "641001", "zonename": "Gandhipuram", "parcels": 12, "milers": 2, "status": "Active" }, - { "zone": "641004", "zonename": "Peelamedu", "parcels": 8, "milers": 1, "status": "Active" }, - { "zone": "641012", "zonename": "Jupiter Nagar","parcels": 3, "milers": 0, "status": "Need Milers" } - ] -} -``` - -Status values: `Active` · `Need Milers` — use this to color the status chip. - ---- - -## 13. Notifications - -### GET /api/v1/hub/notifications -Returns notifications for the header bell icon, generated from real events. - -Response: - -```json -{ - "success": true, - "data": [ - { "id": 1, "title": "Exception: Damaged", "type": "exception", "time": "3 min ago", "read": false }, - { "id": 2, "title": "Truck arriving from Chennai Hub", "type": "inbound", "time": "5 min ago", "read": false }, - { "id": 3, "title": "Pickup waiting 30+ min", "type": "alert", "time": "12 min ago", "read": false } - ], - "total": 3 -} -``` - -Type values: `exception` · `inbound` · `warning` · `alert` - -### PATCH /api/v1/hub/notifications/:id/read -Mark a notification as read. - -Response: - -```json -{ "success": true } -``` - -On bell click → `GET /hub/notifications`. On item click → `PATCH /hub/notifications/:id/read`, then mark it read in local state. - ---- - -## 14. Hub Assignment Override - -The old admin assign endpoint (`POST /admin/bookings/:id/assign-miler`) returned **403** for hub staff. Two new hub-scoped endpoints replace it. - -### POST /api/v1/hub/bookings/:id/assign-miler -Manual assign — hub staff picks the miler. - -Request body: - -```json -{ "mileruserid": 4 } -``` - -Response: - -```json -{ - "success": true, - "data": { - "bookingid": 21, - "mileruserid": 4, - "milername": "Rajesh Kumar", - "status": "Miler_Assigned" - } -} -``` - -Use this on the **Pickup Requests** page when staff manually selects a miler from the dialog. - -### POST /api/v1/hub/bookings/:id/auto-assign -Auto-assign — AI engine picks the miler. - -Request body: - -```json -{} -``` - -Response (success): - -```json -{ - "success": true, - "data": { - "mileruserid": 4, - "milername": "Rajesh Kumar", - "distance_km": 0.4 - } -} -``` - -Response (no miler) — HTTP 422: - -```json -{ - "success": false, - "message": "No eligible miler found in range" -} -``` - -Response (timeout) — HTTP 202: - -```json -{ - "success": true, - "message": "assignment in progress" -} -``` - -Use this for the **Auto-Assign** bulk button. Loop over selected booking IDs and call this for each one. - -**Backend implementation notes:** shared `AssignMilerToBooking()` service (`booking_assignment_service.go`), `TryAssignOnce()` single-attempt wrapper on `crm_assignment`, `assignedbyuserid` is nullable for hub-initiated assignments, and `AdminAssignMiler` now sends FCM to the miler. - ---- - -## 15. Hub Management (Doormile staff only) - -These endpoints return 403 for partner accounts (`is_doormile_staff = false`). -Use the `is_doormile_staff` flag from localStorage to show/hide the UI for these. - -### GET /api/v1/hub/hubs -List all hubs in the logged-in staff's city. Now includes `lat`/`lon` for map pins. - -Response: - -```json -{ - "success": true, - "data": [ - { - "hubid": 1, - "hubname": "Coimbatore Jupiter Hub", - "hubtype": "sorting_center", - "capacity": 50, - "status": "active", - "has_staff": true, - "lat": 11.0168, - "lon": 76.9558 - }, - { - "hubid": 2, - "hubname": "Coimbatore Spoke 1", - "hubtype": "spoke", - "capacity": 50, - "status": "active", - "has_staff": false, - "lat": 11.0210, - "lon": 76.9610 - } - ] -} -``` - -Use `lat/lon` to place hub pins on the Live Map. - -### POST /api/v1/hub/hubs -Create a new hub in the staff's city. - -Request body: - -```json -{ - "hubname": "Coimbatore RS Puram Hub", - "hubtype": "spoke", - "capacity": 30, - "contact": "+91 98765 00000", - "address": "RS Puram, Coimbatore", - "pincode": "641002" -} -``` - -**Note:** `applocationid` (city) is set automatically from the logged-in staff's hub — cannot be overridden. - -### POST /api/v1/hub/staff -Create a hub staff login for any hub in the city. - -Request body: - -```json -{ - "hubid": 2, - "email": "hub.rspuram@doormile.in", - "password": "securepassword", - "displayname": "RS Puram Hub Staff", - "tenantid": null -} -``` - -Set `tenantid` to the partner's tenant ID for partner accounts, `null` for Doormile staff. - -Response: - -```json -{ - "success": true, - "data": { - "staffid": 6, - "email": "hub.rspuram@doormile.in", - "hubid": 2 - } -} -``` - ---- - -## Error response shape - -All errors follow the same shape: - -```json -{ - "success": false, - "message": "human readable error description" -} -``` - -| HTTP code | Meaning | -|---|---| -| 400 | Bad request — invalid body or status transition | -| 401 | Token expired or missing → redirect to /login | -| 202 | Accepted — async assignment in progress | -| 403 | Forbidden — partner account trying Doormile-only endpoint | -| 404 | Resource not found (booking ID, miler ID, tracking no etc.) | -| 422 | Unprocessable — no eligible miler found in range | -| 500 | Server error — show generic "something went wrong" toast | - ---- - -## Page-to-endpoint map (quick reference) - -| Page | Endpoints called | -|---|---| -| Login | POST /hub/login | -| Dashboard | GET /hub/dashboard · GET /hub/inbound/vehicles · GET /hub/activity · GET /hub/zones | -| Receive Parcels | GET /hub/inbound/today · POST /hub/bookings/:id/inbound | -| Pickup Requests | GET /hub/bookings/unassigned · GET /hub/milers · POST /hub/bookings/:id/assign-miler · POST /hub/bookings/:id/auto-assign | -| Where Does It Go? (Routing) | GET /hub/routing/:trackingno | -| Dispatch | GET /hub/batches · POST /hub/batches · PATCH /hub/batches/:id/status | -| Milers | GET /hub/milers · POST /admin/milers · PATCH /admin/milers/:id · DELETE /admin/milers/:id | -| Rider Routes | GET /hub/rider-routes · GET /hub/milers/:id/route | -| Live Map | GET /admin/milers/locations (poll 5s) · GET /hub/tripsheets/in-transit (poll 5s) · GET /hub/hubs | -| Header — Notifications | GET /hub/notifications · PATCH /hub/notifications/:id/read | -| Hub Settings | GET /hub/hubs · POST /hub/hubs · POST /hub/staff | - ---- - -## Frontend implementation notes - -**Token storage:** - -```js -// On login success: -localStorage.setItem('hub_token', response.token) -localStorage.setItem('hub_context', JSON.stringify(response.hub)) -localStorage.setItem('hub_staff', JSON.stringify(response.staff)) -localStorage.setItem('hub_is_doormile', String(response.is_doormile_staff)) - -// On every API call: -headers: { 'Authorization': `Bearer ${localStorage.getItem('hub_token')}` } - -// On logout or 401: -localStorage.clear() -navigate('/login') -``` - -**Show hub name dynamically (not hardcoded):** - -```js -const hub = JSON.parse(localStorage.getItem('hub_context')) -// hub.hubname → "Coimbatore Jupiter Hub" -// hub.city → "Coimbatore" -// hub.hubid → 1 -``` - -**Hide hub management UI for partners:** - -```js -const isDoormile = localStorage.getItem('hub_is_doormile') === 'true' -// Show "Add New Hub" / "Add Staff" buttons only if isDoormile === true -// KPM partner account gets false → those buttons hidden -``` - -**On 401 — token expired, force re-login:** - -```js -if (response.status === 401) { - localStorage.clear() - window.location.href = '/login' -} -``` - -**Polling intervals:** - -- Miler locations → every 5 seconds -- Truck positions → every 5 seconds (same call cycle) -- Dashboard stats → every 30 seconds -- Notifications → every 60 seconds - ---- - -*All endpoints live at `https://api.doormile.com` · Hub Console Backend v1.0 complete* diff --git a/src/pages/auth/Login.jsx b/src/pages/auth/Login.jsx index 479cddc..e97db8d 100644 --- a/src/pages/auth/Login.jsx +++ b/src/pages/auth/Login.jsx @@ -28,8 +28,8 @@ import { setSession } from '@/auth/session'; export default function Login() { const navigate = useNavigate(); const [show, setShow] = useState(false); - const [auth, setAuth] = useState('hub.coimbatore@doormile.in'); - const [pwd, setPwd] = useState('password123'); + const [auth, setAuth] = useState(''); + const [pwd, setPwd] = useState(''); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); diff --git a/src/pages/operations/Dispatch.jsx b/src/pages/operations/Dispatch.jsx index f118923..7720b5d 100644 --- a/src/pages/operations/Dispatch.jsx +++ b/src/pages/operations/Dispatch.jsx @@ -259,7 +259,7 @@ export default function Dispatch() { - + @@ -309,7 +309,7 @@ export default function Dispatch() { return ( - + diff --git a/src/pages/operations/RiderRoutes.jsx b/src/pages/operations/RiderRoutes.jsx index 9888725..79ca69e 100644 --- a/src/pages/operations/RiderRoutes.jsx +++ b/src/pages/operations/RiderRoutes.jsx @@ -548,14 +548,14 @@ export default function RiderRoutes() { )} {/* ── Analysis KPI strip ── */} - + {[ { icon: GroupsOutlinedIcon, label: 'Active Milers', value: kpi.activeRiders, sub: `of ${riders.length}`, color: '#1A73E8', bg: '#E8F0FE' }, { icon: modeCfg.icon, label: modeCfg.label, value: kpi.orders, sub: 'pickups covered', color: '#C01227', bg: alpha('#C01227', 0.1) }, { icon: CheckCircleRoundedIcon, label: modeCfg.doneLabel, value: kpi.done, sub: `${kpi.fail} missed`, color: '#1E8E3E', bg: '#E6F4EA' }, { icon: StraightenRoundedIcon, label: 'Distance', value: `${kpi.km} km`, sub: 'fleet total today', color: '#8E24AA', bg: '#F3E5F5' }, ].map((k, i) => ( - + ))} diff --git a/src/pages/operations/Riders.jsx b/src/pages/operations/Riders.jsx index 5d6f7f8..db1b6c2 100644 --- a/src/pages/operations/Riders.jsx +++ b/src/pages/operations/Riders.jsx @@ -527,10 +527,12 @@ function ProfileDrawer({ rider, onClose, onSave, startInEdit = false }) { // Close button would hide under the app bar. Lift the whole modal above it. zIndex: (t) => t.zIndex.modal, '& .MuiDrawer-paper': { - width: { xs: '100%', sm: 380 }, + width: { xs: '100%', sm: 480 }, maxWidth: '100%', - top: { xs: 0, sm: 64 }, - height: { xs: '100%', sm: 'calc(100% - 64px)' }, + // Run the sheet the full height of the viewport so there is no empty + // strip above the red header (zIndex.modal keeps Close clickable). + top: 0, + height: '100%', borderTopLeftRadius: { sm: 16 }, display: 'flex', flexDirection: 'column', @@ -1185,7 +1187,7 @@ export default function Riders() { {/* KPIs */} - + {[ { icon: GroupsOutlinedIcon, label: 'On Duty', value: kpi.onDuty, sub: `of ${kpi.total}`, color: '#1A73E8', bg: '#E8F0FE', trend: true }, { icon: RouteOutlinedIcon, label: 'In Field', value: kpi.onField, sub: 'Active pickups', color: '#1E8E3E', bg: '#E6F4EA' }, @@ -1193,7 +1195,7 @@ export default function Riders() { { icon: WarningAmberOutlinedIcon, label: 'SLA Risk', value: kpi.slaRisk, sub: 'Overloaded milers', color: '#D93025', bg: '#FCE8E6' }, { icon: PaymentsOutlinedIcon, label: 'COP Pending', value: inr(kpi.codToCollect), sub: 'To be collected', color: '#8E24AA', bg: '#F3E5F5' }, ].map((k, i) => ( - + ))} @@ -1271,24 +1273,28 @@ export default function Riders() { {STATUS_CHIPS.map(s => { const active = statusFilter === s; const meta = STATUS_META[s] || {}; + // Each status carries its own colour; "All" falls back to a neutral dark. + const accent = meta.color || '#1A1A2E'; + const tint = meta.bg || '#F8F9FB'; return ( setStatusFilter(s)} - icon={meta.color ? : undefined} + icon={meta.color ? : undefined} sx={{ height: 38, px: 1, borderRadius: 2, fontSize: '0.82rem', - fontWeight: active ? 700 : 500, - bgcolor: active ? '#1A1A2E' : '#F8F9FB', - color: active ? '#fff' : '#5F6368', - border: active ? 'none' : '1px solid #ECEEF1', + fontWeight: active ? 700 : 600, + bgcolor: active ? accent : tint, + color: active ? '#fff' : accent, + border: active ? 'none' : `1px solid ${alpha(accent, 0.25)}`, + '& .MuiChip-icon': { color: active ? '#fff' : meta.color }, '& .MuiChip-label': { px: 1.25 }, - '&:hover': { bgcolor: active ? '#1A1A2E' : '#F1F3F5' } + '&:hover': { bgcolor: active ? accent : alpha(accent, 0.14) } }} /> );