323 lines
11 KiB
JavaScript
323 lines
11 KiB
JavaScript
import React, { useState, useEffect, Fragment } from 'react';
|
|
import {
|
|
Box,
|
|
Drawer,
|
|
IconButton,
|
|
Toolbar,
|
|
Typography,
|
|
AppBar,
|
|
useMediaQuery,
|
|
Divider,
|
|
List,
|
|
ListItem,
|
|
ListItemText,
|
|
useTheme,
|
|
ListItemAvatar,
|
|
Stack,
|
|
Button,
|
|
Checkbox,
|
|
Skeleton,
|
|
Backdrop,
|
|
Chip
|
|
} from '@mui/material';
|
|
|
|
import MenuIcon from '@mui/icons-material/Menu';
|
|
import SearchBar from 'components/nearle_components/SearchBar';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import Loader from 'components/Loader';
|
|
|
|
import RiderLocationMap from './RiderLocationMap';
|
|
import MainCard from 'components/MainCard';
|
|
import dayjs from 'dayjs';
|
|
import TaskAltIcon from '@mui/icons-material/TaskAlt';
|
|
|
|
import error500 from 'assets/images/maintenance/Error500.png';
|
|
import { fetchRidersLogs } from '../api/api';
|
|
import CircularLoader from 'components/nearle_components/CircularLoader';
|
|
|
|
const drawerWidth = 350;
|
|
|
|
const RidersLogs = () => {
|
|
const theme = useTheme();
|
|
const isDesktop = useMediaQuery('(min-width:900px)');
|
|
const [open, setOpen] = useState(false);
|
|
const [selectedRiders, setSelectedRiders] = useState([]);
|
|
const [riderSearch, setRiderSearch] = useState('');
|
|
const appId = 1;
|
|
const {
|
|
data: riders,
|
|
isLoading: ridersIsLoading,
|
|
isFetching: riderIsFetching,
|
|
refetch: riderLogsRefetch,
|
|
error: riderLogsError
|
|
} = useQuery({
|
|
queryKey: [appId, dayjs().format('YYYY-MM-DD'), riderSearch],
|
|
queryFn: fetchRidersLogs,
|
|
refetchInterval: 5 * 60 * 1000
|
|
});
|
|
|
|
useEffect(() => {
|
|
console.log('riders', riders);
|
|
// const sortedRiders = riders?.sort((a, b) => a.firstname.localeCompare(b.firstname));
|
|
setSelectedRiders(riders);
|
|
}, [riders]);
|
|
|
|
useEffect(() => {
|
|
console.log('selectedRiders', selectedRiders);
|
|
}, [selectedRiders]);
|
|
|
|
useEffect(() => {
|
|
setOpen(isDesktop);
|
|
}, [isDesktop]);
|
|
|
|
return (
|
|
<Fragment>
|
|
{
|
|
<Backdrop
|
|
sx={{
|
|
color: '#fff',
|
|
zIndex: (theme) => theme.zIndex.drawer + 1
|
|
}}
|
|
open={ridersIsLoading || riderIsFetching} // when loader = true, backdrop covers the page
|
|
>
|
|
<CircularLoader color="inherit" />
|
|
</Backdrop>
|
|
}
|
|
<MainCard content={false}>
|
|
<Box sx={{ display: 'flex', width: '100%', height: '100%', position: 'relative' }}>
|
|
{/* Drawer */}
|
|
<Drawer
|
|
variant={isDesktop ? 'persistent' : 'temporary'}
|
|
open={open}
|
|
onClose={() => !isDesktop && setOpen(false)}
|
|
ModalProps={{ keepMounted: true }}
|
|
sx={{
|
|
'& .MuiDrawer-paper': {
|
|
width: drawerWidth,
|
|
position: 'absolute',
|
|
left: 0,
|
|
top: 0,
|
|
height: '100%',
|
|
overflowY: 'auto',
|
|
transition: 'transform 0.35s ease-in-out',
|
|
zIndex: 13
|
|
}
|
|
}}
|
|
>
|
|
{/* Search */}
|
|
<Box sx={{ position: 'sticky', top: 0, zIndex: 1 }}>
|
|
<SearchBar
|
|
value={riderSearch}
|
|
placeholder="Search Rider"
|
|
onChange={(e) => setRiderSearch(e.target.value)}
|
|
sx={{
|
|
height: 60,
|
|
bgcolor: 'white',
|
|
'& .MuiOutlinedInput-notchedOutline': {
|
|
borderBottom: '1px solid',
|
|
borderColor: theme.palette.secondary.light
|
|
}
|
|
}}
|
|
/>
|
|
<List>
|
|
<ListItem sx={{ cursor: 'pointer', '&:hover': { bgcolor: theme.palette.secondary.lighter }, bgcolor: 'white', mt: -1 }}>
|
|
<ListItemAvatar>
|
|
<Checkbox
|
|
checked={riders?.length == selectedRiders?.length}
|
|
onChange={(e) => {
|
|
if (e.target.checked) {
|
|
setSelectedRiders(riders);
|
|
}
|
|
}}
|
|
/>
|
|
</ListItemAvatar>
|
|
<ListItemText primary="All" />
|
|
</ListItem>
|
|
<Divider />
|
|
</List>
|
|
</Box>
|
|
{/* Rider List */}
|
|
<List>
|
|
{/* Individuals */}
|
|
{ridersIsLoading || riderIsFetching
|
|
? Array.from({ length: 10 }).map((_, index) => (
|
|
<Fragment key={index}>
|
|
<ListItem sx={{ py: 1.5, px: 2 }}>
|
|
<ListItemAvatar>
|
|
<Skeleton variant="circular" width={24} height={24} />
|
|
</ListItemAvatar>
|
|
|
|
<ListItemText
|
|
primary={<Skeleton variant="text" width="60%" height={22} />}
|
|
secondary={<Skeleton variant="text" width="40%" height={18} />}
|
|
/>
|
|
|
|
<Stack spacing={0.5} textAlign="right">
|
|
<Skeleton variant="text" width={50} height={18} />
|
|
<Skeleton variant="text" width={80} height={16} />
|
|
</Stack>
|
|
</ListItem>
|
|
|
|
<Divider />
|
|
</Fragment>
|
|
))
|
|
: riders?.map((row) => {
|
|
return (
|
|
<Fragment key={row.userid}>
|
|
<ListItem
|
|
sx={{
|
|
cursor: 'pointer',
|
|
py: 1,
|
|
px: 2,
|
|
borderRadius: 1,
|
|
'&:hover': { bgcolor: theme.palette.secondary.lighter }
|
|
}}
|
|
secondaryAction={
|
|
<Stack textAlign="right" spacing={0.5}>
|
|
<Typography variant="body2" noWrap sx={{ color: row.status == 'active' ? 'success.main' : 'error.main' }}>
|
|
{row.userid}
|
|
</Typography>
|
|
<Typography variant="caption" color="text.secondary" noWrap>
|
|
{dayjs(row.logdate).format('DD/MM/YYYY hh:mm A')}
|
|
</Typography>
|
|
</Stack>
|
|
}
|
|
>
|
|
<ListItemAvatar>
|
|
<Checkbox
|
|
sx={{
|
|
color: row.status == 'active' ? 'green' : 'red',
|
|
'&.Mui-checked': {
|
|
color: row.status == 'active' ? 'green' : 'red'
|
|
}
|
|
}}
|
|
checked={
|
|
// INDIVIDUAL CHECKED CONDITION
|
|
selectedRiders?.length === 1 && selectedRiders[0]?.userid === row?.userid
|
|
}
|
|
onChange={(e) => {
|
|
if (e.target.checked) {
|
|
// SELECT ONE RIDER
|
|
setSelectedRiders([row]);
|
|
} else {
|
|
// UNCHECK -> SELECT ALL
|
|
setSelectedRiders(riders);
|
|
}
|
|
}}
|
|
/>
|
|
</ListItemAvatar>
|
|
|
|
<ListItemText
|
|
primary={
|
|
row.username ? (
|
|
<Typography noWrap>
|
|
{row.username?.slice(0, 25) || ''}
|
|
{row.username?.length > 25 && '...'}
|
|
{/* {row.status === 'active' && <TaskAltIcon fontSize="small" color="success" sx={{ ml: 1 }} />} */}
|
|
</Typography>
|
|
) : (
|
|
<Typography noWrap>
|
|
{row.firstname || ''}
|
|
{row.lastname ? ` ${row.lastname}` : ''}
|
|
</Typography>
|
|
)
|
|
}
|
|
secondary={
|
|
<Typography variant="caption" color="text.secondary" noWrap>
|
|
{row.contactno || '##########'}
|
|
</Typography>
|
|
}
|
|
/>
|
|
</ListItem>
|
|
|
|
<Divider />
|
|
</Fragment>
|
|
);
|
|
})}
|
|
</List>
|
|
</Drawer>
|
|
|
|
{/* AppBar */}
|
|
<AppBar
|
|
elevation={0}
|
|
position="absolute"
|
|
sx={{
|
|
top: 0,
|
|
left: open && isDesktop ? `${drawerWidth}px` : 0,
|
|
width: open && isDesktop ? `calc(100% - ${drawerWidth}px)` : '100%',
|
|
transition: 'left 0.3s ease, width 0.3s ease',
|
|
backgroundColor: 'white',
|
|
borderBottom: '1px solid',
|
|
borderColor: theme.palette.secondary.light
|
|
}}
|
|
>
|
|
<Toolbar>
|
|
<Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ width: '100%' }}>
|
|
<Stack direction="row" alignItems="center">
|
|
<IconButton color="primary" onClick={() => setOpen(!open)}>
|
|
<MenuIcon />
|
|
</IconButton>
|
|
|
|
<Typography variant="h5" color="primary" sx={{ ml: 2 }}>
|
|
Riders Locations
|
|
</Typography>
|
|
</Stack>
|
|
|
|
<Button
|
|
variant="outlined"
|
|
color="primary"
|
|
onClick={() => {
|
|
riderLogsRefetch();
|
|
}}
|
|
>
|
|
Refresh
|
|
</Button>
|
|
</Stack>
|
|
</Toolbar>
|
|
</AppBar>
|
|
|
|
{/* Map */}
|
|
<Box
|
|
sx={{
|
|
flexGrow: 1,
|
|
overflow: 'auto',
|
|
pt: '64px',
|
|
pl: open && isDesktop ? `${drawerWidth}px` : 0,
|
|
transition: 'padding-left 0.3s ease',
|
|
minHeight: '80vh'
|
|
}}
|
|
>
|
|
{(ridersIsLoading || riderIsFetching) && (
|
|
<Box position="relative" width="100%" height="80vh" display="grid" placeItems="center">
|
|
{/* <CircularLoader /> */}
|
|
<Skeleton
|
|
variant="rectangular"
|
|
width="100%"
|
|
height="100%"
|
|
animation="wave"
|
|
sx={{
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
borderRadius: 1,
|
|
zIndex: 1
|
|
}}
|
|
/>
|
|
</Box>
|
|
)}
|
|
|
|
{selectedRiders?.length > 0 && <RiderLocationMap riderLocations={selectedRiders} />}
|
|
{riderLogsError && (
|
|
<Box sx={{ width: '100% ', height: '100%' }}>
|
|
<img src={error500} alt="mantis" style={{ height: '100%', width: '100%' }} />
|
|
</Box>
|
|
)}
|
|
</Box>
|
|
</Box>
|
|
</MainCard>
|
|
</Fragment>
|
|
);
|
|
};
|
|
|
|
export default RidersLogs;
|