// Shared, config-driven qualification quiz. Steps come from window.LP.quiz.steps.
const { useState: useQState, useRef: useQRef } = React;
const LICENSED_STATES = ['NH', 'VT', 'MA', 'CT', 'NE', 'NY', 'MD'];
const ALL_STATES = [
['AL','Alabama'],['AK','Alaska'],['AZ','Arizona'],['AR','Arkansas'],['CA','California'],['CO','Colorado'],['CT','Connecticut'],['DE','Delaware'],
['FL','Florida'],['GA','Georgia'],['HI','Hawaii'],['ID','Idaho'],['IL','Illinois'],['IN','Indiana'],['IA','Iowa'],['KS','Kansas'],
['KY','Kentucky'],['LA','Louisiana'],['ME','Maine'],['MD','Maryland'],['MA','Massachusetts'],['MI','Michigan'],['MN','Minnesota'],['MS','Mississippi'],
['MO','Missouri'],['MT','Montana'],['NE','Nebraska'],['NV','Nevada'],['NH','New Hampshire'],['NJ','New Jersey'],['NM','New Mexico'],['NY','New York'],
['NC','North Carolina'],['ND','North Dakota'],['OH','Ohio'],['OK','Oklahoma'],['OR','Oregon'],['PA','Pennsylvania'],['RI','Rhode Island'],['SC','South Carolina'],
['SD','South Dakota'],['TN','Tennessee'],['TX','Texas'],['UT','Utah'],['VT','Vermont'],['VA','Virginia'],['WA','Washington'],['WV','West Virginia'],
['WI','Wisconsin'],['WY','Wyoming'],['DC','District of Columbia'],
];
const INVESTMENT = [
{ value: 'under-199', label: 'Under $199 / month', tier: 'disqualify' },
{ value: '199-299', label: '$199 – $299 / month', tier: 'standard' },
{ value: '299-499', label: '$299 – $499 / month', tier: 'expanded' },
{ value: '499+', label: '$499 + / month', tier: 'premium' },
];
const BEST_TIME = [
{ value: 'morning', label: 'Morning · 8a–12p' }, { value: 'afternoon', label: 'Afternoon · 12p–5p' },
{ value: 'evening', label: 'Evening · 5p–7p' }, { value: 'flexible', label: "I'm flexible" },
];
function calcBMI(w, ft, inch) {
w = parseFloat(w); ft = parseInt(ft); inch = parseInt(inch) || 0;
if (isNaN(w) || isNaN(ft) || w < 50 || w > 800 || ft < 3 || ft > 8) return null;
const t = ft * 12 + inch; const bmi = (w * 703) / (t * t);
if (isNaN(bmi) || bmi < 10 || bmi > 80) return null;
return Math.round(bmi * 10) / 10;
}
function bmiNote(bmi) {
if (!bmi) return null;
if (bmi < 18.5) return { tone: 'caution', headline: 'Below the typical range for a fat-loss-focused program.', body: "If your starting composition is below the typical range, the conversation may be different, possibly recomposition or something else entirely. The clinical team will discuss what makes sense for you." };
if (bmi < 25) return { tone: 'note', headline: "We've noted your starting point.", body: "Patients in this range often benefit more from composition work, preserving lean mass while reducing body fat, than from weight loss alone. GLP-1 medication may not be appropriate in this range; your provider will review." };
return { tone: 'note', headline: "We've noted your starting point.", body: "Whether medication is appropriate, and what realistic, individualized goals look like, will be decided by our clinical team after your labs and history review." };
}
function Quiz() {
const cfg = window.LP;
const STEPS = cfg.quiz.steps;
const [step, setStep] = useQState(0);
const [data, setData] = useQState({ weight: '', heightFt: '', heightIn: '', state: '', firstName: '', lastName: '', email: '', investment: '', phone: '', bestTime: '', notes: '' });
const [submitting, setSubmitting] = useQState(false);
const [submitted, setSubmitted] = useQState(false);
const [error, setError] = useQState(null);
const advanceRef = useQRef(null);
const cur = STEPS[step];
const update = (k, v) => setData(d => ({ ...d, [k]: v }));
const val = (k, multi) => data[k] ?? (multi ? [] : '');
const toggle = (k, v) => setData(d => { const c = d[k] || []; return { ...d, [k]: c.includes(v) ? c.filter(x => x !== v) : [...c, v] }; });
const bmi = calcBMI(data.weight, data.heightFt, data.heightIn);
const medStep = STEPS.find(s => s.type === 'medical');
const flags = data.medical || [];
const hard = medStep ? flags.some(f => medStep.options.find(o => o.value === f)?.hard) : false;
const soft = flags.length > 0 && !flags.includes('none') && !hard;
const svcStates = cfg.quiz.states || LICENSED_STATES;
const licensed = svcStates.includes(data.state);
const stateStep = STEPS.find(s => s.type === 'state') || {};
const stateName = ALL_STATES.find(([a]) => a === data.state)?.[1];
const canAdvance = () => {
switch (cur.type) {
case 'single': return !!data[cur.id];
case 'multi': return (data[cur.id] || []).length > 0;
case 'composition': return !!bmi;
case 'medical': return flags.length > 0;
case 'state': return !!data.state;
case 'lead': return data.firstName.trim() && /\S+@\S+\.\S+/.test(data.email);
case 'investment': return !!data.investment;
case 'final': return !!data.bestTime;
default: return false;
}
};
const goNext = () => {
if (!canAdvance() || step >= STEPS.length - 1) return;
setStep(step + 1);
setTimeout(() => { const el = document.getElementById('quiz-card'); if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 24, behavior: 'smooth' }); }, 50);
};
advanceRef.current = goNext;
const pickAndAdvance = (k, v) => { update(k, v); setTimeout(() => advanceRef.current && advanceRef.current(), 380); };
const labelFor = (s, v) => s.options.find(o => o.value === v)?.label || v;
const handleSubmit = async (e) => {
e.preventDefault();
if (!canAdvance()) return;
setSubmitting(true); setError(null);
const tier = INVESTMENT.find(i => i.value === data.investment)?.tier || 'unknown';
const payload = {
_subject: `${cfg.subjectPrefix} — ${data.firstName} ${data.lastName} (${data.state}) [${cfg.variantTag}]${tier === 'disqualify' ? ' [DQ-BUDGET]' : ''}${hard ? ' [MED-REVIEW]' : ''}`,
_replyto: data.email, _captcha: 'false', _template: 'table',
'Landing Page': cfg.variantTag,
'First Name': data.firstName, 'Last Name': data.lastName, 'Email': data.email, 'Phone': data.phone || '(not provided)',
'State': data.state, 'In Service State': licensed ? 'Yes' : (cfg.quiz.states ? 'No (therapy not offered in this state)' : 'No (waitlist)'),
};
STEPS.forEach(s => {
if (s.type === 'single') payload[s.field] = labelFor(s, data[s.id]);
if (s.type === 'multi') payload[s.field] = (data[s.id] || []).map(v => labelFor(s, v)).join(' | ');
if (s.type === 'composition') { payload['Weight (lbs)'] = data.weight; payload['Height'] = `${data.heightFt}'${data.heightIn || 0}"`; payload['BMI'] = bmi || 'n/a'; }
if (s.type === 'medical') {
payload['Medical Flags'] = flags.includes('none') ? 'None reported' : flags.map(f => labelFor(s, f)).join(' | ');
payload['Medical Risk Level'] = hard ? 'NEEDS CLINICAL REVIEW' : soft ? 'Soft flag — review' : 'Clear';
}
});
Object.assign(payload, {
'Investment Range': INVESTMENT.find(i => i.value === data.investment)?.label || 'Not specified', 'Investment Tier': tier,
'Best Time to Reach': BEST_TIME.find(t => t.value === data.bestTime)?.label || '', 'Notes': data.notes || '(none)',
'Submitted At': new Date().toISOString(), 'Referrer': document.referrer || '',
});
try { const q = new URLSearchParams(window.location.search); ['utm_source','utm_medium','utm_campaign','utm_content','utm_term'].forEach(k => { if (q.get(k)) payload[k.toUpperCase()] = q.get(k); }); } catch (_) {}
try {
const res = await fetch('https://formsubmit.co/ajax/hello@edenwellnessclinic.com', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(payload) });
if (!res.ok) throw new Error();
setSubmitted(true);
} catch (_) { setError("Something went wrong. Please email hello@edenwellnessclinic.com directly and we'll follow up."); }
finally { setSubmitting(false); }
};
if (submitted) return
{subtitle}
}{children}{!licensed ? (outMsg ? <>{outMsg}> : <>We'll email you at {data.email} as soon as we're licensed in your state.>) : underBudget ? <>Our {program} starts above the range you indicated, and we won't push you into something that's a financial stretch. If your situation changes, you're welcome to reach back out anytime.> : hard ? <>Your assessment is in. Because of what you flagged in the medical screening, our medical director will personally review your responses and reach out within 1–2 business days.> : <>Your assessment is in. A clinical team member will review your responses personally and reach out within 1–2 business days at {data.email}{data.phone ? <> or {data.phone}> : null}.>}