diff --git a/tradein-mvp/frontend/src/app/v2/page.tsx b/tradein-mvp/frontend/src/app/v2/page.tsx
index 813ed0c0..e398c129 100644
--- a/tradein-mvp/frontend/src/app/v2/page.tsx
+++ b/tradein-mvp/frontend/src/app/v2/page.tsx
@@ -599,8 +599,9 @@ export default function TradeInV2Page() {
[locationIndexData],
);
const resultPanelData = useMemo(
- () => (estimate ? mapResultPanel(estimate, streetDealsData) : null),
- [estimate, streetDealsData],
+ () =>
+ estimate ? mapResultPanel(estimate, streetDealsData, analyticsData) : null,
+ [estimate, streetDealsData, analyticsData],
);
const summaryData = useMemo(
() =>
diff --git a/tradein-mvp/frontend/src/components/trade-in/v2/ResultPanel.tsx b/tradein-mvp/frontend/src/components/trade-in/v2/ResultPanel.tsx
index 088fc12a..6bb5bc15 100644
--- a/tradein-mvp/frontend/src/components/trade-in/v2/ResultPanel.tsx
+++ b/tradein-mvp/frontend/src/components/trade-in/v2/ResultPanel.tsx
@@ -484,6 +484,7 @@ export default function ResultPanel({
// M2 — calm delta pill (was a 51px circular gauge that read like a
// tech "занижение" indicator). Full text «−18% к цене объявления»,
// neutral accentDeep on a soft-blue chip, tabular-nums.
+ <>
→
+ {card.exposureNote && (
+
+ {card.exposureNote}
+
+ )}
+ >
)}
);
diff --git a/tradein-mvp/frontend/src/components/trade-in/v2/mappers.ts b/tradein-mvp/frontend/src/components/trade-in/v2/mappers.ts
index 3c965409..79fd9f1e 100644
--- a/tradein-mvp/frontend/src/components/trade-in/v2/mappers.ts
+++ b/tradein-mvp/frontend/src/components/trade-in/v2/mappers.ts
@@ -1038,6 +1038,7 @@ export function mapMarkers(e: AggregatedEstimate | null): MapMarker[] {
export function mapResultPanel(
e: AggregatedEstimate,
streetDeals?: StreetDealsResponse | null,
+ analytics?: HouseAnalyticsResponse | null,
): ResultPanelData {
const dealTier = resolveDealTier(e, streetDeals);
@@ -1105,6 +1106,13 @@ export function mapResultPanel(
emptyNote: hasExpected
? undefined
: "Недостаточно данных для прогноза цены сделки — ориентируйтесь на рекомендованную цену в объявлении",
+ // Median exposure days (house/district), from house_placement_history —
+ // gated on hasExpected: when the card has no forecast it renders only
+ // emptyNote (see above), the exposure aside has nowhere honest to sit.
+ exposureNote:
+ hasExpected && analytics?.kpi?.median_exposure_days != null
+ ? `срок продажи ~${analytics.kpi.median_exposure_days} дн`
+ : undefined,
note:
hasExpected &&
dealTier != null &&
diff --git a/tradein-mvp/frontend/src/components/trade-in/v2/types.ts b/tradein-mvp/frontend/src/components/trade-in/v2/types.ts
index 32021e07..81ca7422 100644
--- a/tradein-mvp/frontend/src/components/trade-in/v2/types.ts
+++ b/tradein-mvp/frontend/src/components/trade-in/v2/types.ts
@@ -55,6 +55,8 @@ export interface ResultCard {
deltaLabel?: string;
/** Reconciliation note under the value (card 2: expected price vs ДКП median). */
note?: string;
+ /** Медиана срока экспозиции по дому/району (house_placement_history), подстрока карточки 2. */
+ exposureNote?: string;
/** H1 empty-state message: when set (card 2, no expected-sold prediction) the
* card renders this instead of value/range/ppm/delta, and the panel moves the
* accent frame onto the «рекомендованная цена» card. */