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,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);
}}
/>
</>
);
}