Commit Graph

24 Commits

Author SHA1 Message Date
wasrusgen
f473f1dc03 feat(podbor): copy report as plain text for messengers
- 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>
2026-05-19 08:32:52 +03:00
wasrusgen
f1b7f71337 fix(podbor): HTML AI output + home button on all steps
- 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>
2026-05-19 08:02:09 +03:00
wasrusgen
2f50f6e920 fix(miniapp): remove location.reload() on back-to-home navigation (splash bug)
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>
2026-05-17 00:39:12 +03:00
wasrusgen
a084542bbf measurements: photo upload + measurement detail page + PDF/print
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.
2026-05-12 18:11:29 +03:00
wasrusgen
43c43af795 remove duplicate vent question + AI must propose charcoal filter on recirc hood
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
2026-05-12 17:22:59 +03:00
wasrusgen
c4f3016b56 miniapp: client profile tab — list + history + lead detail
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
2026-05-12 07:20:54 +03:00
wasrusgen
cecb8d3444 review screen: fix text wrap + cleanup stale answers from removed steps
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)
2026-05-11 23:25:23 +03:00
wasrusgen
ef500fa446 user feedback batch: model count, specs, manual link, dimensions, export
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
2026-05-11 17:11:30 +03:00
wasrusgen
5ceffa4f69 miniapp: phone validation on intro — blocks transition with bad number
- 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
2026-05-11 16:48:52 +03:00
wasrusgen
d7be644aed miniapp: price comparison matrix as PRIMARY view per category
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
2026-05-11 14:56:41 +03:00
wasrusgen
ca342c0641 ai+report: deeper analysis — required pros/cons, category insights, source visibility
AI PROMPT (ai.py):
- Requires minimum 3 pros + 2 cons per model with NUMBERS (36 dB, 463 L, A++, не 'тихий/большой')
- New field 'reasoning' — 1-sentence why-this-model justification
- New per-category 'analysis' — 2-3 sentences about trade-offs
- Strict rules: no fake article numbers, account for parallel-import price markup
- Russian market 2026 awareness: Haier/Korting up, Bosch/Siemens ⚠

TELEGRAM FORMAT (main.py):
- Renders category analysis as italic prelude
- Lists pros/cons as bullet lists (up to 4 pros, 3 cons)
- Shows '🛒 Нашли в: OZON · Citilink · WB' line listing successful sources
- Rating + reviews + stores count line: '📊 ★ 4.7 · 1242 отзыв. · 12 магаз.'
- Direct link to best store: '🔗 Открыть в магазине'

WB PARSER:
- Generates 3 query variants per request: full → brand+model → model only
- Increases hit rate when AI search_query is too verbose
- First non-empty variant wins

MINIAPP REPORT (podbor.js + podbor.css):
- Category analysis block above models (italic, walnut left-border)
- Pros block: green tinted bg, bullet list, header 'Плюсы'
- Cons block: terracotta tinted bg, bullet list, header 'Минусы'
- Reasoning chip: 💡 italic in warm background
- Source badges with per-store price '<store> · 89 990 ₽'
- Color-coded source links: OZON blue, Citilink yellow, WB pink, Я.Маркет red, DNS orange
- 'X магазинов нашли товар' header + plural fix
- '— не найден' fallback if 0 sources

PREVIEW (preview-report.html):
- Mock updated with Haier as flagship (more relevant for 2026 RF)
- Shows analysis, reasoning, source spread (4 stores with different prices)
2026-05-11 14:34:08 +03:00
wasrusgen
4b04f2de54 miniapp: summary page hides Подключение/Вентиляция if hob/hood not picked 2026-05-11 14:26:12 +03:00
wasrusgen
80580db446 miniapp: 4 UX fixes from user feedback
1. PHONE NORMALIZATION
   - On blur (or before submit): '9001234567' -> '+7 900 123-45-67'
   - Handles 8XXX, 7XXX, +7XXX, 10-digit mobile prefixes
   - Leaves untouched if not Russian-looking number

2. BRAND LIST FOR RF 2026
   - PODBOR_SINGLE_BRAND_OPTIONS updated with realistic 2026 brands
   - Promoted: Haier, Korting, Midea, Hisense, Бирюса, Атлант, Pozis, DEXP
   - Bosch/Siemens marked with ⚠ (parallel-import)
   - Miele/Liebherr/Smeg also marked ⚠
   - PODBOR_BRANDS per-category fully refreshed

3. BUDGET ADAPTIVE HINTS
   - Hints now scale by selected categories share of full kitchen
   - Just fridge picked → 'Средний' shows ~88-175 тыс instead of 350-700к
   - Full 8 categories → original 350-700к
   - PODBOR_BUDGET_SHARES + PODBOR_BUDGET_RANGES constants

4. INFRA STEP CONDITIONAL
   - Stove power question only shown if hob category picked
   - Vent question only shown if hood category picked
   - If neither → step auto-skips to summary (with brief notice)
   - Summary 'Назад' button respects skip — goes to strategy if needed
2026-05-11 14:25:25 +03:00
wasrusgen
c2be5e846f miniapp: inline report after submit + standalone preview-report.html
REPORT RENDERER (podbor.js):
- New renderReport(ai, leadId) function — beautiful inline report after submit success
- Shows by_category with up to 5 models per category
- Model card: photo (88x88), brand · name, price range, rating + reviews + stores
- Highlights (with tech translations), pros (green), cons (orange)
- External links to WB / Я.Маркет / OZON / DNS (when enriched data present)
- Comparison table per category (accordion details)
- Total price block (dark theme contrast)
- Warnings block (when AI returns concerns)

CSS (podbor.css):
- .report-* classes: head, summary, cat, model, links, compare, total, warnings
- Editorial Calm palette — walnut accents, paper bg, Newsreader for titles
- Responsive: model card grid 88px image + 1fr body
- Placeholder gradient when no image (camera emoji)

STANDALONE PREVIEW (preview-report.html):
- Mock AI response with 3 fridges + 2 hobs
- Same render logic, runs without backend
- Visit: https://wasrusgen.github.io/zov-tech/preview-report.html

NEXT: integrate proxy6 token → real photos/prices instead of placeholders
2026-05-11 12:26:58 +03:00
wasrusgen
717c6ea138 miniapp: hierarchical wizard for all 8 categories + condition support
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)
2026-05-11 11:28:50 +03:00
wasrusgen
dd400b71ac miniapp: new pricing flow — brand strategy + budget presets + multi pick strategy
NEW STRUCTURE:
- Step 4 'Бренд' — ai/single/different + brand picker or per-cat chips (now 4-state with 'avoid')
- Step 5 'Бюджет' — Люкс/Премиум/Средний/Бюджет/Точные цифры presets
- Step 6 'Стратегия' — multi: Лучшее по отзывам / Цена-качество / Топ-бренды / Доступное / Tech / Стиль
- Step 7 'Инфра' — перенесено после стратегии
- Step 8 'Итог' — обновлённый summary с новыми полями

FIXES:
- Keyboard-disappearing bug in price inputs — removed render() on input, total recomputed locally
- localStorage merge with defaults for backward compat with new fields
- Bumped STORAGE_KEY to v4

REMAINING:
- Backend still reads checklist.priorities (old shape) — needs update to read pick_strategies + brand_strategy + budget_preset
2026-05-11 10:43:54 +03:00
wasrusgen
496ddf793c miniapp: persistent category strip with active highlight + tap-to-jump
- 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
2026-05-11 00:46:43 +03:00
wasrusgen
d289f7601e miniapp: compact pin layout for wizard steps without pictograms
- Steps with pict (1-3 fridge: install/chamber/size) keep grid cards
- Steps without pict (4 features) render as flex-wrap pill pins
- Auto-detect via options.some(o => o.pict)
2026-05-11 00:02:25 +03:00
wasrusgen
17b112f061 miniapp: hierarchical wizard for fridge category (style D pictograms)
- 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
2026-05-10 23:57:03 +03:00
wasrusgen
f85d3a9d1e feat(miniapp): switch BACKEND_URL to Cloudflare Tunnel → VPS backend (GigaChat live) 2026-05-10 22:18:53 +03:00
wasrusgen
cc28984122 feat(podbor iter2): per-category detail menu with primary params + accordion 'Подробнее' for tech features; updated AI prompt to require feature explanations 2026-05-09 15:21:05 +03:00
wasrusgen
129046de07 feat(podbor): drop niches; price-range from-to per cat; ventilation Y/N; priorities multi-select; brand tiers as color (no labels) 2026-05-09 15:10:23 +03:00
wasrusgen
571297c017 fix(podbor): niche inputs overflow — min-width:0 + shorter placeholders 2026-05-09 13:43:17 +03:00
wasrusgen
d1165d5e4f feat(miniapp): «Подбор техники» screen — 7-step picker (categories/niches/budget/infra/scenario/brands/summary) wired to /api/podbor 2026-05-09 13:34:46 +03:00