1722 lines
66 KiB
JavaScript
1722 lines
66 KiB
JavaScript
import { enqueueSnackbar } from 'notistack';
|
|
import { DeleteFilled, EditOutlined } from '@ant-design/icons';
|
|
import { useState, useEffect, Fragment, useRef } from 'react';
|
|
import { Empty } from 'antd';
|
|
import dayjs from 'dayjs';
|
|
var utc = require('dayjs/plugin/utc');
|
|
dayjs.extend(utc);
|
|
import axios from 'axios';
|
|
import HoverSocialCard from 'components/cards/statistics/HoverSocialCard';
|
|
import { useTheme } from '@mui/material/styles';
|
|
import { PiMapPinLineDuotone } from 'react-icons/pi';
|
|
import { MdOutlineDateRange } from 'react-icons/md';
|
|
import { MdOutlineDeliveryDining } from 'react-icons/md';
|
|
import { useQuery, useMutation, useInfiniteQuery } from '@tanstack/react-query';
|
|
|
|
import {
|
|
Avatar,
|
|
Box,
|
|
Button,
|
|
Grid,
|
|
Tabs,
|
|
Tab,
|
|
IconButton,
|
|
Stack,
|
|
Chip,
|
|
Typography,
|
|
Table,
|
|
TableCell,
|
|
TableBody,
|
|
TableHead,
|
|
Collapse,
|
|
Dialog,
|
|
TableRow,
|
|
DialogContent,
|
|
DialogTitle,
|
|
Tooltip,
|
|
DialogActions,
|
|
Popper,
|
|
ClickAwayListener,
|
|
Checkbox,
|
|
Autocomplete,
|
|
TextField,
|
|
FormLabel,
|
|
TablePagination,
|
|
TableContainer,
|
|
Skeleton,
|
|
useMediaQuery,
|
|
Divider,
|
|
CircularProgress,
|
|
Backdrop,
|
|
MenuItem,
|
|
Menu
|
|
} from '@mui/material';
|
|
|
|
import MainCard from 'components/MainCard';
|
|
import {
|
|
MoreOutlined,
|
|
CloseOutlined
|
|
// NotificationOutlined
|
|
} from '@ant-design/icons';
|
|
import { PopupTransition } from 'components/@extended/Transitions';
|
|
import {
|
|
addDays,
|
|
addMonths,
|
|
addWeeks,
|
|
// addYears,
|
|
endOfMonth,
|
|
endOfWeek,
|
|
// endOfYear,
|
|
startOfMonth,
|
|
startOfWeek
|
|
// startOfYear,
|
|
} from 'date-fns';
|
|
import { DateRangePicker } from 'mui-daterange-picker';
|
|
import * as React from 'react';
|
|
import Loader from 'components/Loader';
|
|
import { KeyboardArrowDownOutlined, KeyboardArrowUpOutlined } from '@mui/icons-material';
|
|
import CircularLoader from 'components/CircularLoader';
|
|
|
|
import {
|
|
cancelDeliveryAPI,
|
|
changeRiderAPI,
|
|
fetchCountAPI,
|
|
fetchDeliveries,
|
|
fetchPercentageAPI,
|
|
fetchRidersList,
|
|
notifyRider,
|
|
updateDeliveryAPI,
|
|
getorderdetails,
|
|
gettenantlocations,
|
|
getTenants
|
|
} from 'pages/api/api';
|
|
import DebounceSearchBar from 'components/nearle_components/DebounceSearchBar';
|
|
import TitleCard from 'components/nearle_components/TitleCard';
|
|
import { OpenToast } from 'components/third-party/OpenToast';
|
|
import { OrdersTableSkeleton } from '../orders/OrdersTableSkeleton';
|
|
import LocationAutocomplete from 'components/nearle_components/LocationAutocomplete';
|
|
import LoaderWithImage from 'components/nearle_components/LoaderWithImage';
|
|
|
|
// ================================================= || deliveries (initial point)|| =================================================
|
|
const Deliveries = () => {
|
|
const userid = localStorage.getItem('userid');
|
|
const theme = useTheme();
|
|
const loadMoreRef = useRef();
|
|
const containerRef = useRef();
|
|
const [deliverylist, setDeliverylist] = useState([]);
|
|
const [dialogopen, setDialogopen] = useState(false);
|
|
const [locaName, setLocoName] = useState('All');
|
|
const [appId, setAppId] = useState(0);
|
|
const [startdate, setStartdate] = useState(dayjs().format('YYYY-MM-DD'));
|
|
const [enddate, setEnddate] = useState(dayjs().format('YYYY-MM-DD'));
|
|
const [tabstatus, setTabstatus] = useState('Pending');
|
|
const [tabvalue, setTabvalue] = useState(0);
|
|
const [open, setOpen] = useState(false);
|
|
const [datestatus, setDatestatus] = useState('Today');
|
|
const [kms, setKms] = useState('');
|
|
const [cumulativekms, setCumulativeKms] = useState();
|
|
const [deliveryamount, setDeliveryamount] = useState();
|
|
const [notes, setNotes] = useState('');
|
|
const [currentorder, setCurrentorder] = useState({});
|
|
const [deliverylat, setDeliverylat] = useState('');
|
|
const [deliverylong, setDeliverylong] = useState('');
|
|
const [currentStatus, setCurrentStatus] = useState('pending');
|
|
const locationRef = useRef(null);
|
|
const tenantRef = useRef(null);
|
|
const [page, setPage] = React.useState(0);
|
|
const [rowsPerPage, setRowsPerPage] = React.useState(50);
|
|
const [totalCount, setTotalCount] = React.useState();
|
|
const [productCollapse, setProductCollapse] = useState(null);
|
|
const [orderHeaderid, setOrderHeaderId] = useState(null);
|
|
const [searchword, setSearchword] = useState('');
|
|
const [debouncedSearch, setDebouncedSearch] = useState('');
|
|
const [menuAnchorEl, setMenuAnchorEl] = React.useState(null);
|
|
const [selectedRow, setSelectedRow] = useState(null);
|
|
const [loading1, setLoading1] = useState(false);
|
|
const [anchorEl, setAnchorEl] = React.useState(null);
|
|
const [open2, setOpen2] = useState('');
|
|
const [cancelDeliveryOpen, setCancelDeliveryOpen] = useState(false);
|
|
const [changeDialogOpen, setChangeDialogOpen] = useState(false);
|
|
const [cancelFeed, setCancelFeed] = useState('');
|
|
const [selectedRider, setSelectedRider] = useState(null);
|
|
const [tenantid, setTenantid] = useState(0);
|
|
const [locationid, setLocationid] = useState(0);
|
|
const [tenantValue, setTenantValue] = useState(null);
|
|
const [locationValue, setLocationValue] = useState(null);
|
|
const [riderid, setRiderid] = useState(0);
|
|
const roleid = localStorage.getItem('roleid');
|
|
|
|
useEffect(() => {
|
|
setTenantid(0);
|
|
setTenantValue(null);
|
|
setLocationid(0);
|
|
setLocationValue(null);
|
|
}, [appId]);
|
|
// to clear the location autocomplete
|
|
useEffect(() => {
|
|
setLocationid(0);
|
|
setLocationValue(null);
|
|
}, [tenantid]);
|
|
|
|
const menuOpen = Boolean(menuAnchorEl);
|
|
|
|
const handleMenuOpen = (event, row) => {
|
|
setSelectedRow(row);
|
|
console.log('selectedRow', row);
|
|
|
|
setMenuAnchorEl(event.currentTarget);
|
|
};
|
|
|
|
const handleMenuClose = () => {
|
|
setMenuAnchorEl(null);
|
|
};
|
|
|
|
// =========================================== || cancelDelivery || ===========================================
|
|
|
|
const { mutate: cancelDelivery } = useMutation({
|
|
mutationFn: ({ selectedRow, cancelFeed }) => cancelDeliveryAPI(selectedRow, cancelFeed),
|
|
onSuccess: () => {
|
|
opentoast('Delivery Cancelled Successfully', 'success');
|
|
setCancelDeliveryOpen(false);
|
|
fetchCountRefetch(); // Refresh count data
|
|
fetchDeliveriesRefetch(); // Refresh deliveries
|
|
},
|
|
onError: (error) => {
|
|
opentoast(error.message, 'error');
|
|
}
|
|
});
|
|
|
|
// ==============================|| cancelridernotification ||============================== //
|
|
|
|
const cancelridernotification = async () => {
|
|
console.log('cancelridernotification', selectedRow);
|
|
try {
|
|
const response = await axios.post(`${process.env.REACT_APP_URL}/utils/notifyuser`, {
|
|
token: selectedRow.userfcmtoken,
|
|
notification: {
|
|
title: 'NearleXpress',
|
|
body: `${selectedRow.orderid} have been Cancelled`,
|
|
sound: 'ring',
|
|
image: ''
|
|
},
|
|
data: {
|
|
type: 'cancel'
|
|
}
|
|
});
|
|
return response.data;
|
|
} catch (err) {
|
|
opentoast(err.message, 'error', 2000);
|
|
console.log(err);
|
|
}
|
|
};
|
|
|
|
// ==============================|| getTenants ||============================== //
|
|
|
|
const {
|
|
data: tenantlist,
|
|
isLoading: fetchtenantsIsLoading,
|
|
isError: fetchtenantsIsError,
|
|
error: fetchtenantsError
|
|
} = useQuery({
|
|
queryKey: ['tenantlist', appId],
|
|
queryFn: () => getTenants(appId), // Ensure appId is passed
|
|
enabled: appId !== 0 // Ensures query runs only when appId is valid
|
|
});
|
|
// ==============================|| gettenantlocations ||============================== //
|
|
|
|
const {
|
|
data: locationlist,
|
|
isLoading: fetchlocationsIsLoading,
|
|
isError: fetchlocationsIsError,
|
|
error: fetchlocationsError
|
|
} = useQuery({
|
|
queryKey: ['gettenantlocations', tenantid],
|
|
queryFn: () => gettenantlocations(tenantid), // Ensure appId is passed
|
|
enabled: tenantid !== 0 // Ensures query runs only when appId is valid
|
|
});
|
|
// =========================================== || notifyrider || ===========================================
|
|
|
|
const notifyRiderMutation = useMutation({
|
|
mutationFn: notifyRider, // Using the separate function
|
|
onSuccess: () => {
|
|
enqueueSnackbar('Notification sent Successfully', {
|
|
variant: 'success',
|
|
anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
|
autoHideDuration: 2000
|
|
});
|
|
},
|
|
onError: (error) => {
|
|
enqueueSnackbar(error.message, {
|
|
variant: 'error',
|
|
anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
|
autoHideDuration: 2000
|
|
});
|
|
}
|
|
});
|
|
|
|
// =========================================== || changerider || ===========================================
|
|
const changeRiderMutation = useMutation({
|
|
mutationFn: ({ selectedRider, selectedRow }) => changeRiderAPI(selectedRider, selectedRow),
|
|
onSuccess: (res) => {
|
|
setLoading1(false);
|
|
setChangeDialogOpen(false);
|
|
if (res.data.message === 'Success') {
|
|
opentoast('Rider Changed Successfully', 'success');
|
|
}
|
|
fetchCountRefetch(); // Refresh count data
|
|
fetchDeliveriesRefetch(); // Refresh deliveries
|
|
notifyRiderMutation.mutate(selectedRider.userfcmtoken);
|
|
},
|
|
onError: (err) => {
|
|
console.log(err);
|
|
opentoast(err.message, 'error');
|
|
setLoading1(false);
|
|
}
|
|
});
|
|
|
|
/* ============================================= || opentoast || ============================================= */
|
|
|
|
const opentoast = (message, variant) => {
|
|
enqueueSnackbar(message, {
|
|
variant,
|
|
anchorOrigin: { vertical: 'top', horizontal: 'right' },
|
|
autoHideDuration: 2000
|
|
});
|
|
};
|
|
|
|
// ==============================|| getorderdetails ||============================== //
|
|
|
|
const { data: orderdetails } = useQuery({
|
|
queryKey: ['orderdetails', orderHeaderid],
|
|
queryFn: () => getorderdetails(orderHeaderid),
|
|
enabled: !!orderHeaderid // ✅ prevent initial fetch when undefined
|
|
});
|
|
|
|
const dialogclose = () => {
|
|
setDialogopen(false);
|
|
};
|
|
|
|
const handleChangetab = (e, i) => {
|
|
setPage(0);
|
|
setTabvalue(i);
|
|
setRowsPerPage(50);
|
|
if (i === 0) {
|
|
setTabstatus('Pending');
|
|
setCurrentStatus('pending');
|
|
setTotalCount(countData?.uncoveredLength);
|
|
}
|
|
if (i === 1) {
|
|
setTabstatus('Assigned');
|
|
setCurrentStatus('accepted');
|
|
setTotalCount(countData?.assignedLength);
|
|
}
|
|
if (i === 2) {
|
|
setTabstatus('Arrived');
|
|
setCurrentStatus('arrived');
|
|
setTotalCount(countData?.arrivedLength);
|
|
}
|
|
if (i === 3) {
|
|
setTabstatus('Picked');
|
|
setCurrentStatus('picked');
|
|
setTotalCount(countData?.pickedLength);
|
|
}
|
|
if (i === 4) {
|
|
setTabstatus('Active');
|
|
setCurrentStatus('active');
|
|
setTotalCount(countData?.activeLength);
|
|
}
|
|
if (i === 5) {
|
|
setTabstatus('Skipped');
|
|
setCurrentStatus('skipped');
|
|
setTotalCount(countData?.skippedLength);
|
|
}
|
|
if (i === 6) {
|
|
setTabstatus('Delivered');
|
|
setCurrentStatus('delivered');
|
|
setTotalCount(countData?.coveredLength);
|
|
}
|
|
|
|
if (i === 7) {
|
|
setTabstatus('Cancelled');
|
|
setCurrentStatus('cancelled');
|
|
setTotalCount(countData?.cancelLength);
|
|
}
|
|
console.log(i);
|
|
setSearchword('');
|
|
};
|
|
|
|
const okclicked = () => {
|
|
setOpen(false);
|
|
};
|
|
|
|
/* ============================================= || fetchDeliveries | ============================================= */
|
|
|
|
const {
|
|
data: deliveriesData,
|
|
isLoading: fetchDeliveriesIsLoading,
|
|
isError: fetchDeliveriesIsError,
|
|
error: fetchDeliveriesError,
|
|
fetchNextPage,
|
|
hasNextPage,
|
|
isFetchingNextPage,
|
|
refetch: fetchDeliveriesRefetch
|
|
} = useInfiniteQuery({
|
|
queryKey: [
|
|
'fetchdeliveries',
|
|
appId,
|
|
userid,
|
|
currentStatus,
|
|
startdate,
|
|
enddate,
|
|
rowsPerPage,
|
|
debouncedSearch,
|
|
tenantid,
|
|
locationid,
|
|
riderid
|
|
],
|
|
queryFn: fetchDeliveries,
|
|
getNextPageParam: (lastPage) => lastPage.nextPage ?? undefined
|
|
});
|
|
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'), // 👈 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]);
|
|
|
|
const handleScroll = (event) => {
|
|
const { scrollTop, scrollHeight, clientHeight } = event.currentTarget;
|
|
if (scrollTop + clientHeight >= scrollHeight - 50) {
|
|
if (hasNextPage && !isFetchingNextPage) {
|
|
fetchNextPage();
|
|
}
|
|
}
|
|
};
|
|
|
|
/* ============================================= || fetchPercentageAPI | ============================================= */
|
|
|
|
const {
|
|
data: percentageData,
|
|
isLoading: fetchPercentageIsLoading,
|
|
isError: fetchPercentageIsError,
|
|
error: fetchPercentageError
|
|
} = useQuery({
|
|
queryKey: ['fetchpercentageaPI', appId],
|
|
queryFn: () => fetchPercentageAPI(appId)
|
|
});
|
|
useEffect(() => {
|
|
if (percentageData) {
|
|
console.log('percentageData', percentageData);
|
|
}
|
|
}, [percentageData]);
|
|
|
|
/* ============================================= || fetchcount | ============================================= */
|
|
|
|
const {
|
|
data: countData = {}, // Default to empty object
|
|
isLoading: fetchCountIsLoading,
|
|
isError: fetchCountIsError,
|
|
error: fetchCountError,
|
|
refetch: fetchCountRefetch
|
|
} = useQuery({
|
|
queryKey: ['fetchCountData', appId, userid, startdate, enddate, rowsPerPage, debouncedSearch, tenantid, locationid, riderid, tabstatus],
|
|
queryFn: () => fetchCountAPI(appId, userid, startdate, enddate, rowsPerPage, debouncedSearch, tenantid, locationid, riderid)
|
|
});
|
|
useEffect(() => {
|
|
console.log('countData', countData);
|
|
if (tabvalue === 0 && countData) {
|
|
setTotalCount(countData.uncoveredLength);
|
|
}
|
|
}, [countData]);
|
|
|
|
// ==============================|| fetchRidersList ||============================== //
|
|
|
|
const {
|
|
data: ridersList = [],
|
|
isLoading: riderListIsLoading,
|
|
isError: ridersListIsError,
|
|
error: ridersListError
|
|
} = useQuery({
|
|
queryKey: ['ridersList', appId], // Unique key for caching & re-fetching
|
|
queryFn: fetchRidersList,
|
|
enabled: Boolean(appId),
|
|
onError: (err) => {
|
|
OpenToast(err.message, 'error', 2000);
|
|
}
|
|
});
|
|
|
|
/* ============================================= || updatedelivery | ============================================= */
|
|
|
|
const updateDeliveryMutation = useMutation({
|
|
mutationFn: (orderData) => updateDeliveryAPI(orderData),
|
|
onSuccess: (res) => {
|
|
console.log(res);
|
|
if (res.data.status) {
|
|
opentoast('Updated Successfully', 'success');
|
|
setDeliveryamount('');
|
|
setNotes('');
|
|
setDialogopen(false);
|
|
fetchDeliveriesRefetch();
|
|
fetchCountRefetch();
|
|
}
|
|
},
|
|
onError: (err) => {
|
|
console.log(err);
|
|
opentoast(err.message, 'success');
|
|
}
|
|
});
|
|
|
|
const errorMessage = fetchDeliveriesIsError
|
|
? `Error fetching percentages: ${fetchDeliveriesError?.message}`
|
|
: fetchPercentageIsError
|
|
? `Error fetching percentages: ${fetchPercentageError?.message}`
|
|
: fetchCountIsError
|
|
? `Error fetching percentages: ${fetchCountError?.message}`
|
|
: ridersListIsError
|
|
? `Error fetching percentages: ${ridersListError?.message}`
|
|
: fetchtenantsIsError
|
|
? `Error tenant list: ${fetchtenantsError?.message}`
|
|
: fetchlocationsIsError
|
|
? `Error location list: ${fetchlocationsError?.message}`
|
|
: null;
|
|
|
|
if (errorMessage) {
|
|
console.log('errorMessage', errorMessage);
|
|
OpenToast(errorMessage, 'error', 2000);
|
|
return null; // or return <></> if inside a component
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{(fetchCountIsLoading ||
|
|
fetchPercentageIsLoading ||
|
|
fetchDeliveriesIsLoading ||
|
|
fetchtenantsIsLoading ||
|
|
fetchlocationsIsLoading ||
|
|
riderListIsLoading) && (
|
|
<>
|
|
<Loader />
|
|
{/* <CircularLoader /> */}
|
|
</>
|
|
)}
|
|
{
|
|
<Backdrop
|
|
sx={{
|
|
color: '#fff',
|
|
zIndex: (theme) => theme.zIndex.drawer + 1
|
|
}}
|
|
open={
|
|
fetchCountIsLoading ||
|
|
fetchPercentageIsLoading ||
|
|
fetchDeliveriesIsLoading ||
|
|
fetchtenantsIsLoading ||
|
|
fetchlocationsIsLoading ||
|
|
riderListIsLoading
|
|
}
|
|
>
|
|
{/* <CircularLoader color="inherit" /> */}
|
|
</Backdrop>
|
|
}
|
|
{/* ============================================= || TitleCard | ============================================= */}
|
|
<TitleCard title={'Deliveries'}>
|
|
<LocationAutocomplete
|
|
ref={locationRef}
|
|
locaName={locaName}
|
|
setAppId={setAppId}
|
|
setLocoName={setLocoName}
|
|
setPage={setPage}
|
|
sx={{ width: { xs: '100%', custom450: 300 }, zIndex: '100' }}
|
|
/>
|
|
</TitleCard>
|
|
|
|
{/* ============================================= || hoverCard | ============================================= */}
|
|
<Grid container spacing={2} sx={{ mt: '1px' }}>
|
|
{[
|
|
{
|
|
label: 'Created orders',
|
|
value: percentageData?.uncoveredOrders,
|
|
percentage: percentageData?.percentage1,
|
|
color: theme.palette.info.main
|
|
},
|
|
{
|
|
label: 'Pending orders',
|
|
value: percentageData?.assignedOrders,
|
|
percentage: percentageData?.percentage2,
|
|
color: theme.palette.warning.main
|
|
},
|
|
{
|
|
label: 'Delivered orders',
|
|
value: percentageData?.pickedOrders,
|
|
percentage: percentageData?.percentage3,
|
|
color: theme.palette.success.main
|
|
},
|
|
{
|
|
label: 'Cancelled Orders',
|
|
value: percentageData?.coveredOrders,
|
|
percentage: percentageData?.percentage4,
|
|
color: theme.palette.error.main
|
|
}
|
|
].map((item, index) => (
|
|
<Grid item key={index} xs={12} custom400={6} sm={3} sx={{ cursor: 'pointer' }}>
|
|
<HoverSocialCard
|
|
primary={item.label}
|
|
secondary={fetchPercentageIsLoading ? <Skeleton sx={{ width: '30px' }} animation="wave" /> : item.value}
|
|
percentage={item.percentage?.toString()}
|
|
color={item.color}
|
|
/>
|
|
</Grid>
|
|
))}
|
|
</Grid>
|
|
|
|
{/* ============================================= || orderFilter | ============================================= */}
|
|
|
|
<Stack direction="row" justifyContent="space-between" alignItems="center" gap={3} sx={{ flexWrap: 'wrap', my: 2 }}>
|
|
{startdate && enddate ? (
|
|
<Stack
|
|
direction="row"
|
|
flexWrap="wrap" // ✅ allow wrapping
|
|
gap={1.5} // ✅ space between items when wrapped
|
|
alignItems="center" // optional, for vertical alignment
|
|
>
|
|
<Chip
|
|
avatar={
|
|
<Avatar sx={{ backgroundColor: 'transparent' }}>
|
|
<MdOutlineDeliveryDining fontSize="30px" style={{ color: 'red' }} />
|
|
</Avatar>
|
|
}
|
|
label={`Deliveries-${datestatus}`}
|
|
color="error"
|
|
variant="combined"
|
|
/>
|
|
|
|
<Chip
|
|
avatar={
|
|
<Avatar sx={{ backgroundColor: 'transparent' }}>
|
|
<MdOutlineDateRange fontSize="30px" style={{ color: '#fbc02d' }} />
|
|
</Avatar>
|
|
}
|
|
label={
|
|
<Typography noWrap color="secondary">
|
|
{dayjs(startdate).format('DD/MM/YYYY')} - {dayjs(enddate).format('DD/MM/YYYY')}
|
|
</Typography>
|
|
}
|
|
onClick={() => setOpen(true)}
|
|
variant="combined"
|
|
color="warning"
|
|
sx={{ maxWidth: '100%', cursor: 'pointer' }} // to avoid overflow
|
|
/>
|
|
|
|
<Chip
|
|
avatar={
|
|
<Avatar sx={{ backgroundColor: 'transparent' }}>
|
|
<PiMapPinLineDuotone fontSize="30px" style={{ color: '#00bcd4' }} />
|
|
</Avatar>
|
|
}
|
|
label={locaName}
|
|
color="info"
|
|
variant="combined"
|
|
sx={{ maxWidth: '100%' }}
|
|
/>
|
|
</Stack>
|
|
) : (
|
|
<Chip label="Orders-All" color="primary" variant="light" size="small" />
|
|
)}
|
|
|
|
<Autocomplete
|
|
disablePortal
|
|
options={tenantlist || []}
|
|
value={tenantValue}
|
|
sx={{ minWidth: 200, flex: 1 }}
|
|
onOpen={(event) => {
|
|
if (!appId) {
|
|
event.preventDefault();
|
|
OpenToast('Please select a your 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(0);
|
|
setLocationValue(null);
|
|
}
|
|
}}
|
|
renderInput={(params) => <TextField {...params} inputRef={tenantRef} label="Select Tenant" />}
|
|
/>
|
|
<Autocomplete
|
|
disablePortal
|
|
options={locationlist || []}
|
|
getOptionLabel={(option) => `${option.locationname} (${option.suburb})` || ''}
|
|
value={locationValue}
|
|
sx={{ minWidth: 200, flex: 1 }}
|
|
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) => <TextField {...params} label="Select Location" />}
|
|
/>
|
|
<Autocomplete
|
|
sx={{ minWidth: 200, flex: 1 }}
|
|
fullWidth
|
|
disabled={riderListIsLoading}
|
|
options={ridersList}
|
|
getOptionLabel={(option) => `${option.firstname} ${option.lastname} (${option.contactno})`}
|
|
renderInput={(params) => <TextField {...params} label="Choose Rider" />}
|
|
onChange={(e, value, reason) => {
|
|
if (reason === 'clear') {
|
|
setRiderid(0);
|
|
} else {
|
|
setRiderid(value.userid);
|
|
console.log('selected rider', value);
|
|
}
|
|
}}
|
|
onOpen={(event) => {
|
|
if (!appId) {
|
|
event.preventDefault();
|
|
OpenToast('Please select a your location first!', 'warning', 3000);
|
|
setTimeout(() => {
|
|
locationRef.current?.focus();
|
|
}, 0);
|
|
}
|
|
}}
|
|
/>
|
|
</Stack>
|
|
{/* ============================================= || Tabs || ============================================= */}
|
|
<Stack
|
|
display={'flex'}
|
|
flexDirection={'row'}
|
|
justifyContent={'space-between'}
|
|
alignItems={'center'}
|
|
flexWrap={'wrap-reverse'}
|
|
gap={2}
|
|
sx={{
|
|
border: '1px solid ',
|
|
borderBottom: 0,
|
|
borderColor: 'bg.main',
|
|
p: 1.5
|
|
}}
|
|
>
|
|
<Tabs
|
|
value={tabvalue}
|
|
onChange={handleChangetab}
|
|
variant="scrollable"
|
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
scrollButtons={useMediaQuery(theme.breakpoints.down('custom1000')) ? true : false}
|
|
allowScrollButtonsMobile
|
|
>
|
|
<Tab
|
|
label="Assigned"
|
|
icon={
|
|
<Chip
|
|
label={countData?.uncoveredLength || 0}
|
|
color="primary"
|
|
variant="light"
|
|
size="small"
|
|
sx={{ minWidth: 40, justifyContent: 'center' }}
|
|
/>
|
|
}
|
|
iconPosition="end"
|
|
/>
|
|
<Tab
|
|
label="Accepted"
|
|
icon={
|
|
<Chip
|
|
label={countData?.assignedLength || 0}
|
|
color="primary"
|
|
variant="light"
|
|
size="small"
|
|
sx={{ minWidth: 40, justifyContent: 'center' }}
|
|
/>
|
|
}
|
|
iconPosition="end"
|
|
/>
|
|
<Tab
|
|
label="Arrived"
|
|
icon={
|
|
<Chip
|
|
label={countData?.arrivedLength || 0}
|
|
color="primary"
|
|
variant="light"
|
|
size="small"
|
|
sx={{ minWidth: 40, justifyContent: 'center' }}
|
|
/>
|
|
}
|
|
iconPosition="end"
|
|
/>
|
|
|
|
<Tab
|
|
label="Picked"
|
|
icon={
|
|
<Chip
|
|
label={countData?.pickedLength || 0}
|
|
color="primary"
|
|
variant="light"
|
|
size="small"
|
|
sx={{ minWidth: 40, justifyContent: 'center' }}
|
|
/>
|
|
}
|
|
iconPosition="end"
|
|
/>
|
|
<Tab
|
|
label="Active"
|
|
icon={
|
|
<Chip
|
|
label={countData?.activeLength || 0}
|
|
color="primary"
|
|
variant="light"
|
|
size="small"
|
|
sx={{ minWidth: 40, justifyContent: 'center' }}
|
|
/>
|
|
}
|
|
iconPosition="end"
|
|
/>
|
|
<Tab
|
|
label="Skipped"
|
|
icon={
|
|
<Chip
|
|
label={countData?.skippedLength || 0}
|
|
color="primary"
|
|
variant="light"
|
|
size="small"
|
|
sx={{ minWidth: 40, justifyContent: 'center' }}
|
|
/>
|
|
}
|
|
iconPosition="end"
|
|
/>
|
|
|
|
<Tab
|
|
label="Delivered"
|
|
icon={
|
|
<Chip
|
|
label={countData?.coveredLength || 0}
|
|
color="primary"
|
|
variant="light"
|
|
size="small"
|
|
sx={{ minWidth: 40, justifyContent: 'center' }}
|
|
/>
|
|
}
|
|
iconPosition="end"
|
|
/>
|
|
|
|
<Tab
|
|
label="Cancelled"
|
|
icon={
|
|
<Chip
|
|
label={countData?.cancelLength || 0}
|
|
color="primary"
|
|
variant="light"
|
|
size="small"
|
|
sx={{ minWidth: 40, justifyContent: 'center' }}
|
|
/>
|
|
}
|
|
iconPosition="end"
|
|
/>
|
|
</Tabs>
|
|
|
|
{/* ============================================= || searchOutlined | ============================================= */}
|
|
<DebounceSearchBar
|
|
value={searchword}
|
|
onChange={setSearchword}
|
|
onDebouncedChange={setDebouncedSearch}
|
|
sx={{ m: 0, width: 280, flex: 1 }}
|
|
/>
|
|
</Stack>
|
|
{/* ============================================= || MainCard || ============================================= */}
|
|
<MainCard content={false}>
|
|
<TableContainer
|
|
ref={containerRef}
|
|
onScroll={handleScroll}
|
|
sx={{
|
|
maxHeight: 'calc(100vh - 190px)',
|
|
overflow: 'auto',
|
|
overflowX: 'auto',
|
|
'&::-webkit-scrollbar': {
|
|
width: '12px', // scroll bar width
|
|
cursor: 'pointer'
|
|
},
|
|
'&::-webkit-scrollbar-thumb': {
|
|
backgroundColor: theme.palette.primary.main, // thumb color
|
|
borderRadius: '8px',
|
|
cursor: 'pointer'
|
|
},
|
|
'&::-webkit-scrollbar-thumb:hover': {
|
|
backgroundColor: theme.palette.primary.dark, // hover color
|
|
cursor: 'pointer'
|
|
},
|
|
'&::-webkit-scrollbar-track': {
|
|
backgroundColor: theme.palette.primary.lighter,
|
|
cursor: 'pointer'
|
|
}
|
|
}}
|
|
>
|
|
<Table stickyHeader sx={{ minWidth: 1400 }}>
|
|
<TableHead>
|
|
<TableRow>
|
|
{tabstatus == 'Created' && (
|
|
<TableCell sx={{ whiteSpace: 'nowrap' }}>
|
|
<Checkbox
|
|
indeterminate={deliverylist.length > 0 && deliverylist.length != rows.length}
|
|
onChange={(e) => {
|
|
if (e.target.checked) {
|
|
setDeliverylist([...rows]);
|
|
} else {
|
|
setDeliverylist([]);
|
|
}
|
|
}}
|
|
checked={deliverylist.length == rows.length}
|
|
/>
|
|
</TableCell>
|
|
)}
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>S.No </TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>Tenant </TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>
|
|
Order Location{' '}
|
|
</TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>Pickup </TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>Drop </TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>Rider </TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>Est. Delivery Time</TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>Transit</TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}> Kms</TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>Amount </TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>Notes </TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>Steps</TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>Qty</TableCell>
|
|
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light, whiteSpace: 'nowrap', border: 'none' }}>COD </TableCell>
|
|
{tabstatus !== 'Cancelled' && tabstatus !== 'Delivered' && (
|
|
<TableCell
|
|
align="right"
|
|
sx={{
|
|
position: 'sticky !important',
|
|
backgroundColor: theme.palette.secondary.light,
|
|
whiteSpace: 'nowrap',
|
|
border: 'none'
|
|
}}
|
|
>
|
|
Action
|
|
</TableCell>
|
|
)}
|
|
</TableRow>
|
|
</TableHead>
|
|
{(loading1 || fetchDeliveriesIsLoading) && <OrdersTableSkeleton col={8} />}
|
|
<TableBody>
|
|
{rows.length == 0 && !loading1 && (
|
|
<>
|
|
<TableCell colSpan={14}>
|
|
{/* <Stack width={'100%'} direction={'row'} justifyContent={'center'}> */}
|
|
<Empty description={`No ${tabstatus} Orders`} styles={{ description: { color: theme.palette.error.main } }} />
|
|
</TableCell>
|
|
</>
|
|
)}
|
|
{rows.map((row, index) => {
|
|
return (
|
|
<>
|
|
<TableRow
|
|
role="checkbox"
|
|
tabIndex={-1}
|
|
key={row.tenantname}
|
|
sx={{
|
|
cursor: 'pointer',
|
|
backgroundColor: deliverylist.find((res1) => res1.orderheaderid == row.orderheaderid) ? '#e1bee7' : '',
|
|
'&:hover': {
|
|
backgroundColor: deliverylist.find((res1) => res1.orderheaderid == row.orderheaderid) ? '#e1bee7 !important' : ''
|
|
}
|
|
}}
|
|
>
|
|
{tabstatus == 'Created' && (
|
|
<TableCell>
|
|
<Checkbox
|
|
onChange={(e) => {
|
|
if (e.target.checked) {
|
|
let arr = deliverylist;
|
|
arr.push({ ...row, sno: deliverylist.length + 1 });
|
|
setDeliverylist([...arr]);
|
|
} else {
|
|
let res = deliverylist.find((res1) => res1.orderheaderid == row.orderheaderid);
|
|
if (res) {
|
|
let arr = deliverylist;
|
|
let res = deliverylist.find((res1) => res1.orderheaderid == row.orderheaderid);
|
|
arr.splice(res.sno - 1, 1);
|
|
arr.map((val, i) => {
|
|
val.sno = i + 1;
|
|
});
|
|
setDeliverylist([...arr]);
|
|
}
|
|
}
|
|
console.log('list', deliverylist);
|
|
}}
|
|
checked={deliverylist.find((res1) => res1.orderheaderid == row.orderheaderid)}
|
|
/>
|
|
</TableCell>
|
|
)}
|
|
<TableCell>
|
|
{/* <Typography> {row.sno}</Typography> */}
|
|
<Typography> {page * rowsPerPage + index + 1}</Typography>
|
|
</TableCell>
|
|
{/* Tenants */}
|
|
<TableCell>
|
|
<Tooltip title={row.tenantadress}>
|
|
<Typography noWrap variant="subtitle1">
|
|
{row.tenantname}
|
|
</Typography>
|
|
<Typography noWrap variant="body2">
|
|
{row.tenantsuburb}
|
|
</Typography>
|
|
|
|
<Typography noWrap variant="body2">
|
|
{row.applocation}
|
|
</Typography>
|
|
</Tooltip>
|
|
</TableCell>
|
|
{/* order details */}
|
|
<TableCell align="left">
|
|
<Tooltip title="Location Name-Suburb" placement="top">
|
|
<Typography variant="subtitle1" noWrap>
|
|
{`${row.locationname}-(${row.locationsuburb})`}
|
|
</Typography>
|
|
</Tooltip>
|
|
|
|
<Stack display={'flex'} flexDirection={'row'} gap={3}>
|
|
<Stack>
|
|
<Tooltip title="Order Id" placement="top">
|
|
<Typography variant="body2" noWrap>
|
|
{row.orderid}
|
|
</Typography>
|
|
</Tooltip>
|
|
<Tooltip title="Ordered date" placement="top">
|
|
<Typography noWrap sx={{ fontSize: '12px' }}>
|
|
{dayjs(row.orderdate).utc().format('DD/MM/YYYY')}
|
|
</Typography>
|
|
<Typography noWrap sx={{ fontSize: '11px' }}>
|
|
{dayjs(row.orderdate).utc().format('hh:mm A')}
|
|
</Typography>
|
|
</Tooltip>
|
|
</Stack>
|
|
-
|
|
<Stack>
|
|
<Tooltip title="Delivery Id" placement="top">
|
|
<Typography variant="body2" noWrap>
|
|
{row.deliveryid}
|
|
</Typography>
|
|
</Tooltip>
|
|
<Tooltip title="Delivery date" placement="top">
|
|
<Typography noWrap sx={{ fontSize: '12px' }}>
|
|
{dayjs(row.deliverydate).utc().format('DD/MM/YYYY')}
|
|
</Typography>
|
|
|
|
<Typography noWrap sx={{ fontSize: '11px' }}>
|
|
{dayjs(row.deliverydate).utc().format('hh:mm A')}
|
|
</Typography>
|
|
</Tooltip>
|
|
</Stack>
|
|
</Stack>
|
|
</TableCell>
|
|
{/* pickup */}
|
|
<TableCell align="left">
|
|
<Stack direction={'row'} spacing={1}>
|
|
<Stack direction="column">
|
|
<Typography variant="subtitle1" sx={{ whiteSpace: 'nowrap' }}>
|
|
{row.pickupcustomer}
|
|
</Typography>
|
|
<Typography variant="body2">{row.pickupcontactno}</Typography>
|
|
<Tooltip title={row.Pickupaddress} sx={{ whiteSpace: 'nowrap' }}>
|
|
<Typography variant="body2">{row.pickuplocation || row.Pickupaddress.slice(0, 12) + '...'}</Typography>
|
|
</Tooltip>
|
|
</Stack>
|
|
</Stack>
|
|
</TableCell>
|
|
{/* drop */}
|
|
<TableCell align="left">
|
|
<Stack direction={'row'} spacing={1}>
|
|
<Stack direction="column">
|
|
<Typography variant="subtitle1" sx={{ whiteSpace: 'nowrap' }}>
|
|
{row.deliverycustomer}
|
|
</Typography>
|
|
<Typography variant="body2">{row.deliverycontactno}</Typography>
|
|
<Tooltip title={row.deliveryaddress}>
|
|
<Typography variant="body2" sx={{ whiteSpace: 'nowrap' }}>
|
|
{`${row.deliverylocation || row.deliveryaddress.slice(0, 12) + '...'}`}
|
|
</Typography>
|
|
</Tooltip>
|
|
</Stack>
|
|
</Stack>
|
|
</TableCell>
|
|
{/* rider */}
|
|
<TableCell>
|
|
<Typography variant="subtitle1" noWrap>
|
|
{row.ridername}
|
|
</Typography>
|
|
<Typography variant="subtitle2"> {`ID: ${row.userid}`}</Typography>
|
|
<Typography variant="subtitle2"> {row.ridercontact}</Typography>
|
|
</TableCell>
|
|
{/* Estimated Delivery Time */}
|
|
<TableCell align="left">
|
|
<Typography variant="subtitle1" noWrap>
|
|
{row.expecteddeliverytime ? dayjs(row.expecteddeliverytime).format('hh:mm A') : 'N/A'}
|
|
</Typography>
|
|
</TableCell>
|
|
{/* Transit Minutes */}
|
|
<TableCell align="left">
|
|
<Typography variant="subtitle1" noWrap>
|
|
{row.transitminutes || 0} min
|
|
</Typography>
|
|
</TableCell>
|
|
{/* kms */}
|
|
<TableCell>
|
|
<Stack direction={'column'} spacing={1}>
|
|
<Tooltip title=" KMS" placement="top">
|
|
<Chip label={row.kms || 0} size="small" variant="light" color="error" />
|
|
</Tooltip>
|
|
<Tooltip title="Actual KMS">
|
|
<Chip label={row.cumulativekms || 0} size="small" color="success" variant="light" />
|
|
</Tooltip>
|
|
</Stack>
|
|
</TableCell>
|
|
{/* amount */}
|
|
<TableCell align="left">
|
|
<Stack direction={'column'} spacing={1}>
|
|
<Tooltip title=" Delivery Charge" placement="top">
|
|
<Chip label={`₹ ${row.deliverycharges?.toFixed(2)}` || 0} size="small" variant="light" color="error" />
|
|
</Tooltip>
|
|
<Tooltip title="Delivery Amount">
|
|
<Chip label={`₹ ${row.deliveryamt?.toFixed(2)}` || 0} size="small" color="success" variant="light" />
|
|
</Tooltip>
|
|
</Stack>
|
|
</TableCell>
|
|
{/* notes */}
|
|
<TableCell>
|
|
<Typography>{row.notes}</Typography>
|
|
</TableCell>
|
|
{/* step */}
|
|
<TableCell align="center">
|
|
{row.step ? (
|
|
<Chip
|
|
label={row.step}
|
|
size="small"
|
|
color="primary"
|
|
variant="light"
|
|
sx={{ fontWeight: 700, minWidth: 28 }}
|
|
/>
|
|
) : (
|
|
<Typography variant="subtitle2" color="text.disabled">
|
|
—
|
|
</Typography>
|
|
)}
|
|
</TableCell>
|
|
{/* qty */}
|
|
<TableCell>
|
|
{row.Quantity ? (
|
|
<Typography variant="subtitle1" color={'error'} sx={{ whiteSpace: 'nowrap' }}>
|
|
{row.Quantity}
|
|
</Typography>
|
|
) : (
|
|
<Typography variant="subtitle1" sx={{ whiteSpace: 'nowrap' }}>
|
|
{' '}
|
|
{row.Quantity}
|
|
</Typography>
|
|
)}
|
|
</TableCell>
|
|
{/* {cash} */}
|
|
<TableCell>
|
|
{row.collectionamt ? (
|
|
<Typography variant="subtitle1" color={'error'} sx={{ whiteSpace: 'nowrap' }}>
|
|
{' '}
|
|
{`₹ ${row.collectionamt.toFixed(2)}`}{' '}
|
|
</Typography>
|
|
) : (
|
|
<Typography variant="subtitle1" sx={{ whiteSpace: 'nowrap' }}>
|
|
{' '}
|
|
{`₹ ${row.collectionamt.toFixed(2)}`}{' '}
|
|
</Typography>
|
|
)}
|
|
</TableCell>
|
|
{/* Action */}
|
|
{tabstatus !== 'Cancelled' && tabstatus !== 'Delivered' && (
|
|
<TableCell>
|
|
<Stack display={'flex'} flexDirection={'row'} justifyContent={'end'}>
|
|
{row.deliverytype == 'C' && (
|
|
<Tooltip title="Product details" placement="top">
|
|
<IconButton
|
|
color="primary"
|
|
onClick={() => {
|
|
if (productCollapse?.orderid === row.orderid) {
|
|
setProductCollapse(null); // Collapse if already open
|
|
setOrderHeaderId(null);
|
|
} else {
|
|
setProductCollapse(row); // Open if different
|
|
setOrderHeaderId(row.orderheaderid); // Open if different
|
|
}
|
|
}}
|
|
>
|
|
{productCollapse?.orderid === row.orderid ? <KeyboardArrowUpOutlined /> : <KeyboardArrowDownOutlined />}
|
|
</IconButton>
|
|
</Tooltip>
|
|
)}
|
|
|
|
<IconButton
|
|
color="primary"
|
|
size="small"
|
|
sx={{ bgcolor: 'primary.100' }}
|
|
onClick={(e) => handleMenuOpen(e, row)}
|
|
>
|
|
<EditOutlined />
|
|
</IconButton>
|
|
|
|
<Menu
|
|
anchorEl={menuAnchorEl}
|
|
open={menuOpen}
|
|
onClose={handleMenuClose}
|
|
anchorOrigin={{
|
|
vertical: 'bottom',
|
|
horizontal: 'right'
|
|
}}
|
|
transformOrigin={{
|
|
vertical: 'top',
|
|
horizontal: 'right'
|
|
}}
|
|
PaperProps={{
|
|
elevation: 4,
|
|
sx: {
|
|
minWidth: 200,
|
|
borderRadius: 1
|
|
}
|
|
}}
|
|
>
|
|
{selectedRow?.orderstatus !== 'delivered' && (
|
|
<MenuItem
|
|
onClick={() => {
|
|
notifyRiderMutation.mutate(selectedRow.userfcmtoken);
|
|
handleMenuClose();
|
|
}}
|
|
>
|
|
Notify Rider
|
|
</MenuItem>
|
|
)}
|
|
{['pending', 'accepted', 'arrived'].includes(selectedRow?.orderstatus) && (
|
|
<MenuItem
|
|
onClick={() => {
|
|
if (!appId) {
|
|
opentoast('Please select a location first!', 'warning');
|
|
locationRef.current?.focus();
|
|
return;
|
|
}
|
|
setChangeDialogOpen(true);
|
|
handleMenuClose();
|
|
}}
|
|
>
|
|
Change Rider
|
|
</MenuItem>
|
|
)}
|
|
{(roleid == 1 || roleid == 2) && (
|
|
<MenuItem
|
|
onClick={() => {
|
|
setKms(selectedRow.kms);
|
|
setCumulativeKms(selectedRow.cumulativekms);
|
|
setDeliverylat(selectedRow.droplat);
|
|
setDeliverylong(selectedRow.droplon);
|
|
setNotes(selectedRow.notes);
|
|
setDeliveryamount(selectedRow.deliveryamount);
|
|
setCurrentorder(selectedRow);
|
|
setDialogopen(true);
|
|
handleMenuClose();
|
|
}}
|
|
>
|
|
Update Delivery Status
|
|
</MenuItem>
|
|
)}
|
|
{selectedRow?.orderstatus !== 'cancelled' && selectedRow?.orderstatus !== 'delivered' && (
|
|
<MenuItem
|
|
sx={{ color: 'error.main' }}
|
|
onClick={() => {
|
|
setCancelDeliveryOpen(true);
|
|
handleMenuClose();
|
|
}}
|
|
>
|
|
Cancel Delivery
|
|
</MenuItem>
|
|
)}
|
|
</Menu>
|
|
</Stack>
|
|
</TableCell>
|
|
)}
|
|
</TableRow>
|
|
{productCollapse?.orderid === row?.orderid && (
|
|
<TableRow>
|
|
<TableCell
|
|
colSpan={11}
|
|
sx={{
|
|
p: 0,
|
|
border: 0,
|
|
'&:hover': {
|
|
backgroundColor: 'white' // or use 'inherit'
|
|
}
|
|
}}
|
|
>
|
|
<Collapse in={true} timeout="auto" unmountOnExit>
|
|
<Box
|
|
sx={{
|
|
width: '100%',
|
|
px: 2,
|
|
py: 2
|
|
}}
|
|
>
|
|
<Table size="small" sx={{ minWidth: 800 }}>
|
|
<TableHead>
|
|
<TableRow
|
|
sx={{
|
|
'&:hover': {
|
|
backgroundColor: 'transparent !important'
|
|
}
|
|
}}
|
|
>
|
|
<TableCell sx={{ fontWeight: 600 }}>S.No</TableCell>
|
|
<TableCell sx={{ fontWeight: 600 }}>Product Name</TableCell>
|
|
<TableCell sx={{ fontWeight: 600 }}>Description</TableCell>
|
|
<TableCell align="right" sx={{ fontWeight: 600 }}>
|
|
Quantity
|
|
</TableCell>
|
|
<TableCell align="right" sx={{ fontWeight: 600 }}>
|
|
Cost
|
|
</TableCell>
|
|
<TableCell align="right" sx={{ fontWeight: 600 }}>
|
|
Price
|
|
</TableCell>
|
|
<TableCell align="right" sx={{ fontWeight: 600 }}>
|
|
Tax
|
|
</TableCell>
|
|
<TableCell align="right" sx={{ fontWeight: 600 }}>
|
|
Amount
|
|
</TableCell>
|
|
</TableRow>
|
|
</TableHead>
|
|
|
|
<TableBody>
|
|
{orderdetails?.details?.map((product, index) => (
|
|
<TableRow
|
|
key={index}
|
|
sx={{
|
|
'&:hover': {
|
|
backgroundColor: 'transparent !important'
|
|
}
|
|
}}
|
|
>
|
|
<TableCell>{index + 1}</TableCell>
|
|
<TableCell>
|
|
<Stack direction="row" spacing={1} alignItems="center">
|
|
<img
|
|
src={product?.productimage || 'https://via.placeholder.com/40'} // fallback image
|
|
alt={product?.productname}
|
|
style={{
|
|
width: 40,
|
|
height: 40,
|
|
objectFit: 'cover',
|
|
borderRadius: 4
|
|
}}
|
|
/>
|
|
<Typography variant="body2" noWrap>
|
|
{product?.productname || 'Unnamed'}
|
|
</Typography>
|
|
</Stack>
|
|
</TableCell>
|
|
<TableCell>{product?.productdescription || '-'}</TableCell>
|
|
<TableCell align="right">{product?.orderqty || 0}</TableCell>
|
|
<TableCell align="right">₹ {product?.price || 0}</TableCell>
|
|
<TableCell align="right">₹ {(product?.productsumprice ?? 0).toFixed(2)}</TableCell>
|
|
<TableCell align="right">₹ {(product?.taxamount ?? 0).toFixed(2)}</TableCell>
|
|
<TableCell align="right">
|
|
₹ {(product?.productsumprice + product?.taxamount).toFixed(2) || 0}
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
<TableRow
|
|
sx={{
|
|
'&:hover': {
|
|
backgroundColor: 'transparent !important'
|
|
}
|
|
}}
|
|
>
|
|
<TableCell align="right" colSpan={7} sx={{}}>
|
|
Total Amount :
|
|
</TableCell>
|
|
<TableCell align="right" sx={{}}>
|
|
₹ {orderdetails?.pricedetails?.orderamount.toFixed(2)}
|
|
</TableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table>
|
|
</Box>
|
|
</Collapse>
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</>
|
|
);
|
|
})}
|
|
{rows?.length != 0 && (
|
|
<TableRow>
|
|
<TableCell colSpan={15} rowSpan={3}>
|
|
<div ref={loadMoreRef} style={{ height: 40, textAlign: 'center' }}>
|
|
{isFetchingNextPage ? <LoaderWithImage /> : hasNextPage ? <LoaderWithImage /> : 'No More Deliveries'}
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</TableContainer>
|
|
</MainCard>
|
|
|
|
{/* =============================== || cancel dialog || =============================== */}
|
|
<Dialog open={cancelDeliveryOpen} onClose={() => setCancelDeliveryOpen(false)} maxWidth="xs">
|
|
<DialogContent sx={{ mt: 2, my: 1 }}>
|
|
<Stack alignItems="center" spacing={3.5}>
|
|
<Avatar color="error" sx={{ width: 72, height: 72, fontSize: '1.75rem' }}>
|
|
<DeleteFilled />
|
|
</Avatar>
|
|
|
|
<Stack spacing={2}>
|
|
<Typography variant="h5" align="center">
|
|
Are you sure you want to cancel this delivery?
|
|
</Typography>
|
|
</Stack>
|
|
<TextField
|
|
fullWidth
|
|
label="Enter Feedback"
|
|
multiline
|
|
maxRows={4}
|
|
onChange={(e) => {
|
|
setCancelFeed(e.target.value);
|
|
}}
|
|
/>
|
|
<Stack direction="row" spacing={2} sx={{ width: 1 }}>
|
|
<Button
|
|
// disabled={cancelFeed == '' ? true : false}
|
|
fullWidth
|
|
color="error"
|
|
variant="contained"
|
|
onClick={() => {
|
|
{
|
|
cancelFeed == '' ? opentoast('Enter FeedBack', 'error') : cancelDelivery({ selectedRow, cancelFeed });
|
|
}
|
|
cancelridernotification();
|
|
}}
|
|
autoFocus
|
|
sx={{ border: '1px solid red' }}
|
|
>
|
|
Yes, Cancel
|
|
</Button>
|
|
<Button
|
|
fullWidth
|
|
onClick={() => {
|
|
setCancelDeliveryOpen(false);
|
|
}}
|
|
color="secondary"
|
|
variant="outlined"
|
|
>
|
|
No
|
|
</Button>
|
|
</Stack>
|
|
</Stack>
|
|
</DialogContent>
|
|
</Dialog>
|
|
{/* =============================== || change dialog || =============================== */}
|
|
<Dialog
|
|
open={changeDialogOpen}
|
|
onClose={() => setChangeDialogOpen(false)}
|
|
maxWidth="sm"
|
|
fullWidth
|
|
TransitionComponent={PopupTransition}
|
|
>
|
|
<DialogTitle sx={{ bgcolor: theme.palette.primary.main }}>
|
|
<Typography variant="h3" sx={{ color: 'white' }}>
|
|
Change Rider
|
|
</Typography>
|
|
</DialogTitle>
|
|
<DialogContent dividers>
|
|
<Grid container spacing={2}>
|
|
<Grid item xs={12} sx={{ m: 2 }}>
|
|
<Autocomplete
|
|
fullWidth
|
|
options={ridersList}
|
|
// getOptionLabel={(option) => `${option.firstname} ${option.lastname} | ${option.contactno}`}
|
|
renderInput={(params) => <TextField {...params} label="Choose Rider" />}
|
|
onChange={(e, value) => {
|
|
setSelectedRider(value);
|
|
console.log('selected rider', value);
|
|
}}
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Stack direction={'row'} spacing={3}>
|
|
<Button
|
|
variant="outlined"
|
|
color="secondary"
|
|
onClick={() => {
|
|
setChangeDialogOpen(false);
|
|
}}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
<Button
|
|
variant="contained"
|
|
color="primary"
|
|
onClick={() => {
|
|
setLoading1(true);
|
|
changeRiderMutation.mutate({ selectedRider, selectedRow });
|
|
}}
|
|
>
|
|
Change Rider
|
|
</Button>
|
|
</Stack>
|
|
</DialogActions>
|
|
</Dialog>
|
|
|
|
{/* =============================== || Date filter Dialog || =============================== */}
|
|
<Dialog open={open}>
|
|
<DialogTitle align="left">
|
|
<Typography variant="h4">Select Filter Options</Typography>
|
|
</DialogTitle>
|
|
<DialogContent sx={{ width: '100%' }} className="datedialog">
|
|
<DateRangePicker
|
|
open={open}
|
|
toggle={() => setOpen(!open)}
|
|
id="daterange1"
|
|
onChange={(range) => {
|
|
if (range.label === 'All') {
|
|
setStartdate('');
|
|
setEnddate('');
|
|
|
|
setOpen(false);
|
|
} else {
|
|
setStartdate(dayjs(range.startDate).format('YYYY-MM-DD'));
|
|
setEnddate(dayjs(range.endDate).format('YYYY-MM-DD'));
|
|
if (range.label) {
|
|
setDatestatus(range.label);
|
|
} else {
|
|
setDatestatus('');
|
|
}
|
|
}
|
|
console.log(range);
|
|
}}
|
|
definedRanges={[
|
|
{
|
|
label: 'Today',
|
|
startDate: new Date(),
|
|
endDate: new Date()
|
|
},
|
|
{
|
|
label: 'Yesterday',
|
|
startDate: addDays(new Date(), -1),
|
|
endDate: addDays(new Date(), -1)
|
|
},
|
|
{
|
|
label: 'Tomorrow',
|
|
startDate: addDays(new Date(), +1),
|
|
endDate: addDays(new Date(), +1)
|
|
},
|
|
{
|
|
label: 'This Week',
|
|
startDate: startOfWeek(new Date()),
|
|
endDate: endOfWeek(new Date())
|
|
},
|
|
{
|
|
label: 'Last Week',
|
|
startDate: startOfWeek(addWeeks(new Date(), -1)),
|
|
endDate: endOfWeek(addWeeks(new Date(), -1))
|
|
},
|
|
{
|
|
label: 'Last 7 Days',
|
|
startDate: addWeeks(new Date(), -1),
|
|
endDate: new Date()
|
|
},
|
|
{
|
|
label: 'This Month',
|
|
startDate: startOfMonth(new Date()),
|
|
endDate: endOfMonth(new Date())
|
|
},
|
|
{
|
|
label: 'Last Month',
|
|
startDate: startOfMonth(addMonths(new Date(), -1)),
|
|
endDate: endOfMonth(addMonths(new Date(), -1))
|
|
}
|
|
// {
|
|
// label: 'All',
|
|
// startDate: new Date(),
|
|
// endDate: addDays(new Date(), -1),
|
|
// },
|
|
]}
|
|
/>
|
|
</DialogContent>
|
|
<Stack direction="row" justifyContent="flex-end" sx={{ width: '100%', p: 2 }}>
|
|
<Button variant="contained" size="small" onClick={okclicked}>
|
|
ok
|
|
</Button>
|
|
</Stack>
|
|
</Dialog>
|
|
|
|
{/* =============================== || Update Delivery Dialog || =============================== */}
|
|
<Dialog fullWidth={true} open={dialogopen} onClose={dialogclose} scroll={'paper'} maxWidth="sm" TransitionComponent={PopupTransition}>
|
|
<DialogTitle
|
|
sx={{
|
|
bgcolor: '#662582',
|
|
color: '#fff'
|
|
}}
|
|
>
|
|
Update Delivery Status
|
|
</DialogTitle>
|
|
|
|
<DialogContent dividers={true}>
|
|
<MainCard sx={{ height: '100%' }}>
|
|
<Grid container spacing={2.5}>
|
|
<Grid item xs={12} sm={6}>
|
|
<FormLabel>Kms</FormLabel>
|
|
<TextField
|
|
fullWidth
|
|
value={kms}
|
|
type="number"
|
|
onChange={(e) => {
|
|
setKms(e.target.value);
|
|
console.log(e);
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<FormLabel>Actual Kms</FormLabel>
|
|
<TextField value={cumulativekms} type="number" onChange={(e) => setCumulativeKms(+e.target.value)} fullWidth />
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<FormLabel>Delivery lat</FormLabel>
|
|
<TextField
|
|
fullWidth
|
|
type="number"
|
|
value={deliverylat}
|
|
onChange={(e) => {
|
|
setDeliverylat(e.target.value);
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<FormLabel>Delivery Long</FormLabel>
|
|
<TextField
|
|
value={deliverylong}
|
|
type="number"
|
|
onChange={(e) => {
|
|
setDeliverylong(e.target.value);
|
|
}}
|
|
fullWidth
|
|
/>
|
|
</Grid>
|
|
|
|
<Grid item xs={12}>
|
|
<FormLabel>Amount</FormLabel>
|
|
|
|
<TextField fullWidth type="number" value={deliveryamount} onChange={(e) => setDeliveryamount(+e.target.value)} />
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<FormLabel>Notes</FormLabel>
|
|
<TextField value={notes} fullWidth onChange={(e) => setNotes(e.target.value)} />
|
|
</Grid>
|
|
</Grid>
|
|
</MainCard>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Grid container>
|
|
<Grid item xs={12}>
|
|
<Stack direction={'row'} justifyContent={'flex-end'} spacing={2} sx={{ p: 2 }}>
|
|
<Button
|
|
variant="contained"
|
|
onClick={() => {
|
|
dialogclose();
|
|
}}
|
|
color="error"
|
|
>
|
|
Close
|
|
</Button>{' '}
|
|
<Button
|
|
variant="contained"
|
|
onClick={() => {
|
|
if (!kms) {
|
|
opentoast('Fill Kms', 'warning');
|
|
} else if (!cumulativekms) {
|
|
opentoast('Fill Actual Kms', 'warning');
|
|
} else if (!deliverylat) {
|
|
opentoast('Fill Delivery Latitude', 'warning');
|
|
} else if (!deliverylong) {
|
|
opentoast('Fill Delivery Longitude', 'warning');
|
|
} else if (!deliveryamount) {
|
|
opentoast('Fill Delivery Amount', 'warning');
|
|
} else {
|
|
updateDeliveryMutation.mutate({
|
|
deliveryid: currentorder.deliveryid,
|
|
orderheaderid: currentorder.orderheaderid,
|
|
orderstatus: 'delivered',
|
|
deliverytime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
|
deliverylat,
|
|
deliverylong,
|
|
kms,
|
|
cumulativekms,
|
|
deliveryamt: parseFloat(deliveryamount),
|
|
notes,
|
|
userid: +selectedRow.userid
|
|
});
|
|
}
|
|
}}
|
|
>
|
|
Update
|
|
</Button>
|
|
</Stack>
|
|
</Grid>
|
|
</Grid>
|
|
</DialogActions>
|
|
</Dialog>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Deliveries;
|