gendesign/tradein-mvp/frontend/src/components/trade-in/v2/CacheView.tsx
bot-backend 30e158ad2a
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
fix(tradein/v2): UI/UX-аудит P1 quick-wins (#2062)
Честная полировка живого /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

154 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// OVERLAY 07: ПРЕДЫДУЩИЕ ОЦЕНКИ (cache view).
// Faithful markup port of МЕРА Оценка.dc.html lines 593-613.
// Data via `data` prop (mapCache output); defaults to fixtures (cacheKpi + cacheRows).
import { tokens } from "./tokens";
import { cacheKpi, cacheRows } from "./fixtures";
import type { CacheData } from "./mappers";
const FIXTURE_CACHE: CacheData = { kpis: cacheKpi, rows: cacheRows };
export function CacheView({ data = FIXTURE_CACHE }: { data?: CacheData }) {
const showSrc = data.rows.some((r) => r.src && r.src !== "—");
const gridCols = showSrc ? "2.4fr 1fr 1fr 1fr" : "2.4fr 1fr 1fr";
return (
<div style={{ display: "flex", flexDirection: "column", gap: 22 }}>
{/* 3 KPI cards */}
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(3,1fr)",
gap: 16,
}}
>
{data.kpis.map((kpi) => (
<div
key={kpi.label}
style={{
background: tokens.surface.w55,
border: `1px solid ${tokens.line2}`,
borderRadius: 8,
padding: "16px 18px",
}}
>
<div
style={{
fontSize: 9.5,
letterSpacing: 1.5,
color: tokens.muted2,
}}
>
{kpi.label}
</div>
<div
style={{
fontFamily: tokens.font.mono,
fontSize: 30,
fontWeight: 300,
color: tokens.ink2,
margin: "8px 0 5px",
}}
>
{kpi.value}
{kpi.unit && (
<>
{kpi.unit !== "%" && " "}
<span style={{ fontSize: 14, color: tokens.muted }}>
{kpi.unit}
</span>
</>
)}
</div>
<div style={{ fontSize: 10, color: tokens.hint }}>{kpi.sub}</div>
</div>
))}
</div>
{/* Последние оценки table */}
<div
style={{
background: tokens.surface.w55,
border: `1px solid ${tokens.line2}`,
borderRadius: 8,
overflow: "hidden",
}}
>
<div
style={{
padding: "14px 18px",
borderBottom: `1px solid ${tokens.lineSoft}`,
fontSize: 12,
fontWeight: 600,
color: tokens.ink2,
}}
>
Последние оценки
</div>
<div
style={{
display: "grid",
gridTemplateColumns: gridCols,
gap: 10,
padding: "9px 18px",
fontSize: 9,
letterSpacing: 1,
color: tokens.muted2,
borderBottom: `1px solid ${tokens.lineSoft2}`,
}}
>
<span>АДРЕС</span>
<span>ВРЕМЯ</span>
{showSrc && <span>ИСТОЧНИКОВ</span>}
<span>СТАТУС</span>
</div>
{data.rows.map((r, i) => (
<div
key={`${r.addr}-${i}`}
style={{
display: "grid",
gridTemplateColumns: gridCols,
gap: 10,
padding: "12px 18px",
fontSize: 11,
borderBottom: `1px solid ${tokens.lineSoft3}`,
alignItems: "center",
}}
>
<span style={{ color: tokens.body }}>{r.addr}</span>
<span
style={{ fontFamily: tokens.font.mono, color: tokens.muted2 }}
>
{r.time}
</span>
{showSrc && (
<span
style={{ fontFamily: tokens.font.mono, color: tokens.muted }}
>
{r.src}
</span>
)}
<span
style={{
display: "flex",
alignItems: "center",
gap: 6,
fontSize: 10,
color: r.statusColor,
}}
>
<span
style={{
width: 7,
height: 7,
borderRadius: "50%",
background: r.statusColor,
}}
/>
{r.status}
</span>
</div>
))}
</div>
</div>
);
}