initial commit
This commit is contained in:
454
src/pages/nearle/reports/ridersSummary.js
Normal file
454
src/pages/nearle/reports/ridersSummary.js
Normal file
@@ -0,0 +1,454 @@
|
||||
import { React, useState, useEffect } from 'react';
|
||||
import TitleCard from 'pages/titleCard';
|
||||
import axios from 'axios';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { fetchRidersSummary } from 'pages/api/api';
|
||||
|
||||
import { Empty } from 'antd';
|
||||
// material-ui
|
||||
import {
|
||||
Divider,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Typography,
|
||||
Stack,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
Chip,
|
||||
Collapse,
|
||||
Dialog,
|
||||
DialogContent
|
||||
} from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
|
||||
import { IoLocationOutline } from 'react-icons/io5';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
var utc = require('dayjs/plugin/utc');
|
||||
dayjs.extend(utc);
|
||||
import { CalendarMonth } from '@mui/icons-material';
|
||||
import MainCard from 'components/MainCard';
|
||||
import Loader from 'components/Loader';
|
||||
import DateFilterDialog from 'components/DateFilterDialog';
|
||||
import LocationAutocomplete from 'components/nearle_components/LocationAutocomplete';
|
||||
import { OrdersTableSkeleton } from '../orders/OrdersTableSkeleton';
|
||||
import RidersRoutes from './RidersRoutes';
|
||||
import { OpenToast } from 'components/third-party/OpenToast';
|
||||
|
||||
function formatNumberToRupees(value) {
|
||||
return new Intl.NumberFormat('en-IN', {
|
||||
style: 'currency',
|
||||
currency: 'INR',
|
||||
minimumFractionDigits: 2
|
||||
}).format(value);
|
||||
}
|
||||
|
||||
const getColorByValue = (value) => {
|
||||
return Number(value) !== 0 ? 'red' : 'inherit';
|
||||
};
|
||||
const coloredCell = (value) => <Typography sx={{ color: getColorByValue(value) }}>{value}</Typography>;
|
||||
|
||||
// ==============================|| MUI TABLE - ENHANCED ||============================== //
|
||||
|
||||
export default function RidersSummary() {
|
||||
const [startdate, setStartdate] = useState(dayjs().format('YYYY-MM-DD'));
|
||||
const [enddate, setEnddate] = useState(dayjs().format('YYYY-MM-DD'));
|
||||
const [locaName, setLocoName] = useState('All');
|
||||
const [open, setOpen] = useState(false);
|
||||
const [datestatus, setDatestatus] = useState('Today');
|
||||
const [total, settotal] = useState(0);
|
||||
const [tenantData, setTenantData] = useState([]);
|
||||
const [openRow, setOpenRow] = useState(null); // Initially no row is open
|
||||
// const [appId, setAppId] = useState(localStorage.getItem('applocationid'));
|
||||
const [appId, setAppId] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [mapOpen, setMapOpen] = useState(false);
|
||||
const [logDetails, setLogDetails] = useState(null);
|
||||
|
||||
// ==============================|| fetchRidersSummary (riders summary)||============================== //
|
||||
const { isLoading: isLoadingReports, data: rows } = useQuery({
|
||||
queryKey: ['ridersummary', appId, startdate, enddate],
|
||||
queryFn: fetchRidersSummary
|
||||
});
|
||||
|
||||
// ==============================|| fetchTenantSummary by rider (rider summary)||============================== //
|
||||
const fetchTenantSummary = async (riderUserid) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const tenantRes = await axios.get(
|
||||
`${process.env.REACT_APP_URL}/deliveries/getreportsummary/?&fromdate=${startdate}&todate=${enddate}&userid=${riderUserid}`
|
||||
);
|
||||
console.log('tenantRes', tenantRes.data.details);
|
||||
setTenantData(tenantRes.data.details);
|
||||
} catch (error) {
|
||||
console.log('tenantRes', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// ==============================|| getuserdeliverylogs (rider summary)||============================== //
|
||||
|
||||
const getuserdeliverylogs = async (userid) => {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${process.env.REACT_APP_URL}/deliveries/getuserdeliverylogs/?userid=${userid}&fromdate=2026-01-28&todate=2026-01-28 `
|
||||
);
|
||||
setLogDetails(response.data.details);
|
||||
} catch (err) {
|
||||
OpenToast(err?.message, 'error', 2000);
|
||||
console.log('getuserdeliverylogs', err.message);
|
||||
}
|
||||
};
|
||||
|
||||
// ==============================|| calculate||============================== //
|
||||
const calculate = async () => {
|
||||
let calculatedTotal = 0;
|
||||
rows &&
|
||||
rows.forEach((row, index) => {
|
||||
console.log(index, row.deliveryamt);
|
||||
calculatedTotal += row.deliveryamt;
|
||||
});
|
||||
// Update the state after the calculation is done
|
||||
settotal(calculatedTotal);
|
||||
console.log('calculatedTotal', calculatedTotal);
|
||||
};
|
||||
useEffect(() => {
|
||||
calculate();
|
||||
}, [rows]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{(isLoadingReports || loading) && (
|
||||
<>
|
||||
<Loader />
|
||||
{/* <CircularLoader /> */}
|
||||
</>
|
||||
)}
|
||||
<TitleCard title="Riders Summary" />
|
||||
|
||||
<MainCard
|
||||
content={false}
|
||||
title={
|
||||
<Stack
|
||||
display={'flex'}
|
||||
flexDirection={'row'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'space-between'}
|
||||
flexWrap={'wrap'}
|
||||
gap={1}
|
||||
sx={{ border: '1px solid', borderColor: 'bg.main', p: 2 }}
|
||||
>
|
||||
<Stack direction="column" alignItems="flex-start" spacing={1} sx={{}}>
|
||||
{startdate && enddate && (
|
||||
<Stack direction="row" spacing={2} flexWrap={'wrap'} gap={1}>
|
||||
<Chip label={`Orders-${datestatus}`} color="primary" variant="light" />
|
||||
<Chip
|
||||
label={
|
||||
<Typography noWrap color="secondary">
|
||||
{dayjs(startdate).format('DD/MM/YYYY')} - {dayjs(enddate).format('DD/MM/YYYY')}
|
||||
</Typography>
|
||||
}
|
||||
variant="combined"
|
||||
color="warning"
|
||||
deleteIcon={<CalendarMonth style={{ fontSize: 18 }} />}
|
||||
onDelete={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
onClick={() => setOpen(true)}
|
||||
sx={{ cursor: 'pointer' }}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
{(!startdate || !enddate) && (
|
||||
<>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Chip label="Orders-All" color="primary" variant="light" size="small" />
|
||||
{/* <Chip label={<Typography noWrap color="secondary">ALL</Typography>} variant="combined" color='warning' size='small' /> */}
|
||||
</Stack>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
<Stack style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<LocationAutocomplete
|
||||
// ref={locationRef}
|
||||
locaName={locaName}
|
||||
setAppId={setAppId}
|
||||
setLocoName={setLocoName}
|
||||
// setPage={setPage}
|
||||
sx={{ minWidth: 250, maxWidth: 1000, flex: 1 }}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
}
|
||||
>
|
||||
{/* table */}
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableCell># </TableCell>
|
||||
<TableCell>Rider </TableCell>
|
||||
<TableCell> Orders</TableCell>
|
||||
<TableCell> Pending</TableCell>
|
||||
{/* <TableCell> Assigned</TableCell>
|
||||
<TableCell>Accepted </TableCell>
|
||||
<TableCell>Arrived </TableCell>
|
||||
<TableCell>Picked </TableCell>
|
||||
<TableCell>Active </TableCell>
|
||||
<TableCell>Skipped </TableCell> */}
|
||||
<TableCell>Cancelled </TableCell>
|
||||
<TableCell>Delivered </TableCell>
|
||||
<TableCell align="center">KMS </TableCell>
|
||||
<TableCell align="center">Amount </TableCell>
|
||||
<TableCell align="center">Action </TableCell>
|
||||
</TableHead>
|
||||
{/* ============================================ || TableBody || ============================================ */}
|
||||
|
||||
{isLoadingReports && <OrdersTableSkeleton col={10} />}
|
||||
|
||||
<TableBody>
|
||||
{rows?.length === 0 && (
|
||||
<TableRow>
|
||||
<TableCell colSpan={15}>
|
||||
<Stack width={'100%'} direction={'row'} justifyContent={'center'}>
|
||||
<Empty />
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
|
||||
{rows?.length != 0 &&
|
||||
rows?.map((row, index) => (
|
||||
<>
|
||||
{/* // ============================================ || tablerow 1 || ============================================ */}
|
||||
<TableRow
|
||||
key={row.tenantname}
|
||||
sx={{
|
||||
cursor: openRow === row.userid ? 'pointer' : null
|
||||
}}
|
||||
>
|
||||
<TableCell align="left">{index + 1}</TableCell>
|
||||
<TableCell>
|
||||
<Stack spacing={1}>
|
||||
<Typography sx={{ whiteSpace: 'noWrap' }}> {` ${row?.firstname} ${row?.lastname}`}</Typography>
|
||||
<Typography variant="subtitle2">Id : {row.userid} </Typography>
|
||||
</Stack>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>{coloredCell(row.totalorders)}</TableCell>
|
||||
<TableCell>{coloredCell(row.pending)}</TableCell>
|
||||
{/* <TableCell >{coloredCell(row.assigned)}</TableCell>
|
||||
<TableCell >{coloredCell(row.accepted)}</TableCell>
|
||||
<TableCell >{coloredCell(row.arrived)}</TableCell>
|
||||
<TableCell >{coloredCell(row.picked)}</TableCell>
|
||||
<TableCell >{coloredCell(row.active)}</TableCell>
|
||||
<TableCell >{coloredCell(row.skipped)}</TableCell> */}
|
||||
<TableCell>{coloredCell(row.cancelled)}</TableCell>
|
||||
<TableCell>{coloredCell(row.delivered)}</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
<Stack direction="column" spacing={1}>
|
||||
<Tooltip title="Kms" placement="top">
|
||||
<Chip
|
||||
size="small"
|
||||
label={`${Number(row.kms).toFixed(2)}`}
|
||||
color={row.kms ? 'error' : 'secondary'}
|
||||
variant="combined"
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
minWidth: 80
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Actual Kms" placement="bottom">
|
||||
<Chip
|
||||
size="small"
|
||||
label={`${Number(row.cumulativekms).toFixed(2)}`}
|
||||
color={row.cumulativekms ? 'success' : 'secondary'}
|
||||
variant="combined"
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
minWidth: 80
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
<Tooltip title="Total Amount" placement="top">
|
||||
<Chip
|
||||
size="small"
|
||||
label={formatNumberToRupees(row.charges >= row.deliveryamt ? row.charges : row.deliveryamt)}
|
||||
variant="combined"
|
||||
color={row.deliveryamt ? 'primary' : 'secondary'}
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
minWidth: 100
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<Stack display={'flex'} flexDirection={'row'} gap={1} alignItems={'center'}>
|
||||
<IconButton
|
||||
aria-label="expand row"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
const isOpening = openRow !== row.userid;
|
||||
|
||||
// toggle row
|
||||
setOpenRow(isOpening ? row.userid : null);
|
||||
|
||||
// ❌ closing → no API
|
||||
if (!isOpening) return;
|
||||
|
||||
// ✅ opening → call API
|
||||
fetchTenantSummary(row.userid);
|
||||
}}
|
||||
sx={{
|
||||
bgcolor: openRow === row.userid ? 'primary.main' : null,
|
||||
color: openRow === row.userid ? 'white' : null,
|
||||
'&:hover': {
|
||||
bgcolor: openRow === row.userid ? 'primary.main' : '#e1bee7'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{openRow === row.userid ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
|
||||
</IconButton>
|
||||
<IconButton>
|
||||
<IoLocationOutline
|
||||
onClick={() => {
|
||||
setMapOpen(true);
|
||||
getuserdeliverylogs(row?.userid);
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/* // ============================================ || collapsive row || ============================================ */}
|
||||
{openRow === row.userid && (
|
||||
<TableRow
|
||||
sx={{
|
||||
cursor: openRow === row.userid ? 'pointer' : null
|
||||
}}
|
||||
>
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={15}>
|
||||
<Collapse in={true} timeout="auto" unmountOnExit>
|
||||
<MainCard content={false} sx={{ margin: 1 }}>
|
||||
<Table size="small" aria-label="purchases">
|
||||
<TableHead sx={{ bgcolor: 'primary.lighter' }}>
|
||||
<TableRow>
|
||||
<TableCell>#</TableCell>
|
||||
<TableCell>Client</TableCell>
|
||||
<TableCell align="center">All</TableCell>
|
||||
<TableCell align="center">Pending</TableCell>
|
||||
<TableCell align="center">Completed</TableCell>
|
||||
<TableCell align="center">Cancelled</TableCell>
|
||||
<TableCell align="center">Kms</TableCell>
|
||||
<TableCell align="center">Amount</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{loading && <OrdersTableSkeleton col={3} />}
|
||||
{tenantData?.map((row, index) => (
|
||||
<TableRow key={row.tenantname}>
|
||||
<TableCell align="left">{index + 1}</TableCell>
|
||||
<TableCell align="left">
|
||||
<Stack direction="row" sx={{ ml: -2 }}>
|
||||
{row.tenantname}
|
||||
</Stack>
|
||||
</TableCell>
|
||||
<TableCell align="center">{coloredCell(row.totalorders)}</TableCell>
|
||||
<TableCell align="center">{coloredCell(row.deliveriespending)}</TableCell>
|
||||
<TableCell align="center">{coloredCell(row.deliveriescompleted)}</TableCell>
|
||||
<TableCell align="center">{coloredCell(row.deliveriescancelled)}</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
<Chip
|
||||
size="small"
|
||||
label={row.kms}
|
||||
color="error"
|
||||
variant="combined"
|
||||
sx={{
|
||||
mr: 1,
|
||||
minWidth: 80
|
||||
}}
|
||||
/>
|
||||
<Chip
|
||||
size="small"
|
||||
label={row.cumulativekms}
|
||||
color="success"
|
||||
variant="combined"
|
||||
sx={{
|
||||
minWidth: 80
|
||||
}}
|
||||
/>
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
<Chip
|
||||
size="small"
|
||||
label={formatNumberToRupees(row.charges >= row.deliveryamt ? row.charges : row.deliveryamt)}
|
||||
sx={{
|
||||
color: 'primary.main',
|
||||
bgcolor: '#e1bee7',
|
||||
border: '1px solid #662582 ',
|
||||
minWidth: 100
|
||||
}}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</MainCard>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<Divider />
|
||||
{rows?.length != 0 && (
|
||||
<Stack direction={'row'} sx={{ display: 'flex', justifyContent: 'end', px: 1, py: 2 }}>
|
||||
<Typography variant="h5">Total :</Typography>
|
||||
<Typography variant="h5" sx={{ ml: 5, mr: 1.5 }}>
|
||||
{formatNumberToRupees(total)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
</MainCard>
|
||||
<Dialog
|
||||
maxWidth={'xl'}
|
||||
fullScreen
|
||||
open={mapOpen}
|
||||
onClose={() => {
|
||||
setMapOpen(false);
|
||||
}}
|
||||
>
|
||||
<DialogContent>{logDetails && <RidersRoutes details={logDetails} />}</DialogContent>
|
||||
</Dialog>
|
||||
{/* ============================================= || filter Dialog | ============================================= */}
|
||||
<DateFilterDialog
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
onSelect={(range) => {
|
||||
setStartdate(range.startDate);
|
||||
setEnddate(range.endDate);
|
||||
setDatestatus(range.label);
|
||||
console.log('Selected Date Range:', range);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user