- /api/staff_clients — returns clients grouped by client, filtered by role
(assembler sees assemblies, measurer sees measurements, both if combined)
Supports filter: active | done | all
- staff_clients.js — client list with status tags + detail card view
(phone link, assembly cards → AssemblyDetailScreen, measurement cards)
- app.js — route #/master/clients, button "👥 Мои клиенты" for assembler+measurer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- _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>
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>
InboxScreen.mount() — список замеров без решения по подбору.
Три действия: начать подбор / отложить / не нужен.
Роутинг #/inbox добавлен в routeByHash() и init().
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
.client-name и .client-phone → color: var(--card), текст сливается
с фоном карточки во всех темах. Аватар и счётчики подборов остаются видимыми.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- quickActions: «Новый клиент» → «Заказы» (clipboard → #/assembly),
убрали дублирующую кнопку «Сборки» из быстрых действий
- «Свободный день»: текст теперь использует var(--ink)/var(--muted) вместо
rgba белых значений, которые были невидимы на светлом фоне --card;
заголовок — шрифт карточки ×1.3 (17.5px 600), описание — моно uppercase 9.5px
- styles.css: добавлены явные стили .client-card/.client-name/.client-phone/
.client-avatar и др. — исправлен невидимый текст в карточках клиентов
во всех темах (Foundry, Boardroom, Atelier)
- splash: minShow 1200 → 840 мс (−30%)
- index.html: версия ресурсов → 20260517c
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>
Extracted from reference dashboards (computed styles, class structure, color usage):
B Foundry: r-card 0px, body lh 1.5, Archivo 800 display,
dark #15140F header (palette + greeting full-width),
wide 0.18em kicker tracking, heavy section labels
C Boardroom: r-card 0px, r-tag 999px (pills), body lh 1.12,
Geist 400 display (restrained), dark petrol header,
copper accent on greeting
D Atelier: body lh 1.1, Manrope 700 display, white card header
on dove bg, ink-bottom-border divider,
prominent uppercase section labels
Also: role-card border-radius switched to var(--r-card) from hardcoded 16px
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Manager: suit, lapels, tie, pocket square, face with hair/eyes/nose
Client: house with chimney+smoke, pane windows, paneled door, garden bush
Staff: dark hard hat, face with stubble+brows, work jacket, wrench in hand
All use feTurbulence displacement filter for hand-drawn line wobble
and diagonal hatching lines for shadow/volume.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Premature `};` at line 207 closed the ZAMER_PICTS object early,
leaving wall1/wall2/etc. as orphan code — syntax error on load.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fetchClients() was not sending initDataUnsafe, so on Telegram Desktop
(where initData can be unreliable) _handle_clients returned
{"error":"invalid_init_data"} and the frontend showed an empty list
instead of an error — making newly created clients appear missing.
- fetchClients(): add initDataUnsafe to request body (matches renderManagerHome pattern)
- renderList(): surface data.error explicitly instead of silent empty state
- _handle_client_create: gps_lat/gps_lng None → "" to avoid "None" strings in sheet
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Manager: person with V-collar and tie (professional silhouette)
- Client: house outline with roof, door, windows and door knob
- Staff: hard-hat person silhouette with wrench in hand
- Bump cache version to 20260516g across all assets
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1. _xlsx_auth_manager: возвращал (tg_id, user) при успехе → callers делали
`if err: return err` и возвращали dict пользователя вместо данных.
Исправлено: возвращает (tg_id, None) при успешной авторизации.
2. Promise.all с 4 запросами: ошибка Drive (сервис-аккаунт не добавлен к файлу)
роняла весь дашборд. Исправлено: складские запросы изолированы в отдельный
.then/.catch — дашборд замеров отрисовывается независимо.
3. Секции склада теперь появляются с задержкой (non-blocking), а не блокируют
отрисовку главного экрана.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>