/* ============================================================
SHLOK — Step content renderer → window.StepContent
============================================================ */
const { useState: useS, useEffect: useE, useRef: useR } = React;
function StepHead({ step }) {
return (
{step.eyebrow ?
{step.eyebrow}
: null}
{step.title}
{step.sub ?
{step.sub}
: null}
{step.microcopy ? (
{step.microcopy}
) : null}
);
}
/* ---------- SINGLE (cards or chips) ---------- */
function SingleStep({ step, data, set, requestAdvance }) {
const val = data[step.key];
const [query, setQuery] = useS("");
function pick(opt) {
set(step.key, opt.v);
if (step.allowOther && opt.v !== "Other") set(step.otherKey, "");
if (step.autoAdvance) requestAdvance();
}
if (step.chips) {
const filtered = step.options.filter((o) =>
o.v.toLowerCase().includes(query.toLowerCase().trim())
);
const isOther = val === "Other";
return (
{step.search ? (
setQuery(e.target.value)}
placeholder="Search your business type…"
aria-label="Search business type"
/>
) : null}
{filtered.map((o) => (
pick(o)} />
))}
{filtered.length === 0 ? (
No match — pick “Other” below to tell us.
) : null}
{isOther ? (
) : null}
);
}
return (
{step.options.map((o) => (
pick(o)}
/>
))}
);
}
/* ---------- MULTI ---------- */
function MultiStep({ step, data, set }) {
const arr = data[step.key] || [];
const max = typeof step.maxSelections === "number" ? step.maxSelections : null;
function toggle(opt) {
set(step.key, (prev) => {
const cur = prev || [];
if (cur.includes(opt.v)) return cur.filter((x) => x !== opt.v);
if (max !== null && cur.length >= max) return cur;
return [...cur, opt.v];
});
}
return (
{step.options.map((o) => (
toggle(o)}
/>
))}
);
}
/* ---------- RANK (top 3) ---------- */
function RankStep({ step, data, set }) {
const arr = data[step.key] || [];
const max = typeof step.maxSelections === "number" ? step.maxSelections : step.max;
const full = arr.length >= max;
function toggle(opt) {
set(step.key, (prev) => {
const cur = prev || [];
if (cur.includes(opt.v)) return cur.filter((x) => x !== opt.v);
if (cur.length >= max) return cur;
return [...cur, opt.v];
});
}
return (
{step.options.map((o) => {
const idx = arr.indexOf(o.v);
const selected = idx >= 0;
return (
toggle(o)}
/>
);
})}
);
}
/* ---------- SLIDERS ---------- */
function SliderRow({ s, value, onChange }) {
const [active, setActive] = useS(false);
const pct = ((value - 1) / 9) * 100;
const lo = value <= 4, hi = value >= 7;
return (
{s.name}
{value}
{s.lo}
{s.hi}
);
}
function SlidersStep({ step, data, set }) {
const scores = data[step.key] || {};
function setOne(k, v) {
set(step.key, { ...scores, [k]: v, _touched: true });
}
return (
{step.sliders.map((s) => (
setOne(s.key, v)}
/>
))}
);
}
/* ---------- LOSS (multi chips + optional note) ---------- */
function NoteArea({ type, text, onType, onText }) {
return (
{type === "text" ? (
);
}
function LossStep({ step, data, set }) {
const arr = data[step.key] || [];
const max = typeof step.maxSelections === "number" ? step.maxSelections : null;
const [noteType, setNoteType] = useS(data._lossNoteType || null);
const showPrompt = arr.some((x) => step.triggers.includes(x));
function toggle(opt) {
set(step.key, (prev) => {
const cur = prev || [];
if (cur.includes(opt.v)) return cur.filter((x) => x !== opt.v);
if (max !== null && cur.length >= max) return cur;
return [...cur, opt.v];
});
}
return (
{step.options.map((o) => (
toggle(o)} />
))}
{showPrompt ? (
Want to quickly tell us what happened?
{ setNoteType(t); set("_lossNoteType", t); }}
onText={(v) => set(step.contextKey, v)}
/>
) : null}
);
}
/* ---------- MESSAGE (hero cards) ---------- */
function MessageStep({ step, data, set }) {
const val = data[step.key];
return (
{step.options.map((o) => (
))}
);
}
/* ---------- FINAL NEED (single + optional note) ---------- */
function FinalNeedStep({ step, data, set }) {
const val = data[step.key];
const [noteType, setNoteType] = useS(data._finalNoteType || null);
return (
{step.options.map((o) => (
set(step.key, o.v)} />
))}
{step.noteTitle}
{
setNoteType(t);
set(step.noteTypeKey, t);
set(step.voiceKey, t === "voice");
}}
onText={(v) => set(step.noteTextKey, v)}
/>
);
}
/* ---------- CONTACT ---------- */
function ContactStep({ step, data, set }) {
const perm = data[step.key];
const showFields = perm === "yes" || perm === "maybe_later";
return (
{step.options.map((o) => (
set(step.key, o.val)}
/>
))}
{showFields ? (
) : null}
);
}
/* ---------- Dispatcher ---------- */
function StepContent(props) {
const t = props.step.type;
if (t === "single") return ;
if (t === "multi") return ;
if (t === "rank") return ;
if (t === "sliders") return ;
if (t === "loss") return ;
if (t === "message") return ;
if (t === "finalNeed") return ;
if (t === "contact") return ;
return null;
}
window.StepContent = StepContent;