Раньше интерфейс город вообще не передавал — backend (#2580) больше не
подставляет "Екатеринбург" молча, из-за чего житель Нижнего Тагила, вводя
«Ленина, 1», получал бы результат по одноимённой екатеринбургской улице.
- Новый справочник src/lib/city-registry.ts (растущий список городов области,
сейчас: Екатеринбург, Нижний Тагил, Каменск-Уральский, Первоуральск,
Верхняя Пышма, Серов) — DEFAULT_CITY = Екатеринбург, чтобы ЕКБ-сценарий не
требовал никаких лишних действий.
- ParamsPanel: компактный дропдаун «Город» рядом с лейблом адреса (переиспользует
существующий <Dd> HUD-комбобокс) + автоопределение города из набранного
текста/выбранной подсказки (detectCityInText, word-boundary safe — не путает
"Серов" с "ул. Серова" в ЕКБ). city_hint уходит в geocode/suggest и в
POST /trade-in/estimate.
- useGeocodeSuggest(query, cityHint, limit) — city_hint в query-параметрах и в
queryKey, чтобы смена города рефетчила подсказки.
- Честная подсказка в ParamsPanel, когда estimate.target_city_ambiguous===true:
спокойный (не danger) текст «Город определён автоматически — результат может
относиться к другому населённому пункту области. Если это не {city},
выберите верный город выше и повторите оценку.» — не блокирует форму.
- types/trade-in.ts: TradeInEstimateInput.city_hint,
AggregatedEstimate.target_city_ambiguous (зеркалит backend PR #2580, ещё не
смёржен — codegen не запускался, поля добавлены вручную по контракту схемы).
tsc --noEmit / next lint / next build — чисто (только 2 pre-existing warning
в несвязанных файлах).
FE-5, last FE wiring on the mappers pattern. Closes#2042.
- New hooks (lib/trade-in-api.ts): useEstimateHistory (GET /history), useGeocodeSuggest
(GET /geocode/suggest?q=&limit=, debounced, enabled>=3 chars); useQuota reused.
- types/trade-in.ts: EstimateHistoryItem (area_m2 string, median_price), GeocodeSuggestion.
- mappers.ts: mapCache(history) -> {rows: CacheRow[], kpis: CacheKpi[]} — per-row status
by 24h TTL; KPIs FE-derived from /history (всего/средняя цена/повторные %), NOT the
global /cache-stats.
- CacheView: real previous-estimates list. ParamsPanel: address autocomplete dropdown →
captures lat/lon into submit (cleared on manual edit). HeroBar: «Скачать PDF» → /estimate/
{id}/pdf, UUID-gated + safeUrl scheme check + disabled when no estimate. TopNav: «Мои
отчёты» from quota.used/history. page.tsx: invalidate history+quota on new estimate.
- Hydration-safe: PDF link gated behind a mounted flag (urlId is SSR-null/client-uuid).
- FE-1..4 untouched.
Verified: next build green (/v2 39.6 kB); tsx harness ran mapCache vs real /history (10
items: ВСЕГО 10 / СРЕДНЯЯ 8,85 млн / ПОВТОРНЫЕ 50%, statuses, null graceful).
code-reviewer APPROVE after hydration + reports-fallback fixes.