updated the ui for the mobile view

This commit is contained in:
2026-06-09 13:12:18 +05:30
parent 8513c7c2ec
commit f18b680247
29 changed files with 3664 additions and 225 deletions

View File

@@ -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>
</>