/* ============================================================================
MOWDEW — Review capture at peak trust
Fired right after a great Visit Recap (balanced water + good photos). Forks
by SENTIMENT to protect the business's public rating:
THUMBS-UP → one-tap to the owner's Google / Apple Maps review (Sprout celebrates)
THUMBS-DOWN → a PRIVATE fix-it note to the owner first (calm, apologetic)
Warm, never desperate, hard rate-limited. Reuses the kit. Loads after the
recap; exposed on window.
========================================================================= */
/* owner config (session) — enabled, review URL, frequency, monthly cap */
function reviewCfg() {
return (window.__reviewCfg = window.__reviewCfg || {
on: true, url: 'g.page/marta-lawn-pool/review', freq: '4 great visits', cap: 12, used: 5,
});
}
/* ─── ReviewCapture — the sentiment fork (homeowner, below the recap) ── */
function ReviewCapture({ proName = 'Diego', nameHidden = false }) {
const cfg = reviewCfg();
const [step, setStep] = React.useState('ask'); // ask | happy | shared | private | sent | dismissed
const [reason, setReason] = React.useState('');
const who = nameHidden ? 'your pro' : proName;
if (!cfg.on || step === 'dismissed') return null;
// ASK — tasteful, dismissible, rate-limit reassurance
if (step === 'ask') {
return (
Happy with {who}'s work?
Balanced water, clean pool — looked like a good one.
WE ASK SPARINGLY · ONCE IN A WHILE
);
}
// HAPPY — one tap to the public review
if (step === 'happy') {
return (
Love to hear it!
A quick public review helps {who} reach more neighbors. Takes 20 seconds.
);
}
// SHARED — gratitude
if (step === 'shared') {
return (
Thank you!
It means the world to {who} — and helps a small local business grow.
);
}
// PRIVATE — deflect into a fix-it conversation
if (step === 'private') {
const chips = ['Missed a spot', 'Running late', 'Communication', 'Water still off'];
return (
Sorry it wasn't great
Tell {who} what went wrong — this goes straight to them, privately.
{chips.map(ch => (
))}
Stays between you and {who} — never posted publicly.
);
}
// SENT — reassurance, fix-it framing
return (
Thanks — {who} will make it right
We've passed this along privately. {nameHidden ? 'Your pro' : proName} reaches out personally — no need to chase it.
);
}
/* ─── OWNER · review-requests settings card (used on the o_reviews screen) ─ */
function OwnerReviewSettingsCard({ toast }) {
const cfg = reviewCfg();
const [on, setOn] = React.useState(cfg.on);
const [url, setUrl] = React.useState(cfg.url);
const [freq, setFreq] = React.useState(cfg.freq);
const FREQS = ['Every visit', '4 great visits', 'Monthly'];
return (
Review requests
Ask happy customers, after a great visit
{ setOn(v => { cfg.on = !v; return !v; }); }} tone="green" />
{on && (
<>
How often to ask
{FREQS.map(f => (
))}
Only thumbs-up customers see the public link. Anything less comes to you privately first — so you fix it before it ever hits your rating.
>
)}
);
}
/* ─── OWNER · tiny dashboard stat ───────────────────────────────────── */
function OwnerReviewStat({ onClick }) {
const cfg = reviewCfg();
const left = Math.max(0, cfg.cap - cfg.used);
return (
{cfg.used} review asks this month
{left} left · {cfg.freq.toLowerCase()} cadence
{onClick &&
}
);
}
/* ─── OWNER · review settings screen ────────────────────────────────── */
function OwnerReviewsM({ go, toast }) {
return (
}>
go('o_settings')} />
Ask settings
Warm, never desperate — Mowdew only asks after a genuinely good visit, and never nags.
);
}
Object.assign(window, { reviewCfg, ReviewCapture, OwnerReviewSettingsCard, OwnerReviewStat, OwnerReviewsM });