// Interactive flow screens — drawer, dispatch list, call detail, map, login.
// Each screen is a self-contained component that takes navigation callbacks.
const { useState: useStateS, useEffect: useEffectS } = React;
// ─────── Sample data ─────────────────────────────────────────
const SAMPLE_CALLS = [
{
id: 1, number: '3206', status: 'towing',
statusSentence: 'L. Brown is towing', type: 'Tow',
vehicleYear: "17'", vehicleMakeModel: 'Chevrolet Corvette', vehicleColor: 'Red',
account: 'McDonald Investments',
receivedTime: '4:28 PM', timeAgo: '25m ago', eta: '5:45 PM',
pickup: '157 Carney Drive, Saint Clair, MI 48079',
dropoff: '1655 Yeager St, Port Huron, MI 48060',
},
{
id: 2, number: '3205', status: 'onscene',
statusSentence: 'W. Smith is on scene', type: 'Tow',
vehicleYear: "18'", vehicleMakeModel: 'GMC Yukon', vehicleColor: 'Black',
account: "Newfie's Chevrolet",
receivedTime: '4:27 PM', timeAgo: '26m ago', eta: '6:35 PM',
pickup: '1296 Pickwick Pl, Flint, MI 48507',
dropoff: '345 Cox Rd, St Clair, MI 48079',
},
{
id: 3, number: '3204', status: 'enroute',
statusSentence: 'E. Brown is en route', type: 'Tow',
vehicleYear: "16'", vehicleMakeModel: 'Jaguar XF', vehicleColor: 'Black',
account: 'Cash / Private Retail Customer',
receivedTime: '4:25 PM', timeAgo: '28m ago', eta: '6:25 PM',
pickup: '5402 Lapeer Rd, Burton, MI 48509',
dropoff: '880 W Maple Rd, Troy, MI 48084',
},
];
const SAMPLE_WAITING = [
{
id: 10, number: '3210', status: 'waiting',
statusSentence: 'Unassigned', type: 'Roadside · Lockout',
vehicleYear: "21'", vehicleMakeModel: 'Honda Civic', vehicleColor: 'Silver',
account: 'AAA',
receivedTime: '4:48 PM', timeAgo: '6m ago',
pickup: '4400 Court St, Saginaw, MI 48602',
dropoff: '—',
},
{
id: 11, number: '3209', status: 'waiting',
statusSentence: 'Unassigned', type: 'Tow · Accident',
vehicleYear: "19'", vehicleMakeModel: 'Ford F-150', vehicleColor: 'White',
account: 'State Farm',
receivedTime: '4:42 PM', timeAgo: '12m ago',
pickup: 'I-94 W at Exit 198, Detroit, MI',
dropoff: 'Bobby\'s Auto Body, Detroit, MI',
},
];
window.SAMPLE_CALLS = SAMPLE_CALLS;
window.SAMPLE_WAITING = SAMPLE_WAITING;
// ─────── Driver profile (used in drawer header) ──────────────
function DrawerHeader({ name = 'Ellie Brown', role = 'Driver', onClose }) {
return (
{name.split(' ').map(s => s[0]).join('')}
);
}
function DrawerLink({ icon, label, badge, active, onClick }) {
const [pressed, setPressed] = useStateS(false);
return (
);
}
function NavDrawerScreen({ active = 'dispatching', onNavigate, onClose, checkedIn, onCheckedInChange }) {
return (
Checked in
{checkedIn ? 'Available for calls' : 'Off duty'}
onNavigate?.('dispatching')}/>
onNavigate?.('impounds')}/>
onNavigate?.('stickering')}/>
onNavigate?.('accounts')}/>
onNavigate?.('chats')}/>
onNavigate?.('inspection')}/>
onNavigate?.('settings')}/>
onNavigate?.('logout')}/>
);
}
// ─────── Dispatch list screen ────────────────────────────────
function DispatchListScreen({ onOpenCall, onOpenDrawer, refreshing, onRefresh, tab, onTabChange }) {
const [t, setT] = useStateS(tab || 'active');
const activeTab = tab !== undefined ? tab : t;
const setTab = onTabChange || setT;
const calls = activeTab === 'active' ? SAMPLE_CALLS
: activeTab === 'waiting' ? SAMPLE_WAITING
: activeTab === 'completed' ? [{...SAMPLE_CALLS[0], status: 'completed', statusSentence: 'Cleared 2:14 PM'}, {...SAMPLE_CALLS[1], status: 'completed', statusSentence: 'Cleared 11:48 AM'}]
: [];
return (
{calls.length === 0 ? (
) : (
calls.map(c => (
onOpenCall?.(c)}
onEdit={() => onOpenCall?.(c)}
onUpdateStatus={() => onOpenCall?.(c, 'updateStatus')}
onCallContact={() => {}}
/>
))
)}
{}}/>
);
}
function EmptyState() {
return (
No calls yet
Create the first one to get started.
New call
);
}
// ─────── Call detail screen (#3176) ──────────────────────────
function CallDetailScreen({ onBack, onUpdateStatus }) {
const [sheetOpen, setSheetOpen] = useStateS(false);
const [status, setStatus] = useStateS('onscene');
const accent = (TBT.status[status] || {}).solid || 'var(--green-9)';
return (
{/* status accent strip — follows the current status */}
{/* Vehicle header */}
06' Acura TL (Black)
Fuel Delivery
Joes Apt. Complex · 04:06 PM
{/* Address */}
1234 6th St, Marysville, MI 48040, USA
(1234 6th Street) · 7.4 mi
>}
action={Go}
/>
{/* Contacts */}
Contacts
John Smith
810-320-5063
>}
action={}
/>
{/* Vehicle / details */}
Vehicle
Scan}/>
{/* Times */}
{/* Photos */}
{/* Bottom action bar */}
setSheetOpen(true) },
{ icon: I.Camera, label: 'Add Photo' },
{ icon: I.Map, label: 'Show Map' },
{ icon: I.Layers, label: 'More' },
]}/>
{/* Status update sheet */}
setSheetOpen(false)} title="Update status">
{['waiting','enroute','onscene','towing','completed','canceled'].map(s => {
const isCurrent = s === status;
return (
);
})}
);
}
function TimeRow({ color, label, value }) {
return (
{label}
{value}
);
}
// ─────── Map screen ──────────────────────────────────────────
function MapScreen({ onOpenCall }) {
const [filter, setFilter] = useStateS('calls');
const [selected, setSelected] = useStateS(null);
const dark = typeof document !== 'undefined' && document.documentElement.getAttribute('data-theme') === 'dark';
return (
{/* Stylized map (SVG) */}
{/* Filter chips top */}
setFilter('drivers')} icon={I.User}>Drivers
setFilter('calls')} icon={I.MapPin}>Calls
{/* Pins */}
setSelected('3204')}/>
setSelected('3205')}/>
setSelected('3206')}/>
setSelected('3207')}/>
{/* Floating action stack (right) */}
{/* Bottom info card if a pin is selected */}
{selected && (
{selected}
17' Chevrolet Corvette (Red)
157 Carney Drive, Saint Clair
Directions
onOpenCall?.()}>Open
)}
);
}
function SegBtn({ active, onClick, icon, children }) {
return (
);
}
function RoundIconBtn({ icon, onClick }) {
return (
);
}
function Pin({ top, left, number, status, onClick }) {
const dark = typeof document !== 'undefined' && document.documentElement.getAttribute('data-theme') === 'dark';
const palette = (dark ? TBT.statusDark : TBT.status)[status];
return (
);
}
// ─────── Login screen ────────────────────────────────────────
function LoginScreen() {
const [pwd, setPwd] = useStateS('');
const [show, setShow] = useStateS(false);
return (
T
Sign in
Use your Towbook driver credentials.
Sign in
Towbook · v8.2.0
);
}
// ─────── Equipment inspection screen ─────────────────────────
function InspectionScreen() {
const [data, setData] = useStateS({});
const set = (k, v) => setData(prev => ({...prev, [k]: v}));
const items = [
'Engine oil level', 'Transmission fluid level', 'Brake fluid level',
'Windshield washer fluid', 'Hoses & belts', 'Battery cable connections',
'Tire condition (front)', 'Tire condition (rear)', 'Lights & turn signals',
'Mirrors & glass', 'Wheel lift function', 'Boom & winch operation',
];
return (
Pre-shift inspection
Unit #3 · {Object.keys(data).filter(k => data[k]).length}/{items.length} complete
data[k]).length / items.length}/>
Truck
{items.map((label, i) => (
set(i, v)}
photoCount={data[i] === 'fail' ? 1 : 0}/>
))}
Submit inspection
);
}
Object.assign(window, {
NavDrawerScreen, DispatchListScreen, CallDetailScreen,
MapScreen, LoginScreen, InspectionScreen,
});