/* ============================================================ Views: Schedule Viewer, Dispatch Board, Settings ============================================================ */ /* =================== SCHEDULE VIEWER =================== */ function ScheduleView({ ctx }) { const activeDrivers = ctx.drivers.filter(d => d.status === 'Active'); const [sel, setSel] = useState(activeDrivers[0] ? activeDrivers[0].id : (ctx.drivers[0] && ctx.drivers[0].id)); const driver = ctx.drivers.find(d => d.id === sel); const legs = ctx.schedule.filter(l => l.driverId === sel).sort((a, b) => a.date < b.date ? -1 : 1); const trk = legs[0] ? ctx.trucks.find(t => t.id === legs[0].truckId) : null; // build display rows incl. night rest const rows = []; legs.forEach((l, i) => { rows.push({ kind: 'leg', leg: l }); if (l.leg === 'outbound') { rows.push({ kind: 'rest', date: l.date }); } }); return (
{driver && (
{driver.id}
{driver.name}
{driver.phone || 'No phone'} · {driver.license || 'CDL-A'}
Truck
{trk ? trk.name : 'Unassigned'}
Status
{driver.status}
)}

Weekly Cycle

{legs.length ? 'NC ⇄ NJ round trip' : 'Not scheduled this week'}
{legs.length === 0 ? (
This driver has no loads this week.
Generate the schedule or set the driver to Active.
) : ( {rows.map((r, i) => { if (r.kind === 'rest') { return ( ); } const l = r.leg; return ( ); })}
DateActivityRouteStatus
{Engine.fmtLong(r.date)} · PM Mandatory 10-hour DOT rest — NJ NJ overnight Rest
{Engine.fmtLong(l.date)} {l.leg === 'outbound' ? 'Outbound — Pickup NC' : 'Backhaul — Return NC'} {l.delayed && Weekend delay}
)}
); } /* =================== DISPATCH BOARD =================== */ function BoardView({ ctx }) { const [pop, setPop] = useState(null); // {leg, x, y} const dates = Engine.scheduleDates(ctx.schedule); const trucks = ctx.trucks; // index legs by truck+date const cellMap = {}; ctx.schedule.forEach(l => { const key = l.truckId + '|' + l.date; (cellMap[key] = cellMap[key] || []).push(l); }); const gridCols = '150px repeat(' + Math.max(dates.length, 1) + ', minmax(108px, 1fr))'; const openPop = (e, leg) => { e.stopPropagation(); const r = e.currentTarget.getBoundingClientRect(); let x = r.left, y = r.bottom + 6; if (x + 230 > window.innerWidth) x = window.innerWidth - 240; if (y + 230 > window.innerHeight) y = r.top - 236; setPop({ leg, x, y }); }; return (
setPop(null)}>
Outbound (NC→NJ)
Backhaul (NJ→NC)
Delayed return
Off duty
Click a load to override status
{/* header row */}
{dates.map(dt => { const wd = Engine.dow(dt); const weekend = wd === 0 || wd === 6; return (
{Engine.weekdayName(dt)}
{Engine.fmtShort(dt)}
); })} {/* truck rows */} {trucks.map(t => (
{t.code}
{t.plate}
{dates.map(dt => { const legs = cellMap[t.id + '|' + dt] || []; if (legs.length === 0) return
; return (
{legs.map(l => { const drv = ctx.drivers.find(d => d.id === l.driverId); const cls = l.delayed ? 'l-delayed' : (l.leg === 'outbound' ? 'l-out' : 'l-back'); return (
openPop(e, l)}>
{drv ? drv.name.split(' ')[0] : 'Driver'} {l.from}→{l.to}
{l.delayed && l.status !== 'completed' ? 'DELAYED · ' : ''}{(STATUS_META[l.status] || {}).label}
); })}
); })}
))}
{pop && setPop(null)} />}
); } function STATUS_COLOR(l) { if (l.delayed && l.status !== 'completed') return 'var(--amber)'; if (l.status === 'completed') return 'var(--green)'; if (l.status === 'in_transit') return 'var(--accent-2)'; return 'var(--text-faint)'; } function CellPopover({ pop, ctx, close }) { const drv = ctx.drivers.find(d => d.id === pop.leg.driverId); const opts = [ { v: 'scheduled', label: 'Scheduled', color: 'var(--gray)' }, { v: 'in_transit', label: 'In Transit', color: 'var(--accent)' }, { v: 'completed', label: 'Completed', color: 'var(--green)' }, { v: 'delayed', label: 'Delayed Return', color: 'var(--amber)' }, ]; const choose = (v) => { if (v === 'delayed') ctx.overrideLeg(pop.leg.id, { delayed: true }); else ctx.overrideLeg(pop.leg.id, { status: v, delayed: v === 'completed' ? pop.leg.delayed : false }); close(); }; return (
e.stopPropagation()}>
{drv ? drv.name : 'Load'} · {pop.leg.from}→{pop.leg.to}
{opts.map(o => { const sel = (o.v === 'delayed') ? (pop.leg.delayed && pop.leg.status !== 'completed') : (pop.leg.status === o.v && !(pop.leg.delayed && pop.leg.status !== 'completed')); return (
choose(o.v)}> {o.label} {sel && }
); })}
); } /* =================== SETTINGS =================== */ function SettingsView({ ctx }) { const [localDate, setLocalDate] = useState(ctx.weekStart); const [showPw, setShowPw] = useState(false); const snappedNote = Engine.dow(localDate) !== 1; return (

Week Start Date

Editable every Monday
setLocalDate(e.target.value)} />
{snappedNote && (
Not a Monday — the scheduler will snap to the Monday of that week ({Engine.fmtFull(Engine.snapToMonday(localDate))}).
)}

Scheduler Rules

Appearance

Quick Admin

{showPw && setShowPw(false)} />}
); } function ChangePasswordModal({ ctx, close }) { const [cur, setCur] = useState(''); const [next, setNext] = useState(''); const [conf, setConf] = useState(''); const [err, setErr] = useState(''); const save = () => { if (next !== conf) { setErr('New passwords do not match.'); return; } const res = ctx.changePassword(cur, next); if (res === 'wrong-current') { setErr('Current password is incorrect.'); return; } if (res === 'too-short') { setErr('New password must be at least 4 characters.'); return; } close(); }; return (
}>
{ setCur(e.target.value); setErr(''); }} placeholder="Enter current password" />
{ setNext(e.target.value); setErr(''); }} placeholder="At least 4 characters" />
{ setConf(e.target.value); setErr(''); }} placeholder="Re-enter new password" />
{err &&
{err}
}
The new password is saved on this device and required next time the dashboard is locked or reopened.
); } function RuleRow({ icon, title, desc }) { return (
{title}
{desc}
); } Object.assign(window, { ScheduleView, BoardView, SettingsView });