From ba88501bc41353dcefb47d80d0fea30cc541727e Mon Sep 17 00:00:00 2001 From: dharaneesh-r Date: Fri, 29 May 2026 15:08:01 +0530 Subject: [PATCH] updates on the api and dispatch page and preview page --- src/menu-items/nearle.js | 14 +- src/pages/api/api.js | 16 +- src/pages/nearle/dispatch/Dispatch.js | 3445 +++++++++++++------------ src/pages/nearle/dispatch/Preview.js | 63 +- 4 files changed, 1802 insertions(+), 1736 deletions(-) diff --git a/src/menu-items/nearle.js b/src/menu-items/nearle.js index 5732179..3b7d19e 100644 --- a/src/menu-items/nearle.js +++ b/src/menu-items/nearle.js @@ -63,6 +63,13 @@ const nearle = { icon: icons.FileDoneOutlined, type: 'group', children: [ + { + id: 'dispatch', + title: , + type: 'item', + url: '/nearle/dispatch', + icon: icons.DirectionsBikeOutlinedIcon + }, { id: 'orders', title: , @@ -151,13 +158,6 @@ const nearle = { type: 'item', url: '/nearle/invoice', icon: icons.ReceiptOutlinedIcon - }, - { - id: 'dispatch', - title: , - type: 'item', - url: '/nearle/dispatch', - icon: icons.DirectionsBikeOutlinedIcon } ] }; diff --git a/src/pages/api/api.js b/src/pages/api/api.js index b23c7af..988720f 100644 --- a/src/pages/api/api.js +++ b/src/pages/api/api.js @@ -173,8 +173,20 @@ export const fetchBatchEfficiency = async ({ batch, tenantId }) => { // ==============================|| finalCreatedeliveries (orders) ||============================== // export const finalCreatedeliveries = async (deliveryData) => { - console.log('deliveryData', deliveryData.deliveries); - const response = await axios.post(`https://jupiter.nearle.app/live/api/v1/deliveries/createdeliveries`, deliveryData.deliveries); + // Go backend types Deliveries.userid (and rider_id) as int. Coerce at the + // boundary so any upstream string — including ones that only surface in the + // deployed build's data flow — can't cause a 500 unmarshal error. + const toInt = (v) => { + const n = Number(v); + return Number.isFinite(n) ? n : v; + }; + const deliveries = (deliveryData.deliveries || []).map((d) => ({ + ...d, + userid: toInt(d.userid), + rider_id: toInt(d.rider_id) + })); + console.log('deliveryData', deliveries); + const response = await axios.post(`https://jupiter.nearle.app/live/api/v1/deliveries/createdeliveries`, deliveries); return response.data; }; // ==============================|| createAutomationDeliveries (orders) Auto rider Assign ||============================== // diff --git a/src/pages/nearle/dispatch/Dispatch.js b/src/pages/nearle/dispatch/Dispatch.js index 2289042..ef28e76 100644 --- a/src/pages/nearle/dispatch/Dispatch.js +++ b/src/pages/nearle/dispatch/Dispatch.js @@ -610,9 +610,9 @@ const Ico = ({ children }) => ( // Batch windows for the standalone Dispatch Analysis view. Maps the UI label // to the X-Batch-Window header value the backend expects. const ANALYSIS_BATCH_WINDOWS = [ - { key: 'morning', label: 'Morning', timeRange: '12:00 AM – 8:00 AM', sub: 'Early shift orders', color: '#f59e0b', bg: '#fffbeb', border: '#fde68a' }, - { key: 'afternoon', label: 'Noon', timeRange: '9:00 AM – 12:00 PM', sub: 'Lunch rush window', color: '#10b981', bg: '#ecfdf5', border: '#a7f3d0' }, - { key: 'evening', label: 'Evening', timeRange: '4:00 PM – 7:00 PM', sub: 'Dinner & end-of-day', color: '#6366f1', bg: '#eef2ff', border: '#c7d2fe' } + { key: 'morning', label: 'Morning', timeRange: '12:00 AM – 8:00 AM', sub: 'Early shift orders', color: '#f59e0b', bg: '#fffbeb', border: '#fde68a' }, + { key: 'afternoon', label: 'Noon', timeRange: '9:00 AM – 12:00 PM', sub: 'Lunch rush window', color: '#10b981', bg: '#ecfdf5', border: '#a7f3d0' }, + { key: 'evening', label: 'Evening', timeRange: '4:00 PM – 7:00 PM', sub: 'Dinner & end-of-day', color: '#6366f1', bg: '#eef2ff', border: '#c7d2fe' } ]; // Tolerant field-name lookup so the Analysis card still renders cleanly even @@ -2383,8 +2383,8 @@ const Dispatch = ({ let ordersToRender = allOrders; if (focusedZone) ordersToRender = focusedZone.orders; - if (focusedRider) ordersToRender = focusedRider.orders; if (focusedKitchen) ordersToRender = focusedKitchen.orders; + if (focusedRider) ordersToRender = focusedRider.orders; ordersToRender = ordersToRender.filter(hasValidDrop); // Pre-build the deliveryid → sequenceStep lookup once per render so each @@ -2418,6 +2418,7 @@ const Dispatch = ({ } const isRiderFocused = !!focusedRider; + const showNumbers = isRiderFocused || !!focusedKitchen; const statusStyle = getStatusStyle(o.orderstatus); const statusLow = String(o.orderstatus || '').toLowerCase(); const isDelivered = statusLow === 'delivered'; @@ -2431,7 +2432,7 @@ const Dispatch = ({ ` : ''; - const icon = isRiderFocused + const icon = showNumbers ? (() => { const seq = compareSeq || o.step || (ordersToRender.indexOf(o) + 1); const sz = 32; @@ -2453,7 +2454,7 @@ const Dispatch = ({ return ( -
- - - - - -
+
+ + + + + +
- {shouldFetchLive && viewMode !== 'rider-info' && ( -
- Batch - {/* Status-wise (time-field) filter is hidden for now per spec — + {shouldFetchLive && viewMode !== 'rider-info' && ( +
+ Batch + {/* Status-wise (time-field) filter is hidden for now per spec — bucketing is locked to `assigntime`. Restore this block to bring back the Delivered/Pending/Assigned/... dropdown.
@@ -3059,7 +3060,7 @@ const Dispatch = ({ )}
*/} - {/* Slot editor (Edit slots button + panel) is hidden for now per + {/* Slot editor (Edit slots button + panel) is hidden for now per spec — the three batches (Morning / Afternoon / Evening) are fixed. Restore this block to bring back the operator-editable start/end hours, add-slot, and reset-to-defaults controls. @@ -3179,312 +3180,312 @@ const Dispatch = ({ )}
*/} - {/* Inner scroller — keeps the "Slot" label fixed while the chip list scrolls + {/* Inner scroller — keeps the "Slot" label fixed while the chip list scrolls horizontally when it overflows. */} -
- {BATCHES.map((b) => { - const isActive = selectedBatch === b.id; - return ( - - ); - })} -
-
- )} - - {viewMode === 'rider-info' ? ( -
-
-
-
Riders
-
{ridersAllDay.length} {ridersAllDay.length === 1 ? 'rider' : 'riders'} today
+
+ {BATCHES.map((b) => { + const isActive = selectedBatch === b.id; + return ( + + ); + })}
-
- - setRiderInfoSearch(e.target.value)} - /> -
- {(() => { - const q = riderInfoSearch.trim().toLowerCase(); - const matched = ridersAllDay.filter((r) => { - if (!q) return true; - return String(r.riderName || '').toLowerCase().includes(q) || String(r.id).includes(q); - }); - if (matched.length === 0) { - return
{riderInfoSearch ? `No riders match "${riderInfoSearch}"` : 'No riders have orders today'}
; - } - return ( -
- {matched.map((r) => { - const isActive = String(riderInfoUserid) === String(r.id); - return ( - - ); - })} -
- ); - })()}
+ )} -
- {riderInfoUserid == null ? ( -
-
-
Pick a rider
-
- Select a rider from the list on the left to see their live GPS, - battery, connection, and current order snapshot. -
+ {viewMode === 'rider-info' ? ( +
+
+
+
Riders
+
{ridersAllDay.length} {ridersAllDay.length === 1 ? 'rider' : 'riders'} today
- ) : ( - <> - {riderInfoFetching && !riderInfoData && ( -
Loading rider snapshot…
- )} - - {riderInfoIsError && ( -
- Couldn't load this rider's log. {riderInfoError?.message || ''} -
- )} - - {riderInfoData && (() => { - const d = riderInfoData; - const lat = parseFloat(d.latitude); - const lon = parseFloat(d.longitude); - const hasCoords = Number.isFinite(lat) && Number.isFinite(lon); - const batteryNum = parseInt(String(d.battery || '').replace('%', ''), 10); - const batteryLow = Number.isFinite(batteryNum) && batteryNum <= 20; - const speedNum = parseFloat(d.speed); - const statusKey = String(d.status || '').toLowerCase(); - return ( -
-
-
{d.username || `Rider #${d.userid}`}
-
- #{d.userid} - {d.status && ( - {d.status} - )} - - - {riderInfoFetching ? 'Updating…' : 'Live'} +
+ + setRiderInfoSearch(e.target.value)} + /> +
+ {(() => { + const q = riderInfoSearch.trim().toLowerCase(); + const matched = ridersAllDay.filter((r) => { + if (!q) return true; + return String(r.riderName || '').toLowerCase().includes(q) || String(r.id).includes(q); + }); + if (matched.length === 0) { + return
{riderInfoSearch ? `No riders match "${riderInfoSearch}"` : 'No riders have orders today'}
; + } + return ( +
+ {matched.map((r) => { + const isActive = String(riderInfoUserid) === String(r.id); + return ( +
- {d.logdate && ( -
- Last seen {d.logdate} -
- )} -
+ + + ); + })} +
+ ); + })()} +
-
-
-
-
-
Battery
-
- {d.battery || '—'} - {d.is_charging && Charging} +
+ {riderInfoUserid == null ? ( +
+
+
Pick a rider
+
+ Select a rider from the list on the left to see their live GPS, + battery, connection, and current order snapshot. +
+
+ ) : ( + <> + {riderInfoFetching && !riderInfoData && ( +
Loading rider snapshot…
+ )} + + {riderInfoIsError && ( +
+ Couldn't load this rider's log. {riderInfoError?.message || ''} +
+ )} + + {riderInfoData && (() => { + const d = riderInfoData; + const lat = parseFloat(d.latitude); + const lon = parseFloat(d.longitude); + const hasCoords = Number.isFinite(lat) && Number.isFinite(lon); + const batteryNum = parseInt(String(d.battery || '').replace('%', ''), 10); + const batteryLow = Number.isFinite(batteryNum) && batteryNum <= 20; + const speedNum = parseFloat(d.speed); + const statusKey = String(d.status || '').toLowerCase(); + return ( +
+
+
{d.username || `Rider #${d.userid}`}
+
+ #{d.userid} + {d.status && ( + {d.status} + )} + + + {riderInfoFetching ? 'Updating…' : 'Live'} + +
+ {d.logdate && ( +
+ Last seen {d.logdate} +
+ )} +
+ +
+
+
+
+
Battery
+
+ {d.battery || '—'} + {d.is_charging && Charging} +
+
+
+ +
+
+
+
Connection
+
{d.connection || '—'}
+
+
+ +
+
+
+
GPS Accuracy
+
{d.accuracy ? `${d.accuracy} m` : '—'}
+
+
+ +
+
+
+
Location Service
+
{d.location_service || '—'}
+
+
+ +
+
+
+
Speed
+
+ {Number.isFinite(speedNum) ? `${speedNum.toFixed(2)} km/h` : '—'} +
+
+
+ +
+
+
+
Heading
+
{d.heading != null ? `${d.heading}°` : '—'}
+
+
+ +
+
+
+
App State
+
{d.is_background ? 'Background' : 'Foreground'}
+
+
+ +
+
+
+
Current Order
+
{d.orderid || '—'}
-
-
-
-
Connection
-
{d.connection || '—'}
-
-
- -
-
-
-
GPS Accuracy
-
{d.accuracy ? `${d.accuracy} m` : '—'}
-
-
- -
-
-
-
Location Service
-
{d.location_service || '—'}
-
-
- -
-
-
-
Speed
-
- {Number.isFinite(speedNum) ? `${speedNum.toFixed(2)} km/h` : '—'} + {hasCoords && ( +
+
+ {lat.toFixed(6)}, {lon.toFixed(6)}
-
-
- -
-
-
-
Heading
-
{d.heading != null ? `${d.heading}°` : '—'}
-
-
- -
-
-
-
App State
-
{d.is_background ? 'Background' : 'Foreground'}
-
-
- -
-
-
-
Current Order
-
{d.orderid || '—'}
-
-
-
- - {hasCoords && ( -
-
- {lat.toFixed(6)}, {lon.toFixed(6)} -
-
- {/* `key` forces a remount when the rider changes so the +
+ {/* `key` forces a remount when the rider changes so the MapContainer re-centers on the new coords (leaflet's center prop is only read on mount). */} - - - - {/* Permanent banner above the pin — Nominatim + + + + {/* Permanent banner above the pin — Nominatim reverse-geocode tells the operator which suburb/area the rider is in. Falls back to a "Locating…" hint while the request is in flight so the pin never looks unlabeled. */} - - {riderInfoArea?.area || 'Locating area…'} - - -
{d.username || `Rider #${d.userid}`}
- {riderInfoArea?.area && ( -
- {riderInfoArea.area} + + {riderInfoArea?.area || 'Locating area…'} + + +
{d.username || `Rider #${d.userid}`}
+ {riderInfoArea?.area && ( +
+ {riderInfoArea.area} +
+ )} +
+ {d.logdate ? `Last seen ${d.logdate}` : `${lat.toFixed(6)}, ${lon.toFixed(6)}`}
- )} -
- {d.logdate ? `Last seen ${d.logdate}` : `${lat.toFixed(6)}, ${lon.toFixed(6)}`} -
-
- - + + + +
-
- )} -
- ); - })()} - - )} + )} +
+ ); + })()} + + )} +
-
- ) : ( -
- -