// wizard.jsx — New reading order wizard const WIZARD_STEPS = [ { id: 'product', label: 'Продукт' }, { id: 'person', label: 'Персона' }, { id: 'data', label: 'Данные' }, { id: 'pay', label: 'Оплата' }, ]; // Mapping наш UI-id → backend service-id. const PRODUCT_TO_SERVICE = { natal: 'natal', forecast: 'year_ahead', compat: 'compatibility', matrix: 'matrix' }; // Конвертация "DD.MM.YYYY" → "YYYY-MM-DD" (формат, который ждёт бэкенд). const dotDateToISO = (s) => { s = (s || '').trim(); const m = s.match(/^(\d{1,2})[.\-/](\d{1,2})[.\-/](\d{4})$/); if (!m) return s; // оставим как есть, бэк сам ругнётся return `${m[3]}-${m[2].padStart(2,'0')}-${m[1].padStart(2,'0')}`; }; // Маска даты: из любых символов оставляем цифры и расставляем точки ДД.ММ.ГГГГ // по мере ввода. Бэкспейс работает естественно — точки убираются вместе с цифрами. const maskDate = (s) => { const d = (s || '').replace(/\D/g, '').slice(0, 8); const parts = []; parts.push(d.slice(0, 2)); if (d.length >= 3) parts.push(d.slice(2, 4)); if (d.length >= 5) parts.push(d.slice(4, 8)); return parts.filter(Boolean).join('.'); }; // Маска времени: цифры → чч:мм. const maskTime = (s) => { const d = (s || '').replace(/\D/g, '').slice(0, 4); return d.length <= 2 ? d : d.slice(0, 2) + ':' + d.slice(2, 4); }; // PlaceField — поле «место рождения» с автокомплитом от геокодера. Юзер выбирает // конкретный город (одноимённые различаются) → onPick фиксирует lat/lng/tz, и // бэкенд не геокодит свободный текст заново (без расползания данных). const PlaceField = ({ value, onChange, onPick }) => { const [sugg, setSugg] = React.useState([]); const [open, setOpen] = React.useState(false); const tRef = React.useRef(null); const fetchSugg = (q) => { clearTimeout(tRef.current); if ((q || '').trim().length < 3) { setSugg([]); setOpen(false); return; } tRef.current = setTimeout(async () => { try { const r = await fetch('/api/geocode/suggest?q=' + encodeURIComponent(q), { credentials: 'same-origin' }); const d = await r.json(); setSugg(d.suggestions || []); setOpen((d.suggestions || []).length > 0); } catch (_) { setSugg([]); } }, 300); }; return (
Выбери, что важно прямо сейчас. Каждый разбор основан на твоей натальной карте.
{product === 'compat' ? 'Выбери двух из сохранённых — или оставь как есть и заполни данные вручную. Данные обоих можно отредактировать на следующем шаге.' : 'Выбери из сохранённых или добавь нового человека.'}
{/* Mode toggle (для совместимости скрыт — оба партнёра редактируются на шаге «Данные») */} {product !== 'compat' && (Чем точнее данные — тем глубже разбор. Особенно важно время рождения для домов карты.
{product === 'compat' ? ( <>