diff --git a/src/pages/nearle/reports/ordersSummary.js b/src/pages/nearle/reports/ordersSummary.js
index 4cd3ea3..9544ba2 100644
--- a/src/pages/nearle/reports/ordersSummary.js
+++ b/src/pages/nearle/reports/ordersSummary.js
@@ -1,56 +1,206 @@
-import { React, useState, useEffect, useRef } from 'react';
-import TitleCard from 'pages/titleCard';
+import React, { useState, useEffect, useMemo, useRef } from 'react';
import axios from 'axios';
import { useQuery } from '@tanstack/react-query';
-import { Empty } from 'antd';
+
// material-ui
import {
+ Autocomplete,
+ Avatar,
Box,
+ Chip,
+ Collapse,
Divider,
+ Grid,
+ IconButton,
+ Paper,
+ Stack,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
- Typography,
- Stack,
- IconButton,
+ TextField,
Tooltip,
- Chip,
- Autocomplete,
- TextField
+ Typography
} from '@mui/material';
-import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
-import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
+import {
+ MdAssignment,
+ MdCalendarMonth,
+ MdCancel,
+ MdCheckCircle,
+ MdCurrencyRupee,
+ MdExpandLess,
+ MdExpandMore,
+ MdGroups,
+ MdHourglassEmpty,
+ MdLocalShipping,
+ MdLocationOn,
+ MdMyLocation,
+ MdPerson,
+ MdReceiptLong,
+ MdStraighten,
+ MdStore
+} from 'react-icons/md';
+
import dayjs from 'dayjs';
var utc = require('dayjs/plugin/utc');
dayjs.extend(utc);
-import { CalendarMonth } from '@mui/icons-material';
+
import { getreportlocationsummary, getreportsummary, gettenantlocations, getTenants } from 'pages/api/api';
-import MainCard from 'components/MainCard';
import Loader from 'components/Loader';
-import { useTheme } from '@mui/material/styles';
import DateFilterDialog from 'components/DateFilterDialog';
import LocationAutocomplete from 'components/nearle_components/LocationAutocomplete';
-import { OpenToast } from 'components/third-party/OpenToast';
+import DebounceSearchBar from 'components/nearle_components/DebounceSearchBar';
import { OrdersTableSkeleton } from '../orders/OrdersTableSkeleton';
+import { OpenToast } from 'components/third-party/OpenToast';
+
+// ============================================================================
+// Design tokens — shared with deliveries / ridersSummary / customers /
+// tenants 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}
+
+);
+
+// Pill used in cells for km / amount metrics.
+const MetricPill = ({ color, icon, label, tooltip, minWidth = 80 }) => (
+
+
+ {icon}
+ {label}
+
+
+);
+
+// Coloured numeric cell — non-zero values get a soft accent badge to draw
+// the eye, preserving the legacy "red when present" affordance with the
+// modern soft-pill aesthetic.
+const CountCell = ({ value, color = '#ef4444', icon }) => {
+ const n = Number(value) || 0;
+ if (n === 0) {
+ return (
+
+ 0
+
+ );
+ }
+ return (
+
+ {icon}
+ {n}
+
+ );
+};
+
+// Pill-style filter inputs for the Tenant / Location autocompletes.
+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 }
+ }
+});
function formatNumberToRupees(value) {
return new Intl.NumberFormat('en-IN', {
style: 'currency',
currency: 'INR',
minimumFractionDigits: 2
- }).format(value);
+ }).format(Number(value) || 0);
}
-// ==============================|| MUI TABLE - ENHANCED ||============================== //
-
+// ============================================================================
+// Orders Summary
+// ============================================================================
export default function OrdersReport() {
- // const [rows, setRows] = useState([]);
- const theme = useTheme();
const locationRef = useRef(null);
const tenantRef = useRef(null);
+
const [appId, setAppId] = useState(0);
const [startdate, setStartdate] = useState(dayjs().format('YYYY-MM-DD'));
const [enddate, setEnddate] = useState(dayjs().format('YYYY-MM-DD'));
@@ -58,28 +208,17 @@ export default function OrdersReport() {
const [open, setOpen] = useState(false);
const [openRow, setOpenRow] = useState(null);
const [datestatus, setDatestatus] = useState('Today');
- const [total, settotal] = useState(0);
- const [totalOrders, settotalOrders] = useState(0);
- const [totalOrderPend, setTotalOrderPend] = useState(0);
- const [totalOrderComplete, setTotalOrderComplete] = useState(0);
- const [totalOrderCancel, setTotalOrderCancel] = useState(0);
- const [totalDeliPend, setTotalDeliPend] = useState(0);
- const [totalDeliComplete, setTotalDeliComplete] = useState(0);
- const [totalDeliCancel, setTotalDeliCancel] = useState(0);
const [ridersdata, setRidersdata] = useState([]);
- const userid = localStorage.getItem('userid');
const [loading, setLoading] = useState(false);
const [locationid, setLocationid] = useState(0);
const [tenantid, setTenantid] = useState(0);
const [tenantValue, setTenantValue] = useState(null);
const [locationValue, setLocationValue] = useState(null);
- const [page, setPage] = useState(0);
+ const [searchword, setSearchword] = useState('');
+ const [debouncedSearch, setDebouncedSearch] = useState('');
+ const [, setPage] = useState(0);
- useEffect(() => {
- console.log('openRow', openRow);
- }, [openRow]);
-
- // to clear the tenant and location and rider autocomplete
+ // Clear nested filters when scope widens.
useEffect(() => {
setTenantid(0);
setTenantValue(null);
@@ -87,839 +226,998 @@ export default function OrdersReport() {
setLocationValue(null);
setOpenRow(null);
}, [appId]);
- // to clear the location and rider autocomplete
+
useEffect(() => {
setLocationid(0);
setLocationValue(null);
setOpenRow(null);
}, [tenantid]);
- // table header
- const headCells = [
- {
- id: 's.no',
- numeric: false,
- disablePadding: true,
- label: '#',
- rowSpan: 2,
- colSpan: 1,
- bgcolor: '#f3e5f5'
- },
- {
- id: 'clients',
- numeric: 'true',
- disablePadding: false,
- label: tenantid ? 'Location' : 'Tenant',
- rowSpan: 2,
- colSpan: 1,
- bgcolor: '#f3e5f5'
- },
- {
- id: 'all',
- numeric: 'center',
- disablePadding: false,
- label: 'All',
- rowSpan: 2,
- colSpan: 1,
- bgcolor: '#f3e5f5'
- },
-
- {
- id: 'orders',
- numeric: 'center',
- disablePadding: false,
- label: 'orders',
- rowSpan: 1,
- colSpan: 3,
- bgcolor: '#ffcdd2'
- },
- {
- id: 'deliveries',
- numeric: 'center',
- disablePadding: false,
- label: 'deliveries',
- rowSpan: 1,
- colSpan: 3,
- bgcolor: '#f8bbd0'
- },
- {
- id: 'Charges',
- numeric: 'center',
- disablePadding: false,
- label: 'Collection Amt',
- rowSpan: 2,
- colSpan: 1,
- bgcolor: '#f3e5f5'
- },
- {
- id: 'kilometer',
- numeric: 'center',
- disablePadding: false,
- label: 'Kms/Actual Kms',
- rowSpan: 2,
- colSpan: 1,
- bgcolor: '#f3e5f5'
- },
-
- {
- id: 'Amount',
- numeric: 'center',
- disablePadding: true,
- label: 'Amount',
- rowSpan: 2,
- colSpan: 1,
- bgcolor: '#f3e5f5'
- },
- {
- id: 'action',
- numeric: 'center',
- disablePadding: true,
- label: 'Action',
- rowSpan: 2,
- colSpan: 1,
- bgcolor: '#f3e5f5'
- }
- ];
-
- const headCells1 = [
- {
- id: 'pending',
- numeric: false,
- disablePadding: false,
- label: 'pending',
- rowSpan: 1,
- colSpan: 1,
- bgcolor: '#ffcdd2'
- },
- {
- id: 'cancelled',
- numeric: false,
- disablePadding: false,
- label: 'cancelled',
- rowSpan: 1,
- colSpan: 1,
- bgcolor: '#ffcdd2'
- },
- {
- id: 'completed',
- numeric: false,
- disablePadding: false,
- label: 'completed',
- rowSpan: 1,
- colSpan: 1,
- bgcolor: '#ffcdd2'
- },
-
- {
- id: 'pending',
- numeric: false,
- disablePadding: false,
- label: 'pending',
- rowSpan: 1,
- colSpan: 1,
- bgcolor: '#f8bbd0'
- },
-
- {
- id: 'cancelled',
- numeric: false,
- disablePadding: false,
- label: 'cancelled',
- rowSpan: 1,
- colSpan: 1,
- bgcolor: '#f8bbd0'
- },
- {
- id: 'completed',
- numeric: false,
- disablePadding: false,
- label: 'completed',
- rowSpan: 1,
- colSpan: 1,
- bgcolor: '#f8bbd0'
- }
- ];
- const getColorByValue = (value) => {
- return Number(value) !== 0 ? 'red' : 'inherit';
- };
- const coloredCell = (value) => {value};
-
- // ==============================|| MUI TABLE - HEADER ||============================== //
-
- function EnhancedTableHead() {
- return (
-
-
- {headCells.map((headCell) => (
-
- {headCell.label}
-
- ))}
-
-
- {headCells1.map((headCell) => (
-
- {headCell.label}
-
- ))}
-
-
- );
- }
-
- // ==============================|| fetchOrdersSummary (orders summary)||============================== //
+ // ==============================|| primary summary query ||============================== //
+ // The api.js destructure expects [appId, tenantid, locationid, startdate, enddate]
+ // — do NOT prepend a name slot without updating api.js in lockstep.
const {
data: rows,
isLoading: isLoadingReports,
- isError: isErrorReports, //true or false
+ isError: isErrorReports,
error: reportsError
} = useQuery({
queryKey: [appId, tenantid, locationid, startdate, enddate],
queryFn: tenantid ? getreportlocationsummary : getreportsummary
});
- // ==============================|| getTenants ||============================== //
- const {
- data: tenantlist
- } = useQuery({
+ // ==============================|| tenant list ||============================== //
+ const { data: tenantlist } = useQuery({
queryKey: ['tenantlist', appId],
- queryFn: () => getTenants(appId), // Ensure appId is passed
- enabled: appId !== 0 // Ensures query runs only when appId is valid
+ queryFn: () => getTenants(appId),
+ enabled: appId !== 0
});
- // ==============================|| gettenantlocations ||============================== //
- const {
- data: locationlist
- } = useQuery({
+ // ==============================|| tenant locations ||============================== //
+ const { data: locationlist } = useQuery({
queryKey: ['gettenantlocations', tenantid],
- queryFn: () => gettenantlocations(tenantid), // Ensure appId is passed
- enabled: tenantid !== 0 // Ensures query runs only when appId is valid
+ queryFn: () => gettenantlocations(tenantid),
+ enabled: tenantid !== 0
});
- // ==============================|| fetchridersummary by tenid (orders summary)||============================== //
- // ==============================|| getuserreportsummary by tenid (orders summary)||============================== //
- const getuserreportsummary = async (tenantid) => {
+ // Defensive: backend sometimes returns null for empty results.
+ const safeRows = useMemo(() => (Array.isArray(rows) ? rows : []), [rows]);
+
+ // Client-side filter on tenant / location name.
+ const filteredRows = useMemo(() => {
+ if (!debouncedSearch) return safeRows;
+ const q = debouncedSearch.toLowerCase().trim();
+ return safeRows.filter((r) =>
+ [r.tenantname, r.locationname, String(r.tenantid || ''), String(r.locationid || '')]
+ .filter(Boolean)
+ .some((field) => String(field).toLowerCase().includes(q))
+ );
+ }, [safeRows, debouncedSearch]);
+
+ // KPIs + grand total derived directly from the loaded summary.
+ const stats = useMemo(() => {
+ return filteredRows.reduce(
+ (acc, row) => {
+ acc.totalOrders += Number(row.totalorders) || 0;
+ acc.orderPend += Number(row.Orderspending) || 0;
+ acc.orderComplete += Number(row.orderscompleted) || 0;
+ acc.orderCancel += Number(row.orderscancelled) || 0;
+ acc.deliPend += Number(row.deliveriespending) || 0;
+ acc.deliComplete += Number(row.deliveriescompleted) || 0;
+ acc.deliCancel += Number(row.deliveriescancelled) || 0;
+ acc.collection += Number(row.collectionamt) || 0;
+ acc.kms += Number(row.kms) || 0;
+ acc.cumulativekms += Number(row.cumulativekms) || 0;
+ acc.amount += Math.max(Number(row.charges) || 0, Number(row.deliveryamt) || 0);
+ return acc;
+ },
+ {
+ totalOrders: 0,
+ orderPend: 0,
+ orderComplete: 0,
+ orderCancel: 0,
+ deliPend: 0,
+ deliComplete: 0,
+ deliCancel: 0,
+ collection: 0,
+ kms: 0,
+ cumulativekms: 0,
+ amount: 0
+ }
+ );
+ }, [filteredRows]);
+
+ // ==============================|| per-tenant rider breakdown ||============================== //
+ const getuserreportsummary = async (tenantId) => {
setLoading(true);
try {
- const riderRes = await axios.get(
- `${process.env.REACT_APP_URL}/deliveries/getuserreportsummary/?&tenantid=${tenantid}&fromdate=${startdate}&todate=${enddate}`
+ const res = await axios.get(
+ `${process.env.REACT_APP_URL}/deliveries/getuserreportsummary/?tenantid=${tenantId}&fromdate=${startdate}&todate=${enddate}`
);
- console.log('riderRes', riderRes.data.details);
- setRidersdata(riderRes.data.details);
- } catch (error) {
- console.log('riderRes', error);
+ setRidersdata(Array.isArray(res.data?.details) ? res.data.details : []);
+ } catch (err) {
+ OpenToast(err?.message || 'Failed to load rider breakdown', 'error', 2000);
+ setRidersdata([]);
} finally {
setLoading(false);
}
};
- // ==============================|| getriderlocationsummary by tenid (orders summary)||============================== //
- const getriderlocationsummary = async (id) => {
+
+ // ==============================|| per-location rider breakdown ||============================== //
+ const getriderlocationsummary = async (locId) => {
+ setLoading(true);
try {
- const riderRes = await axios.get(
- `${process.env.REACT_APP_URL}/deliveries/getriderlocationsummary/?&tenantid=${tenantid}&locationid=${id}&fromdate=${startdate}&todate=${enddate}`
+ const res = await axios.get(
+ `${process.env.REACT_APP_URL}/deliveries/getriderlocationsummary/?tenantid=${tenantid}&locationid=${locId}&fromdate=${startdate}&todate=${enddate}`
);
- console.log('riderRes', riderRes.data.details);
- setRidersdata(riderRes.data.details);
- } catch (error) {
- console.log('riderRes', error);
- }
- };
-
- // ==============================|| calculate||============================== //
- const calculate = () => {
- let calculatedTotal = 0;
- let ordersTotal = 0;
- let Orderpending = 0;
- let OrderComplete = 0;
- let OrderCancel = 0;
- let deliverypending = 0;
- let deliverycomplete = 0;
- let deliverycancel = 0;
- rows &&
- rows.forEach((row) => {
- calculatedTotal += row.charges;
- ordersTotal += row.totalorders;
- Orderpending += row.Orderspending;
- OrderComplete += row.orderscompleted;
- OrderCancel += row.orderscancelled;
- deliverypending += row.deliveriespending;
- deliverycomplete += row.deliveriescompleted;
- deliverycancel += row.deliveriescancelled;
- });
- // Update the state after the calculation is done
- settotal(calculatedTotal);
- settotalOrders(ordersTotal);
- setTotalOrderPend(Orderpending);
- setTotalOrderComplete(OrderComplete);
- setTotalOrderCancel(OrderCancel);
- setTotalDeliPend(deliverypending);
- setTotalDeliComplete(deliverycomplete);
- setTotalDeliCancel(deliverycancel);
- };
- useEffect(() => {
- calculate();
- }, [rows]);
-
- // ==============================|| fetchAppLocations ||============================== //
- const fetchAppLocations = async () => {
- try {
- const locationRes = await axios.get(`${process.env.REACT_APP_URL}/partners/getlocations/?userid=${userid}`);
- const updatedLocations = [
- ...locationRes.data.details,
- { locationname: 'All', applocationid: 0 } // Add your new object here
- ];
- console.log('fetchAppLocations', updatedLocations);
- setLocations(updatedLocations);
+ setRidersdata(Array.isArray(res.data?.details) ? res.data.details : []);
} catch (err) {
- console.log('locationRes', err);
+ OpenToast(err?.message || 'Failed to load rider breakdown', 'error', 2000);
+ setRidersdata([]);
+ } finally {
+ setLoading(false);
}
};
- useEffect(() => {
- fetchAppLocations();
- }, []);
- if (isErrorReports) console.log('An error has occurred:(isErrorReports) ' + reportsError.message);
+ if (isErrorReports) console.warn('ordersSummary error:', reportsError?.message);
+
+ const KPI_META = [
+ {
+ key: 'orders',
+ label: 'Total Orders',
+ color: BRAND,
+ icon: MdLocalShipping,
+ value: stats.totalOrders
+ },
+ {
+ key: 'pending',
+ label: 'Orders Pending',
+ color: '#f59e0b',
+ icon: MdHourglassEmpty,
+ value: stats.orderPend
+ },
+ {
+ key: 'completed',
+ label: 'Orders Completed',
+ color: '#10b981',
+ icon: MdCheckCircle,
+ value: stats.orderComplete
+ },
+ {
+ key: 'amount',
+ label: 'Total Amount',
+ color: '#0ea5e9',
+ icon: MdCurrencyRupee,
+ value: formatNumberToRupees(stats.amount)
+ }
+ ];
+
+ const isLocationGroup = Boolean(tenantid);
return (
<>
- {(loading || isLoadingReports) && (
- <>
- {/* */}
-
- >
- )}
+ {(loading || isLoadingReports) && }
- {/* theme.zIndex.drawer + 1
+ mb: { xs: 1.5, md: 2 },
+ p: { xs: 1.5, sm: 2, md: 2.5 },
+ borderRadius: DT.radiusCard / 8,
+ border: '1px solid',
+ borderColor: DT.borderSubtle,
+ background: `linear-gradient(135deg, ${tint(BRAND)} 0%, ${tint(BRAND_LIGHT)} 100%)`,
+ boxShadow: DT.shadowMd
}}
- open={loading || isLoadingReports} // when loader = true, backdrop covers the page
>
-
- */}
-
-
+
+
+
+
+
+
+ Orders Summary
+
+
+
+
+ Live · {locaName || 'All Zones'} · {datestatus}
+
+
+
+
}
+ placeholder="Select Zone"
+ paperComponent={SoftPaper}
+ sx={{ width: { xs: '100%', sm: 280 }, zIndex: 100 }}
/>
- }
- />
+
+
-
-
- {startdate && enddate && (
-
-
-
-
- {dayjs(startdate).format('DD/MM/YYYY')} - {dayjs(enddate).format('DD/MM/YYYY')}
-
+ {/* ============================================= || KPI Cards || ============================================= */}
+
+ {KPI_META.map((item) => {
+ const Icon = item.icon;
+ return (
+
+ }
- onDelete={() => {
- setOpen(true);
+ }}
+ >
+ setOpen(true)}
- sx={{ cursor: 'pointer' }}
/>
-
-
- )}
-
+
+
+
+ {item.label}
+
+
+ {item.value}
+
+
+
+
+
+
+
+
+ );
+ })}
+
+
+ {/* ============================================= || Filter bar || ============================================= */}
+
- {
- if (!appId) {
- event.preventDefault();
- OpenToast('Please select a your app location first!', 'warning', 3000);
- setTimeout(() => {
- locationRef.current?.focus();
- }, 0);
+
+
+ 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')}` }
+ }}
+ >
+
+ Orders · {datestatus} · {dayjs(startdate).format('DD/MM/YY')} – {dayjs(enddate).format('DD/MM/YY')}
+
+
+
+ option?.tenantname || option?.label || ''}
+ isOptionEqualToValue={(opt, val) => opt?.tenantid === val?.tenantid}
+ PaperComponent={SoftPaper}
+ sx={{ minWidth: { xs: '100%', sm: 220 }, ...pillFieldSx(BRAND) }}
+ onOpen={(event) => {
+ if (!appId) {
+ event.preventDefault();
+ OpenToast('Please select a Zone first!', 'warning', 3000);
+ setTimeout(() => locationRef.current?.focus(), 0);
+ }
+ }}
+ onChange={(e, val, reason) => {
+ if (reason === 'clear' || !val) {
+ setTenantid(0);
+ setTenantValue(null);
+ setLocationid(0);
+ setLocationValue(null);
+ } else {
+ setTenantid(val?.tenantid || 0);
+ setTenantValue(val);
+ setLocationid(val?.locationid || 0);
+ setLocationValue(null);
+ }
+ }}
+ renderInput={(params) => (
+
+
+
+
+ {params.InputProps.startAdornment}
+
+ )
+ }}
+ />
+ )}
+ />
+
+
+ option?.locationname ? `${option.locationname}${option.suburb ? ` (${option.suburb})` : ''}` : ''
}
- }}
- 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) => }
- />
- {/* ==================================================== || Location Autocomplete || ==================================================== */}
- `${option.locationname} (${option.suburb})` || ''}
- value={locationValue}
- sx={{ minWidth: 250, flex: { xs: 1, custom950: 0 } }}
- 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) => }
- />
+ isOptionEqualToValue={(opt, val) => opt?.locationid === val?.locationid}
+ PaperComponent={SoftPaper}
+ sx={{ minWidth: { xs: '100%', sm: 220 }, ...pillFieldSx('#0ea5e9') }}
+ onOpen={(event) => {
+ if (!appId && !tenantid) {
+ event.preventDefault();
+ OpenToast('Please select Zone and Tenant first!', 'warning', 3000);
+ setTimeout(() => locationRef.current?.focus(), 0);
+ } else if (!tenantid) {
+ event.preventDefault();
+ OpenToast('Please select a Tenant first!', 'warning', 3000);
+ setTimeout(() => tenantRef.current?.focus(), 0);
+ }
+ }}
+ onChange={(e, val, reason) => {
+ if (reason === 'clear' || !val) {
+ setLocationid(0);
+ setLocationValue(null);
+ } else {
+ setLocationid(val?.locationid || 0);
+ setLocationValue(val);
+ }
+ }}
+ renderInput={(params) => (
+
+
+
+
+ {params.InputProps.startAdornment}
+
+ )
+ }}
+ />
+ )}
+ />
+
+
+
+
+
-
-
+
+
+ {/* ============================================= || Table || ============================================= */}
+
-
- {/* ============================================ ||EnhancedTableHead || ============================================ */}
-
-
- {/* ============================================ || TableBody || ============================================ */}
+
+
+
+ #
+ {isLocationGroup ? 'Location' : 'Tenant'}
+
+ All
+
+
+ Orders
+
+
+ Deliveries
+
+
+ Collection
+
+
+ KMS / Actual
+
+
+ Amount
+
+
+ Action
+
+
+
+
+ Pending
+
+
+ Cancelled
+
+
+ Completed
+
+
+ Pending
+
+
+ Cancelled
+
+
+ Completed
+
+
+
- {isLoadingReports && }
- {rows?.length == 0 && (
+ {isLoadingReports && }
+
+ {!isLoadingReports && filteredRows.length === 0 && (
-
-
-
+
+
+
+
+
+
+ No {isLocationGroup ? 'locations' : 'tenants'} to show
+
+
+ {debouncedSearch
+ ? 'Try a different keyword.'
+ : isErrorReports
+ ? 'Something went wrong fetching the summary. Try a different filter.'
+ : 'Pick a zone, tenant, or date range to load the summary.'}
+
)}
- {(rows?.length != 0 || rows) &&
- rows?.map((row, index) => (
- <>
- {/* ============================================ || tablerow 1 || ============================================ */}
+ {filteredRows.map((row, index) => {
+ const rowKey = isLocationGroup ? row.locationname : row.tenantname;
+ const isOpen = openRow === rowKey;
+ const amount = Math.max(Number(row.charges) || 0, Number(row.deliveryamt) || 0);
+
+ return (
+
- {index + 1}
-
-
- {tenantid ? row.locationname : row.tenantname}
- Id : {tenantid ? row.locationid : row.tenantid}
+
+
+ {String(index + 1).padStart(2, '0')}
+
+
+
+
+
+ {isLocationGroup ? : }
+
+
+
+ {(isLocationGroup ? row.locationname : row.tenantname) || '—'}
+
+
+ ID #{isLocationGroup ? row.locationid : row.tenantid}
+
+
- {coloredCell(row.totalorders)}
- {coloredCell(row.Orderspending)}
- {coloredCell(row.orderscancelled)}
- {coloredCell(row.orderscompleted)}
- {coloredCell(row.deliveriespending)}
- {coloredCell(row.deliveriescancelled)}
- {coloredCell(row.deliveriescompleted)}
+
- {/*
-
-
-
*/}
- {/* */}
- } />
+
+
+ } />
+
+
+ } />
+
+
+ } />
+
+
+ } />
+
+
+ } />
+
+
+ } />
+
+
+
+ }
+ label={Number(row.collectionamt || 0).toFixed(2)}
+ tooltip="Collection Amount"
+ minWidth={90}
/>
- {/* */}
- {' '}
-
-
-
-
-
-
-
-
-
+
+
+
+ }
+ label={`${Number(row.kms || 0).toFixed(2)} km`}
+ tooltip="KMS"
+ />
+ }
+ label={`${Number(row.cumulativekms || 0).toFixed(2)} km`}
+ tooltip="Actual KMS"
+ />
+
+
+
+
+ }
+ label={formatNumberToRupees(amount).replace('₹', '').trim()}
+ tooltip="Total Amount"
+ minWidth={100}
+ />
+
+
-
-
+ = row.deliveryamt ? row.charges : row.deliveryamt)}
- color={row.deliveryamt || row.charges ? 'primary' : 'secondary'}
- variant="combined"
- sx={{
- cursor: 'pointer',
- minWidth: 100
+ onClick={() => {
+ const isOpening = !isOpen;
+ setOpenRow(isOpening ? rowKey : null);
+ if (!isOpening) return;
+ setRidersdata([]);
+ if (isLocationGroup) {
+ getriderlocationsummary(row.locationid);
+ } else {
+ getuserreportsummary(row.tenantid);
+ }
}}
- />
+ sx={{
+ bgcolor: isOpen ? BRAND : soft(BRAND),
+ color: isOpen ? '#fff' : BRAND,
+ border: `1px solid ${edge(BRAND)}`,
+ '&:hover': { bgcolor: BRAND, color: '#fff' }
+ }}
+ >
+ {isOpen ? : }
+
-
- {
- // setRidersdata([]); // yo avoid appending new data list to exiting
- // setTimeout(() => {
- // openRow !== row.tenantname && (tenantid
- // ? getriderlocationsummary(row.locationid)
- // : getuserreportsummary(row.tenantid));
- // setOpenRow(openRow === row.tenantname ? null : row.tenantname);
- // }, 0);
- // }}
- onClick={() => {
- if (tenantid) {
- // if tenant selected and shows the location list
- const isOpening = openRow !== row.tenantname;
- // toggle row
- setOpenRow(isOpening ? row.tenantname : null);
- if (!isOpening) return; // ❌ closing → don't call API
- // clear old data only when opening
- setRidersdata([]);
- // ✅ call correct API
- getriderlocationsummary(row.locationid);
- } else {
- const isOpening = openRow !== row.locationname;
-
- // toggle row
- setOpenRow(isOpening ? row.locationname : null);
-
- if (!isOpening) return; // ❌ closing → don't call API
-
- // clear old data only when opening
- setRidersdata([]);
-
- // ✅ call correct API
-
- getuserreportsummary(row.tenantid);
- }
- }}
- sx={{
- bgcolor: openRow === row.tenantname ? 'primary.main' : null,
- color: openRow === row.tenantname ? 'white' : null,
- '&:hover': {
- bgcolor: openRow === row.tenantname ? 'primary.main' : '#e1bee7'
- }
- }}
- >
-
- {tenantid ? (
- openRow === row.tenantname ? (
-
- ) : (
-
- )
- ) : openRow === row.locationname ? (
-
- ) : (
-
- )}
-
-
-
- {/* ============================================ || collapsive row || ============================================ */}
- {(tenantid ? openRow === row.tenantname : openRow === row.locationname) && (
-
-
-
-
-
-
- #
- Rider
- Orders
- Deliveries
- Pending
- Cancelled
- Completed
- Collection Amt
- kms/Actual kms
- Charges
-
-
-
- {loading && }
- {/* {ridersdata?.length == 0 && (
-
-
-
-
-
-
-
- )} */}
- {ridersdata?.map((row, index) => (
-
- {index + 1}
-
-
- {` ${row.firstname} ${row.lastname}`}
-
- {row.ridercontact}
-
-
- ID : {row.userid}
-
-
-
+ {/* ============================================= || Collapsible rider breakdown || ============================================= */}
+ {isOpen && (
+
+
+
+
+
+
+
+
+
+
+ Rider Breakdown · {isLocationGroup ? row.locationname : row.tenantname}
+
+
- {coloredCell(row.orderscreated)}
- {coloredCell(row.totalorders)}
- {coloredCell(row.deliveriespending)}
- {coloredCell(row.deliveriescancelled)}
- {coloredCell(row.deliveriescompleted)}
- {/* {coloredCell(row.picked)}
- {coloredCell(row.active)}
- {coloredCell(row.skipped)}
- {coloredCell(row.cancelled)}
- {coloredCell(row.delivered)} */}
-
- {/*
-
-
-
*/}
- {/* */}
-
- {/* */}
-
-
-
-
-
-
-
-
-
-
-
-
-
- = row.deliveryamt ? row.charges : row.deliveryamt)}
- color={row.deliveryamt || row.charges ? 'primary' : 'secondary'}
- variant="combined"
- sx={{
- cursor: 'pointer',
- minWidth: 100
- }}
- />
-
-
-
- ))}
-
-
-
+
+
+
+ #
+ Rider
+ Orders
+ Deliveries
+ Pending
+ Cancelled
+ Completed
+ Collection
+ KMS / Actual
+ Amount
+
+
+
+ {loading && }
+ {!loading && (!ridersdata || ridersdata.length === 0) ? (
+
+
+
+ No rider activity for this row.
+
+
+
+ ) : (
+ ridersdata.map((sub, sidx) => {
+ const subAmount = Math.max(Number(sub.charges) || 0, Number(sub.deliveryamt) || 0);
+ return (
+
+
+
+ {String(sidx + 1).padStart(2, '0')}
+
+
+
+
+
+
+
+
+
+ {`${sub.firstname || ''} ${sub.lastname || ''}`.trim() || '—'}
+
+
+ {sub.ridercontact || `ID #${sub.userid}`}
+
+
+
+
+
+ } />
+
+
+ } />
+
+
+ }
+ />
+
+
+ } />
+
+
+ }
+ />
+
+
+ }
+ label={Number(sub.collectionamt || 0).toFixed(2)}
+ tooltip="Collection"
+ minWidth={80}
+ />
+
+
+
+ }
+ label={`${Number(sub.kms || 0).toFixed(2)} km`}
+ tooltip="KMS"
+ />
+ }
+ label={`${Number(sub.cumulativekms || 0).toFixed(2)} km`}
+ tooltip="Actual KMS"
+ />
+
+
+
+ }
+ label={formatNumberToRupees(subAmount).replace('₹', '').trim()}
+ tooltip="Total Amount"
+ minWidth={100}
+ />
+
+
+ );
+ })
+ )}
+
+
+
+
+
)}
- >
- ))}
-
- {rows?.length != 0 && rows && (
-
-
- Total
-
-
- {totalOrders}
-
-
- {totalOrderPend}
-
-
- {totalOrderCancel}
-
-
- {totalOrderComplete}
-
-
- {totalDeliPend}
-
-
- {totalDeliCancel}
-
-
- {totalDeliComplete}
-
-
-
-
- {formatNumberToRupees(total)}
-
-
-
- )}
+
+ );
+ })}
-
-
- {/* ============================================ || date filter dialog || ============================================ */}
+ {/* ============================================= || Total Bar || ============================================= */}
+ {filteredRows.length > 0 && (
+ <>
+
+
+
+
+ Grand Total
+
+
+
+
+
+
+
+ >
+ )}
+
+
+ {/* ============================================= || Date Filter Dialog || ============================================= */}
setOpen(false)}
@@ -927,7 +1225,6 @@ export default function OrdersReport() {
setStartdate(range.startDate);
setEnddate(range.endDate);
setDatestatus(range.label);
- console.log('Selected Date Range:', range);
}}
/>
>