- _ai(): markdown→HTML fallback (**, *, _, `) when no HTML tags found
- podbor-header: position:sticky so back/home always visible while scrolling
- renderReport(): footer with "← Главное меню" + "+ Новый подбор" buttons
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
Frontend (request.js):
- Поиск клиентов из списка менеджера (autocomplete dropdown)
по имени или цифрам телефона, макс. 6 результатов
- Режимы: search → selected (карточка + редактируемый адрес)
или → new (ручной ввод ФИО/тел/адрес)
- «Создать нового клиента» всегда в конце dropdown
- Выпадающий список замерщиков (existing)
- Новый select «Передать менеджеру» — передаёт заявку коллеге
- Platform.initData / Platform.initDataUnsafe вместо tg?.
Backend (main.py):
- _handle_managers_list: список всех менеджеров кроме себя
- _handle_measurement_request: поддержка target_manager_tg_id
(заявка создаётся от имени целевого менеджера + уведомление)
- Роут managers_list добавлен в handlers dict
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
page.route() перехватывает /api/clients и возвращает тестового клиента.
Карточка клиента теперь открывается и проверяется без реальных данных.
17 чеков, 0 пропущено.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1. Дублирование: init() теперь вызывает routeByHash() вместо копии логики.
#/master, #/me, #/c/cabinet теперь работают при прямом переходе по ссылке.
2. Множественные hashchange listeners: guard _hashListenerAdded.
3. #/picker → #/c/proposal в cabinet.js и me.js (неверный роут).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Тригер: Deploy MiniApp to GitHub Pages → completed + success.
Скриншот сохраняется как артефакт при провале.
workflow_dispatch с опциональным SMOKE_URL для ручного запуска.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
InboxScreen.mount() — список замеров без решения по подбору.
Три действия: начать подбор / отложить / не нужен.
Роутинг #/inbox добавлен в routeByHash() и init().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- measurement_detail: любой мастер (measurer+assembler) видит фото замера
- assembly_list: клиент видит все свои сборки (по client_tg_id)
- assembly_detail: клиент видит детальную карточку сборки
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 роли: manager / measurer / assembler / client
Цикл сделки, доступ по экранам, правило совместного подбора техники.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Каждый агент обязан начинать ответ с бейджа роли:
🤖 КООРДИНАТОР / 🔧 DEV / ⚙️ DEVOPS / 🎨 DESIGN / 🧩 FEATURE / 🧪 TEST / 🔍 REVIEW
Правило прописано в CLAUDE.md и в каждом агент-файле.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Блокирует push при JS-ошибках в интерфейсе или CSS-нарушениях.
API-тесты в хук не включены — зависят от VPS/Drive, запускать вручную.
Активируется через: git config core.hooksPath .githooks
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Кнопки больше не зависают бесконечно при медленном или недоступном бэкенде.
AbortController + дружелюбное сообщение «Сервер не отвечает — попробуйте ещё раз».
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- _fetchWithTimeout() — единый fetch с AbortController
- saveClientNote, fetchClientNote, fetchClients, fetchMeasurements
теперь через таймаут вместо бесконечного ожидания
- При таймауте показывает 'Сервер не отвечает — попробуйте ещё раз'
- Версия clients.js: 20260518e
escAttr использовалась в 11 местах (карта, форма редактирования)
но не была объявлена в clients.js — отсюда пустая карточка.
Версия clients.js: 20260518d
- Обернуть renderClientHistory в try/catch — показывает текст ошибки
- Добавить .catch() в mount() для перехвата unhandled promise rejection
- Версия clients.js: 20260518c
- Добавить проверку data.error после fetchClients() в renderClientHistory
- Сравнивать client_tg_id как строки (String(c.client_tg_id) === String(clientKey))
чтобы избежать 5937498515 !== '5937498515'
- Показывать явное сообщение если клиент не найден вместо пустой страницы
- Версия clients.js: 20260518b
- Заголовок 'История подборов' → 'Карточка клиента'
- Убрать инлайн-монтирование Proposals.mountManager в карточке клиента
- Оставить только кнопку 'Открыть →' для перехода к подборам
- Версия clients.js: 20260518a