Это ваш краткий бриф. Менеджер изучит выбранные параметры, при необходимости задаст уточняющие вопросы и подготовит точную смету и сроки.
// 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 (
Это ваш краткий бриф. Менеджер изучит выбранные параметры, при необходимости задаст уточняющие вопросы и подготовит точную смету и сроки.
Ответьте на 7 коротких шагов — мы изучим, что именно вам нужно, и подготовим персональный расчёт с фиксированной стоимостью и сроками. Заявка ни к чему не обязывает.