/* ============================================================================
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 (
{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) => (
))}
{/* 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 */}
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 });