- New button "📋 Скопировать текст" in report export panel
- _copyReportText(): formats structured text (brand, price, pros/cons, links)
- _stripHtml(): strips HTML tags for clean clipboard output
- Clipboard API with execCommand fallback for Telegram WebApp
- Button shows "✅ Скопировано!" feedback for 2.2s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- AI prompt: use HTML tags (b, em, br, li) instead of markdown
- renderReport: _ai() helper renders AI text as innerHTML (safe, backend-controlled)
- Header: added podbor-home button (top-right) → goes to main menu from any step
- After successful submit: show "← Вернуться в главное меню" button immediately
- Fixes: no way to leave podbor after result was received
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Every "Назад" / "На главную" button was calling location.reload() which
triggered a full page reload → splash screen appeared again. Fix: replace
reload() with routeByHash() call (global router function from app.js) which
re-renders the role-appropriate home screen from cached window.__zovMe
without any network round-trips.
Affected files: app.js, clients.js, measurements.js, request.js,
assembly.js, podbor.js. Bump asset versions to 20260517b to bust cache.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wizard: new 'photos' step (6 total) — camera/gallery input, client-side
canvas compression to 1600px @ ~78% JPEG, max 12 photos. Thumbnails
with delete in step; preview in summary.
Backend: POST /api/measurement now decodes data-URL photos and saves
to /app/photos/<id>/N.jpg (volume-mounted). New GET /api/photo/{id}/{n}
serves files with path-traversal protection. New POST /api/measurement_detail
returns full measurement record (walls/openings/photos/notes/...).
Clients page: measurement rows now clickable → renderMeasurement detail
view with key-value grid + photo gallery + 'Скачать PDF / Печать'.
Print stylesheet (@media print) hides navigation/buttons/uploaders and
prints clean A4-friendly layout.
Podbor report: existing 'Печать → PDF' now falls back to inline
window.print() inside Telegram WebApp (popups are blocked there).
Cache bust v=20260513a.
USER REPORT: 'после прогона всей техники, перед запросом опять вопрос про фильтр для вытяжки в конце'
ROOT CAUSE: Infra-шаг спрашивает 'Вытяжка → вентшахта?', хотя у hood-категории уже есть шаг 'Подключение' с вариантами Отвод/Рециркуляция/Универсальная. Это дубликат.
FIX:
- renderInfra: убран блок vent. Шаг показывается только если выбрана варочная.
- Auto-skip infra если нет hob (раньше требовался hob ИЛИ hood, теперь только hob)
- renderSummary: убрана строка 'Вентиляция'
- summaryBack: 'infra' только если cats.includes('hob')
AI PROMPT:
- Новый блок: режим вытяжки читать из per_cat.hood.answers.mode
- exhaust → обычная установка
- recirc → ОБЯЗАТЕЛЬНО упомянуть 'Угольный фильтр в комплекте/докупаем' в pros
+ в первой строке pros указать 'для квартир без вентшахты'
- combi → упомянуть универсальность
- 'Если recirc и фильтр не предложен — это ОШИБКА'
Cache: v=20260512b
NEW FILE assets/clients.js:
- Clients.mount(container) — hash-routed view
- #/clients — list of all clients (cards: avatar, name, phone, leads count, last date)
- #/clients/client/<key> — single client history (all leads as items)
- #/clients/lead/<id> — full lead detail with re-rendered report
UI:
- Card style: avatar with initial, name + phone, footer with N подборов + дата
- Pluralization for Russian (1 подбор / 2 подбора / 5 подборов)
- Date format: 'сегодня · 14:30' or 'DD.MM.YYYY'
- Status pills: new / sent / viewed / ordered
PODBOR.JS:
- Exposed renderSavedReport(ai, leadId) for Clients module reuse
- Same renderer as live podbor — same matrix, pros/cons, links
APP.JS:
- Quick action 'Клиенты' added (icon: user)
- Hash router: #/clients → Clients.mount()
INDEX.HTML:
- clients.js script added
- Cache bumped to v=20260512a
CSS:
- .client-list, .client-card with avatar+meta+footer
- .client-detail-head (big card with avatar 56px)
- .leads-list with .lead-item (grid: date | id | status | arrow)
- .loader-inline for async fetch
- .ai-text-fallback for legacy text-only responses
CSS:
- .rev-val: flex:1, min-width:0, overflow-wrap:break-word — длинные значения
больше не ломаются мид-словом ('энергоэффективнос·...')
- .rev-label: max-width:40% — лейбл не съедает всё место
- hyphens:auto для перенос длинных слов на дефис
JS (getCatState):
- При загрузке per_cat фильтруем answers — оставляем только ключи которые
есть в текущем config.steps
- Это убирает stale-поля типа 'class' у ПММ, оставшиеся в localStorage
после рефакторинга шагов
- Безопасно: меняет только в памяти, не перезаписывает state (renderReview
всё равно итерирует config.steps)
1. MODEL COUNT SELECTOR (strategy step):
- new PODBOR_MODEL_COUNTS [3/5/7]
- state.model_count default '5'
- UI on strategy page with description (быстро/оптимально/максимум)
2. AI PROMPT EXPANDED:
- new field: manual_search_query — for Google search instruction PDF
- new specs object per model: dimensions_mm/volume_l/weight_kg/noise_db/energy_class/color
- 'specs ОБЯЗАТЕЛЬНЫ для проектирования кухни' explicit rule
- reads checklist.model_count to determine how many models per category
- max_tokens 4000 → 8000 (room for richer responses)
3. MODEL CARD RICHER:
- _renderSpecsBlock — characteristics in 2-col grid, dimensions highlighted
- _renderUtilityLinks — Google search buttons for инструкция (PDF) + Схема установки
- Specs critical for ZOV kitchen design (manager needs to verify niche fits)
4. EXPORT BUTTONS:
- 'Скачать HTML' — generates standalone HTML with inline styles, downloads as file
- 'Печать → PDF' — opens new window with cleaned layout + auto-prints
- User can save as PDF via system print dialog
5. PREVIEW updated with realistic specs/manual_query for all 3 fridges
- New isValidPhone(raw): checks 11-digit Russian after normalization (8/7/+7/9-prefix)
- Intro 'Начать' button now custom click handler instead of data-go
- Validates name (non-empty) and phone (Russian format)
- Inline .field-error red message under invalid field
- .field-hint shows format help under phone input
- Haptic 'warning' feedback on invalid submit
- Phone is auto-normalized to '+7 900 123-45-67' before transition
WHAT CHANGED:
- New _renderPriceMatrix(models) — table with rows=models, columns=stores
- Inserted as PRIMARY view above model cards (was secondary accordion)
- Columns dynamically include only stores that returned data
- Sticky model column (left) — scrolls horizontally on mobile
- Best price per row highlighted: green bg + ✓ badge + green text
- Empty cells: '—' if no URL, 'смотреть →' if URL but no price yet
- 'Мин' column on far right — explicit cheapest price summary
CSS:
- .report-matrix-wrap with rounded card
- Sticky col-model with box-shadow on right edge
- Cell-price.best with rgba green background
- .best-mark circle badge
PREVIEW:
- Updated mock with 3 fridges + 3 hobs across multiple stores (real pricing spread)
- Demonstrates min-price highlighting working
UX:
- User can now visually compare 'where is it cheapest' at a glance
- Tap any cell with price → opens store page
- Tap empty cell with URL → opens search in store
NEXT: same matrix can become PDF/Excel export for client briefcase
CATEGORIES MIGRATED to steps[] schema:
- hob: Источник нагрева → Подтип (multi, optionsBy) → Размер → Конфорки → Особенности
- oven: Установка → Функции (multi) → Размер → Где ставим (cond:built_in) → Особенности
- dw: Тип встройки → Класс (multi) → Ширина → Корзины → Особенности
- hood: Форм-фактор → Подключение → Ширина → Цвет (cond:visible-types) → Особенности
- microwave: Установка → Функции (multi) → Размер (optionsBy) → Особенности
- coffee: Тип → Молоко (cond:grinder/manual) → Вода (cond:built-in/tap) → Размер (cond:built-in) → Особенности
- washer: Установка → Функция → Глубина → Загрузка → Объём → Особенности
NEW PODBOR.JS FEATURES:
- isStepActive(step, answers) — predicate for condition field
- findNextActiveIdx / findPrevActiveIdx — skip inactive steps in navigation
- Auto-advance through inactive on single-select pick
- Review screen filters inactive steps
- isCategoryFilled checks only active single-steps
- buildPerCatSummary skips inactive
- Clearing dependent answers when condition's parent changes (in addition to optionsBy)
NEXT: pictograms for step 1 of each category (currently text-pin layout)
- Visible on all steps after categories are selected
- Highlights current category when inside its wizard
- Filled categories show checkmark
- Tap chip jumps directly to that category's wizard
- Horizontal scroll if many categories don't fit
- New PODBOR_PARAMS schema with steps[] supporting single/multi + optionsBy branches
- 11 fridge SVG pictograms in podbor.picts.js (style D — 3D perspective with shadow)
- renderCategoryWizard with step-by-step flow, chips for prior answers, review screen
- Legacy renderCategoryDetail still used for other 7 categories until migrated
- Auto-advance on single-select, Дальше button for multi-select
- Backend-compatible: per_cat[catKey].answers replaces .params/.features