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:
@@ -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={() => {
|
||||
|
||||
Reference in New Issue
Block a user