/* ============================================================================ MOWDEW — Provider screens p_today (Today/Route · HERO) · p_homes · p_property · p_visit · p_invoices · p_invoice_build · p_getpaid Each screen: (props) => JSX. Shared helpers from kit + frame + data. ========================================================================= */ /* ---- small shared bits ---- */ function statusChip(h) { if (h.status === 'done') return Done; if (h.status === 'onsite') return On-site; return Upcoming; } function fmtClock(sec) { const m = Math.floor(sec / 60), s = sec % 60; return `${m}:${String(s).padStart(2, '0')}`; } /* ---- Route map: numbered stops over the mini neighborhood ---- */ function RouteMap({ height = 156, onExpand }) { const stops = [ [44, 50, 'done'], [104, 98, 'onsite'], [178, 128, 'soon'], [248, 98, 'soon'], [280, 44, 'soon'] ]; const col = { done: 'var(--green-500)', onsite: 'var(--blue-500)', soon: 'var(--yellow-500)' }; return (
{/* route line connecting stops */} {stops.map(([x, y, st], i) => (
{i + 1}
))} TODAY · 5 STOPS
); } /* ============================== TODAY / ROUTE (HERO) ===================== */ function ProviderToday({ go, openFab }) { const done = HOMES.filter(h => h.status === 'done').length; const earned = HOMES.reduce((s, h) => s + SERVICE[h.svc].price, 0); return ( }> {/* header */}
{TODAY}
Good morning, Diego
{/* summary strip */}
{[['Stops', '5', 'route', 'green'], ['Done', String(done), 'check-circle', 'green'], ['On track', fmtMoney(earned), 'invoice', 'blue']].map(([k, v, ic, tn], i) => (
{v}
{k}
))}
{/* auto check-in banner */}
Auto check-in is on
You'll clock in automatically when you arrive.
{/* map */}
{}} />
{/* route list */}
The route
{HOMES.map((h, i) => )}
); } function RouteCard({ h, n, go }) { const s = SERVICE[h.svc]; const onsite = h.status === 'onsite'; const done = h.status === 'done'; return (
go(h.status === 'onsite' ? 'p_visit' : 'p_property', { id: h.id })} className="card" style={{ padding: 14, cursor: 'pointer', borderColor: onsite ? 'var(--blue-200,#8FD2F6)' : 'var(--ink-100)', boxShadow: onsite ? '0 0 0 3px var(--blue-50), var(--shadow-md)' : 'var(--shadow-sm)' }}>
{n}

{h.addr}

{h.who} · {s.label}
{statusChip(h)}
{done && (
{h.in} – {h.out} · {h.dur} VERIFIED
)} {onsite && } {h.status === 'upcoming' && (
ETA {h.eta} {h.geo ? Auto check-in armed : Manual check-in}
)}
); } function OnsiteFooter({ h, go }) { const [sec, setSec] = React.useState(764); React.useEffect(() => { const t = setInterval(() => setSec(s => s + 1), 1000); return () => clearInterval(t); }, []); return (
CHECKED IN · {h.in}
{fmtClock(sec)}
); } /* ============================== HOMES LIST ============================== */ function ProviderHomes({ go, openFab }) { return ( }> } />
{HOMES.map(h => { const s = SERVICE[h.svc]; return (
go('p_property', { id: h.id })} className="card" style={{ padding: 14, cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 12 }}>

{h.addr}

{h.who} · {h.city}
{h.cadence.replace('Every ', '')}
); })}
); } /* ============================== PROPERTY DETAIL ========================= */ function ProviderProperty({ go, params }) { const h = HOMES.find(x => x.id === params.id) || HOMES[0]; const s = SERVICE[h.svc]; return ( }> go('p_today')} /> {/* hero map */}
{/* meta cards */}
Cadence
{h.cadence}
Service
{fmtMoney(s.price)}
{/* homeowner contact */}

{h.name}

Homeowner · on Mowdew
{/* recent visits */}
Recent visits
{h.visits.map((v, i) => (
go('h_visit', { id: h.id })} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '13px 14px', borderTop: i ? '1px solid var(--ink-100)' : 'none', cursor: 'pointer' }}>
{v.date}
{v.who} · {v.dur}
VERIFIED
))}
); } Object.assign(window, { ProviderToday, ProviderHomes, ProviderProperty, RouteMap, statusChip, fmtClock });