/* ============================================================================ MOWDEW HOMEOWNER — Pool chemistry timeline + Reschedule / message owner POV: Emma Walsh, 88 Crestline Ave (pool). Readings captured from a photo of the test strip on each verified visit, trended over time. ========================================================================= */ /* Homeowner POV: Emma Walsh, 88 Crestline Ave. Full readings live in POOL_CHEM_LOG (mowdew-chem.jsx, loaded first). CHEM_LOG kept as an alias. */ const CHEM_LOG = (window.POOL_CHEM_LOG || []); /* ============================== POOL CHEMISTRY ====================== */ function HomeChemistry({ go, openFab }) { const log = window.POOL_CHEM_LOG || []; const latest = log[0]; const [trendKey, setTrendKey] = React.useState('ph'); const [showAll, setShowAll] = React.useState(false); const TREND_KEYS = ['ph', 'cl', 'alk']; const r = READINGS[trendKey]; const series = log.map(x => x[trendKey]).reverse(); const labels = log.map(x => x.short).reverse().map((s, i, a) => (i === 0 || i === a.length - 1 || i === Math.floor(a.length / 2)) ? s : ''); labels[labels.length - 1] = 'Now'; const inRange = log.filter(x => chemState(trendKey, x[trendKey]) === 'ideal').length; const span = r.max - r.min; return ( }>
88 Crestline Ave
Your pool
{/* THE STAR — plain, reassuring verdict */}
{/* what's in the water — the actual readings, simply framed */}
from today's visit}>What's in the water
{/* per-reading trends — tap a reading, ~8 visits, ideal band shaded */}
Trends over time
{TREND_KEYS.map(k => { const on = trendKey === k; return ( ); })}
{r.label} {inRange} of {log.length} in range
IDEAL {r.band}
{/* reading history */}
setShowAll(s => !s)} style={{ border: 'none', background: 'none', cursor: 'pointer', fontFamily: 'var(--font-mono)', fontSize: 10.5, fontWeight: 600, letterSpacing: '.06em', color: 'var(--aqua-700)' }}>{showAll ? 'SHOW LESS' : 'SHOW ALL'}}>Every reading, on the record
{(showAll ? log : log.slice(0, 4)).map((x, i) => { const st = chemState('ph', x.ph); return (
go('h_visit', { id: x.visit })} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 14px', borderTop: i ? '1px solid var(--ink-100)' : 'none', cursor: 'pointer' }}>
{x.date}
FC {x.cl.toFixed(1)} · TA {x.alk}{x.handled ? ' · handled on-site' : ''}
{x.handled ? Looked after :
{x.ph.toFixed(1)}
pH
}
); })}
Every reading comes from a verified on-site visit — your pro tests, Mowdew records, you see it here.
{/* your equipment — every part on the record */}
go('h_equipment')} className="card" style={{ cursor: 'pointer', padding: 14, display: 'flex', alignItems: 'center', gap: 12, borderColor: 'var(--aqua-100)' }}>
Your equipment
5 parts · pump, filter, heater & more
); } /* ============================== RESCHEDULE / MESSAGE OWNER ========== Upgraded: quick slots + a real date & time picker, reason chips, and a hand-off into the live negotiation thread (h_resched). */ function HomeRequest({ go, toast }) { const [mode, setMode] = React.useState('reschedule'); const slots = ['Keep Mon, May 18', 'Thu, May 21', 'Fri, May 22', 'Skip this week']; const [slot, setSlot] = React.useState('Thu, May 21'); const [custom, setCustom] = React.useState(false); const [date, setDate] = React.useState(null); const [time, setTime] = React.useState(null); const REASONS = ['Guests coming', 'Gate will be locked', "We'll be away", 'Rain makeup']; const [msg, setMsg] = React.useState('We have a pool party Wednesday — could Diego come Thursday instead?'); const to = custom ? (date && time ? `${date} · ${time}` : null) : slot; const ready = mode === 'message' ? msg.trim().length > 0 : !!to; const send = () => { if (mode === 'message') { toast('Message sent to Diego', 'green'); go('h_feed'); return; } toast('Request sent to Diego', 'green'); go('h_resched', { fresh: true, to, note: msg.trim() }); }; return ( }> go('h_feed')} /> {/* mode switch */}
{[['reschedule', 'Reschedule', 'calendar-check'], ['message', 'Message', 'message']].map(([id, lb, ic]) => ( ))}
{/* provider context — which provider, which visit */}
Diego Marta
Marta Lawn & Pool · weekly pool
Approves it
{mode === 'reschedule' && (
Next visit · Mon, May 18 · 10 AM
{slots.map(sl => { const on = !custom && slot === sl; return ( ); })} {/* arbitrary date + time */} {custom && (
{date && time && (
Asking for {date} · {time}
)}
)}
)} {/* reason */}
{mode === 'reschedule' ? 'Why? Diego sees this' : 'Your message'} {mode === 'reschedule' && (
{REASONS.map(r => ( ))}
)}