import { React, useState, useEffect, useRef } from 'react';
import axios from 'axios';
import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
// material-ui
import {
Avatar,
Backdrop,
Box,
Button,
Chip,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Divider,
Grid,
IconButton,
List,
ListItem,
Paper,
Skeleton,
Stack,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
TextField,
Tooltip,
Typography,
Autocomplete
} from '@mui/material';
import {
MdAssignment,
MdMyLocation,
MdGroups,
MdPlace,
MdDirectionsBike,
MdCalendarMonth,
MdFileDownload,
MdHourglassEmpty,
MdPersonPin,
MdLocationOn,
MdInventory2,
MdRoute,
MdSkipNext,
MdCheckCircle,
MdCancel,
MdList,
MdLocalShipping,
MdStraighten,
MdCurrencyRupee,
MdMap,
MdNoteAlt,
MdClose
} from 'react-icons/md';
import { FaCircleCheck } from 'react-icons/fa6';
import MapWithRoute from './mapWithRoute';
import CircularLoader from 'components/CircularLoader';
import { fetchDeliveries, fetchRidersList, gettenantlocations, getTenants } from 'pages/api/api';
import { CSVExport } from 'components/third-party/ReactTable';
import Loader from 'components/Loader';
import { enqueueSnackbar } from 'notistack';
import DateFilterDialog from 'components/DateFilterDialog';
import DebounceSearchBar from 'components/nearle_components/DebounceSearchBar';
import LoaderWithImage from 'components/nearle_components/LoaderWithImage';
import LocationAutocomplete from 'components/nearle_components/LocationAutocomplete';
import dayjs from 'dayjs';
import { OpenToast } from 'components/third-party/OpenToast';
import TableLoader from 'components/nearle_components/TableLoader';
var utc = require('dayjs/plugin/utc');
dayjs.extend(utc);
const opentoast = (message, variant, time) => {
enqueueSnackbar(message, {
variant: variant,
anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: time ? time : 1500
});
};
// ============================================================================
// Design tokens — shared with deliveries / tenants / customers / pricing pages.
// ============================================================================
const DT = {
radiusPill: 999,
radiusCard: 16,
shadowSoft: '0 14px 40px rgba(15, 23, 42, 0.10)',
shadowMd: '0 8px 24px rgba(15, 23, 42, 0.08)',
shadowPop: '0 18px 50px rgba(15, 23, 42, 0.18)',
textPrimary: '#0f172a',
textSecondary: '#64748b',
textMuted: '#94a3b8',
borderSubtle: '#e2e8f0',
divider: '#f1f5f9',
surface: '#ffffff',
surfaceAlt: '#f8fafc'
};
const a = (c, suffix) => `${c}${suffix}`;
const tint = (c) => a(c, '08');
const soft = (c) => a(c, '18');
const ring = (c) => a(c, '26');
const edge = (c) => a(c, '55');
const BRAND = '#662582';
const BRAND_LIGHT = '#9255AB';
const SoftPaper = (props) => (
);
const AccentAvatar = ({ color, selected, size = 24, children }) => (
{children}
);
const pillFieldSx = (color) => ({
'& .MuiOutlinedInput-root': {
borderRadius: DT.radiusPill + 'px',
bgcolor: tint(color),
fontWeight: 600,
'& fieldset': { borderColor: edge(color), borderWidth: 1.5 },
'&:hover fieldset': { borderColor: color },
'&.Mui-focused': { boxShadow: `0 0 0 3px ${ring(color)}` },
'&.Mui-focused fieldset': { borderColor: color, borderWidth: 2 }
}
});
// Status visual meta — semantic colours, NOT brand. Each lifecycle state has
// its own colour so operators can recognise it at a glance.
const STATUS_META = {
all: { label: 'All', color: BRAND, icon: MdList },
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 },
delivered: { label: 'Delivered', color: '#10b981', icon: MdCheckCircle },
skipped: { label: 'Skipped', color: '#f97316', icon: MdSkipNext },
cancelled: { label: 'Cancelled', color: '#ef4444', icon: MdCancel }
};
const STATUS_TABS = ['all', 'pending', 'accepted', 'arrived', 'picked', 'active', 'delivered', 'skipped', 'cancelled'];
// Soft pill used for metric cells (km, charges) inside the table.
const MetricPill = ({ color, icon, label, tooltip }) => (
{icon}
{label}
);
// Stamp cell — date + time stack with skeleton fallback for empty timestamps.
const StampCell = ({ value, formatDate, formatTime, success }) => {
if (!value) {
return (
);
}
return (
{formatDate(value)}
{formatTime(value)}
{success && }
);
};
// ==============================|| Orders Details ||============================== //
// Haversine distance between two [lat, lng] points in kilometers.
function haversineKm(a, b) {
const R = 6371; // km
const toRad = (d) => (d * Math.PI) / 180;
const lat1 = toRad(a[0]);
const lat2 = toRad(b[0]);
const dLat = toRad(b[0] - a[0]);
const dLon = toRad(b[1] - a[1]);
const s = Math.sin(dLat / 2) ** 2 + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2) ** 2;
return 2 * R * Math.asin(Math.min(1, Math.sqrt(s)));
}
function kalmanSmoothGps(pings, options = {}) {
if (!Array.isArray(pings) || pings.length === 0) return [];
// 1. Filter out obviously invalid coordinate pings (e.g. 0,0 or NaN)
const cleanedPings = pings.filter(p =>
Number.isFinite(p.lat) &&
Number.isFinite(p.lng) &&
(Math.abs(p.lat) > 0.1 || Math.abs(p.lng) > 0.1)
);
if (cleanedPings.length === 0) return [];
if (cleanedPings.length === 1) {
return [{ lat: cleanedPings[0].lat, lng: cleanedPings[0].lng, logdate: cleanedPings[0].logdate, _ts: cleanedPings[0]._ts }];
}
const processNoise =
options.processNoise != null ? options.processNoise : 1e-10;
const measurementNoise =
options.measurementNoise != null ? options.measurementNoise : 2e-9;
const outlierGate =
options.outlierGate != null ? options.outlierGate : 9.0;
const maxSpeedKmh =
options.maxSpeedKmh != null ? options.maxSpeedKmh : 120;
const tsOf = (p) =>
p._ts || (p.logdate ? new Date(p.logdate).getTime() : 0);
// 2. Scan forward to find the first valid starting anchor
let startIdx = 0;
while (startIdx < cleanedPings.length - 1) {
const p0 = cleanedPings[startIdx];
const p1 = cleanedPings[startIdx + 1];
const ts0 = tsOf(p0);
const ts1 = tsOf(p1) || ts0 + 1000;
const dtSec = Math.max(0.001, (ts1 - ts0) / 1000);
const km = haversineKm([p0.lat, p0.lng], [p1.lat, p1.lng]);
const speedKmh = (km / dtSec) * 3600;
if (speedKmh <= maxSpeedKmh) {
break;
} else {
// Speed is too high. Check if p1->p2 is normal (meaning p0 is the outlier)
if (startIdx + 2 < cleanedPings.length) {
const p2 = cleanedPings[startIdx + 2];
const ts2 = tsOf(p2) || ts1 + 1000;
const dtSec12 = Math.max(0.001, (ts2 - ts1) / 1000);
const km12 = haversineKm([p1.lat, p1.lng], [p2.lat, p2.lng]);
const speedKmh12 = (km12 / dtSec12) * 3600;
if (speedKmh12 <= maxSpeedKmh) {
startIdx = startIdx + 1;
continue;
}
}
startIdx++;
}
}
// 3. Teleport filter starting from the valid anchor
const accepted = [cleanedPings[startIdx]];
let lastTs = tsOf(cleanedPings[startIdx]);
for (let i = startIdx + 1; i < cleanedPings.length; i++) {
const p = cleanedPings[i];
const ts = tsOf(p) || lastTs + 1000;
const dtSec = Math.max(0.001, (ts - lastTs) / 1000);
const prev = accepted[accepted.length - 1];
const km = haversineKm([prev.lat, prev.lng], [p.lat, p.lng]);
const speedKmh = (km / dtSec) * 3600;
if (speedKmh > maxSpeedKmh) continue;
accepted.push(p);
lastTs = ts;
}
if (accepted.length < 2) {
return accepted.map((p) => ({ lat: p.lat, lng: p.lng, logdate: p.logdate, _ts: p._ts }));
}
// Run a 1D Kalman + RTS smoother over one axis. Returns smoothed
// positions parallel to `accepted`.
const smoothAxis = (axisKey) => {
const N = accepted.length;
const xPost = new Array(N);
const pPost = new Array(N);
const xPrior = new Array(N);
const pPrior = new Array(N);
const dtArr = new Array(N);
const ts0 = tsOf(accepted[0]);
const ts1 = tsOf(accepted[1]);
const dt01 = Math.max(0.1, (ts1 - ts0) / 1000);
const v0 = (accepted[1][axisKey] - accepted[0][axisKey]) / dt01;
xPost[0] = [accepted[0][axisKey], v0];
pPost[0] = [measurementNoise, 0, 0, 1];
xPrior[0] = xPost[0].slice();
pPrior[0] = pPost[0].slice();
dtArr[0] = 0;
let prevTs = ts0;
for (let i = 1; i < N; i++) {
const ts = tsOf(accepted[i]) || prevTs + 1000;
const dt = Math.max(0.1, (ts - prevTs) / 1000);
prevTs = ts;
dtArr[i] = dt;
// Predict
const [xPrev, vPrev] = xPost[i - 1];
const xPredPos = xPrev + vPrev * dt;
const xPredVel = vPrev;
const [pp00, pp01, pp10, pp11] = pPost[i - 1];
const dt2 = dt * dt;
const dt3 = dt2 * dt;
const dt4 = dt3 * dt;
const np00 = pp00 + dt * (pp01 + pp10) + dt2 * pp11 + (dt4 / 4) * processNoise;
const np01 = pp01 + dt * pp11 + (dt3 / 2) * processNoise;
const np10 = pp10 + dt * pp11 + (dt3 / 2) * processNoise;
const np11 = pp11 + dt2 * processNoise;
xPrior[i] = [xPredPos, xPredVel];
pPrior[i] = [np00, np01, np10, np11];
// Update
const z = accepted[i][axisKey];
const y = z - xPredPos;
const S = np00 + measurementNoise;
const mahal2 = (y * y) / S;
if (mahal2 > outlierGate) {
xPost[i] = [xPredPos, xPredVel];
pPost[i] = [np00, np01, np10, np11];
continue;
}
const K0 = np00 / S;
const K1 = np10 / S;
const newPos = xPredPos + K0 * y;
const newVel = xPredVel + K1 * y;
xPost[i] = [newPos, newVel];
pPost[i] = [
(1 - K0) * np00,
(1 - K0) * np01,
np10 - K1 * np00,
np11 - K1 * np01
];
}
// RTS backward smoother
const xSmooth = new Array(N);
xSmooth[N - 1] = xPost[N - 1].slice();
for (let i = N - 2; i >= 0; i--) {
const dt = dtArr[i + 1];
const [pp00, pp01, pp10, pp11] = pPost[i];
const a = pp00 + dt * pp01;
const b = pp01;
const c = pp10 + dt * pp11;
const d = pp11;
const [q00, q01, q10, q11] = pPrior[i + 1];
const det = q00 * q11 - q01 * q10;
if (!Number.isFinite(det) || Math.abs(det) < 1e-30) {
xSmooth[i] = xPost[i].slice();
continue;
}
const inv00 = q11 / det;
const inv01 = -q01 / det;
const inv10 = -q10 / det;
const inv11 = q00 / det;
const c00 = a * inv00 + b * inv10;
const c01 = a * inv01 + b * inv11;
const c10 = c * inv00 + d * inv10;
const c11 = c * inv01 + d * inv11;
const dxPos = xSmooth[i + 1][0] - xPrior[i + 1][0];
const dxVel = xSmooth[i + 1][1] - xPrior[i + 1][1];
xSmooth[i] = [
xPost[i][0] + c00 * dxPos + c01 * dxVel,
xPost[i][1] + c10 * dxPos + c11 * dxVel
];
}
return xSmooth.map((s) => s[0]);
};
const lats = smoothAxis('lat');
const lngs = smoothAxis('lng');
return accepted.map((p, i) => ({
lat: lats[i],
lng: lngs[i],
logdate: p.logdate,
_ts: p._ts
}));
}
export default function OrdersDetails() {
const loadMoreRef = useRef();
const containerRef = useRef();
const locationRef = useRef(null);
const tenantRef = useRef(null);
const userid = localStorage.getItem('userid');
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(50);
const [locaName, setLocoName] = useState('All');
const [startdate, setStartdate] = useState(dayjs().format('YYYY-MM-DD'));
const [enddate, setEnddate] = useState(dayjs().format('YYYY-MM-DD'));
const [open, setOpen] = useState(false);
const [mapOpen, setMapOpen] = useState(false);
const [datestatus, setDatestatus] = useState('Today');
const [appId, setAppId] = useState(0);
const [searchword, setSearchword] = useState('');
const [debouncedSearch, setDebouncedSearch] = useState('');
const [riderCoordinates, setRiderCoordinates] = useState([]);
const [riderStart, setRiderStart] = useState();
const [riderEnd, setRiderEnd] = useState();
const [mapTenant, setMapTenant] = useState({});
const [isLoading, setIsLoading] = useState(false);
let [total, settotal] = useState(0);
let [deliveredLenght, setDeliveredLenght] = useState(0);
let [pendingLenght, setPendingLenght] = useState(0);
let [cancelLenght, setCancelLenght] = useState(0);
let [assignLenght, setAssignLenght] = useState(0);
let [pickedLenght, setPickedLenght] = useState(0);
let [activeLenght, setActiveLenght] = useState(0);
let [arrivesLenght, setArrivedLenght] = useState(0);
let [skippedLenght, setSkippedLenght] = useState(0);
const [currentStatus, setCurrentStatus] = useState('All');
const [locationid, setLocationid] = useState(0);
const [tenantid, setTenantid] = useState(0);
const [tenantValue, setTenantValue] = useState(null);
const [locationValue, setLocationValue] = useState(null);
const [selectedRider, setSelectedRider] = useState();
const [riderValue, setRiderValue] = useState(null);
const [reportDialog, setReportDialog] = useState(false);
const [logsLoading, setLogsLoading] = useState(false);
// Map status key (lowercase) → count value from the summary endpoint.
const statusCountByKey = {
all: total,
pending: pendingLenght,
accepted: assignLenght,
arrived: arrivesLenght,
picked: pickedLenght,
active: activeLenght,
delivered: deliveredLenght,
skipped: skippedLenght,
cancelled: cancelLenght
};
// Cascading clears so changing a parent filter resets its children.
useEffect(() => {
setTenantid(0);
setTenantValue(null);
setLocationid(0);
setLocationValue(null);
setSelectedRider(null);
setRiderValue(null);
}, [appId]);
useEffect(() => {
setLocationid(0);
setLocationValue(null);
setRiderValue(null);
}, [tenantid]);
useEffect(() => {
setRiderValue(null);
}, [locationid]);
// ============== Haversine distance calculation for the map route ==============
function calculateDistance(lat1, lon1, lat2, lon2) {
const R = 6371;
const dLat = (lat2 - lat1) * (Math.PI / 180);
const dLon = (lon2 - lon1) * (Math.PI / 180);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
function calculateTotalDistance(routeCoordinates) {
let totalDistance = 0;
for (let i = 0; i < routeCoordinates.length - 1; i++) {
const { lat: lat1, lng: lon1 } = routeCoordinates[i];
const { lat: lat2, lng: lon2 } = routeCoordinates[i + 1];
totalDistance += calculateDistance(lat1, lon1, lat2, lon2);
}
return totalDistance;
}
const getdeliverylogs = async (id) => {
setLogsLoading(true);
try {
const res = await axios.get(`${process.env.REACT_APP_URL3}/deliveries/getdeliverylogs/?deliveryid=${id}`);
const datas = res.data.details;
if (Array.isArray(datas) && datas.length !== 0) {
// Sort chronologically by logdate
const sorted = datas
.map((r) => {
const ts = r?.logdate ? dayjs(r.logdate) : null;
return {
lat: parseFloat(r?.latitude ?? r?.lat),
lng: parseFloat(r?.longitude ?? r?.lng ?? r?.lon),
logdate: r?.logdate,
_ts: ts && ts.isValid() ? ts.valueOf() : Number.MAX_SAFE_INTEGER
};
})
.filter((p) => Number.isFinite(p.lat) && Number.isFinite(p.lng))
.sort((a, b) => a._ts - b._ts);
if (sorted.length !== 0) {
setRiderStart(sorted[0].logdate);
setRiderEnd(sorted[sorted.length - 1].logdate);
// Apply Kalman filter
const smoothed = kalmanSmoothGps(sorted);
const coData = smoothed.map((data) => ({ lat: data.lat, lng: data.lng }));
setRiderCoordinates(coData);
calculateTotalDistance(coData);
setMapOpen(true);
} else {
opentoast('No Valid Logs Found', 'error', 2000);
}
} else {
opentoast('No Logs Found ', 'error', 2000);
}
} catch (error) {
console.log('getdeliverylogs', error);
} finally {
setLogsLoading(false);
}
};
// ==============================|| fetchDeliveries (infinite) ||============================== //
const {
data: deliveriesData,
isLoading: fetchDeliveriesIsLoading,
isError: fetchDeliveriesIsError,
error: fetchDeliveriesError,
fetchNextPage,
hasNextPage,
isFetchingNextPage
} = useInfiniteQuery({
queryKey: [
'fetchdeliveries',
appId,
userid,
currentStatus,
startdate,
enddate,
rowsPerPage,
debouncedSearch,
tenantid,
locationid,
selectedRider?.userid || 0
],
queryFn: fetchDeliveries,
getNextPageParam: (lastPage) => lastPage.nextPage ?? undefined,
refetchOnWindowFocus: true,
refetchOnMount: true,
refetchOnReconnect: true
});
const rows = deliveriesData?.pages.flatMap((page) => page.rows) || [];
useEffect(() => {
if (!hasNextPage) return;
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
fetchNextPage();
}
},
{
root: document.querySelector('.MuiTableContainer-root'),
rootMargin: '0px',
threshold: 1.0
}
);
if (loadMoreRef.current) observer.observe(loadMoreRef.current);
return () => {
if (loadMoreRef.current) observer.unobserve(loadMoreRef.current);
};
}, [hasNextPage, fetchNextPage]);
const handleScroll = (event) => {
const { scrollTop, scrollHeight, clientHeight } = event.currentTarget;
if (scrollTop + clientHeight >= scrollHeight - 50) {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
}
};
// ==============================|| Tenant / Location / Rider lookups ||============================== //
const {
data: tenantlist,
isLoading: fetchtenantsIsLoading,
isError: fetchtenantsIsError,
error: fetchtenantsError
} = useQuery({
queryKey: ['tenantlist', appId],
queryFn: () => getTenants(appId),
enabled: appId !== 0
});
const {
data: ridersList,
isLoading: getriderbydeliveryIsLoading,
isError: getriderbydeliveryIsError,
error: getriderbydeliveryError
} = useQuery({
queryKey: ['fetchRidersList', appId],
queryFn: fetchRidersList,
enabled: appId !== 0
});
const {
data: locationlist,
isLoading: fetchlocationsIsLoading,
isError: fetchlocationsIsError,
error: fetchlocationsError
} = useQuery({
queryKey: ['gettenantlocations', tenantid],
queryFn: () => gettenantlocations(tenantid),
enabled: tenantid !== 0
});
// ==============================|| status summary counts ||============================== //
const fetchcount = async () => {
setIsLoading(true);
try {
await axios
.get(
appId == 0
? `${process.env.REACT_APP_URL}/deliveries/deliverysummary/?fromdate=${startdate}&todate=${enddate}`
: `${
process.env.REACT_APP_URL
}/deliveries/deliverysummary/?applocationid=${appId}&tenantid=${tenantid}&locationid=${locationid}&fromdate=${startdate}&todate=${enddate}&userid=${
selectedRider?.userid || 0
}`
)
.then((res) => {
settotal(res.data.details.total);
setPendingLenght(res.data.details.pending);
setAssignLenght(res.data.details.accepted);
setArrivedLenght(res.data.details.arrived);
setPickedLenght(res.data.details.picked);
setActiveLenght(res.data.details.active);
setDeliveredLenght(res.data.details.delivered);
setSkippedLenght(res.data.details.skipped);
setCancelLenght(res.data.details.cancelled);
})
.catch((err) => {
enqueueSnackbar(err.message, {
variant: 'error',
anchorOrigin: { vertical: 'top', horizontal: 'right' },
autoHideDuration: 2000
});
});
} catch (err) {
console.log(err);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
fetchcount();
}, [appId, startdate, enddate, currentStatus, tenantid, locationid, selectedRider]);
// CSV export payload — flat schema preserved for backwards compatibility.
const csvData = rows?.map((order) => ({
tenantname: order.tenantname,
tenantcity: order.tenantcity,
tenantcontactno: order.tenantcontactno,
rider: order.ridername,
orderid: order.orderid,
paymenttype: order.paymenttype == 64 ? 'Pay Later' : order.paymenttype == 42 ? 'Pay on Delivery' : 'Digital',
deliverydate: order.deliverydate,
orderstatus: order.orderstatus,
ordernotes: order.ordernotes,
kms: order.kms,
cumulativekms: order.cumulativekms,
assigntime: order.assigntime,
starttime: order.starttime,
arrivaltime: order.arrivaltime,
pickuptime: order.pickuptime,
deliverytime: order.deliverytime,
canceltime: order.canceltime,
deliverycharge: order.deliverycharges,
deliveryamt: order.deliveryamt,
pickupcustomer: order.pickupcustomer,
pickupcontactno: order.pickupcontactno,
Pickupaddress: order.pickupaddress,
pickupsuburb: order.pickupsuburb,
pickupcity: order.applocation,
pickuplat: order.pickuplat,
pickuplong: order.pickuplon,
deliverycustomer: order.deliverycustomer,
deliverycontactno: order.deliverycontactno,
deliveryaddress: order.deliveryaddress,
deliverysuburb: order.locationsuburb,
deliverylat: order.deliverylat,
deliverylong: order.deliverylong,
locationname: order.locationname,
locationsuburb: order.pickuplocation,
deliverylocation: order.deliverylocation,
locationcontactno: order.locationcontactno
}));
function formatDate(dateString) {
return dayjs(dateString).format('DD/MM/YYYY ');
}
function formatTime(dateString) {
return dayjs(dateString).format(' hh:mm A');
}
const errormessage = fetchDeliveriesIsError
? `An error has occurred: (fetchDeliveries) ${fetchDeliveriesError.message}`
: fetchtenantsIsError
? `An error has occurred: (getTenants) ${fetchtenantsError.message}`
: fetchlocationsIsError
? `An error has occurred: (gettenantlocations) ${fetchlocationsError.message}`
: getriderbydeliveryIsError
? `An error has occurred: (getriderbydelivery) ${getriderbydeliveryError.message}`
: null;
useEffect(() => {
if (errormessage) {
opentoast(errormessage, 'warning', 2000);
}
}, [errormessage]);
const KPI_META = [
{ key: 'total', label: 'Total Orders', color: BRAND, icon: MdLocalShipping, value: total },
{ key: 'delivered', label: 'Delivered', color: '#10b981', icon: MdCheckCircle, value: deliveredLenght },
{ key: 'pending', label: 'Pending', color: '#f59e0b', icon: MdHourglassEmpty, value: pendingLenght },
{ key: 'cancelled', label: 'Cancelled', color: '#ef4444', icon: MdCancel, value: cancelLenght }
];
return (
<>
{(isLoading ||
fetchtenantsIsLoading ||
fetchlocationsIsLoading ||
logsLoading ||
getriderbydeliveryIsLoading ||
isFetchingNextPage) && (
)}
{fetchDeliveriesIsLoading && (
theme.zIndex.drawer + 1
}}
open={fetchDeliveriesIsLoading}
/>
)}
{/* ============================================= || Header || ============================================= */}
Orders Details
Live · {locaName || 'All Zones'} · {datestatus}
}
placeholder="Select Zone"
paperComponent={SoftPaper}
sx={{ width: { xs: '100%', sm: 280 }, zIndex: 100 }}
/>
{/* ============================================= || KPI Cards || ============================================= */}
{KPI_META.map((item) => {
const Icon = item.icon;
return (
{item.label}
{item.value}
);
})}
{/* ============================================= || Filter Bar (tenant, location, rider, date, export) || ============================================= */}
option?.tenantname || ''}
PaperComponent={SoftPaper}
onOpen={(event) => {
if (!appId) {
event.preventDefault();
OpenToast('Please select a your app location first!', 'warning', 3000);
setTimeout(() => {
locationRef.current?.focus();
}, 0);
}
}}
onChange={(e, val, reason) => {
if (reason === 'clear') {
setTenantid(0);
setTenantValue(null);
setLocationid(0);
setLocationValue(null);
} else {
setTenantid(val?.tenantid || 0);
setTenantValue(val);
setLocationid(val.locationid);
setLocationValue(null);
}
}}
renderInput={(params) => (
)
}}
/>
)}
/>
(option ? `${option.locationname} (${option.suburb})` : '')}
value={locationValue}
PaperComponent={SoftPaper}
onOpen={(event) => {
if (!appId && !tenantid) {
event.preventDefault();
OpenToast('Please select a your Location and Tenant first!', 'warning', 3000);
setTimeout(() => {
locationRef.current?.focus();
}, 0);
} else if (!tenantid) {
event.preventDefault();
OpenToast('Please select a your Tenant first!', 'warning', 3000);
setTimeout(() => {
tenantRef.current?.focus();
}, 0);
}
}}
onChange={(e, val, reason) => {
if (reason === 'clear') {
setLocationid(0);
setLocationValue(null);
} else {
setLocationid(val.locationid || 0);
setLocationValue(val);
}
}}
renderInput={(params) => (
)
}}
/>
)}
/>
`${option.firstname} ${option.lastname}`}
PaperComponent={SoftPaper}
onOpen={() => {
if (!appId) {
OpenToast('Select App Location First', 'warning', 2000);
}
}}
onChange={(event, value, reason) => {
if (reason === 'clear') {
setSelectedRider(null);
setRiderValue(null);
} else {
setSelectedRider(value);
setRiderValue(value);
}
}}
renderInput={(params) => (
)
}}
/>
)}
/>
setOpen(true)}
sx={{
display: 'inline-flex',
alignItems: 'center',
gap: 0.75,
px: 1.25,
py: 0.75,
borderRadius: 999,
cursor: 'pointer',
bgcolor: tint('#f59e0b'),
border: `1.5px solid ${edge('#f59e0b')}`,
color: '#f59e0b',
fontWeight: 800,
fontSize: 12,
transition: 'all 0.18s',
'&:hover': { borderColor: '#f59e0b', boxShadow: `0 0 0 3px ${ring('#f59e0b')}` }
}}
>
{dayjs(startdate).format('DD/MM/YY')} – {dayjs(enddate).format('DD/MM/YY')}
}
onClick={() => {
setReportDialog(true);
setTimeout(() => {
setRowsPerPage('');
}, 0);
}}
sx={{
borderRadius: 999,
px: 1.5,
py: 0.75,
fontWeight: 800,
fontSize: 12,
textTransform: 'none',
background: `linear-gradient(135deg, ${BRAND} 0%, ${BRAND_LIGHT} 100%)`,
boxShadow: `0 6px 18px ${ring(BRAND)}`,
'&:hover': {
background: `linear-gradient(135deg, ${BRAND} 0%, ${BRAND_LIGHT} 100%)`,
boxShadow: `0 8px 22px ${ring(BRAND)}`
}
}}
>
Export
{/* ============================================= || Status Tabs + Search || ============================================= */}
{STATUS_TABS.map((key) => {
const meta = STATUS_META[key];
const Icon = meta.icon;
const active = currentStatus.toLowerCase() === key;
const count = statusCountByKey[key] ?? 0;
return (
setCurrentStatus(key === 'all' ? 'All' : key)}
sx={{
display: 'inline-flex',
alignItems: 'center',
gap: { xs: 0.625, md: 0.875 },
pl: 0.5,
pr: { xs: 1, md: 1.25 },
py: 0.5,
flexShrink: 0,
cursor: 'pointer',
borderRadius: 999,
border: `1.5px solid ${active ? meta.color : edge(meta.color)}`,
bgcolor: active ? meta.color : tint(meta.color),
color: active ? '#fff' : meta.color,
fontWeight: 700,
boxShadow: active ? `0 6px 18px ${ring(meta.color)}` : 'none',
transition: 'all 0.18s',
'&:hover': {
borderColor: meta.color,
boxShadow: active ? `0 6px 18px ${ring(meta.color)}` : `0 0 0 3px ${ring(meta.color)}`
}
}}
>
{meta.label}
{count}
);
})}
{/* ============================================= || Table || ============================================= */}
#
Map
Client
Pickup
Drop
Status / Rider
Assigned
Accepted
Arrived
Picked
Active
Delivered
Cancelled
Notes
KMS
Charges
{fetchDeliveriesIsLoading ? (
) : rows?.length == 0 ? (
No orders to show
{searchword ? 'Try a different keyword.' : 'Adjust the filters above to load orders.'}
) : (
rows?.map((row, index) => {
const statusKey = String(row.orderstatus || '').toLowerCase();
const rowStatusMeta = STATUS_META[statusKey] || {
label: row.orderstatus || '—',
color: BRAND,
icon: MdAssignment
};
const StatusIcon = rowStatusMeta.icon;
const cancelled = statusKey === 'cancelled';
return (
{String(page * rowsPerPage + index + 1).padStart(2, '0')}
{/* ====================== Map button ====================== */}
{
if (row.orderstatus === 'delivered') {
getdeliverylogs(row.deliveryid);
setMapTenant(row);
}
}}
sx={{
bgcolor: row.orderstatus === 'delivered' ? soft(BRAND) : soft('#94a3b8'),
color: row.orderstatus === 'delivered' ? BRAND : DT.textMuted,
border: `1px solid ${row.orderstatus === 'delivered' ? edge(BRAND) : edge('#94a3b8')}`,
'&:hover': {
bgcolor: row.orderstatus === 'delivered' ? BRAND : soft('#94a3b8'),
color: row.orderstatus === 'delivered' ? '#fff' : DT.textMuted
}
}}
>
{/* ====================== Client ====================== */}
{row.tenantname}
#{row.orderid}
{dayjs(row.deliverydate).utc().format('DD/MM/YYYY · hh:mm A')}
{/* ====================== Pickup ====================== */}
{row.pickupcustomer || '—'}
{row.pickupcontactno}
{row.pickupsuburb || (row.Pickupaddress ? row.Pickupaddress.slice(0, 22) + '…' : '')}
{row.applocation && (
{row.applocation}
)}
{/* ====================== Drop ====================== */}
{row.deliverycustomer || '—'}
{row.deliverycontactno}
{row.deliverysuburb || (row.deliveryaddress ? row.deliveryaddress.slice(0, 22) + '…' : '')}
{/* ====================== Status / Rider ====================== */}
{rowStatusMeta.label}
{row.ridername && (
{row.ridername}
)}
{/* ====================== Timestamps ====================== */}
{/* ====================== Notes ====================== */}
{row.ordernotes ? (
{row.ordernotes}
) : (
—
)}
{/* ====================== KMS ====================== */}
}
label={cancelled || row.kms == '' ? '0 km' : `${row.kms} km`}
tooltip="KMS"
/>
}
label={`${row.cumulativekms ?? 0} km`}
tooltip="Actual KMS"
/>
}
label={`${row.previouskms || (cancelled ? '0.00' : row.kms) || 0} km`}
tooltip="Rider KMS"
/>
{/* ====================== Charges ====================== */}
}
label={cancelled || row.deliverycharges == '' ? `0.00` : `${row.deliverycharges}.00`}
tooltip="Delivery Charge"
/>
}
label={row.deliveryamt == '' ? `0.00` : `${row.deliveryamt}.00`}
tooltip="Delivery Amount"
/>
);
})
)}
{rows?.length !== 0 && (
{isFetchingNextPage || hasNextPage ? (
) : (
No more orders
)}
)}
{/* ============================================= || Export Dialog || ============================================= */}
{/* ============================================= || Date Filter Dialog || ============================================= */}
setOpen(false)}
onSelect={(range) => {
setStartdate(range.startDate);
setEnddate(range.endDate);
setDatestatus(range.label);
}}
/>
{/* ============================================= || Map Dialog || ============================================= */}
>
);
}