updates on the orders and assign page
This commit is contained in:
@@ -552,62 +552,39 @@ const Preview = () => {
|
||||
<CircularLoader color="inherit" />
|
||||
</Backdrop>
|
||||
|
||||
<Box sx={{ py: 1.25, px: 2, borderBottom: '1px solid #eef2f6' }}>
|
||||
<Box
|
||||
sx={{
|
||||
py: 1.5,
|
||||
px: 2.5,
|
||||
borderBottom: '1px solid #e2e8f0',
|
||||
background: 'linear-gradient(135deg, rgba(102,37,130,0.06) 0%, rgba(146,85,171,0.06) 100%)'
|
||||
}}
|
||||
>
|
||||
<Stack direction="row" alignItems="center" justifyContent="space-between">
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<Stack direction="row" alignItems="center" spacing={1.5}>
|
||||
<Tooltip title="Back to orders" placement="top">
|
||||
<IconButton
|
||||
onClick={() => navigate('/nearle/orders')}
|
||||
sx={{ bgcolor: 'action.hover', '&:hover': { bgcolor: 'action.selected' } }}
|
||||
sx={{
|
||||
bgcolor: '#ffffff',
|
||||
border: '1px solid #e2e8f0',
|
||||
color: '#662582',
|
||||
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.04)',
|
||||
'&:hover': { bgcolor: '#f8fafc', borderColor: '#662582' }
|
||||
}}
|
||||
>
|
||||
<HiOutlineArrowLeft size={20} />
|
||||
<HiOutlineArrowLeft size={18} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Typography variant="h3" fontWeight={600}>
|
||||
<Typography variant="h3" fontWeight={700} sx={{ color: '#0f172a' }}>
|
||||
Assign Orders
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<Autocomplete
|
||||
options={tuningTypes || []}
|
||||
getOptionLabel={(option) => option.type}
|
||||
sx={{ minWidth: 250, maxWidth: 600, flex: 1 }}
|
||||
renderInput={(params) => <TextField {...params} label="Hyper Tuning" />}
|
||||
onChange={(e, val, reason) => {
|
||||
if (reason === 'clear') handleCreateDelivery(null);
|
||||
else handleCreateDelivery(val.value);
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<IoReload />}
|
||||
onClick={() => {
|
||||
setIsLoading(true);
|
||||
handleCreateDelivery('reshuffle');
|
||||
}}
|
||||
>
|
||||
Re-Assign
|
||||
</Button>
|
||||
<CSVExport
|
||||
data={csvExportData}
|
||||
filename={`Orders_Detail_${dayjs().format('YYYY-MM-DD_HHmmss')}.csv`}
|
||||
label=" CSV"
|
||||
style={{ m: 1 }}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ px: 2, borderBottom: '1px solid #eef2f6' }}>
|
||||
<Tabs value={tabValue} onChange={(e, v) => setTabValue(v)} sx={{ minHeight: 40 }}>
|
||||
<Tab label="Dispatch" sx={{ minHeight: 40, textTransform: 'none', fontWeight: 600 }} />
|
||||
<Tab label="Reconcile" sx={{ minHeight: 40, textTransform: 'none', fontWeight: 600 }} />
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
|
||||
{tabValue === 0 && dispatchPreviewData && (
|
||||
{dispatchPreviewData && (
|
||||
<Dispatch
|
||||
// The key forces a full re-mount when the cache reference changes
|
||||
// (after Change Rider / Reconcile / Re-Assign) so Dispatch's
|
||||
@@ -620,144 +597,57 @@ const Preview = () => {
|
||||
onChangeRider={(order, focusedRider) => openChangeRider(focusedRider, order)}
|
||||
/>
|
||||
)}
|
||||
{tabValue === 1 && (
|
||||
<Box sx={{ flex: 1, overflow: 'auto', p: 2, bgcolor: '#f8fafc' }}>
|
||||
{reconcileRiders.length === 0 ? (
|
||||
<Typography sx={{ color: '#94a3b8', textAlign: 'center', mt: 4 }}>
|
||||
No rider data available to reconcile.
|
||||
</Typography>
|
||||
) : (
|
||||
<Stack spacing={1.75}>
|
||||
<Box
|
||||
sx={{
|
||||
bgcolor: hasReconciled ? '#ecfdf5' : '#fffbeb',
|
||||
border: `1px solid ${hasReconciled ? '#a7f3d0' : '#fde68a'}`,
|
||||
color: hasReconciled ? '#065f46' : '#92400e',
|
||||
borderRadius: '10px',
|
||||
px: 1.5,
|
||||
py: 1,
|
||||
fontSize: 13
|
||||
}}
|
||||
>
|
||||
{hasReconciled
|
||||
? 'Steps have been reconciled. The Dispatch tab and Assign payload are updated.'
|
||||
: 'Click a numbered step to change its rider. Hit Reconcile to verify the corrected steps with the server.'}
|
||||
</Box>
|
||||
|
||||
{reconcileRiders.map((r) => {
|
||||
const totalKms = r.orders.reduce((s, o) => s + parseFloat(o.actualkms || o.kms || 0), 0);
|
||||
return (
|
||||
<Card key={r.rider_id} sx={{ p: 2, borderRadius: '12px', boxShadow: '0 1px 3px rgba(15,23,42,0.06)' }}>
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="center" sx={{ mb: 1.25 }}>
|
||||
<Stack direction="row" alignItems="center" gap={1.25}>
|
||||
<Box
|
||||
sx={{
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: '8px',
|
||||
bgcolor: '#eef2ff',
|
||||
color: '#4f46e5',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<MdTwoWheeler size={18} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography sx={{ fontWeight: 700, fontSize: 14, color: '#1e293b' }}>
|
||||
{r.rider_name}
|
||||
</Typography>
|
||||
<Typography sx={{ fontSize: 11.5, color: '#64748b' }}>
|
||||
ID: {r.rider_id}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Stack>
|
||||
<Stack direction="row" gap={1}>
|
||||
<Chip size="small" label={`${r.orders.length} stops`} sx={{ fontWeight: 600 }} />
|
||||
<Chip size="small" label={`${totalKms.toFixed(1)} km`} variant="outlined" />
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" gap={1.25} sx={{ flexWrap: 'wrap', alignItems: 'center' }}>
|
||||
{r.orders.map((o, idx) => {
|
||||
const stepNum = o.step ?? idx + 1;
|
||||
const color = stepColor(Number(stepNum) - 1);
|
||||
return (
|
||||
<Tooltip
|
||||
key={`${o.orderid}-${idx}`}
|
||||
title={
|
||||
<Box>
|
||||
<div>Order #{o.orderid}</div>
|
||||
<div>{o.deliveryaddress || o.deliverysuburb || ''}</div>
|
||||
<div style={{ marginTop: 4, opacity: 0.8 }}>Click to change rider</div>
|
||||
</Box>
|
||||
}
|
||||
>
|
||||
<Box
|
||||
onClick={() => openChangeRider(r, o)}
|
||||
sx={{
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: '50%',
|
||||
bgcolor: color,
|
||||
color: '#fff',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontWeight: 800,
|
||||
fontSize: 14,
|
||||
cursor: 'pointer',
|
||||
boxShadow:
|
||||
'0 0 0 2px rgba(255,255,255,0.6), 0 1px 3px rgba(15,23,42,0.15)',
|
||||
transition: 'transform 0.15s',
|
||||
'&:hover': { transform: 'scale(1.08)' }
|
||||
}}
|
||||
>
|
||||
{stepNum}
|
||||
</Box>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
})}
|
||||
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', pt: 1.5, pb: 2 }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
size="large"
|
||||
startIcon={<MdSwapHoriz />}
|
||||
onClick={handleReconcile}
|
||||
disabled={reconcileLoading || dirtyRiderIds.size === 0}
|
||||
sx={{ minWidth: 220, borderRadius: '10px', textTransform: 'none', fontWeight: 700 }}
|
||||
>
|
||||
{reconcileLoading
|
||||
? 'Reconciling...'
|
||||
: dirtyRiderIds.size === 0
|
||||
? 'Reconcile'
|
||||
: `Reconcile (${dirtyRiderIds.size})`}
|
||||
</Button>
|
||||
</Box>
|
||||
</Stack>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Box sx={{ px: 2, py: 1.25, borderTop: '1px solid #eef2f6' }}>
|
||||
<Box
|
||||
sx={{
|
||||
px: 3,
|
||||
py: 1.75,
|
||||
borderTop: '1px solid #e2e8f0',
|
||||
bgcolor: '#ffffff',
|
||||
boxShadow: '0 -4px 20px rgba(0, 0, 0, 0.03)'
|
||||
}}
|
||||
>
|
||||
<Stack direction="row" gap={2} alignItems="center" justifyContent="end">
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
startIcon={<ArrowBackIcon />}
|
||||
variant="outlined"
|
||||
onClick={() => navigate(-1)}
|
||||
sx={{
|
||||
borderRadius: 999,
|
||||
px: 3,
|
||||
py: 1,
|
||||
borderColor: '#e2e8f0',
|
||||
color: '#64748b',
|
||||
textTransform: 'none',
|
||||
fontWeight: 700,
|
||||
'&:hover': {
|
||||
borderColor: '#cbd5e1',
|
||||
bgcolor: '#f8fafc'
|
||||
}
|
||||
}}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Button variant="contained" onClick={handleFinalCreateDelivery}>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleFinalCreateDelivery}
|
||||
sx={{
|
||||
borderRadius: 999,
|
||||
px: 4,
|
||||
py: 1,
|
||||
bgcolor: '#662582',
|
||||
color: '#ffffff',
|
||||
textTransform: 'none',
|
||||
fontWeight: 800,
|
||||
boxShadow: '0 4px 14px rgba(102, 37, 130, 0.25)',
|
||||
'&:hover': {
|
||||
bgcolor: '#9255ab',
|
||||
transform: 'translateY(-1px)',
|
||||
boxShadow: '0 6px 20px rgba(102, 37, 130, 0.35)'
|
||||
},
|
||||
transition: 'all 0.2s'
|
||||
}}
|
||||
>
|
||||
Assign Orders
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
Reference in New Issue
Block a user