initial commit

This commit is contained in:
2026-05-13 17:48:36 +05:30
commit 5a80256856
305 changed files with 80994 additions and 0 deletions

View File

@@ -0,0 +1,623 @@
import {
Autocomplete,
Button,
Chip,
Divider,
Grid,
Stack,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
TextField,
Tooltip,
Typography,
Backdrop,
IconButton
} from '@mui/material';
import React, { Fragment, useEffect, useMemo, useState } from 'react';
import { useTheme } from '@mui/material/styles';
import { useLocation, useNavigate } from 'react-router-dom';
import dayjs from 'dayjs';
import MainCard from 'components/MainCard';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import { fetchPaymentType, fetchRidersList, finalCreatedeliveries, notifyRider } from 'pages/api/api';
import { OpenToast } from 'components/third-party/OpenToast';
import { useMutation, useQuery } from '@tanstack/react-query';
import Loader from 'components/Loader';
import CircularLoader from 'components/CircularLoader';
import { Empty } from 'antd';
import HoverSocialCard from 'components/cards/statistics/HoverSocialCard';
import { DashboardFilled, OpenAIFilled } from '@ant-design/icons';
import { MdDirectionsBike } from 'react-icons/md';
import { FaMapLocationDot } from 'react-icons/fa6';
import { HiOutlineArrowLeft } from 'react-icons/hi';
var utc = require('dayjs/plugin/utc');
dayjs.extend(utc);
const OrdersPreview = () => {
const theme = useTheme();
const navigate = useNavigate();
const location = useLocation();
console.log('location.state', location.state);
const [rider, setRider] = useState(null);
const [payment, setPayment] = useState(null);
const [finaldeliveryList, setFinalDeliveryList] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const deliverylist = location.state?.deliverylist;
const zoneData = location.state?.zoneData;
const metaData = location.state?.metaData;
const riderToken = location.state?.riderToken;
const appId = location.state?.appId;
const aiMode = location.state?.aiMode;
const reassignOrders = location.state?.reassignOrders;
useEffect(() => {
console.log('aiMode', aiMode);
console.log('riderToken', riderToken);
console.log('zoneData', zoneData);
console.log('metaData', metaData);
console.log('reassignOrders', reassignOrders);
}, []);
useEffect(() => {
if (!deliverylist?.length) return;
const updateDeliveryAmtList = deliverylist.map((list) => {
const cumulativeKms = Number(list.cumulativekms || 0);
const minKm = Number(list.minkm || 0);
const basePrice = Number(list.baseprice || 0);
const pricePerKm = Number(list.priceperkm || 0);
if (cumulativeKms <= minKm) {
return {
...list,
deliveryamt: basePrice
};
}
return {
...list,
deliveryamt: (cumulativeKms - minKm) * pricePerKm + basePrice
};
});
setFinalDeliveryList(updateDeliveryAmtList);
console.log('finaldeliveryList', updateDeliveryAmtList);
}, [deliverylist]);
// ==============================|| fetchPaymentType ||============================== //
const {
data: paymentModes = [],
isLoading: paymentModesLoading,
isError: paymentModesError,
error: paymentModesErrorMessage
} = useQuery({
queryKey: ['paymentmodes'],
queryFn: fetchPaymentType
});
// ==============================|| fetchRidersList ||============================== //
const {
data: ridersList = [],
isLoading: ridersListLoading,
isError: ridersListError,
error: ridersListErrorMessage,
refetch: ridersListRefetch
} = useQuery({
queryKey: ['ridersList', appId], // Unique key for caching & re-fetching
queryFn: fetchRidersList,
enabled: appId !== 0 // Ensures query runs only when appId is valid
});
const getRiderName = async (userid) => {
await ridersList.map((rider) => {
if (rider.userid == userid) {
return rider.firstname;
}
});
};
// ======================================================= || notifyRiderMutation || =======================================================
const notifyRiderMutation = useMutation({
mutationFn: notifyRider, // Using the separate function
onSuccess: () => {
OpenToast('Notification sent Successfully', 'success', 2000);
},
onError: (error) => {
OpenToast(error.message, 'error', 2000);
}
});
const createNormalDeliveryMutation = useMutation({
mutationFn: finalCreatedeliveries, // for optimised delivery create
onSuccess: (data, variables) => {
console.log('data', data);
console.log('varialbles', variables);
notifyRiderMutation.mutate(rider.userfcmtoken || riderToken); // Call notifyRider after success
if (data.status == 'accepted') {
OpenToast('Delivery Created Successfully', 'success', 2000);
}
setTimeout(() => {
setIsLoading(false);
navigate('/nearle/deliveries');
}, 2000);
},
onError: (error) => {
OpenToast(error.message, 'error', 4000);
}
});
const handleManualCreateDelivery = async () => {
setIsLoading(true);
createNormalDeliveryMutation.mutate({
deliveries: finaldeliveryList
});
};
return (
<MainCard
content={false}
title={
<Stack direction="row" alignItems="center" spacing={1} sx={{ ml: 1 }}>
<Tooltip title="Back to orders" placement="top">
<IconButton
onClick={() => navigate('/nearle/orders')}
sx={{
backgroundColor: 'action.hover',
color: 'text.primary',
'&:hover': {
backgroundColor: 'action.selected'
}
}}
>
<HiOutlineArrowLeft size={22} />
</IconButton>{' '}
</Tooltip>
<Typography sx={{ m: 2 }} variant="h3">
Assign Orders
</Typography>
</Stack>
}
secondary={
<Button sx={{ m: 2 }} color="primary" variant="contained" startIcon={<ArrowBackIcon />}>
Re-Assign
</Button>
}
>
{(paymentModesLoading || ridersListLoading || isLoading) && (
<>
<Loader />
<CircularLoader />
</>
)}
{
<Backdrop
sx={{
color: '#fff',
zIndex: (theme) => theme.zIndex.drawer + 1
}}
open={paymentModesLoading || ridersListLoading || isLoading} // when loader = true, backdrop covers the page
>
<CircularLoader color="inherit" />
</Backdrop>
}
{aiMode == 1 && (
<Stack sx={{ m: 2 }}>
<Grid container spacing={2}>
<Grid item xs={12} sm={3}>
<HoverSocialCard
secondary={metaData?.total_orders}
primary={'Orders'}
percentage={<DashboardFilled />}
color={theme.palette.success.main}
sx={{ cursor: 'pointer' }}
/>
</Grid>
<Grid item xs={12} sm={3}>
<HoverSocialCard
secondary={metaData?.total_riders}
primary={'Riders'}
percentage={<MdDirectionsBike />}
color={theme.palette.warning.main}
/>
</Grid>
<Grid item xs={12} sm={3}>
<HoverSocialCard
secondary={zoneData?.length}
primary={'Zones'}
percentage={<FaMapLocationDot />}
color={theme.palette.info.main}
/>
</Grid>
<Grid item xs={12} sm={3}>
<HoverSocialCard
secondary={zoneData?.length}
primary={'Kilometer'}
percentage={<FaMapLocationDot />}
color={theme.palette.error.main}
/>
</Grid>
</Grid>
</Stack>
)}
<TableContainer
sx={{
maxHeight: 'calc(100vh - 250px)',
overflow: '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>
<TableHead>
<TableRow sx={{ backgroundColor: 'red' }}>
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>#</TableCell>
{aiMode == 1 && (
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>Zone </TableCell>
)}
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>Tenant </TableCell>
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>order Location</TableCell>
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>Pickup </TableCell>
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>Delivery</TableCell>
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>Notes</TableCell>
{aiMode == 1 && (
<TableCell sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>Rider</TableCell>
)}
<TableCell align="center" sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>
Type
</TableCell>
<TableCell align="center" sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>
Profit
</TableCell>
<TableCell align="center" sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>
Charges
</TableCell>
<TableCell align="center" sx={{ position: 'sticky !important', backgroundColor: theme.palette.secondary.light }}>
KMS
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{finaldeliveryList?.length == 0 && (
<TableRow>
<TableCell colSpan={10}>
<Empty />
</TableCell>
</TableRow>
)}
{finaldeliveryList && aiMode == 1 // ai mode , ai automation
? finaldeliveryList?.map((val, index) => {
return (
<Fragment key={index}>
<TableRow sx={{}}>
<TableCell>
<Typography> {index + 1}</Typography>
</TableCell>
{aiMode == 1 && (
<TableCell>
<Chip color="primary" label={val.zone_name} />
</TableCell>
)}
<TableCell>
<Tooltip title={val.tenantaddress}>
<Typography variant="body1" noWrap>
{val.tenantname}
</Typography>
<Typography noWrap sx={{ fontSize: '11px' }}>
{val.tenantsuburb}
<br />
</Typography>
<Typography noWrap variant="body2">
{val.applocation}
</Typography>
</Tooltip>
</TableCell>
<TableCell align="left">
<Tooltip title={val.locationaddress} placement="top">
<Typography variant="body1" noWrap>
{`${val.locationname}-(${val.locationsuburb})`}
</Typography>
</Tooltip>
<Tooltip title="Order Id">
<Typography variant="body2" noWrap>
{val.orderid}
</Typography>
</Tooltip>
<Stack display={'flex'} flexDirection={'row'} gap={3}>
<Tooltip title="Ordered date">
<Typography noWrap sx={{ fontSize: '12px' }}>
{dayjs(val.orderdate).utc().format('DD/MM/YYYY')}
</Typography>
<Typography noWrap sx={{ fontSize: '11px' }}>
{dayjs(val.orderdate).utc().format('hh:mm A')}
</Typography>
</Tooltip>
-
<Tooltip title="Delivery date">
<Typography noWrap sx={{ fontSize: '12px' }}>
{dayjs(val.deliverydate).utc().format('DD/MM/YYYY')}
</Typography>
<Typography noWrap sx={{ fontSize: '11px' }}>
{dayjs(val.deliverydate).utc().format('hh:mm A')}
</Typography>
</Tooltip>
</Stack>
</TableCell>
<TableCell align="left">
<Stack direction={'row'} spacing={1}>
<Stack direction="column">
<Typography variant="caption">{val.pickupcustomer}</Typography>
<Typography variant="caption">{val.pickupcontactno}</Typography>
<Tooltip title={val.pickupaddress}>
<Typography variant="caption">{val.pickupsuburb || val.pickupaddress.slice(0, 20)}</Typography>
</Tooltip>
</Stack>
</Stack>
</TableCell>
<TableCell align="left">
<Stack direction={'row'} spacing={1}>
<Stack direction="column">
<Typography variant="caption">{val.deliverycustomer}</Typography>
<Typography variant="caption">{val.deliverycontactno}</Typography>
<Tooltip title={val.deliveryaddress}>
<Typography variant="caption">{val.deliverysuburb || val.deliveryaddress.slice(0, 20)}</Typography>
</Tooltip>
</Stack>
</Stack>
</TableCell>
<TableCell align="left">{val.ordernotes}</TableCell>
{aiMode == 1 && (
<TableCell align="left">
<Typography sx={{ whiteSpace: 'nowrap' }}>{val.username}</Typography>
<Typography>ID : {val.userid}</Typography>
</TableCell>
)}
<TableCell align="center">
<Chip
size="small"
label={val.ordertype}
color={val.ordertype == 'Economy' ? 'success' : val.ordertype == 'Risky' ? 'error' : 'primary'}
/>
</TableCell>
<TableCell align="center">
<Stack display={'flex'} flexDirection={'column'} gap={1} sx={{ cursor: 'pointer' }}>
<Tooltip title="Charges" placement="top">
<Chip size="small" label={`${val.deliverycharge.toFixed(2)} `} color="error" />
</Tooltip>
<Tooltip title="Amount" placement="left">
<Chip size="small" label={`${val.deliveryamt.toFixed(2)} `} color="success" />
</Tooltip>
</Stack>
</TableCell>
<TableCell align="center">
<Stack display={'flex'} flexDirection={'column'} gap={1} sx={{ cursor: 'pointer' }}>
<Tooltip title="KMS" placement="top">
<Chip size="small" label={`${val.kms} km`} color="error" />
</Tooltip>
<Tooltip title="Cumulative Kms" placement="right">
<Chip size="small" label={`${val.cumulativekms} km`} color="success" />
</Tooltip>
</Stack>
</TableCell>
</TableRow>
</Fragment>
);
})
: // normal optimisation
finaldeliveryList?.map((val, index) => {
return (
<Fragment key={index}>
<TableRow sx={{}}>
<TableCell>
<Typography> {index + 1}</Typography>
</TableCell>
{/* {aiMode == 1 && (
<TableCell>
<Chip color="primary" label={val.zone_name} />
</TableCell>
)} */}
<TableCell>
<Tooltip title={val.tenantaddress}>
<Typography variant="body1" noWrap>
{val.tenantname}
</Typography>
<Typography noWrap sx={{ fontSize: '11px' }}>
{val.tenantsuburb}
<br />
</Typography>
<Typography noWrap variant="body2">
{val.applocation}
</Typography>
</Tooltip>
</TableCell>
<TableCell align="left">
<Tooltip title={val.locationaddress} placement="top">
<Typography variant="body1" noWrap>
{`${val.locationname}-(${val.locationsuburb})`}
</Typography>
</Tooltip>
<Tooltip title="Order Id">
<Typography variant="body2" noWrap>
{val.orderid}
</Typography>
</Tooltip>
<Stack display={'flex'} flexDirection={'row'} gap={3}>
<Tooltip title="Ordered date">
<Typography noWrap sx={{ fontSize: '12px' }}>
{dayjs(val.orderdate).utc().format('DD/MM/YYYY')}
</Typography>
<Typography noWrap sx={{ fontSize: '11px' }}>
{dayjs(val.orderdate).utc().format('hh:mm A')}
</Typography>
</Tooltip>
-
<Tooltip title="Delivery date">
<Typography noWrap sx={{ fontSize: '12px' }}>
{dayjs(val.deliverydate).utc().format('DD/MM/YYYY')}
</Typography>
<Typography noWrap sx={{ fontSize: '11px' }}>
{dayjs(val.deliverydate).utc().format('hh:mm A')}
</Typography>
</Tooltip>
</Stack>
</TableCell>
<TableCell align="left">
<Stack direction={'row'} spacing={1}>
<Stack direction="column">
<Typography variant="caption">{val.pickupcustomer}</Typography>
<Typography variant="caption">{val.pickupcontactno}</Typography>
<Tooltip title={val.pickupaddress}>
<Typography variant="caption">{val.pickupsuburb || val.pickupaddress.slice(0, 20)}</Typography>
</Tooltip>
</Stack>
</Stack>
</TableCell>
<TableCell align="left">
<Stack direction={'row'} spacing={1}>
<Stack direction="column">
<Typography variant="caption">{val.deliverycustomer}</Typography>
<Typography variant="caption">{val.deliverycontactno}</Typography>
<Tooltip title={val.deliveryaddress}>
<Typography variant="caption">{val.deliverysuburb || val.deliveryaddress.slice(0, 20)}</Typography>
</Tooltip>
</Stack>
</Stack>
</TableCell>
<TableCell align="left">{val.ordernotes}</TableCell>
{/* {aiMode == 1 && (
<TableCell align="left">
<Typography sx={{ whiteSpace: 'nowrap' }}>{val.username}</Typography>
<Typography>ID : {val.userid}</Typography>
</TableCell>
)} */}
<TableCell align="center">
<Chip
size="small"
label={val.ordertype}
color={val.ordertype == 'Economy' ? 'success' : val.ordertype == 'Risky' ? 'error' : 'primary'}
/>
</TableCell>
<TableCell align="center">
<Stack display={'flex'} flexDirection={'column'} gap={1} sx={{ cursor: 'pointer' }}>
<Tooltip title="Charges" placement="top">
<Chip size="small" label={`${val.deliverycharge.toFixed(2)} `} color="error" />
</Tooltip>
<Tooltip title="Amount" placement="left">
<Chip size="small" label={`${val.deliveryamt.toFixed(2)} `} color="success" />
</Tooltip>
</Stack>
</TableCell>
<TableCell align="center">
<Stack display={'flex'} flexDirection={'column'} gap={1} sx={{ cursor: 'pointer' }}>
<Tooltip title="KMS" placement="top">
<Chip size="small" label={`${val.kms} km`} color="error" />
</Tooltip>
<Tooltip title="Cumulative Kms" placement="right">
<Chip size="small" label={`${val.cumulativekms} km`} color="success" />
</Tooltip>
</Stack>
</TableCell>
</TableRow>
</Fragment>
);
})}
</TableBody>
</Table>
</TableContainer>
<Divider />
{aiMode == 0 && (
<Grid container spacing={2} sx={{ p: 2 }}>
<Grid item xs={12} sm={6}>
<Autocomplete
id="free-solo-demo"
options={paymentModes}
renderInput={(params) => <TextField {...params} label="Choose Payment" />}
onChange={(event, newValue, reason) => {
if (reason === 'clear') {
setPayment(null);
return;
}
if (newValue) {
console.log('Selected:', newValue);
setPayment(newValue);
const newList = finaldeliveryList?.map((list) => ({
...list,
paymenttype: newValue.apptypeid // merge selected rider into each list item
}));
setFinalDeliveryList(newList);
}
}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<Autocomplete
id="free-solo-demo"
options={ridersList}
renderInput={(params) => <TextField {...params} label="Choose Rider" />}
onChange={(event, newValue, reason) => {
if (reason === 'clear') {
setRider(null);
return;
}
if (newValue) {
setRider(newValue);
console.log('Selected:', newValue);
const newList = finaldeliveryList?.map((list) => ({
...list,
userid: newValue.userid,
userfcmtoken: newValue.userfcmtoken
}));
setFinalDeliveryList(newList);
}
}}
/>
</Grid>
</Grid>
)}
<Divider />
<Stack display={'flex'} flexDirection={'row'} gap={2} alignItems={'center'} justifyContent={'end'} sx={{ p: 2 }}>
<Button
sx={{}}
variant="contained"
color="secondary"
startIcon={<ArrowBackIcon />}
onClick={() => {
navigate('/nearle/orders');
}}
>
Back
</Button>
<Button sx={{ my: 2 }} variant="contained" disabled={aiMode === 0 && (!rider || !payment)} onClick={handleManualCreateDelivery}>
Assign Orders
</Button>
</Stack>
</MainCard>
);
};
export default OrdersPreview;