From b27c27a4446498c83d9c9680650b5c3848620e27 Mon Sep 17 00:00:00 2001 From: joshikannan Date: Tue, 11 Nov 2025 16:54:45 +0530 Subject: [PATCH] orderdetails scroll --- src/menu-items/index.js | 6 +- src/menu-items/nearle.js | 88 +++ src/pages/nearle/api/api.js | 55 +- src/pages/nearle/reports/ordersDetails.js | 665 ++++++++++------------ 4 files changed, 431 insertions(+), 383 deletions(-) create mode 100644 src/menu-items/nearle.js diff --git a/src/menu-items/index.js b/src/menu-items/index.js index 88f7ffb..c9f5f93 100644 --- a/src/menu-items/index.js +++ b/src/menu-items/index.js @@ -1,10 +1,14 @@ // project import +// import nearle from './nearle'; import other from './other'; // ==============================|| MENU ITEMS ||============================== // const menuItems = { - items: [other] + items: [ + other + // nearle + ] }; export default menuItems; diff --git a/src/menu-items/nearle.js b/src/menu-items/nearle.js new file mode 100644 index 0000000..b892a02 --- /dev/null +++ b/src/menu-items/nearle.js @@ -0,0 +1,88 @@ +// third-party +import { FormattedMessage } from 'react-intl'; +import { AiOutlineBarChart } from 'react-icons/ai'; +import { AiOutlineDashboard } from 'react-icons/ai'; +import { TbListDetails } from 'react-icons/tb'; +import { LiaFileInvoiceSolid } from 'react-icons/lia'; + +// assets +import { + BorderOutlined, + BoxPlotOutlined, + ChromeOutlined, + DeploymentUnitOutlined, + GatewayOutlined, + MenuUnfoldOutlined, + QuestionOutlined, + SmileOutlined, + StopOutlined, + DashboardOutlined, + ClockCircleOutlined, + UserOutlined, + SettingOutlined +} from '@ant-design/icons'; + +// icons +const icons = { + ChromeOutlined, + MenuUnfoldOutlined, + BoxPlotOutlined, + StopOutlined, + BorderOutlined, + SmileOutlined, + GatewayOutlined, + QuestionOutlined, + DeploymentUnitOutlined, + DashboardOutlined, + ClockCircleOutlined, + UserOutlined, + SettingOutlined +}; + +// ==============================|| MENU ITEMS - SUPPORT ||============================== // + +const nearle = { + id: 'nearle', + title: , + type: 'group', + children: [ + { + id: 'orders', + title: , + type: 'item', + url: '/nearle/orders', + icon: AiOutlineDashboard + }, + { + id: 'customers', + title: , + type: 'item', + url: '/nearle/customers', + icon: icons.UserOutlined + }, + { + id: 'reports', + title: , + type: 'collapse', + icon: AiOutlineBarChart, + children: [ + { + id: 'OrdersDetails', + title: , + type: 'item', + url: '/nearle/ordersdetails', + icon: TbListDetails + } + ] + }, + { + id: 'invoice', + title: , + type: 'item', + url: '/nearle/invoice', + icon: LiaFileInvoiceSolid + } + ] +}; + +export default nearle; diff --git a/src/pages/nearle/api/api.js b/src/pages/nearle/api/api.js index 76b59d1..4fcdc9e 100644 --- a/src/pages/nearle/api/api.js +++ b/src/pages/nearle/api/api.js @@ -24,13 +24,6 @@ export const fetchOrderInsight = async () => { return response.data.details; }; -// ==============================|| fetchDeliverySummary (delivery)||============================== // -export const fetchDeliverySummary = async () => { - const response = await axios.get(`${process.env.REACT_APP_URL}/deliveries/deliverysummary`); - console.log('fetchDeliverySummary', response.data.details); - return response.data.details; -}; - // ==============================|| fetchDeliveryInsight (delivery)||============================== // export const fetchDeliveryInsight = async () => { const response = await axios.get(`${process.env.REACT_APP_URL}/deliveries/getdeliveryinsight`); @@ -49,7 +42,7 @@ export const fetchDeliveryLocationSummary = async () => { // ==============================|| fetchAllTenants (clients)||============================== // export const fetchAllTenants = async ({ queryKey }) => { - const [size, status, pageno, search, rough] = queryKey; + const [size, pageno, search] = queryKey; let url = ''; if (search) { @@ -95,7 +88,7 @@ export const fetchOrdersSummary = async ({ queryKey }) => { }; // ==============================|| fetchLocations (orders summary))||============================== // -export const fetchLocations = async ({ queryKey }) => { +export const fetchLocations = async () => { const response = await axios.get(`${process.env.REACT_APP_URL}/partners/getpartners`); const updatedLocations = [ ...response.data.details, @@ -105,9 +98,18 @@ export const fetchLocations = async ({ queryKey }) => { return updatedLocations; }; +// ==============================|| fetchDeliverySummary (orders summary)||============================== // +export const fetchDeliverySummary = async ({ queryKey }) => { + const [, startdate, enddate, currentStatus] = queryKey; + const response = await axios.get( + `${process.env.REACT_APP_URL}/deliveries/deliverysummary?tenantid=${tenid}&fromdate=${startdate}&todate=${enddate}` + ); + console.log('fetchDeliverySummary', response.data.details); + return response.data.details; +}; // ==============================|| fetchAppLocations (report summary))||============================== // -export const fetchAppLocations = async ({ queryKey }) => { +export const fetchAppLocations = async () => { const response = await axios.get(`${process.env.REACT_APP_URL}/partners/getpartners`); const updatedLocations = [ ...response.data.details, @@ -134,17 +136,38 @@ export const fetchRidersSummary = async ({ queryKey }) => { }; // ==============================|| fetchorderdetails (orders detail)||============================== // -export const fetchorderdetails = async ({ queryKey }) => { - console.log('queryKey of fetchorderdetails', queryKey); +export const fetchorderdetails = async ({ pageParam = 0, queryKey }) => { const [startdate, enddate, currentStatus] = queryKey; + + const limit = 10; + const pageno = pageParam + 1; // ✅ increment page by 1 each time + const response = await axios.get( `${process.env.REACT_APP_URL}/deliveries/getdeliveries/?tenantid=${tenid}&fromdate=${startdate}&todate=${enddate}&status=${ - currentStatus == 'All' ? '' : currentStatus - }` + currentStatus === 'All' ? '' : currentStatus + }&pageno=${pageno}&pagesize=${limit}` ); - console.log('fetchorderdetails', response.data.details); - return response.data.details; + + const details = response.data.details || []; + const hasMore = details.length === limit; // ✅ only if you got full data + + return { + details, + nextPage: hasMore ? pageParam + 1 : undefined // nextPage increments correctly + }; }; + +// export const fetchorderdetails = async ({ queryKey }) => { +// console.log('queryKey of fetchorderdetails', queryKey); +// const [startdate, enddate, currentStatus] = queryKey; +// const response = await axios.get( +// `${process.env.REACT_APP_URL}/deliveries/getdeliveries/?tenantid=${tenid}&fromdate=${startdate}&todate=${enddate}&status=${ +// currentStatus == 'All' ? '' : currentStatus +// }` +// ); +// console.log('fetchorderdetails', response.data.details); +// return response.data.details; +// }; // ==============================|| fetchCount (orders detail)||============================== // export const fetchCount = async ({ queryKey }) => { console.log('queryKey of fetchCount', queryKey); diff --git a/src/pages/nearle/reports/ordersDetails.js b/src/pages/nearle/reports/ordersDetails.js index e2f5597..3855064 100644 --- a/src/pages/nearle/reports/ordersDetails.js +++ b/src/pages/nearle/reports/ordersDetails.js @@ -1,7 +1,7 @@ import { React, useState, useEffect, useRef } from 'react'; import TitleCard from 'pages/nearle/titleCard'; import axios from 'axios'; -import { useQuery } from '@tanstack/react-query'; +import { useInfiniteQuery, useQuery } from '@tanstack/react-query'; import { Empty } from 'antd'; import ClearIcon from '@mui/icons-material/Clear'; import { useTheme } from '@mui/material/styles'; @@ -18,7 +18,6 @@ import { TableContainer, TableHead, TableRow, - Grid, Dialog, DialogTitle, Typography, @@ -34,7 +33,8 @@ import { InputAdornment, Badge, Autocomplete, - TextField + TextField, + CircularProgress } from '@mui/material'; import { SearchOutlined } from '@ant-design/icons'; import dayjs from 'dayjs'; @@ -56,34 +56,11 @@ import { import { FilterList } from '@mui/icons-material'; // project imports -import { fetchorderdetails, fetchCount, fetchAppLocations } from '../api/api'; +import { fetchDeliverySummary, fetchorderdetails } from '../api/api'; import MainCard from 'components/MainCard'; import { CSVExport } from 'components/third-party/ReactTable'; import Loader from 'components/Loader'; -function descendingComparator(a, b, orderBy) { - if (b[orderBy] < a[orderBy]) { - return -1; - } - if (b[orderBy] > a[orderBy]) { - return 1; - } - return 0; -} - -function getComparator(order, orderBy) { - return order === 'desc' ? (a, b) => descendingComparator(a, b, orderBy) : (a, b) => -descendingComparator(a, b, orderBy); -} - -function stableSort(array, comparator) { - const stabilizedThis = array.map((el, index) => [el, index]); - stabilizedThis.sort((a, b) => { - const order = comparator(a[0], b[0]); - if (order !== 0) return order; - return a[1] - b[1]; - }); - return stabilizedThis.map((el) => el[0]); -} function formatNumberToRupees(value) { return new Intl.NumberFormat('en-IN', { style: 'currency', @@ -91,119 +68,26 @@ function formatNumberToRupees(value) { minimumFractionDigits: 2 }).format(value); } -const headCells = [ - { - id: 'sno', - disablePadding: false, - label: '#' - }, - - { - id: 'tenantname', - disablePadding: false, - label: 'Client' - }, - - { - id: 'Pickup loco', - disablePadding: false, - label: 'Pickup' - }, - { - id: 'Delivery loco', - disablePadding: false, - label: 'Drop' - }, - { - id: 'order status', - disablePadding: false, - label: 'status' - }, - { - id: 'assigned', - disablePadding: false, - label: 'assigned' - }, - { - id: 'Accepted', - disablePadding: false, - label: 'Accepted' - }, - { - id: 'arrived', - disablePadding: false, - label: 'arrived' - }, - { - id: 'picked', - disablePadding: false, - label: 'picked' - }, - { - id: 'Delivered', - disablePadding: false, - label: 'Delivered' - }, - { - id: 'cancelled', - disablePadding: false, - label: 'cancelled' - }, - { - id: ' notes', - disablePadding: false, - label: 'NOTES' - }, - - { - id: 'kms', - disablePadding: false, - label: 'KMS' - }, - { - id: 'charges', - disablePadding: false, - label: 'Charges', - numeric: true - } -]; // ==============================|| MUI TABLE - ENHANCED ||============================== // export default function OrdersDetails() { const textFieldRef = useRef(null); - const [order, setOrder] = useState('asc'); - const [orderBy, setOrderBy] = useState('calories'); - const [selected, setSelected] = useState([]); - const [page, setPage] = useState(0); - const [dense] = useState(false); - const [rowsPerPage, setRowsPerPage] = useState(20); - const [selectedValue, setSelectedValue] = useState([]); - const [locaName, setLocoName] = useState('All'); + const loadMoreRef = useRef(); + const containerRef = useRef(); const [startdate, setStartdate] = useState(dayjs().format('YYYY-MM-DD')); const [enddate, setEnddate] = useState(dayjs().format('YYYY-MM-DD')); const [open, setOpen] = useState(false); - const [open1, setOpen1] = useState(false); - const [dateselect, setDateselect] = useState('select'); - const [tabstatus1, setTabstatus1] = useState('Today'); const [datestatus, setDatestatus] = useState('Today'); const [totalCharge, settotalCharge] = useState(0); const [totalAmount, settotalAmount] = useState(0); - const [appId, setAppId] = useState(-1); - const [value, setValue] = useState(0); - const [tabvalue, setTabvalue] = useState(0); - const [deliCount, setDeliCount] = useState(0); - const [pendCount, setPendCount] = useState(0); - const [cancelCount, setCancelCount] = useState(0); const [searchword, setSearchword] = useState(''); - const [count, setCount] = useState(0); const theme = useTheme(); const [riderCoordinates, setRiderCoordinates] = useState([]); const [riderStart, setRiderStart] = useState(); const [riderEnd, setRiderEnd] = useState(); const [mapOpen, setMapOpen] = useState(false); const [mapTenant, setMapTenant] = useState({}); - let [total, settotal] = useState(0); let [coveredLenght, setCoveredLenght] = useState(0); let [uncoveredLenght, setUncoveredLenght] = useState(0); @@ -212,8 +96,9 @@ export default function OrdersDetails() { let [pickedLenght, setPickedLenght] = useState(0); let [activeLenght, setActiveLenght] = useState(0); let [arrivesLenght, setArrivedLenght] = useState(0); - const [statusCount, setStatusCount] = useState(); const [currentStatus, setCurrentStatus] = useState('All'); + const [statusLabel, setStatuslabel] = useState('All'); + const [statusCount, setStatusCount] = useState(0); const status = [ { id: 0, status: 'All', statusLow: 'All', count: total }, @@ -238,7 +123,6 @@ export default function OrdersDetails() { const coData = datas.map((data) => ({ lat: data.latitude, lng: data.longitude })); console.log('coData', coData); setRiderCoordinates(coData); - setOpen1(true); } else { opentoast('No Logs Found ', 'error', 2000); } @@ -278,15 +162,87 @@ export default function OrdersDetails() { // ==============================|| fetchorderdetails (orders)||============================== // + // const { + // isLoading: isLoadingOrderDetails, + // isError: isErrorOrderDetails, //true or false + // data: rows, + // error: orderDetailsError + // } = useQuery({ + // queryKey: [startdate, enddate, currentStatus], + // queryFn: fetchorderdetails + // }); const { + data: rowdata, + isError: isErrorOrderDetails, + error: orderDetailsError, + fetchNextPage, isLoading: isLoadingOrderDetails, - isError: isErrorOrderDetails, //true or false - data: rows, - error: orderDetailsError - } = useQuery({ + hasNextPage, + isFetchingNextPage + // status: rowdataStatus + } = useInfiniteQuery({ queryKey: [startdate, enddate, currentStatus], - queryFn: fetchorderdetails + queryFn: fetchorderdetails, + getNextPageParam: (lastPage) => lastPage.nextPage }); + const rows = rowdata?.pages.flatMap((page) => page.details) || []; + + useEffect(() => { + if (!hasNextPage) return; + + const observer = new IntersectionObserver( + (entries) => { + if (entries[0].isIntersecting) { + fetchNextPage(); + } + }, + { + root: document.querySelector('.MuiTableContainer-root'), // 👈 or explicitly TableContainer + rootMargin: '0px', + threshold: 1.0 + } + ); + + if (loadMoreRef.current) observer.observe(loadMoreRef.current); + + return () => { + if (loadMoreRef.current) observer.unobserve(loadMoreRef.current); + }; + }, [hasNextPage, fetchNextPage]); + + // ==================================== || fetchDeliverySummary || ==================================== + + const { + data: deliverycount, + isLoading, + isError, + error + } = useQuery({ + queryKey: ['deliverycount', startdate, enddate, currentStatus], + queryFn: fetchDeliverySummary + }); + + useEffect(() => { + console.log('currentStatus', currentStatus); + + currentStatus == 'All' + ? setStatusCount(deliverycount?.total) + : currentStatus == 'pending' + ? setStatusCount(deliverycount?.pending) + : currentStatus == 'accepted' + ? setStatusCount(deliverycount?.accepted) + : currentStatus == 'arrived' + ? setStatusCount(deliverycount?.arrived) + : currentStatus == 'picked' + ? setStatusCount(deliverycount?.picked) + : currentStatus == 'active' + ? setStatusCount(deliverycount?.active) + : currentStatus == 'delivered' + ? setStatusCount(deliverycount?.delivered) + : currentStatus == 'cancelled' + ? setStatusCount(deliverycount?.cancelled) + : setStatusCount(0); + }, [currentStatus, deliverycount]); // ==============================|| calculate||============================== // const calculate = () => { @@ -306,32 +262,12 @@ export default function OrdersDetails() { }; useEffect(() => { calculate(); - rows && setRowsPerPage(rows.length + 1); - rows && setCount(rows.length); }, [rows]); - // ==============================|| fetchOrdersCount (orders)||============================== // - const { - isLoading: isLoadingOrderCount, - isError: isErrorOrderCount, //true or false - data: countData, - error: orderCountError - } = useQuery({ - queryKey: [startdate, enddate], - queryFn: fetchCount - }); - useEffect(() => { - if (countData) { - setDeliCount(countData.deliveredCount); - setPendCount(countData.pendingCount); - setCancelCount(countData.cancelledCount); - } - }, [fetchCount, startdate, enddate]); // ==============================|| fetchAppLocations ||============================== // - if (isLoadingOrderDetails || isLoadingOrderCount) return ; + if (isLoadingOrderDetails) return ; if (isErrorOrderDetails) return 'An error has occurred:(isErrorOrderDetails) ' + orderDetailsError.message; - if (isErrorOrderCount) return 'An error has occurred:(isErrorOrderCount) ' + orderCountError.message; const filteredOrders = rows.filter((row) => row.orderstatus == '' @@ -389,8 +325,6 @@ export default function OrdersDetails() { locationcontactno: order.locationcontactno })); - const isSelected = (name) => selected.indexOf(name) !== -1; - function formatDate(dateString) { const date = dayjs(dateString); const formattedDate = date.format('DD/MM/YYYY '); @@ -401,6 +335,14 @@ export default function OrdersDetails() { const formattedDate = date.format(' hh:mm A'); return formattedDate; } + const handleScroll = (event) => { + const { scrollTop, scrollHeight, clientHeight } = event.currentTarget; + if (scrollTop + clientHeight >= scrollHeight - 50) { + if (hasNextPage && !isFetchingNextPage) { + fetchNextPage(); + } + } + }; return ( <> @@ -417,8 +359,8 @@ export default function OrdersDetails() { {startdate && enddate && ( `${option.status}`} onChange={(event, value, reason) => { if (reason === 'clear') { setCurrentStatus('All'); - setStatusCount(status[0].count); } else { console.log('status', value); setCurrentStatus(value.statusLow); - setStatusCount(value.count); } }} - renderInput={(params) => } + renderInput={(params) => } /> # - {/* Map */} + Map Tenant Name Pickup Drop @@ -579,220 +520,214 @@ export default function OrdersDetails() { )} - {stableSort(filteredOrders, getComparator(order, orderBy)) - .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) - .map((row, index) => { - if (typeof row === 'number') return null; - const isItemSelected = isSelected(row.name); - return ( - filteredOrders.length !== 0 && ( - - {index + 1} - {/* { - console.log('row', row); - setMapTenant(row); - setMapOpen(true); - getdeliverylogs(row.deliveryid); - }} - > - {} - */} - - {row.tenantname} - - {row.orderid} - - - {dayjs(row.orderdate).utc().format('DD/MM/YYYY')} - - - {dayjs(row.orderdate).utc().format('hh:mm A')} - - - - - - {row.pickupcustomer} - - {row.pickupcontactno} + {filteredOrders.map((row, index) => { + return ( + filteredOrders.length !== 0 && ( + + {index + 1} + { + console.log('row', row); + setMapTenant(row); + setMapOpen(true); + getdeliverylogs(row.deliveryid); + }} + > + {} + + + {row.tenantname} + + {row.orderid} + + + {dayjs(row.orderdate).utc().format('DD/MM/YYYY')} + + + {dayjs(row.orderdate).utc().format('hh:mm A')} + + + + + + {row.pickupcustomer} + + {row.pickupcontactno} + + + + {row.pickupsuburb || row.pickuplocation || row.Pickupaddress.slice(0, 20)} - - - {row.pickupsuburb || row.pickuplocation || row.Pickupaddress.slice(0, 20)} - - - + - - - - - {row.deliverycustomer} - - {row.deliverycontactno} + + + + + + {row.deliverycustomer} + + {row.deliverycontactno} + + + + {/* {row.Pickupaddress.slice(0, 20)} */} + {row.deliverysuburb || row.deliverylocation || row.deliveryaddress.slice(0, 20)} - - - {/* {row.Pickupaddress.slice(0, 20)} */} - {row.deliverysuburb || row.deliverylocation || row.deliveryaddress.slice(0, 20)} - - - + - - - - {row.orderstatus === 'created' && } - {row.orderstatus === 'pending' && } - {row.orderstatus === 'accepted' && ( - - )} - {row.orderstatus === 'arrived' && ( - - )} - {row.orderstatus === 'picked' && } - {row.orderstatus === 'active' && } - {row.orderstatus === 'delivered' && ( - - )} + + + + + {row.orderstatus === 'created' && } + {row.orderstatus === 'pending' && } + {row.orderstatus === 'accepted' && ( + + )} + {row.orderstatus === 'arrived' && ( + + )} + {row.orderstatus === 'picked' && } + {row.orderstatus === 'active' && } + {row.orderstatus === 'delivered' && } - {row.orderstatus === 'cancelled' && } - - - - - {row.ridername} - - - {/* {dayjs(row.pending).format('DD/MM/YYYY')} */} - {row.assigntime === '' ? '' : formatDate(row.assigntime)} - - - {row.assigntime === '' ? '' : formatTime(row.assigntime)} - - - - {' '} - - {row.starttime === '' ? '' : formatDate(row.starttime)} - - - {row.starttime === '' ? '' : formatTime(row.starttime)} - - - - {' '} - - {row.arrivaltime === '' ? '' : formatDate(row.arrivaltime)} - - - {row.arrivaltime === '' ? '' : formatTime(row.arrivaltime)} - - - - {' '} - - {row.pickuptime === '' ? '' : formatDate(row.pickuptime)} - - - {row.pickuptime === '' ? '' : formatTime(row.pickuptime)} - - - - {' '} - - {row.deliverytime === '' ? '' : formatDate(row.deliverytime)} - - - {row.deliverytime === '' ? '' : formatTime(row.deliverytime)} - - - - {' '} - - {row.canceltime === '' ? '' : formatDate(row.canceltime)} - - - {row.canceltime === '' ? '' : formatTime(row.canceltime)} - - + {row.orderstatus === 'cancelled' && } + + + + + {row.ridername} + + + {/* {dayjs(row.pending).format('DD/MM/YYYY')} */} + {row.assigntime === '' ? '' : formatDate(row.assigntime)} + + + {row.assigntime === '' ? '' : formatTime(row.assigntime)} + + + + {' '} + + {row.starttime === '' ? '' : formatDate(row.starttime)} + + + {row.starttime === '' ? '' : formatTime(row.starttime)} + + + + {' '} + + {row.arrivaltime === '' ? '' : formatDate(row.arrivaltime)} + + + {row.arrivaltime === '' ? '' : formatTime(row.arrivaltime)} + + + + {' '} + + {row.pickuptime === '' ? '' : formatDate(row.pickuptime)} + + + {row.pickuptime === '' ? '' : formatTime(row.pickuptime)} + + + + {' '} + + {row.deliverytime === '' ? '' : formatDate(row.deliverytime)} + + + {row.deliverytime === '' ? '' : formatTime(row.deliverytime)} + + + + {' '} + + {row.canceltime === '' ? '' : formatDate(row.canceltime)} + + + {row.canceltime === '' ? '' : formatTime(row.canceltime)} + + - - {row.ordernotes} - + + {row.ordernotes} + - - - - - - - - - - - - - - - - - - - - - - ) - ); - })} + + + + + + + + + + + + + + + + + + + + + + ) + ); + })} + + +
+ {isFetchingNextPage ? : hasNextPage ? : 'No more results'} +
+
+
+ {/* ========================================= || bottom row || ========================================= */} @@ -845,13 +780,11 @@ export default function OrdersDetails() { id="daterange1" onChange={(range) => { if (range.label === 'All') { - setDateselect('all'); setStartdate(''); setEnddate(''); setOpen(false); } else { - setDateselect('select'); setStartdate(dayjs(range.startDate).format('YYYY-MM-DD')); setEnddate(dayjs(range.endDate).format('YYYY-MM-DD')); if (range.label) {