import { useMemo, useState } from 'react'; import { Card, Box, Stack, Typography, Tabs, Tab, TextField, InputAdornment, LinearProgress, Chip, MenuItem, IconButton, Button, Tooltip } from '@mui/material'; import SearchOutlinedIcon from '@mui/icons-material/SearchOutlined'; import ScheduleOutlinedIcon from '@mui/icons-material/ScheduleOutlined'; import ArrowRightAltRoundedIcon from '@mui/icons-material/ArrowRightAltRounded'; import FlagOutlinedIcon from '@mui/icons-material/FlagOutlined'; import OpenInNewRoundedIcon from '@mui/icons-material/OpenInNewRounded'; import './tracking.css'; import StatusChip from '@/components/StatusChip'; import { vehicleTypes } from '@/data/mock'; import { vehicleIconComponents } from './vehicleMarker'; // ==============================|| OPERATIONAL DELIVERY QUEUE ||============================== // // Left panel of the control tower: tabbed, searchable, city-filterable list of shipment cards. // Selecting drives the map; per-card quick actions (Flag / Open 360) commit via `actions`. const ETA_TONE = { 'on-time': '#00773B', 'at-risk': '#8A6500', delayed: '#A82216' }; const PRIORITY = { high: { fg: '#A82216', bg: '#FEEAE9' }, express: { fg: '#8A6500', bg: '#FFF7E0' }, standard: { fg: '#595959', bg: '#F0F0F0' } }; const matches = (d, q) => [d.id, d.rider, d.vehicle, d.origin, d.destination, d.city].some((f) => f.toLowerCase().includes(q)); function DeliveryCard({ d, selected, onSelect, actions }) { const tone = ETA_TONE[d.etaStatus] || ETA_TONE['on-time']; const vt = vehicleTypes[d.vehicle] || vehicleTypes.Bike; const pr = PRIORITY[d.priority] || PRIORITY.standard; const live = d.status !== 'Delivered'; const stop = (fn) => (e) => { e.stopPropagation(); fn(); }; return ( onSelect(d.id)} sx={{ p: 1.5, borderRadius: 2, cursor: 'pointer', border: '1px solid', borderColor: selected ? 'primary.main' : 'grey.200', borderLeft: '4px solid', borderLeftColor: d.etaStatus === 'on-time' ? 'transparent' : tone, bgcolor: selected ? 'rgba(192,18,39,0.03)' : 'background.paper', transition: 'border-color .15s, background .15s', '&:hover': { borderColor: 'primary.light' } }} > {(() => { const G = vehicleIconComponents[d.vehicle]; return G ? : null; })()} {d.id} {d.rider} · {d.vehicle} {d.priority} {live && ( } label="Live" sx={{ height: 20, bgcolor: 'success.lighter', color: 'success.dark', fontWeight: 700, '& .MuiChip-label': { px: 0.75, fontSize: 11 } }} /> )} {d.origin} {d.destination} {d.progress}% {d.status === 'Delivered' ? `Delivered ${d.eta}` : `ETA ${d.eta}`} {d.etaStatus !== 'on-time' && ` · +${d.delayMin}m`} {/* quick actions */} {actions && ( actions.flag(d.id))} sx={{ p: 0.5 }}> )} ); } const TABS = [ { key: 'active', label: 'Active', test: (d) => d.status !== 'Delivered' }, { key: 'delayed', label: 'Delayed', test: (d) => d.etaStatus !== 'on-time' }, { key: 'completed', label: 'Completed', test: (d) => d.status === 'Delivered' }, { key: 'all', label: 'All', test: () => true } ]; export default function DeliveryQueue({ deliveries, selectedId, onSelect, actions }) { const [tab, setTab] = useState(0); const [q, setQ] = useState(''); const [city, setCity] = useState('all'); const cities = useMemo(() => [...new Set(deliveries.map((d) => d.city))], [deliveries]); const rows = useMemo(() => { const query = q.trim().toLowerCase(); return deliveries .filter(TABS[tab].test) .filter((d) => (city === 'all' ? true : d.city === city)) .filter((d) => (query ? matches(d, query) : true)) .sort((a, b) => Number(b.etaStatus !== 'on-time') - Number(a.etaStatus !== 'on-time')); }, [deliveries, tab, q, city]); const counts = useMemo(() => TABS.map((t) => deliveries.filter(t.test).length), [deliveries]); return ( Active Deliveries {rows.length} shown setQ(e.target.value)} InputProps={{ startAdornment: () }} /> setCity(e.target.value)} sx={{ minWidth: 120 }}> All cities {cities.map((c) => {c})} setTab(v)} variant="fullWidth" sx={{ px: 1, minHeight: 40, '& .MuiTab-root': { minHeight: 40, textTransform: 'none', fontWeight: 600, fontSize: 13 } }} > {TABS.map((t, i) => ( ))} {rows.map((d) => ( ))} {rows.length === 0 && ( No deliveries match this view. )} ); }