diff --git a/tradein-mvp/frontend/src/components/trade-in/DistributionCard.tsx b/tradein-mvp/frontend/src/components/trade-in/DistributionCard.tsx
index e39214c8..bb8b77bc 100644
--- a/tradein-mvp/frontend/src/components/trade-in/DistributionCard.tsx
+++ b/tradein-mvp/frontend/src/components/trade-in/DistributionCard.tsx
@@ -25,6 +25,7 @@ interface Props {
}
const BIN_COUNT = 12;
+const MIN_CHART_ANALOGS = 8;
const fmtK = (n: number) => `${Math.round(n / 1000)}k`;
interface Bin {
@@ -74,7 +75,7 @@ export function DistributionCard({ estimate }: Props) {
return out;
}, [estimate.analogs, subject]);
- // Empty state: меньше 3 валидных аналогов — распределение не показываем.
+ // Empty state: меньше 3 валидных аналогов — бины не строим вовсе.
if (bins.length === 0) return null;
const n = estimate.analogs.filter((l) => l.price_per_m2 > 0).length;
@@ -94,63 +95,73 @@ export function DistributionCard({ estimate }: Props) {
- {/* #835: декоративный чарт — aria-hidden (данные в тексте/легенде карточки). */}
-
-
-
-
-
-
- [`${value} лот.`, "В диапазоне"]}
- labelFormatter={(mid: number) => {
- const b = bins.find((x) => x.mid === mid);
- return b
- ? `${Math.round(b.start).toLocaleString("ru-RU")}–${Math.round(
- b.end,
- ).toLocaleString("ru-RU")} ₽/м²`
- : `${Math.round(mid).toLocaleString("ru-RU")} ₽/м²`;
- }}
- />
-
- {bins.map((b, i) => (
-
+
+ Мало аналогов для графика — нужно не менее {MIN_CHART_ANALOGS}.
+
+ |
+ ) : (
+ <>
+ {/* #835: декоративный чарт — aria-hidden (данные в тексте/легенде карточки). */}
+
+
+
+
+
- ))}
-
-
-
-
-
+
+ [`${value} лот.`, "В диапазоне"]}
+ labelFormatter={(mid: number) => {
+ const b = bins.find((x) => x.mid === mid);
+ return b
+ ? `${Math.round(b.start).toLocaleString("ru-RU")}–${Math.round(
+ b.end,
+ ).toLocaleString("ru-RU")} ₽/м²`
+ : `${Math.round(mid).toLocaleString("ru-RU")} ₽/м²`;
+ }}
+ />
+
+ {bins.map((b, i) => (
+ |
+ ))}
+
+
+
+
+
-
-
- Ваша оценка:{" "}
- {subject.toLocaleString("ru-RU")} ₽/м² ·
- оранжевый столбец — ваш диапазон
-
-
+
+
+ Ваша оценка:{" "}
+ {subject.toLocaleString("ru-RU")} ₽/м² ·
+ оранжевый столбец — ваш диапазон
+
+
+ >
+ )}
);
}
diff --git a/tradein-mvp/frontend/src/components/trade-in/ExposureCard.tsx b/tradein-mvp/frontend/src/components/trade-in/ExposureCard.tsx
index 8c099d49..5a6c1a15 100644
--- a/tradein-mvp/frontend/src/components/trade-in/ExposureCard.tsx
+++ b/tradein-mvp/frontend/src/components/trade-in/ExposureCard.tsx
@@ -25,6 +25,7 @@ interface Props {
estimate: AggregatedEstimate;
}
+const MIN_CHART_ANALOGS = 8;
const fmtM = (n: number) => `${(n / 1_000_000).toFixed(1)}`;
interface Point {
@@ -72,64 +73,74 @@ export function ExposureCard({ estimate }: Props) {
- {/* #835: чарт декоративный (данные — в заголовке/легенде/тексте карточки);
- aria-hidden убирает recharts symbol'ы role="img" без accessible-name. */}
-
-
-
-
-
-
-
-
- name === "Цена"
- ? [`${value.toLocaleString("ru-RU")} ₽`, name]
- : [`${value} дн.`, name]
- }
- />
-
-
-
-
-
+ {points.length < MIN_CHART_ANALOGS ? (
+
+
+ Недостаточно данных для графика — нужно не менее {MIN_CHART_ANALOGS} аналогов со сроком.
+
+
+ ) : (
+ <>
+ {/* #835: чарт декоративный (данные — в заголовке/легенде/тексте карточки);
+ aria-hidden убирает recharts symbol'ы role="img" без accessible-name. */}
+
+
+
+
+
+
+
+
+ name === "Цена"
+ ? [`${value.toLocaleString("ru-RU")} ₽`, name]
+ : [`${value} дн.`, name]
+ }
+ />
+
+
+
+
+
-
-
- Каждая точка — аналог в продаже · вертикаль — ваша оценка{" "}
- {fmtM(subjectPrice)} млн ₽
-
-
+
+
+ Каждая точка — аналог в продаже · вертикаль — ваша оценка{" "}
+ {fmtM(subjectPrice)} млн ₽
+
+
+ >
+ )}
);
}
diff --git a/tradein-mvp/frontend/src/components/trade-in/PriceHistoryChart.tsx b/tradein-mvp/frontend/src/components/trade-in/PriceHistoryChart.tsx
index fec51da6..a4b2c6df 100644
--- a/tradein-mvp/frontend/src/components/trade-in/PriceHistoryChart.tsx
+++ b/tradein-mvp/frontend/src/components/trade-in/PriceHistoryChart.tsx
@@ -46,10 +46,10 @@ export function PriceHistoryChart({ points }: Props) {
- Динамика цен в доме
+ История цен в этом доме
- Медиана ₽/м² по году · Avito + Яндекс (по {totalLots} лотам)
+ Медиана ₽/м² по годам · только этот дом · Avito + Яндекс ({totalLots} лотов)
{/* #835: декоративный чарт — aria-hidden (данные в тексте/легенде карточки). */}
diff --git a/tradein-mvp/frontend/src/components/trade-in/PriceTrendCard.tsx b/tradein-mvp/frontend/src/components/trade-in/PriceTrendCard.tsx
index 9d30f3d8..70dfe2c4 100644
--- a/tradein-mvp/frontend/src/components/trade-in/PriceTrendCard.tsx
+++ b/tradein-mvp/frontend/src/components/trade-in/PriceTrendCard.tsx
@@ -58,8 +58,8 @@ export function PriceTrendCard({ estimate }: Props) {
-
Аналитика · Тренд
-
Динамика ₽/м²
+
Аналитика · Тренд рынка
+
Динамика ₽/м² по рынку района
@@ -101,7 +101,7 @@ export function PriceTrendCard({ estimate }: Props) {
- Медиана ₽/м² по месяцам · {fmtMonth(data[0].month)} →{" "}
+ Медиана ₽/м² по аналогам рынка · {fmtMonth(data[0].month)} →{" "}
{fmtMonth(data[data.length - 1].month)}
diff --git a/tradein-mvp/frontend/src/components/trade-in/SourcesProgress.tsx b/tradein-mvp/frontend/src/components/trade-in/SourcesProgress.tsx
index 65f34492..adbeb289 100644
--- a/tradein-mvp/frontend/src/components/trade-in/SourcesProgress.tsx
+++ b/tradein-mvp/frontend/src/components/trade-in/SourcesProgress.tsx
@@ -198,13 +198,6 @@ export function SourcesProgress({ estimate, isPending }: Props) {
-
- CACHE-KEY ·{" "}
-
-
- {estimate?.estimate_id?.slice(0, 18) ?? "—"}
- {" "}
- ·{" "}
при недоступности источника частичный результат не блокируется