diff --git a/src/pages/Dashboard.jsx b/src/pages/Dashboard.jsx index a0db701..b5c5ac9 100644 --- a/src/pages/Dashboard.jsx +++ b/src/pages/Dashboard.jsx @@ -47,6 +47,68 @@ const DAY_LABELS = ['S', 'M', 'T', 'W', 'T', 'F', 'S']; // ── Doormile-themed range calendar ─────────────────────────────────────────────── // Click a day to set the start, click again to set the end (auto-swaps if reversed). // In-range days get a soft red wash; the two endpoints are solid brand red. +// Renders two compact months side-by-side (single month on small screens). + +// A single compact month grid — kept lightweight so both months render fast. +function MonthGrid({ view, start, end, max, onDay }) { + const gridStart = view.startOf('month').subtract(view.startOf('month').day(), 'day'); + const cells = Array.from({ length: 42 }, (_, i) => gridStart.add(i, 'day')); + + return ( + + + {view.format('MMMM YYYY')} + + + {/* Weekday labels */} + + {DAY_LABELS.map((d, i) => ( + + {d} + + ))} + + + {/* Days */} + + {cells.map((d) => { + const inMonth = d.month() === view.month(); + const isStart = start && d.isSame(start, 'day'); + const isEnd = end && d.isSame(end, 'day'); + const isEndpoint = isStart || isEnd; + const inRange = start && end && d.isAfter(start, 'day') && d.isBefore(end, 'day'); + const isToday = d.isSame(dayjs(), 'day'); + const disabled = max && d.isAfter(max, 'day'); + return ( + + onDay(d)} + sx={{ + width: 28, height: 28, m: '1px', border: 'none', cursor: disabled ? 'default' : 'pointer', + borderRadius: 1.5, fontSize: '0.72rem', fontFamily: 'inherit', + fontWeight: isEndpoint ? 700 : 500, + color: disabled ? '#D5D9DD' : isEndpoint ? '#fff' : inMonth ? '#3C4043' : '#C4C9CE', + bgcolor: isEndpoint ? BRAND : 'transparent', + boxShadow: isToday && !isEndpoint ? `inset 0 0 0 1.5px ${BRAND}` : 'none', + transition: 'background-color .12s', + '&:hover': { bgcolor: disabled ? 'transparent' : isEndpoint ? '#9E0E20' : alpha(BRAND, 0.1) } + }} + > + {d.date()} + + + ); + })} + + + ); +} + function RangeCalendar({ from, to, maxDate, onSelect }) { const [view, setView] = useState(dayjs(to || from || undefined).startOf('month')); const [anchorDate, setAnchorDate] = useState(null); // first click while picking a new range @@ -55,9 +117,6 @@ function RangeCalendar({ from, to, maxDate, onSelect }) { const end = to ? dayjs(to) : null; const max = maxDate ? dayjs(maxDate) : null; - const gridStart = view.startOf('month').subtract(view.startOf('month').day(), 'day'); - const cells = Array.from({ length: 42 }, (_, i) => gridStart.add(i, 'day')); - const handleDay = (d) => { if (!anchorDate) { setAnchorDate(d); @@ -72,63 +131,23 @@ function RangeCalendar({ from, to, maxDate, onSelect }) { }; return ( - - {/* Month header */} - - setView((v) => v.subtract(1, 'month'))} sx={{ color: '#5F6368' }}> - + + {/* Shared nav header spanning both months */} + + setView((v) => v.subtract(1, 'month'))} sx={{ color: '#9AA0A6', p: 0.5 }}> + - {view.format('MMMM YYYY')} - setView((v) => v.add(1, 'month'))} sx={{ color: '#5F6368' }}> - + setView((v) => v.add(1, 'month'))} sx={{ color: '#9AA0A6', p: 0.5 }}> + - {/* Weekday labels */} - - {DAY_LABELS.map((d, i) => ( - - {d} - - ))} - - - {/* Days */} - - {cells.map((d) => { - const inMonth = d.month() === view.month(); - const isStart = start && d.isSame(start, 'day'); - const isEnd = end && d.isSame(end, 'day'); - const isEndpoint = isStart || isEnd; - const inRange = start && end && d.isAfter(start, 'day') && d.isBefore(end, 'day'); - const isToday = d.isSame(dayjs(), 'day'); - const disabled = max && d.isAfter(max, 'day'); - return ( - - handleDay(d)} - sx={{ - width: 36, height: 36, m: '2px', border: 'none', cursor: disabled ? 'default' : 'pointer', - borderRadius: 2, fontSize: '0.85rem', fontFamily: 'inherit', - fontWeight: isEndpoint ? 800 : 600, - color: disabled ? '#CED4DA' : isEndpoint ? '#fff' : inMonth ? '#212529' : '#B9BEC4', - bgcolor: isEndpoint ? BRAND : 'transparent', - boxShadow: isToday && !isEndpoint ? `inset 0 0 0 1.5px ${BRAND}` : 'none', - transition: 'background-color .15s', - '&:hover': { bgcolor: disabled ? 'transparent' : isEndpoint ? '#9E0E20' : alpha(BRAND, 0.12) } - }} - > - {d.date()} - - - ); - })} - + + + + + + ); } @@ -317,11 +336,11 @@ export default function Dashboard() { onClose={() => setCalAnchor(null)} anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} transformOrigin={{ vertical: 'top', horizontal: 'right' }} - PaperProps={{ sx: { mt: 1, borderRadius: 3, border: '1px solid #ECEEF1', boxShadow: '0 12px 40px rgba(0,0,0,0.14)', overflow: 'hidden' } }} + PaperProps={{ sx: { mt: 1, borderRadius: 2.5, border: '1px solid #EEF0F2', boxShadow: '0 8px 28px rgba(0,0,0,0.10)', overflow: 'hidden' } }} > - - Select date range - + + Select date range + {dayjs(range.from).format('DD MMM')} – {dayjs(range.to).format('DD MMM YYYY')} · {dayCount} {dayCount === 1 ? 'day' : 'days'} diff --git a/src/pages/operations/Dispatch.jsx b/src/pages/operations/Dispatch.jsx index 9b4a90d..46d639a 100644 --- a/src/pages/operations/Dispatch.jsx +++ b/src/pages/operations/Dispatch.jsx @@ -147,7 +147,7 @@ export default function Dispatch() { diff --git a/src/pages/operations/RiderRoutes.jsx b/src/pages/operations/RiderRoutes.jsx index 10a900b..2540d8e 100644 --- a/src/pages/operations/RiderRoutes.jsx +++ b/src/pages/operations/RiderRoutes.jsx @@ -529,7 +529,7 @@ export default function RiderRoutes() { Rider Routes - Pickups each miler covered today — open any order for full details, or press play to replay the trip. + Pickups each miler covered today open any order for full details, or press play to replay the trip. diff --git a/src/pages/operations/Routing.jsx b/src/pages/operations/Routing.jsx index a2a1e81..c31d4fc 100644 --- a/src/pages/operations/Routing.jsx +++ b/src/pages/operations/Routing.jsx @@ -146,7 +146,7 @@ export default function Routing() { Where Does It Go? - Scan a parcel and we'll tell you exactly what to do with it next — deliver locally, transfer to another city, or set it aside. + Scan a parcel and we'll tell you exactly what to do with it next deliver locally, transfer to another city, or set it aside.