feat: Doormile console Phase 2 complete

Part A: remaining api.js legacy functions replaced
  - fetchRidersList, cancelOrder/Delivery, changeRiderAPI
  - fetchPercentageAPI, fetchCountAPI → Doormile status counts
  - getpricinglist, fetchLocations, fetchRidersLogs, getusers
  - fetchPaymentType, getorderdetails

Part B: deliveries.js status tabs → Doormile statuses

Part C: 3 new pages
  - pages/nearle/hubs/Hubs.js (hub CRUD + miler counts)
  - pages/nearle/bookings/BookingDetail.js (booking detail + timeline)
  - pages/nearle/dashboard/Dashboard.js (live KPIs + city breakdown)

Part D: routes + menu updated
This commit is contained in:
2026-07-08 19:12:28 +05:30
parent b8f1cd5f1d
commit 1a71732396
8 changed files with 1323 additions and 520 deletions

View File

@@ -25,8 +25,6 @@ import {
MdCancel,
MdInventory2,
MdHourglassEmpty,
MdRoute,
MdSkipNext,
MdTune,
MdMyLocation,
MdOutlineLocalShipping,
@@ -161,30 +159,34 @@ const pillFieldSx = () => ({
'& .MuiAutocomplete-endAdornment .MuiSvgIcon-root': { color: DT.textMuted }
});
// Status palette — drives tab pills, row status badges, dialogs.
// Status palette — drives tab pills, row status badges, dialogs. Keys are
// Doormile's real booking statuses, lowercased (row.status is compared
// lowercased everywhere below so exact backend casing doesn't matter).
const STATUS_META = {
pending: { label: 'Pending', color: '#f59e0b', icon: MdHourglassEmpty },
accepted: { label: 'Accepted', color: '#6366f1', icon: MdPersonPin },
arrived: { label: 'Arrived', color: '#06b6d4', icon: MdLocationOn },
picked: { label: 'Picked', color: '#8b5cf6', icon: MdInventory2 },
active: { label: 'Active', color: '#14b8a6', icon: MdRoute },
skipped: { label: 'Skipped', color: '#f97316', icon: MdSkipNext },
delivered: { label: 'Delivered', color: '#10b981', icon: MdCheckCircle },
cancelled: { label: 'Cancelled', color: '#ef4444', icon: MdCancel }
all: { label: 'All', color: '#94a3b8', icon: MdAllInclusive },
pending_pickup: { label: 'Pending', color: '#f59e0b', icon: MdHourglassEmpty },
miler_assigned: { label: 'Assigned', color: '#6366f1', icon: MdPersonPin },
pickup_scheduled: { label: 'Scheduled', color: '#06b6d4', icon: MdHistoryToggleOff },
at_customer: { label: 'At Customer', color: '#8b5cf6', icon: MdLocationOn },
picked_up: { label: 'Picked Up', color: '#14b8a6', icon: MdInventory2 },
at_hub: { label: 'At Hub', color: '#0ea5e9', icon: MdStorefront },
delivered: { label: 'Delivered', color: '#10b981', icon: MdCheckCircle },
cancelled: { label: 'Cancelled', color: '#ef4444', icon: MdCancel }
};
// Ordered status list driving the tabs row (left → right). Each entry binds
// the visual meta above to the `currentStatus` key the queries use AND to the
// `batchCounts` key (so the chip count for the tab is one lookup).
// Ordered status list driving the tabs row (left → right). `status` is the
// lowercased key into STATUS_META/batchCounts; `apiStatus` is the exact
// casing Doormile's /admin/bookings status filter expects.
const STATUS_TABS = [
{ status: 'pending', countKey: 'uncoveredLength' },
{ status: 'accepted', countKey: 'assignedLength' },
{ status: 'arrived', countKey: 'arrivedLength' },
{ status: 'picked', countKey: 'pickedLength' },
{ status: 'active', countKey: 'activeLength' },
{ status: 'skipped', countKey: 'skippedLength' },
{ status: 'delivered', countKey: 'coveredLength' },
{ status: 'cancelled', countKey: 'cancelLength' }
{ status: 'all', apiStatus: 'all', countKey: 'all' },
{ status: 'pending_pickup', apiStatus: 'Pending_Pickup', countKey: 'pending_pickup' },
{ status: 'miler_assigned', apiStatus: 'Miler_Assigned', countKey: 'miler_assigned' },
{ status: 'pickup_scheduled', apiStatus: 'Pickup_Scheduled', countKey: 'pickup_scheduled' },
{ status: 'at_customer', apiStatus: 'At_Customer', countKey: 'at_customer' },
{ status: 'picked_up', apiStatus: 'Picked_Up', countKey: 'picked_up' },
{ status: 'at_hub', apiStatus: 'At_Hub', countKey: 'at_hub' },
{ status: 'delivered', apiStatus: 'Delivered', countKey: 'delivered' },
{ status: 'cancelled', apiStatus: 'Cancelled', countKey: 'cancelled' }
];
// KPI palette + icons — mirrors the four cards across the top of the page.
@@ -321,7 +323,7 @@ const Deliveries = () => {
const [appId, setAppId] = useState(0);
const [startdate, setStartdate] = useState(dayjs().format('YYYY-MM-DD'));
const [enddate, setEnddate] = useState(dayjs().format('YYYY-MM-DD'));
const [tabstatus, setTabstatus] = useState('Pending');
const [tabstatus, setTabstatus] = useState('All');
const [tabvalue, setTabvalue] = useState(0);
const [open, setOpen] = useState(false);
const [kms, setKms] = useState('');
@@ -331,7 +333,7 @@ const Deliveries = () => {
const [currentorder, setCurrentorder] = useState({});
const [deliverylat, setDeliverylat] = useState('');
const [deliverylong, setDeliverylong] = useState('');
const [currentStatus, setCurrentStatus] = useState('pending');
const [currentStatus, setCurrentStatus] = useState('all');
const [updateStatus, setUpdateStatus] = useState('delivered');
const locationRef = useRef(null);
const tenantRef = useRef(null);
@@ -516,40 +518,9 @@ const Deliveries = () => {
setPage(0);
setTabvalue(i);
setRowsPerPage(50);
if (i === 0) {
setTabstatus('Pending');
setCurrentStatus('pending');
}
if (i === 1) {
setTabstatus('Assigned');
setCurrentStatus('accepted');
}
if (i === 2) {
setTabstatus('Arrived');
setCurrentStatus('arrived');
}
if (i === 3) {
setTabstatus('Picked');
setCurrentStatus('picked');
}
if (i === 4) {
setTabstatus('Active');
setCurrentStatus('active');
}
if (i === 5) {
setTabstatus('Skipped');
setCurrentStatus('skipped');
}
if (i === 6) {
setTabstatus('Delivered');
setCurrentStatus('delivered');
}
if (i === 7) {
setTabstatus('Cancelled');
setCurrentStatus('cancelled');
}
console.log(i);
const tab = STATUS_TABS[i];
setTabstatus(STATUS_META[tab.status]?.label || tab.status);
setCurrentStatus(tab.apiStatus);
setSearchword('');
};
@@ -647,21 +618,10 @@ const Deliveries = () => {
const q = String(debouncedSearch || '').trim().toLowerCase();
return countSourceRows.filter((r) => {
if (selectedBatch !== 'all' && getRowBatchId(r) !== selectedBatch) return false;
const s = String(r.orderstatus || '').toLowerCase();
if (wantStatus && s !== wantStatus) return false;
const s = String(r.status || '').toLowerCase();
if (wantStatus && wantStatus !== 'all' && s !== wantStatus) return false;
if (q) {
const hay = [
r.deliverycustomer,
r.deliveryaddress,
r.deliverysuburb,
r.pickupcustomer,
r.pickupaddress,
r.pickupsuburb,
r.orderid,
r.tenantname,
r.ridername,
r.username
]
const hay = [r.bookingreference, r.bookingid, r.pickupaddress, r.deliveryaddress, r.assignedmileruserid]
.map((v) => String(v || '').toLowerCase())
.join(' ');
if (!hay.includes(q)) return false;
@@ -674,49 +634,12 @@ const Deliveries = () => {
// *Length keys returned by fetchCountAPI so the JSX swap-in is mechanical
// (countData?.uncoveredLength → batchCounts.uncoveredLength).
const batchCounts = useMemo(() => {
const c = {
uncoveredLength: 0,
assignedLength: 0,
arrivedLength: 0,
pickedLength: 0,
activeLength: 0,
skippedLength: 0,
coveredLength: 0,
cancelLength: 0
};
const c = {};
countSourceRows.forEach((r) => {
if (selectedBatch !== 'all' && getRowBatchId(r) !== selectedBatch) return;
const s = String(r.orderstatus || '').toLowerCase();
switch (s) {
case 'pending':
c.uncoveredLength += 1;
break;
case 'accepted':
case 'assigned':
c.assignedLength += 1;
break;
case 'arrived':
c.arrivedLength += 1;
break;
case 'picked':
c.pickedLength += 1;
break;
case 'active':
c.activeLength += 1;
break;
case 'skipped':
c.skippedLength += 1;
break;
case 'delivered':
c.coveredLength += 1;
break;
case 'cancelled':
case 'canceled':
c.cancelLength += 1;
break;
default:
break;
}
const s = String(r.status || '').toLowerCase();
c[s] = (c[s] || 0) + 1;
c.all = (c.all || 0) + 1;
});
return c;
}, [countSourceRows, selectedBatch]);
@@ -1433,7 +1356,7 @@ const Deliveries = () => {
{(() => {
const showAction = tabstatus !== 'Cancelled' && tabstatus !== 'Delivered';
const showSelect = tabstatus == 'Created';
const totalCols = 15 + (showAction ? 1 : 0) + (showSelect ? 1 : 0);
const totalCols = 7 + (showAction ? 1 : 0) + (showSelect ? 1 : 0);
return isMobile ? (
/* ===================== MOBILE: card list ===================== */
<MobileCardList sx={{ p: 1.25 }}>
@@ -1461,15 +1384,14 @@ const Deliveries = () => {
</Stack>
)}
{filteredRows.map((row, index) => {
const rowStatusMeta = STATUS_META[String(row.orderstatus || '').toLowerCase()] || {
label: row.orderstatus || '—',
const rowStatusMeta = STATUS_META[String(row.status || '').toLowerCase()] || {
label: row.status || '—',
color: '#94a3b8',
icon: MdHistoryToggleOff
};
const RowStatusIcon = rowStatusMeta.icon;
const isSelected = !!deliverylist.find((res1) => res1.orderheaderid == row.orderheaderid);
const isOpen = productCollapse?.orderid === row?.orderid;
const chipSx = (c) => ({ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', color: c, fontWeight: 700, fontSize: 12, whiteSpace: 'nowrap' });
return (
<MobileCard
key={row.orderheaderid ?? `${row.tenantname}-${index}`}
@@ -1551,54 +1473,35 @@ const Deliveries = () => {
</Stack>
<Box sx={{ minWidth: 0 }}>
<Typography sx={{ fontWeight: 800, color: DT.textPrimary, fontSize: 15 }} noWrap>
{row.tenantname}
{row.bookingreference || `#${row.bookingid}`}
</Typography>
<Typography variant="caption" sx={{ color: DT.textSecondary }} noWrap>
{[row.tenantsuburb, row.applocation].filter(Boolean).join(' · ') || '—'}
{row.createdat ? dayjs(row.createdat).format('DD/MM/YYYY hh:mm A') : '—'}
</Typography>
</Box>
</Stack>
}
>
<MobileFieldGrid>
<MobileField label="Order / Location" full>
<MobileField label="Pickup" full>
<Typography sx={{ fontSize: 13, fontWeight: 600, color: DT.textPrimary }} noWrap>
{`${row.locationname}-(${row.locationsuburb})`}
</Typography>
<Typography variant="caption" sx={{ color: DT.textSecondary }}>
{row.orderid} · {row.deliveryid}
{row.pickupaddress || '—'}
</Typography>
</MobileField>
<MobileField label="Pickup">
<MobileField label="Delivery" full>
<Typography sx={{ fontSize: 13, fontWeight: 600, color: DT.textPrimary }} noWrap>
{row.pickupcustomer || '—'}
</Typography>
<Typography variant="caption" sx={{ color: DT.textSecondary }} noWrap>
{row.pickupcontactno}
{row.deliveryaddress || '—'}
</Typography>
</MobileField>
<MobileField label="Drop">
<Typography sx={{ fontSize: 13, fontWeight: 600, color: DT.textPrimary }} noWrap>
{row.deliverycustomer || '—'}
</Typography>
<Typography variant="caption" sx={{ color: DT.textSecondary }} noWrap>
{row.deliverycontactno}
</Typography>
</MobileField>
<MobileField label="Rider" full>
{row.ridername ? (
<MobileField label="Miler" full>
{row.assignedmileruserid ? (
<Stack direction="row" alignItems="center" spacing={1}>
<AccentAvatar color="#8b5cf6" size={24}>
<MdDirectionsBike size={13} />
</AccentAvatar>
<Stack sx={{ minWidth: 0 }}>
<Typography sx={{ fontSize: 13, fontWeight: 700, color: DT.textPrimary }} noWrap>
{row.ridername}
</Typography>
<Typography variant="caption" sx={{ color: DT.textSecondary }} noWrap>
ID #{row.userid} · {row.ridercontact || '—'}
</Typography>
</Stack>
<Typography sx={{ fontSize: 13, fontWeight: 700, color: DT.textPrimary }} noWrap>
#{row.assignedmileruserid}
</Typography>
</Stack>
) : (
<Typography variant="caption" sx={{ color: DT.textMuted, fontWeight: 600 }}>
@@ -1606,40 +1509,6 @@ const Deliveries = () => {
</Typography>
)}
</MobileField>
<MobileField label="ETA" value={row.expecteddeliverytime ? dayjs(row.expecteddeliverytime).format('hh:mm A') : '—'} />
<MobileField label="Transit">
<Box sx={chipSx('#06b6d4')}>{row.transitminutes || 0}m</Box>
</MobileField>
<MobileField label="Kms · plan / act">
<Stack direction="row" spacing={0.5} flexWrap="wrap" useFlexGap>
<Box sx={chipSx('#ef4444')}>{row.kms || 0} km</Box>
<Box sx={chipSx('#10b981')}>{row.cumulativekms || 0} km</Box>
</Stack>
</MobileField>
<MobileField label="Amount · chg / amt">
<Stack direction="row" spacing={0.5} flexWrap="wrap" useFlexGap>
<Box sx={chipSx('#ef4444')}> {row.deliverycharges?.toFixed(2) ?? '0.00'}</Box>
<Box sx={chipSx('#10b981')}> {row.deliveryamt?.toFixed(2) ?? '0.00'}</Box>
</Stack>
</MobileField>
<MobileField label="Qty" value={row.Quantity || '—'} />
<MobileField label="COD">
<Typography sx={{ fontSize: 13, fontWeight: 800, color: row.collectionamt ? '#ef4444' : DT.textMuted }}>
{row.collectionamt ? `${row.collectionamt.toFixed(2)}` : '—'}
</Typography>
</MobileField>
<MobileField label="Step">
{row.step ? (
<Box sx={{ ...chipSx('#C01227'), minWidth: 30, fontWeight: 800 }}>{row.step}</Box>
) : (
<Typography variant="caption" sx={{ color: DT.textMuted }}></Typography>
)}
</MobileField>
{row.notes && (
<MobileField label="Notes" full>
<Typography variant="caption" sx={{ color: DT.textSecondary }}>{row.notes}</Typography>
</MobileField>
)}
</MobileFieldGrid>
{isOpen && (
<Box sx={{ mt: 1.5, p: 1.25, borderRadius: 2, bgcolor: DT.surfaceAlt, border: `1px solid ${DT.divider}` }}>
@@ -1726,19 +1595,11 @@ const Deliveries = () => {
)}
<TableCell>#</TableCell>
<TableCell>Status</TableCell>
<TableCell>Tenant</TableCell>
<TableCell>Order / Location</TableCell>
<TableCell>Booking</TableCell>
<TableCell>Pickup</TableCell>
<TableCell>Drop</TableCell>
<TableCell>Rider</TableCell>
<TableCell>ETA</TableCell>
<TableCell>Transit</TableCell>
<TableCell>Kms</TableCell>
<TableCell>Amount</TableCell>
<TableCell>Notes</TableCell>
<TableCell>Step</TableCell>
<TableCell>Qty</TableCell>
<TableCell>COD</TableCell>
<TableCell>Delivery</TableCell>
<TableCell>Miler</TableCell>
<TableCell>Created</TableCell>
{showAction && <TableCell align="right">Action</TableCell>}
</TableRow>
</TableHead>
@@ -1774,8 +1635,8 @@ const Deliveries = () => {
</TableRow>
)}
{filteredRows.map((row, index) => {
const rowStatusMeta = STATUS_META[String(row.orderstatus || '').toLowerCase()] || {
label: row.orderstatus || '—',
const rowStatusMeta = STATUS_META[String(row.status || '').toLowerCase()] || {
label: row.status || '—',
color: '#94a3b8',
icon: MdHistoryToggleOff
};
@@ -1856,108 +1717,38 @@ const Deliveries = () => {
</Typography>
</Stack>
</TableCell>
{/* Tenants */}
{/* Booking */}
<TableCell>
<Tooltip title={row.tenantadress}>
<Stack>
<Typography noWrap variant="subtitle2" sx={{ fontWeight: 700, color: DT.textPrimary }}>
{row.tenantname}
</Typography>
<Typography noWrap variant="caption" sx={{ color: DT.textSecondary }}>
{row.tenantsuburb}
</Typography>
<Typography noWrap variant="caption" sx={{ color: DT.textMuted }}>
{row.applocation}
</Typography>
</Stack>
<Typography variant="subtitle2" sx={{ fontWeight: 700, color: DT.textPrimary }} noWrap>
{row.bookingreference || `#${row.bookingid}`}
</Typography>
</TableCell>
{/* Pickup */}
<TableCell sx={{ maxWidth: 220 }}>
<Tooltip title={row.pickupaddress || ''} placement="top">
<Typography variant="body2" noWrap>
{row.pickupaddress || '—'}
</Typography>
</Tooltip>
</TableCell>
{/* order details */}
<TableCell align="left">
<Tooltip title="Location Name-Suburb" placement="top">
<Typography variant="subtitle1" noWrap>
{`${row.locationname}-(${row.locationsuburb})`}
{/* Delivery */}
<TableCell sx={{ maxWidth: 220 }}>
<Tooltip title={row.deliveryaddress || ''} placement="top">
<Typography variant="body2" noWrap>
{row.deliveryaddress || '—'}
</Typography>
</Tooltip>
<Stack display={'flex'} flexDirection={'row'} gap={3}>
<Stack>
<Tooltip title="Order Id" placement="top">
<Typography variant="body2" noWrap>
{row.orderid}
</Typography>
</Tooltip>
<Tooltip title="Ordered date" placement="top">
<Typography noWrap sx={{ fontSize: '12px' }}>
{dayjs(row.orderdate).utc().format('DD/MM/YYYY')}
</Typography>
<Typography noWrap sx={{ fontSize: '11px' }}>
{dayjs(row.orderdate).utc().format('hh:mm A')}
</Typography>
</Tooltip>
</Stack>
-
<Stack>
<Tooltip title="Delivery Id" placement="top">
<Typography variant="body2" noWrap>
{row.deliveryid}
</Typography>
</Tooltip>
<Tooltip title="Delivery date" placement="top">
<Typography noWrap sx={{ fontSize: '12px' }}>
{dayjs(row.deliverydate).utc().format('DD/MM/YYYY')}
</Typography>
<Typography noWrap sx={{ fontSize: '11px' }}>
{dayjs(row.deliverydate).utc().format('hh:mm A')}
</Typography>
</Tooltip>
</Stack>
</Stack>
</TableCell>
{/* pickup */}
<TableCell align="left">
<Stack>
<Typography variant="subtitle2" sx={{ fontWeight: 700, color: DT.textPrimary, whiteSpace: 'nowrap' }}>
{row.pickupcustomer}
</Typography>
<Typography variant="caption" sx={{ color: DT.textSecondary }}>{row.pickupcontactno}</Typography>
<Tooltip title={row.Pickupaddress} sx={{ whiteSpace: 'nowrap' }}>
<Typography variant="caption" sx={{ color: DT.textMuted }}>
{row.pickuplocation || (row.Pickupaddress ? row.Pickupaddress.slice(0, 14) + '…' : '—')}
</Typography>
</Tooltip>
</Stack>
</TableCell>
{/* drop */}
<TableCell align="left">
<Stack>
<Typography variant="subtitle2" sx={{ fontWeight: 700, color: DT.textPrimary, whiteSpace: 'nowrap' }}>
{row.deliverycustomer}
</Typography>
<Typography variant="caption" sx={{ color: DT.textSecondary }}>{row.deliverycontactno}</Typography>
<Tooltip title={row.deliveryaddress}>
<Typography variant="caption" sx={{ color: DT.textMuted, whiteSpace: 'nowrap' }}>
{row.deliverylocation || (row.deliveryaddress ? row.deliveryaddress.slice(0, 14) + '…' : '—')}
</Typography>
</Tooltip>
</Stack>
</TableCell>
{/* rider */}
{/* Miler */}
<TableCell>
{row.ridername ? (
{row.assignedmileruserid ? (
<Stack direction="row" alignItems="center" spacing={1}>
<AccentAvatar color="#8b5cf6" size={28}>
<MdDirectionsBike size={14} />
</AccentAvatar>
<Stack>
<Typography variant="subtitle2" sx={{ fontWeight: 700, color: DT.textPrimary }} noWrap>
{row.ridername}
</Typography>
<Typography variant="caption" sx={{ color: DT.textSecondary }}>
ID #{row.userid} · {row.ridercontact || '—'}
</Typography>
</Stack>
<Typography variant="subtitle2" sx={{ fontWeight: 700, color: DT.textPrimary }} noWrap>
#{row.assignedmileruserid}
</Typography>
</Stack>
) : (
<Typography variant="caption" sx={{ color: DT.textMuted, fontWeight: 600 }}>
@@ -1965,116 +1756,10 @@ const Deliveries = () => {
</Typography>
)}
</TableCell>
{/* Estimated Delivery Time */}
<TableCell align="left">
<Typography variant="subtitle2" sx={{ fontWeight: 700, color: DT.textPrimary, whiteSpace: 'nowrap' }}>
{row.expecteddeliverytime ? dayjs(row.expecteddeliverytime).format('hh:mm A') : '—'}
</Typography>
</TableCell>
{/* Transit Minutes */}
<TableCell align="left">
<Box
sx={{
display: 'inline-flex',
alignItems: 'center',
gap: 0.5,
px: 1,
py: 0.5,
borderRadius: 999,
bgcolor: tint('#06b6d4'),
color: '#06b6d4',
fontWeight: 700,
fontSize: 12,
border: `1px solid ${edge('#06b6d4')}`
}}
>
{row.transitminutes || 0}m
</Box>
</TableCell>
{/* kms */}
{/* Created */}
<TableCell>
<Stack direction="column" spacing={0.5} alignItems="flex-start">
<Tooltip title="Planned KMS" placement="top">
<Box sx={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', px: 1.25, py: 0.375, borderRadius: 999, bgcolor: tint('#ef4444'), color: '#ef4444', fontWeight: 700, fontSize: 11, border: `1px solid ${edge('#ef4444')}`, whiteSpace: 'nowrap', minWidth: 75 }}>
{row.kms || 0} km
</Box>
</Tooltip>
<Tooltip title="Actual KMS" placement="top">
<Box sx={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', px: 1.25, py: 0.375, borderRadius: 999, bgcolor: tint('#10b981'), color: '#10b981', fontWeight: 700, fontSize: 11, border: `1px solid ${edge('#10b981')}`, whiteSpace: 'nowrap', minWidth: 75 }}>
{row.cumulativekms || 0} km
</Box>
</Tooltip>
</Stack>
</TableCell>
{/* amount */}
<TableCell align="left">
<Stack direction="column" spacing={0.5} alignItems="flex-start">
<Tooltip title="Delivery Charge" placement="top">
<Box sx={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', px: 1.25, py: 0.375, borderRadius: 999, bgcolor: tint('#ef4444'), color: '#ef4444', fontWeight: 700, fontSize: 11, border: `1px solid ${edge('#ef4444')}`, whiteSpace: 'nowrap', minWidth: 85 }}>
{row.deliverycharges?.toFixed(2) ?? '0.00'}
</Box>
</Tooltip>
<Tooltip title="Delivery Amount" placement="top">
<Box sx={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', px: 1.25, py: 0.375, borderRadius: 999, bgcolor: tint('#10b981'), color: '#10b981', fontWeight: 700, fontSize: 11, border: `1px solid ${edge('#10b981')}`, whiteSpace: 'nowrap', minWidth: 85 }}>
{row.deliveryamt?.toFixed(2) ?? '0.00'}
</Box>
</Tooltip>
</Stack>
</TableCell>
{/* notes */}
<TableCell>
{row.notes ? (
<Tooltip title={row.notes}>
<Typography variant="caption" sx={{ color: DT.textSecondary, maxWidth: 160, display: 'inline-block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
{row.notes}
</Typography>
</Tooltip>
) : (
<Typography variant="caption" sx={{ color: DT.textMuted }}></Typography>
)}
</TableCell>
{/* step */}
<TableCell align="center">
{row.step ? (
<Box
sx={{
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
minWidth: 30,
height: 24,
px: 0.875,
borderRadius: 999,
bgcolor: tint('#C01227'),
border: `1px solid ${edge('#C01227')}`,
color: '#C01227',
fontWeight: 800,
fontSize: 11
}}
>
{row.step}
</Box>
) : (
<Typography variant="caption" sx={{ color: DT.textMuted }}></Typography>
)}
</TableCell>
{/* qty */}
<TableCell>
<Typography variant="subtitle2" sx={{ fontWeight: 700, color: row.Quantity ? DT.textPrimary : DT.textMuted, whiteSpace: 'nowrap' }}>
{row.Quantity || '—'}
</Typography>
</TableCell>
{/* COD */}
<TableCell>
<Typography
variant="subtitle2"
sx={{
fontWeight: 800,
color: row.collectionamt ? '#ef4444' : DT.textMuted,
whiteSpace: 'nowrap'
}}
>
{row.collectionamt ? `${row.collectionamt.toFixed(2)}` : '—'}
<Typography variant="caption" sx={{ color: DT.textSecondary }} noWrap>
{row.createdat ? dayjs(row.createdat).format('DD/MM/YYYY hh:mm A') : '—'}
</Typography>
</TableCell>
{/* Action */}
@@ -2278,7 +1963,7 @@ const Deliveries = () => {
}
}}
>
{selectedRow?.orderstatus !== 'delivered' && (
{String(selectedRow?.status || '').toLowerCase() !== 'delivered' && (
<MenuItem
onClick={() => {
notifyRiderMutation.mutate(selectedRow.userfcmtoken);
@@ -2289,7 +1974,9 @@ const Deliveries = () => {
Notify Rider
</MenuItem>
)}
{['pending', 'accepted', 'arrived'].includes(selectedRow?.orderstatus) && (
{['pending_pickup', 'miler_assigned', 'pickup_scheduled', 'at_customer'].includes(
String(selectedRow?.status || '').toLowerCase()
) && (
<MenuItem
onClick={() => {
if (!appId) {
@@ -2314,7 +2001,7 @@ const Deliveries = () => {
setDeliverylong(selectedRow.droplon);
setNotes(selectedRow.notes);
setDeliveryamount(selectedRow.deliveryamount);
setUpdateStatus(selectedRow.orderstatus || 'delivered');
setUpdateStatus(selectedRow.status || 'delivered');
setCurrentorder(selectedRow);
setDialogopen(true);
handleMenuClose();
@@ -2324,7 +2011,7 @@ const Deliveries = () => {
Update Status
</MenuItem>
)}
{selectedRow?.orderstatus !== 'cancelled' && selectedRow?.orderstatus !== 'delivered' && (
{!['cancelled', 'delivered'].includes(String(selectedRow?.status || '').toLowerCase()) && (
<MenuItem
sx={{ color: '#ef4444 !important' }}
onClick={() => {