gendesign/frontend/src/components/site-finder/LandTab.tsx
Light1YT 6adba229f0
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 51s
CI / openapi-codegen-check (pull_request) Successful in 1m45s
fix(site-finder): wire encumbrance/obj_class/ЗОУИТ display + forecast axis & flat-state (#1953)
Four frontend display fixes for the Site Finder analysis report (audit #1953);
all consume fields the (already-deployed) backend now returns.

- #1954: ЕГРН «Обременения» row was hardcoded «—». Wire top-level
  `encumbrance` block {has_zouit, zouit_count, zouit_types} via
  formatEncumbrance → «ЗОУИТ: N (types)» / «не выявлено (НСПД)».
- #1955: show obj_class per success bucket («Студии 15-30 · Комфорт») so
  rows with identical area-labels are distinct; fix top-row match + React key
  to (bucket, obj_class).
- #1957: NspdZouitOverlapsBlock renders human type_zone + reg_numb_border,
  adds a СЗЗ caveat banner (СанПиН 2.2.1/2.1.1.1200-03) and «СЗЗ вашего
  участка» highlight; switched raw hex to UI tokens.
- #1958: ForecastChart axis names → nameLocation:middle + nameGap (no legend
  overlap); grey flat-state callout when the deficit line is degenerate
  (scenarios_collapsed or all points clamped at ±1).

Tests: formatEncumbrance + isDeficitDegenerate (15 new). Real segment
differentiation is backend #1959 (separate).
2026-06-27 16:51:40 +05:00

148 lines
5.1 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.

"use client";
import type { ParcelAnalysis } from "@/types/site-finder";
import { SectionLabel } from "@/components/ui/SectionLabel";
import { EmptyState } from "@/components/ui/EmptyState";
import { GeologyBlock } from "./GeologyBlock";
import { GeometrySuitabilityBlock } from "./GeometrySuitabilityBlock";
import { GeotechRiskBlock } from "./GeotechRiskBlock";
import { NeighborsBlock } from "./NeighborsBlock";
import { NspdZoningBlock } from "./NspdZoningBlock";
import { NspdZouitOverlapsBlock } from "./NspdZouitOverlapsBlock";
import { NspdEngineeringNearbyBlock } from "./NspdEngineeringNearbyBlock";
import { NspdRiskZonesBlock } from "./NspdRiskZonesBlock";
import { NspdOpportunityBlock } from "./NspdOpportunityBlock";
import { NspdRedLinesBlock } from "./NspdRedLinesBlock";
import { NspdFreshnessBadge } from "./NspdFreshnessBadge";
interface Props {
data: ParcelAnalysis;
}
export function LandTab({ data }: Props) {
const hasAny =
data.geotech_risk !== undefined ||
data.geology !== undefined ||
data.geometry_suitability !== undefined ||
data.neighbors_summary !== undefined ||
data.nspd_zoning !== undefined ||
data.nspd_zouit_overlaps !== undefined ||
data.nspd_engineering_nearby !== undefined ||
data.nspd_risk_zones !== undefined ||
(data.nspd_opportunity_parcels !== undefined &&
(data.nspd_opportunity_parcels?.length ?? 0) > 0) ||
(data.nspd_red_lines !== undefined &&
(data.nspd_red_lines?.length ?? 0) > 0);
return (
<div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
{/* P2 (#46) — Соседи + overlap warning (hard warn если overlap) */}
{data.neighbors_summary && (
<NeighborsBlock data={data.neighbors_summary} />
)}
{/* P1 (#45) — Geometry suitability */}
{data.geometry_suitability !== undefined && (
<GeometrySuitabilityBlock data={data.geometry_suitability} />
)}
{/* Issue #202 — Зонирование (ПЗЗ) из НСПД */}
<div>
<div
style={{
display: "flex",
alignItems: "center",
gap: 8,
marginBottom: 10,
}}
>
<SectionLabel>Зонирование (ПЗЗ)</SectionLabel>
<NspdFreshnessBadge dump={data.nspd_dump} />
</div>
<NspdZoningBlock
data={data.nspd_zoning}
dump={data.nspd_dump}
cadNum={data.cad_num}
/>
</div>
{/* Issue #202 — ЗОУИТ пересечения */}
{data.nspd_zouit_overlaps !== undefined && (
<div>
<SectionLabel style={{ marginBottom: 10 }}>
Зоны с особыми условиями использования (ЗОУИТ)
</SectionLabel>
<NspdZouitOverlapsBlock
overlaps={data.nspd_zouit_overlaps ?? []}
parcelCad={data.cad_num}
/>
</div>
)}
{/* Issue #94 PR2 TIER 4 — Opportunity parcels */}
{(data.nspd_opportunity_parcels?.length ?? 0) > 0 && (
<div>
<SectionLabel style={{ marginBottom: 10 }}>
Возможности рядом (НСПД)
</SectionLabel>
<NspdOpportunityBlock
opportunityParcels={data.nspd_opportunity_parcels}
/>
</div>
)}
{/* Issue #94 PR2 TIER 4 — Red lines */}
{(data.nspd_red_lines?.length ?? 0) > 0 && (
<div>
<SectionLabel style={{ marginBottom: 10 }}>
Красные линии застройки (НСПД)
</SectionLabel>
<NspdRedLinesBlock redLines={data.nspd_red_lines} />
</div>
)}
{/* Issue #94 TIER 3 — Риск-зоны НСПД */}
{data.nspd_risk_zones !== undefined && (
<div>
<SectionLabel style={{ marginBottom: 10 }}>
Природные риски (НСПД)
</SectionLabel>
<NspdRiskZonesBlock riskZones={data.nspd_risk_zones} />
</div>
)}
{/* Issue #202 — Инженерные объекты в 200 м */}
{data.nspd_engineering_nearby !== undefined && (
<div>
<SectionLabel style={{ marginBottom: 10 }}>
Инженерные объекты вблизи участка
</SectionLabel>
<NspdEngineeringNearbyBlock
nearby={data.nspd_engineering_nearby ?? []}
cadNum={data.cad_num}
/>
</div>
)}
{/* Geotech risk */}
{data.geotech_risk !== undefined && (
<div>
<SectionLabel style={{ marginBottom: 12 }}>
Геотехнический риск
</SectionLabel>
<GeotechRiskBlock risk={data.geotech_risk} />
</div>
)}
{/* Geology */}
{data.geology !== undefined && (
<div>
<SectionLabel style={{ marginBottom: 12 }}>Геология</SectionLabel>
<GeologyBlock geology={data.geology} />
</div>
)}
{!hasAny && <EmptyState message="Данные о земле и геологии недоступны" />}
</div>
);
}