Commit graph

10 commits

Author SHA1 Message Date
bot-backend
a3cab9023f fix(tradein/v2/a11y): немодальный SectionOverlay + контраст токенов + headings — a11y round 3 (#2264)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 16s
CI / changes (pull_request) Successful in 16s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m13s
- SectionOverlay: убран aria-modal (честный non-modal fullscreen-view); focus-trap
  теперь охватывает живой верхний nav + оверлей (query по артборду, фильтр [inert]),
  Tab из nav возвращается в оверлей, не в спрятанный main/footer.
- Контраст 6 muted/disabled токенов затемнён до >=4.6:1 vs worst-case #dce6f1
  (hue сохранён, lightness-only): muted2/3/4, hint, disabledValue/Label.
- accent -> accentDeep как мелкий текст: номер секции оверлея (15px), счётчик
  "Мои отчёты" (10px).
- Семантика заголовков: sr-only h1 «Мера — оценка квартиры» + h2 (оверлей,
  ResultPanel, ObjectSummary, placeholder-панели).
- HeroBar «КОЭФ. ЛОКАЦИИ»: role=button + tabIndex + Enter/Space + aria-label.
- Фокус после успешной оценки переносится на результат-регион (role=region,
  tabIndex=-1, aria-labelledby); live-region «Оценка готова» сохранён.
- Инпут focus-ring усилен (2px solid accentDeep).
- combobox адреса: aria-live анонс количества подсказок; aria-required на
  адрес + площадь; декоративные inline-SVG помечены aria-hidden.
2026-07-03 10:37:42 +03:00
bot-backend
35a0e29122 fix(tradein/v2): keep top nav active over overlays, stronger «К оценке», backdrop-close
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
Three UX fixes on the /trade-in/v2 overlays (feedback):

1. TopNav stays interactive while a section overlay is open. The a11y
   audit #2081 put inert on the whole content wrap (which contains
   TopNav), so opening an overlay disabled the top tabs. Move inert off
   the wrap onto <main>/<footer> only; the nav is inert just for the
   full-screen LocationDrawer. Users can now switch sections directly
   from an open overlay. role=dialog/aria-modal/Esc/focus-trap kept.

2. «← К ОЦЕНКЕ» made a clear filled primary button (solid accentDeep bg,
   white text ≥4.9:1 AA, shadow, hover lift) instead of the weak ghost
   pill. Uses existing accent tokens only.

3. Backdrop click closes the overlay. Add a transparent sibling layer
   below the panel (z below it, starting under the nav so tabs stay
   clickable); clicks in the margin close it. Clicks inside the panel /
   on its buttons never reach it (sibling, not ancestor) so they don't
   close. Esc + focus restore preserved.
2026-07-02 21:28:47 +03:00
f5a7f9b437 fix(tradein/v2): UI/UX audit round 2 — AA contrast, honesty, a11y (#2081)
All checks were successful
CI / changes (pull_request) Successful in 8s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
C1 (tokens): darken muted scale to WCAG AA (>=4.5:1 vs worst-case canvas
  #e6eef7); reclassify primary labels muted->body2 across components.
H1 (mappers): planning chip derived from rooms actually present in the
  analog set («Все планировки» when heterogeneous) — no number shifted.
H2 (ResultPanel): make «ОЖИДАЕМАЯ ЦЕНА СДЕЛКИ» the headline (accent
  border/tint/glow + larger value); demote ДКП·Росреестр to a muted
  СПРАВОЧНО reference tile. All three values + mapResultPanel wiring intact.
H3 (mappers): parseAddress keeps the house number for prefix-less
  addresses («Белинского, 86»); prefixed path unchanged.
M4 (page/HeroBar/Footer): gate dead controls (КАК РАССЧИТАНО / PDF /
  ДЕЙСТВИТЕЛЕН ДО / footer validity) on hasEstimate (mounted && estimate && !insufficient).
M5 (LocationDrawer): real dialog — role=dialog/aria-modal/aria-labelledby
  + focus-trap + <button> close + Esc preventDefault/stopPropagation.
M6 (ParamsPanel): address autocomplete -> combobox ARIA + Arrow/Home/End/
  Enter/Escape keyboard nav (mirrors Dd listbox).
M7 (Sources/Cache/Analytics/History): ARIA table semantics over the grids;
  Analytics scroll region keyboard-focusable (clears the serious
  scrollable-region-focusable axe violation); chart SVGs get role=img+title+aria-label.
M8 (CacheView): normalize the ВРЕМЯ column (normTime) to consistent minute precision.
M9 (LocationDrawer): honest «как считаем» source list (Циан, Я.Недвижимость,
  Авито, N1.ru + Росреестр) — drop dead Домклик/Restate per #1968.
M10 (ParamsPanel/mapMarkers): subject pin shows the subject's own area; drop
  analog pins overlapping the subject center (was misread as subject data).
M11 (ObjectSummary/SourcesView): label «медиана объявлений»; hide all-«—» columns/rows.
M13 (page): clamp artboard scale >=0.88 so micro-type doesn't drop below ~8px.
L1 (Analytics): suppress fake «X–Y дн» range when n<2.
L2 (Analytics): drop zero-data series from price-history subtitle.
L7 (TopNav): replace hardcoded #6f8195 icon strokes with tokens.muted.

tsc + next build green. No FE test infra in tradein-mvp/frontend — parseAddress
verified via standalone harness (6/6). Backend data-contract items M1/M2/M3/H4
(source counter, ratio vs medians, bargain bases, cross-source dedup) filed
separately — not FE bugs. L6 (blueprint-grid axe-blindness) deferred: base
gradient + glass surfaces keep axe contrast «incomplete» regardless, so the
authoritative check stays the manual computed-color sweep.
2026-06-29 01:01:30 +03:00
7066117cb8 fix(tradein/v2): a11y P3a — нативные контролы + модальный диалог + aria-live (#2062)
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CRITICAL-доступность (часть 1): клавиатура/скринридер. Без визуальных изменений
(chrome-reset кнопок вынесен в CSS-классы, :hover и font-size сохранены).

- Клик-only <div> → нативные <button>: nav-табы (+aria-current), user-меню
  (aria-haspopup/expanded + Esc-close), «Выйти», «Подробнее →» (ResultPanel,
  +aria-label по разделу), строки 03 СВОДКИ (ObjectSummary, +aria-label).
- SectionOverlay → настоящая модалка: role=dialog, aria-modal, aria-labelledby,
  Esc-close, фокус на диалог при открытии, focus-trap (Tab/Shift+Tab),
  возврат фокуса на триггер при закрытии; «← К ОЦЕНКЕ» → <button>.
- page.tsx: aria-live="polite" role=status — «Идёт расчёт… / Оценка готова /
  Недостаточно данных / Ошибка»; фон (content-wrap) inert когда открыт
  оверлей или drawer (overlay/drawer остаются интерактивны).

Остаётся P3b: ParamsPanel-форма (Dd→listbox+клавиши, БАЛКОН→radiogroup,
input <label>/aria) — заход «с клавиатуры можно завершить оценку».
2026-06-28 21:29:19 +03:00
30e158ad2a fix(tradein/v2): UI/UX-аудит P1 quick-wins (#2062)
All checks were successful
CI / changes (pull_request) Successful in 8s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
Честная полировка живого /trade-in/v2 без правок архитектуры (FE-only).

- Провенанс из data, без хардкодов: footer «ПОСТРОЕНО ПО N АНАЛОГАМ И M
  СДЕЛКАМ» из meta.builtOn; единый счётчик источников (activeSourceCount =
  залитые плитки) в шапке 02, СВОДКЕ и оверлее; убраны «6/10», «2/7»,
  «Avito·10», «из 2 источников».
- Единый ru-форматтер: запятая везде (CV/площадь/%), NBSP число+единица,
  один en-dash и одна точность для денежных диапазонов.
- CTA «ОЦЕНИТЬ КВАРТИРУ» → solid brand-blue + белый текст; :focus-visible
  HUD-glow на инпутах и кнопке.
- Лендмарки <nav>/<main>/<footer> (display:contents, 0 визуальных изменений);
  scale-fit артборда — на 1366×768 / 1440×900 ужимается, не режется.
- Мини-карта: честный зум (min=1, без пустых краёв при отдалении), убран
  мёртвый crosshair-двойник, расклеены налезающие метки цен.
- CRM-дропдаун явно задизейблен («скоро», без ▼); убран «ШАГ 1/1».
- Карточка 02 → «ОЖИДАЕМАЯ ЦЕНА СДЕЛКИ · с учётом торга» + строка-примирение
  с медианой ДКП; КОЭФ.ЛОКАЦИИ → muted-пилюля «скоро».
- Бейдж СВОДКИ «В РАСЧЁТЕ» → «АКТУАЛЬНО»; скрыты целиком-прочерк колонки
  (ИСТОЧНИКОВ в 07, ОБЪЯВЛЕНИЕ ДО СДЕЛКИ в 04) data-driven.
2026-06-28 19:33:12 +03:00
5a2b6d91cd fix(tradein/v2): audit findings — de-fabricate location drawer, real map markers, validation, hero image, real user (#2036)
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
Browser audit of the live /trade-in/v2 found honesty + UX defects; fixes:
- 🔴 LocationDrawer: removed FABRICATED coef 0.87 / fake 'base×coef=result' / invented
  POI factors / false 'OpenStreetMap' source. Now honest static 'ПОЯСНЕНИЕ К РАСЧЁТУ'
  (real methodology) + 'коэф. локации в разработке' note. + Escape-to-close.
- 🔴 Map (ParamsPanel): removed static fixture price markers; renders REAL analog
  markers via new mapMarkers(estimate) (projects lat/lon around target, cap 6).
- ParamsPanel: empty площадь/address now shows a validation message instead of
  silently blocking submit; numeric placeholders made clearly placeholders ('напр. 54').
- HeroBar: dead 'КАК РАССЧИТАНО' button now opens the info drawer; building.png next/image
  400 fixed (unoptimized + onError fallback — basePath wasn't applied to the optimizer URL).
- TopNav: real user from useMe() (name/initials/org/email) instead of fixture
  'Андрей Петров'; dead Профиль/Настройки/Помощь dimmed/disabled; Выйти → logout().
- mappers: de-glue analog addresses ('69/2Геологическая'→'69/2 Геологическая', preserves
  house letters like 14А); 'Продажи в доме'→'Продажи рядом' (radius data); торг sign fixed
  (backend (start−last)/start positive=reduction → renders '−3.3%').
- HistoryView: '0 ЛОТА' → correct plural via pluralRu.

next build green; code-reviewer  APPROVE.
2026-06-28 17:26:12 +03:00
81ae21ada9 feat(tradein/v2): CacheView history + PDF link + quota + address autocomplete (#2042)
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
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.
2026-06-28 16:14:34 +03:00
267585e312 feat(tradein/v2): wire overlays History/Analytics/Sources to real API (#2039 #2040 #2041)
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
FE-2/3/4 on the FE-1 mappers architecture. Adds mapHistory/mapAnalytics/mapSources
(+helpers) to mappers.ts; HistoryView/AnalyticsView/SourcesView accept composite
data props (fixture default); SectionOverlay forwards overlay data; page.tsx adds
useEstimatePlacementHistory/useSalesVsListings/useEstimateSellTimeSensitivity and
feeds mapped data. FE-1 main dashboard untouched.

- History: house sales (placement-history); ДКП KPI/header (street-deals +
  sales-vs-listings); per-deal rows with REAL addr/date/listing-source/discount.
- Analytics: KPIs (экспозиция/торг/доля снятых), 4 sell-time tiers, price-history
  polylines computed from year×source, detail scatter.
- Sources: ad rows from analogs (real source/distance/url via safeUrl), deal rows
  from actual_deals (real source/tier/date), market KPIs.
- Un-hardcoded fabricated cells: DKP addr/date/source, deal date, deals footer count.
- FE-approx (TODO BE-1 #2043): CV, per-source counts, days_on_market->listing_date.

Verified: next build green (/v2 37.8 kB); tsx harness ran the 3 overlay mappers vs
real estimate 701795d8 (houseSales/KPIs/sellTime/priceHistory/scatter/ad+deal rows
correct). code-reviewer APPROVE after honesty fixes.
2026-06-28 15:46:07 +03:00
890daa4a31 feat(tradein/v2): wire main dashboard to real API (mappers + page shell) (#2038)
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / openapi-codegen-check (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
FE-1 foundation for #2036. app/v2/page.tsx now owns data: ParamsPanel form ->
useEstimateMutation, restore-by-id via window.location.search (mirrors v1, avoids
useSearchParams Suspense build break), sub-hooks useStreetDeals/useEstimateHouseAnalytics;
loading/empty/insufficient/error states (honest placeholders, no fixtures-as-real).

New components/trade-in/v2/mappers.ts: pure AggregatedEstimate(+street-deals/analytics)
-> fixture-shape transforms — 3 price tiers (asking/expected_sold/DKP), ranges, scatter,
7 source slots, summary. CV + per-source counts are FE-approx pending BE-1 (#2043).

ParamsPanel -> controlled form (onSubmit/isPending/error/initialValues). ResultPanel/
ObjectSummary/HeroBar/Footer accept a composite data prop defaulting to the existing
fixture (pixel-perfect markup unchanged). next build green (/v2 34 kB).
2026-06-28 14:48:57 +03:00
fcb85deab8 refactor(tradein/v2): перенос HUD v2 в tradein-mvp frontend
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 1m3s
CI / openapi-codegen-check (pull_request) Successful in 1m59s
Прод-/trade-in/* обслуживает tradein-mvp/frontend (basePath=/trade-in,
standalone), а не главный frontend — v2 по ошибке попал в главный, где
прод его не отдаёт. Markup-only порт (fixtures, без API):

- компоненты v2 → tradein-mvp/frontend/src/components/trade-in/v2/
- роут src/app/v2/ (basePath даёт прод-URL /trade-in/v2)
- public/trade-in-v2/building.png
- HeroBar: <img> → next/image (плоский img не префиксит basePath → 404)
- удалён мёртвый v2 из главного frontend

next build (NEXT_PUBLIC_BASE_PATH=/trade-in) зелёный, роут /v2 prerendered.
2026-06-28 13:10:23 +03:00