From 225c5912f5d973d52c0939454df5c3f2e6079da0 Mon Sep 17 00:00:00 2001 From: dharaneesh-r Date: Fri, 5 Jun 2026 03:33:51 +0530 Subject: [PATCH] updates and issues fixed in the order summary page and used the existing design is followed --- src/pages/nearle/reports/ordersSummary.js | 1851 ++++++++++++--------- 1 file changed, 1074 insertions(+), 777 deletions(-) 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); }} />