updated the ui for the mobile view
This commit is contained in:
@@ -20,8 +20,10 @@ import {
|
||||
Grid,
|
||||
Box,
|
||||
Skeleton,
|
||||
Divider
|
||||
Divider,
|
||||
useMediaQuery
|
||||
} from '@mui/material';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
var utc = require('dayjs/plugin/utc');
|
||||
import dayjs from 'dayjs';
|
||||
dayjs.extend(utc);
|
||||
@@ -45,6 +47,7 @@ import {
|
||||
MdTwoWheeler
|
||||
} from 'react-icons/md';
|
||||
import LocationAutocomplete from 'components/nearle_components/LocationAutocomplete';
|
||||
import { MobileCard, MobileCardList, MobileField, MobileFieldGrid } from 'components/nearle_components/MobileCard';
|
||||
import DebounceSearchBar from 'components/nearle_components/DebounceSearchBar';
|
||||
import CircularLoader from 'components/CircularLoader';
|
||||
import { fetchAllRiders, getallridersummary, getriderstatus } from 'pages/api/api';
|
||||
@@ -137,6 +140,8 @@ const KPI_META = (summary) => [
|
||||
|
||||
const Riders = () => {
|
||||
const navigate = useNavigate();
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const loadMoreRef = useRef();
|
||||
const containerRef = useRef();
|
||||
const [searchword, setSearchword] = useState('');
|
||||
@@ -567,6 +572,307 @@ const Riders = () => {
|
||||
'&::-webkit-scrollbar-track': { backgroundColor: DT.surfaceAlt }
|
||||
}}
|
||||
>
|
||||
{isMobile ? (
|
||||
/* ===================== MOBILE: card list ===================== */
|
||||
<MobileCardList sx={{ p: 1.25 }}>
|
||||
{allRidersLoading && (
|
||||
<Stack alignItems="center" sx={{ py: 6 }}>
|
||||
<LoaderWithImage />
|
||||
<Typography variant="caption" color="text.secondary" sx={{ mt: 1 }}>
|
||||
Loading riders…
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{rows?.length === 0 && !allRidersLoading && (
|
||||
<Stack alignItems="center" spacing={1.5} sx={{ py: 6 }}>
|
||||
<Avatar sx={{ width: 64, height: 64, bgcolor: soft('#94a3b8'), color: DT.textMuted }}>
|
||||
<MdTwoWheeler size={28} />
|
||||
</Avatar>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 700, color: DT.textPrimary }}>
|
||||
No riders to show
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary, textAlign: 'center', px: 2 }}>
|
||||
{searchword
|
||||
? 'Try a different keyword.'
|
||||
: `No ${tabvalue === 0 ? '' : 'active '}riders for this zone.`}
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{rows?.length !== 0 &&
|
||||
rows?.map((row, index) => {
|
||||
const statusMeta = getRowStatusMeta(row);
|
||||
const StatusIcon = statusMeta.icon;
|
||||
const expanded = logsRow === row.userid;
|
||||
return (
|
||||
<MobileCard
|
||||
key={row.userid ?? index}
|
||||
accent={statusMeta.color}
|
||||
selected={expanded}
|
||||
header={
|
||||
<Stack spacing={1.25}>
|
||||
<Stack direction="row" alignItems="center" justifyContent="space-between" spacing={1}>
|
||||
<Stack direction="row" alignItems="center" spacing={0.75} sx={{ minWidth: 0 }}>
|
||||
<Typography variant="caption" sx={{ fontWeight: 700, color: DT.textMuted }}>
|
||||
{String(index + 1).padStart(2, '0')}
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
px: 1,
|
||||
py: 0.375,
|
||||
borderRadius: 999,
|
||||
bgcolor: tint(BRAND),
|
||||
border: `1px solid ${edge(BRAND)}`,
|
||||
color: BRAND,
|
||||
fontWeight: 800,
|
||||
fontSize: 11
|
||||
}}
|
||||
>
|
||||
#{row?.userid}
|
||||
</Box>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
spacing={0.5}
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
pl: 0.5,
|
||||
pr: 1,
|
||||
py: 0.25,
|
||||
borderRadius: 999,
|
||||
bgcolor: tint(statusMeta.color),
|
||||
border: `1px solid ${edge(statusMeta.color)}`,
|
||||
color: statusMeta.color
|
||||
}}
|
||||
>
|
||||
<AccentAvatar color={statusMeta.color} size={18}>
|
||||
<StatusIcon size={11} />
|
||||
</AccentAvatar>
|
||||
<Typography variant="caption" sx={{ fontWeight: 800, fontSize: 10.5, lineHeight: 1 }}>
|
||||
{statusMeta.label}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
{roleid == 1 && (
|
||||
<Stack direction="row" spacing={0.75} sx={{ flexShrink: 0 }}>
|
||||
<IconButton
|
||||
size="small"
|
||||
sx={{
|
||||
borderRadius: 999,
|
||||
bgcolor: soft(BRAND),
|
||||
color: BRAND,
|
||||
border: `1px solid ${edge(BRAND)}`,
|
||||
'&:hover': { bgcolor: BRAND, color: '#fff' }
|
||||
}}
|
||||
onClick={() => {
|
||||
navigate('/nearle/riders/edit', { state: { riderdata: row } });
|
||||
}}
|
||||
>
|
||||
<MdEdit size={14} />
|
||||
</IconButton>
|
||||
{tabvalue != 0 && (
|
||||
<IconButton
|
||||
size="small"
|
||||
sx={{
|
||||
borderRadius: 999,
|
||||
bgcolor: expanded ? '#0ea5e9' : soft('#0ea5e9'),
|
||||
color: expanded ? '#fff' : '#0ea5e9',
|
||||
border: `1px solid ${edge('#0ea5e9')}`,
|
||||
'&:hover': { bgcolor: '#0ea5e9', color: '#fff' }
|
||||
}}
|
||||
onClick={() => {
|
||||
if (row.userid == logsRow) {
|
||||
setLogsRow(null);
|
||||
} else {
|
||||
setLogsRow(row.userid);
|
||||
getRiderLogs(row.userid);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{expanded ? <MdKeyboardArrowUp size={14} /> : <MdKeyboardArrowDown size={14} />}
|
||||
</IconButton>
|
||||
)}
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<Avatar
|
||||
sx={{
|
||||
width: 36,
|
||||
height: 36,
|
||||
bgcolor: soft(BRAND),
|
||||
color: BRAND,
|
||||
fontWeight: 800,
|
||||
fontSize: 16,
|
||||
border: `1px solid ${edge(BRAND)}`,
|
||||
flexShrink: 0
|
||||
}}
|
||||
>
|
||||
{(row.fullname || row.username || '?').charAt(0).toUpperCase()}
|
||||
</Avatar>
|
||||
<Box sx={{ minWidth: 0 }}>
|
||||
<Typography sx={{ fontWeight: 800, color: DT.textPrimary, fontSize: 15 }} noWrap>
|
||||
{row.username || '—'}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary }} noWrap>
|
||||
{row.contactno || '—'}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Stack>
|
||||
}
|
||||
>
|
||||
<MobileFieldGrid>
|
||||
<MobileField label="Address" full>
|
||||
<Typography sx={{ fontSize: 13, fontWeight: 600, color: DT.textSecondary }} noWrap>
|
||||
{row.suburb || (row.address ? row.address.slice(0, 20) + '…' : '—')}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textMuted }} noWrap>
|
||||
{row.city || ''}
|
||||
</Typography>
|
||||
</MobileField>
|
||||
<MobileField label="Vehicle">
|
||||
<Stack direction="row" alignItems="center" spacing={0.75}>
|
||||
<AccentAvatar color="#0ea5e9" size={22}>
|
||||
<MdTwoWheeler size={12} />
|
||||
</AccentAvatar>
|
||||
<Typography variant="caption" sx={{ fontWeight: 700, color: DT.textPrimary }}>
|
||||
{row.vehicleno || '—'}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
<MobileField label="Shift" value={`#${row.shiftid ?? '—'}`} />
|
||||
<MobileField label="Time">
|
||||
<Stack spacing={0.5}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
px: 0.875,
|
||||
py: 0.25,
|
||||
borderRadius: 999,
|
||||
bgcolor: tint('#10b981'),
|
||||
border: `1px solid ${edge('#10b981')}`,
|
||||
color: '#10b981',
|
||||
fontSize: 10.5,
|
||||
fontWeight: 800
|
||||
}}
|
||||
>
|
||||
{row.starttime ? dayjs(`${dayjs().format('MM-DD-YYYY')} ${row.starttime}`).format('hh:mm A') : '—'}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
px: 0.875,
|
||||
py: 0.25,
|
||||
borderRadius: 999,
|
||||
bgcolor: tint('#ef4444'),
|
||||
border: `1px solid ${edge('#ef4444')}`,
|
||||
color: '#ef4444',
|
||||
fontSize: 10.5,
|
||||
fontWeight: 800
|
||||
}}
|
||||
>
|
||||
{row.endtime ? dayjs(`${dayjs().format('MM-DD-YYYY')} ${row.endtime}`).format('hh:mm A') : '—'}
|
||||
</Box>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
<MobileField label="Fare" value={row.basefare ?? '—'} />
|
||||
<MobileField label="Fuel" value={row.fuelcharge ?? '—'} />
|
||||
</MobileFieldGrid>
|
||||
|
||||
{expanded && tabvalue !== 0 && (
|
||||
<Box
|
||||
sx={{
|
||||
mt: 1.5,
|
||||
p: 1.25,
|
||||
borderRadius: 2,
|
||||
bgcolor: tint(BRAND),
|
||||
border: `1px solid ${edge(BRAND)}`
|
||||
}}
|
||||
>
|
||||
<Stack direction="row" alignItems="center" spacing={1} sx={{ mb: 1.25 }}>
|
||||
<AccentAvatar color={BRAND} size={26}>
|
||||
<MdGpsFixed size={14} />
|
||||
</AccentAvatar>
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: 800,
|
||||
color: DT.textSecondary,
|
||||
letterSpacing: 0.6,
|
||||
textTransform: 'uppercase',
|
||||
fontSize: 11
|
||||
}}
|
||||
>
|
||||
Live telemetry — {row.username || `Rider #${row.userid}`}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Grid container spacing={1.25}>
|
||||
<LogChip
|
||||
color="#ef4444"
|
||||
icon={MdLocationOn}
|
||||
label="Location"
|
||||
value={riderLogsdata?.latitude ? `${riderLogsdata.latitude}, ${riderLogsdata.longitude}` : '—'}
|
||||
/>
|
||||
<LogChip
|
||||
color="#10b981"
|
||||
icon={MdBatteryStd}
|
||||
label="Battery"
|
||||
value={riderLogsdata?.battery ? `${riderLogsdata.battery}%` : 'N/A'}
|
||||
/>
|
||||
<LogChip
|
||||
color={riderLogsdata?.is_charging ? '#10b981' : '#94a3b8'}
|
||||
icon={MdPowerSettingsNew}
|
||||
label="Charging"
|
||||
value={riderLogsdata?.is_charging ? 'Charging' : 'Not Charging'}
|
||||
/>
|
||||
<LogChip
|
||||
color="#0ea5e9"
|
||||
icon={MdSpeed}
|
||||
label="Speed"
|
||||
value={riderLogsdata?.speed !== undefined ? `${riderLogsdata.speed} km/h` : '—'}
|
||||
/>
|
||||
<LogChip
|
||||
color="#8b5cf6"
|
||||
icon={MdGpsFixed}
|
||||
label="Accuracy"
|
||||
value={riderLogsdata?.accuracy !== undefined ? `${riderLogsdata.accuracy} m` : '—'}
|
||||
/>
|
||||
<LogChip color="#f59e0b" icon={MdAccessTime} label="Log time" value={riderLogsdata?.logdate || '—'} />
|
||||
<LogChip color={BRAND} icon={MdInventory2} label="Active order" value={riderLogsdata?.orderid || 'N/A'} />
|
||||
<LogChip
|
||||
color={riderLogsdata?.status === 'idle' ? '#f59e0b' : '#10b981'}
|
||||
icon={MdCheckCircle}
|
||||
label="Status"
|
||||
value={riderLogsdata?.status || 'unknown'}
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
)}
|
||||
</MobileCard>
|
||||
);
|
||||
})}
|
||||
|
||||
{rows?.length !== 0 && (
|
||||
<div ref={loadMoreRef} style={{ height: 40, textAlign: 'center' }}>
|
||||
{isFetchingNextPage || hasNextPage ? (
|
||||
<LoaderWithImage />
|
||||
) : (
|
||||
<Typography variant="caption" sx={{ color: DT.textMuted, fontWeight: 600 }}>
|
||||
No more riders
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</MobileCardList>
|
||||
) : (
|
||||
<Table stickyHeader sx={{ minWidth: { xs: 1100, md: 1300 } }}>
|
||||
<TableHead>
|
||||
<TableRow
|
||||
@@ -962,6 +1268,7 @@ const Riders = () => {
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
)}
|
||||
</TableContainer>
|
||||
</Paper>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user