// Main calculator React app. Configuration form only — no pricing displayed. // Customer selects what they need; submit fires a request for a manual quote. const { useState, useMemo, useEffect } = React; const initialState = { siteTypeId: 'corporate', designId: 'adapted', cmsId: 'bitrix', pages: 12, features: ['adaptive', 'seo'], extras: [], urgencyId: 'normal' }; function Calculator() { const [t, setTweak] = useTweaks(TWEAK_DEFAULTS); const [state, setState] = useState(initialState); const [summaryOpen, setSummaryOpen] = useState(false); const [contactOpen, setContactOpen] = useState(false); useEffect(() => { const root = document.documentElement; const theme = THEMES[t.theme] || THEMES.brand; Object.entries(theme).forEach(([k, v]) => root.style.setProperty(k, v)); root.dataset.density = t.density; root.dataset.layout = t.layout; }, [t.theme, t.density, t.layout]); function setSiteType(id) { const st = SITE_TYPES.find((s) => s.id === id); if (!st) return; setState((s) => ({ ...s, siteTypeId: id, pages: Math.min(st.pages.max, Math.max(st.pages.min, s.pages || st.pages.default)) })); } function toggleFeature(id) { setState((s) => ({ ...s, features: s.features.includes(id) ? s.features.filter((x) => x !== id) : [...s.features, id] })); } function toggleExtra(id) { setState((s) => ({ ...s, extras: s.extras.includes(id) ? s.extras.filter((x) => x !== id) : [...s.extras, id] })); } const selection = useMemo(() => buildSelection(state), [state]); const siteType = selection.siteType; return (
{SITE_TYPES.map((s) => setSiteType(s.id)} icon={} title={s.name} sub={s.desc} /> )}
{DESIGN_OPTIONS.map((d) => setState((s) => ({ ...s, designId: d.id }))} title={d.name} sub={d.desc} /> )}
{CMS_OPTIONS.map((c) => setState((s) => ({ ...s, cmsId: c.id }))}> {c.name} )}
setState((s) => ({ ...s, pages: v }))} />
{FEATURES.map((f) => toggleFeature(f.id)} name={f.name} desc={f.desc} /> )}
{EXTRAS.map((e) => toggleExtra(e.id)} name={e.name} desc={e.desc} /> )}
{URGENCY.map((u) => setState((s) => ({ ...s, urgencyId: u.id }))} title={u.name} sub={u.desc} /> )}

Это ваш краткий бриф. Менеджер изучит выбранные параметры, при необходимости задаст уточняющие вопросы и подготовит точную смету и сроки.

setSummaryOpen(true)} onContact={() => setContactOpen(true)} /> {summaryOpen &&
setSummaryOpen(false)}>
e.stopPropagation()}> {setSummaryOpen(false);setContactOpen(true);}} />
} {contactOpen && setContactOpen(false)} /> }
); } function Header({ onReset }) { return (
); } function Intro() { return (
Калькулятор

Рассчитайте стоимость разработки сайта

Ответьте на 7 коротких шагов — мы изучим, что именно вам нужно, и подготовим персональный расчёт с фиксированной стоимостью и сроками. Заявка ни к чему не обязывает.

); } function Step({ index, title, hint, children }) { return (
{children}
); } Object.assign(window, { Calculator });