// survey.jsx — встроенный интерактивный опрос
function Survey({ visible }) {
if (!visible) return null;
const schema = window.SURVEY_SCHEMA;
const isMiniApp = Boolean(window.__TG_INIT_DATA);
const questions = isMiniApp ? schema.questions.filter((q) => q.kind !== "contact") : schema.questions;
const sections = schema.sections.reduce((acc, section) => ({ ...acc, [section.id]: section }), {});
const draftKey = `ekokrug-survey-draft-${schema.schema_version}`;
const params = new URLSearchParams(window.location.search);
const startParam = params.get("tgWebAppStartParam") || window.__TG_WEB_APP?.initDataUnsafe?.start_param || "";
const source = params.get("source") || (isMiniApp ? "tg" : "");
const [step, setStep] = React.useState(0);
const [answers, setAnswers] = React.useState(() => {
try {
return JSON.parse(localStorage.getItem(draftKey) || "{}");
} catch (e) {
return {};
}
});
const [website, setWebsite] = React.useState(""); // honeypot
const [sending, setSending] = React.useState(false);
const [totalResponses, setTotalResponses] = React.useState(null);
const total = questions.length;
React.useEffect(() => {
localStorage.setItem(draftKey, JSON.stringify(publicAnswers()));
}, [answers]);
React.useEffect(() => {
if (step !== 0) return;
fetch("/api/results.php")
.then((r) => r.json())
.then((d) => { if (d && d.ok) setTotalResponses(d.count); })
.catch(() => {});
}, [step]);
const setAns = (id, v) => setAnswers((a) => ({ ...a, [id]: v }));
const getContact = () => {
const raw = answers.contact || {};
if (raw.intent === "Пока без контакта") return null;
if (!raw.value || !raw.value.trim()) return null;
return {
intent: raw.intent || "Хочу получить итоги",
value: raw.value.trim()
};
};
const publicAnswers = () => {
const copy = { ...answers };
delete copy.contact;
return copy;
};
const submit = async () => {
setSending(true);
try {
const headers = { "Content-Type": "application/json" };
if (window.__TG_INIT_DATA) {
headers["X-Telegram-Init-Data"] = window.__TG_INIT_DATA;
}
await fetch("/api/survey.php", {
method: "POST",
headers,
body: JSON.stringify({
schema_version: schema.schema_version,
source,
start_param: startParam,
answers: publicAnswers(),
contact: getContact(),
website
})
});
localStorage.removeItem(draftKey);
} catch (e) {
// Всё равно показываем спасибо: не оставляем человека в тупике.
}
setSending(false);
setStep(total + 1);
};
const next = () => {
if (step === total) { submit(); return; }
setStep((s) => Math.min(s + 1, total + 1));
};
const prev = () => setStep((s) => Math.max(s - 1, 0));
const progress = step === 0 ? 0 : step > total ? 100 : Math.round(step / total * 100);
if (step === 0) {
return (
{schema.intro.lead}
{total} вопросов. Можно отвечать коротко, но честно. Если вопрос не про вас — так и напишите.
Контакт возьмём из Telegram автоматически, вручную вводить его не нужно.
Ваши ответы помогут сделать ЭкоКруг ближе к реальной жизни.
Мы используем результаты только в обобщённом виде, а контакты не публикуем.
{q.hint}{schema.intro.heading}
{schema.title}
Спасибо!
{q.q}
{q.hint &&