/* global window, React */ // ============================================================ // Trip list — left column // ============================================================ const { useState } = React; function TripCard({ trip, selected, checked, onClick, onCheck, onEdit }) { const urgClass = `urg-${trip.urgency}`; const fleetPillKind = { private: 'green', dedicated: 'amber', market: 'blue', spot: 'red', }[trip.fleet]; const utilFillClass = trip.utilState === 'low' ? 'low' : trip.utilState === 'red' ? 'over' : trip.utilState === 'amber' ? 'warn' : ''; const minsAgoLabel = (m) => m < 60 ? `${m}m ago` : `${Math.round(m/60*10)/10}h ago`; return (
{ e.stopPropagation(); onCheck(); }} title="Select for bulk action" >
{trip.changedInLastRun && ( UPD · {minsAgoLabel(trip.updatedMinsAgo)} )}
{trip.id} {trip.fleetLabel}
{trip.route.from} {trip.route.to}
{trip.customer}
{trip.chips.map((c, i) => ( {c.label} ))}
{trip.util}% {trip.window.icon} {trip.window.value}
); } function TripList({ trips, selectedId, onSelect, onBatchApprove, checked, onCheck, onClearChecks, onEdit, onBulkEdit }) { const [filter, setFilter] = useState('action'); const filters = [ { id: 'action', label: 'Needs action', n: trips.length }, { id: 'changed', label: 'Changed', n: trips.filter(t => t.changedInLastRun).length }, { id: 'recent', label: '< 2h', n: trips.filter(t => t.updatedMinsAgo < 120).length }, { id: 'held', label: 'HELD', n: trips.filter(t => /HELD/i.test(t.chips.map(c=>c.label).join(' '))).length }, ]; const filtered = trips.filter(t => { if (filter === 'changed') return t.changedInLastRun; if (filter === 'recent') return t.updatedMinsAgo < 120; if (filter === 'held') return /HELD/i.test(t.chips.map(c=>c.label).join(' ')); return true; // 'action' shows all needing review }); const numChecked = checked.size; return ( ); } Object.assign(window, { TripList });