diff --git a/frontend/src/components/site-finder/MarketTab.tsx b/frontend/src/components/site-finder/MarketTab.tsx index 85f92eae..52901e58 100644 --- a/frontend/src/components/site-finder/MarketTab.tsx +++ b/frontend/src/components/site-finder/MarketTab.tsx @@ -14,6 +14,35 @@ interface Props { data: ParcelAnalysis; } +/** Derive radius_km from available nested fields. */ +function getRadiusKm(data: ParcelAnalysis): number { + return data.market_trend?.radius_km ?? data.pipeline_24mo?.radius_km ?? 3; +} + +/** + * Max success score (%) from success_recommendation ranking. + * Returns null when recommendation is absent or ranking is empty. + */ +function getMaxMixPct(data: ParcelAnalysis): number | null { + const ranking = data.success_recommendation?.ranking; + if (!ranking || ranking.length === 0) return null; + const maxScore = Math.max(...ranking.map((r) => r.success_score)); + return Math.round(maxScore * 100); +} + +/** + * Estimated sales period in months (supply / flats_per_month). + * Uses pipeline_24mo.flats_total as supply proxy, velocity for rate. + * Assumes ~50 m² avg flat for unit conversion. + */ +function getSalesPeriodMonths(data: ParcelAnalysis): number | null { + const supply = data.pipeline_24mo?.flats_total; + const velocitySqm = data.velocity?.monthly_velocity_sqm; + if (!supply || !velocitySqm || velocitySqm <= 0) return null; + const flatsPerMonth = velocitySqm / 50; + return Math.round(supply / flatsPerMonth); +} + export function MarketTab({ data }: Props) { const hasTrend = "market_trend" in data; const hasRecommendation = "success_recommendation" in data; @@ -26,8 +55,186 @@ export function MarketTab({ data }: Props) { hasVelocity || data.competitors.length > 0; + // ── Above-the-fold values ──────────────────────────────────────────────── + // Note: site_status field pending fix #2/#3 (backend PR). Using total + // competitors count as proxy for active (строящихся) count for now. + const activeCount = data.competitors.length; + const radiusKm = getRadiusKm(data); + const velocityPerMonth = data.velocity?.monthly_velocity_sqm ?? null; + const maxMixPct = getMaxMixPct(data); + const salesPeriodMonths = getSalesPeriodMonths(data); + + const showHeadlineBar = activeCount > 0 || velocityPerMonth !== null; + return (