/* ============================================================================ MOWDEW — Homeowner screens h_feed (Visit feed · HERO) · h_visit · h_inbox (invoice + pay) · h_ledger (payment ledger) · h_summary (monthly summary) ========================================================================= */ /* ============================== VISIT FEED (HERO) ====================== */ function HomeFeed({ go, openFab, toast }) { const [arr, setArr] = React.useState('enroute'); const [banner, setBanner] = React.useState('enroute'); const advance = (n) => { setArr(n); if (n === 'enroute' || n === 'complete') setBanner(n); }; return ( }> setBanner(null)} onOpen={() => { setBanner(null); if (arr === 'complete') go('h_visit', { id: 'v2' }); else go('h_arrival'); }} /> {/* header */}
88 Crestline Ave
Your visits
go('h_notifs')} />
{/* provider strip — with a clear request action at top */}
Diego Marta
Marta Lawn & Pool · Weekly pool
4.9
{/* TODAY'S VISIT — live arrival arc (the verified-visit spine, real-time) */}
go('h_arrival')} style={{ border: 'none', background: 'none', cursor: 'pointer', fontFamily: 'var(--font-mono)', fontSize: 10.5, fontWeight: 600, letterSpacing: '.06em', color: 'var(--aqua-700)' }}>SEE THE ARC}>Today's visit
{/* live reschedule negotiation — Diego suggested a new time */}
{/* coming up — scheduled work waiting on your OK (heterogeneous timeline starts here) */}
Coming up
{/* tagline banner */}
Every visit, on the record
GPS check-in proves when your pro arrived and left — no honor system.
{/* timeline */}
{(() => { const out = []; FEED.forEach((v, i) => { out.push(); if (i === 1) out.push(); }); return out; })()}
); } function FeedCard({ v, go, alt = false }) { const s = SERVICE[v.svc]; const sx = alt ? '-2' : ''; return (
{/* node */}
go(v.live ? 'h_visit' : 'h_recap', { id: v.id })} className="card" style={{ flex: 1, padding: 13, cursor: 'pointer', borderColor: v.live ? 'var(--blue-200,#8FD2F6)' : 'var(--ink-100)', boxShadow: v.live ? '0 0 0 3px var(--blue-50), var(--shadow-sm)' : 'var(--shadow-sm)' }}>
{s.label}
Marco · {v.date}
{v.live ? On-site : Recap}
{/* photos */}
{v.live ? In progress : }
{/* meta */}
{v.in}{v.out ? `–${v.out}` : ''} {v.dur} AUTO CHECK-IN
); } /* ============================== VISIT DETAIL =========================== */ function HomeVisit({ go, params }) { const v = FEED.find(x => x.id === params.id) || FEED[1]; const s = SERVICE[v.svc]; return ( go('h_feed')} /> {/* big before/after */}
{v.live ? 'In progress' : ''}
{/* verified row */}
Verified on-site
Auto check-in · {v.in}{v.out ? ` – ${v.out}` : ''} · {v.dur}
40 FT
{/* map */}
Where Diego checked in
{/* notes */}
Notes from Diego

{v.note}

); } /* ============================== INVOICE INBOX + PAY ==================== */ function HomeInbox({ go, openFab, toast }) { const inv = INVOICES[0]; const [paid, setPaid] = React.useState(false); const [rail, setRail] = React.useState(null); const [sheet, setSheet] = React.useState(false); const [share, setShare] = React.useState(false); const confirmPay = () => { setSheet(false); setPaid(true); toast(`Paid via ${RAIL[rail].label} · ${fmtMoney(inv.total)}`, 'green'); }; return ( <> }> go('h_feed')} right={} /> {/* invoice hero */}
{inv.biz}
{inv.id} · DUE {inv.due.toUpperCase()}
{paid ? Paid : Due {inv.due}}
{paid ? 'Paid in full' : 'Amount due'}
{/* lines — same verified visits */}
4 visits in May · tap any to see its recap
{inv.lines.map((v, i) => (
go('h_recap', { id: FEED[i] ? FEED[i].id : 'v2' })} style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '11px 0', borderTop: '1px solid var(--ink-100)', cursor: 'pointer' }}>
{v.label}
{v.date} · Verified · see recap
))}
{/* pay module — one amount (in header above) + 3 brand rails; no amount on the buttons */} {!paid ? (
Pay Diego in one tap
{PROVIDER.rails.map(r => { setRail(r); setSheet(true); }} />)}
Mowdew never touches your money.
) : (
Paid via {RAIL[rail].label}
Marked in your ledger — you won't pay this twice.
)}
{/* never double-pay reassurance */} {!paid && (
This invoice isn't in your ledger as paid yet. Pay once here and it's marked — you'll never pay twice.
)}
{/* slim confirm sheet — rail already chosen; no re-pick, no amount on the button */} setSheet(false)} title={`Pay with ${rail ? RAIL[rail].label : ''}`}>
Mowdew opens {rail ? RAIL[rail].label : 'the app'} with the amount and Diego prefilled — confirm there to finish.
{rail ? RAIL[rail].label : ''}
{rail === 'zelle' ? PROVIDER.zelle : rail === 'venmo' ? PROVIDER.venmo : 'pay.mowdew.co/diego'}
Mowdew never touches your money.
{/* share / download the same PDF Diego emailed */} setShare(false)} inv={inv.id} toast={toast} /> ); } Object.assign(window, { HomeFeed, FeedCard, HomeVisit, HomeInbox });