"use client"; import type { NspdEngineeringNearby } from "@/types/nspd"; import { useConnectionPoints } from "@/hooks/useConnectionPoints"; interface Props { nearby: NspdEngineeringNearby[]; cadNum: string | null | undefined; } interface MergedRow { label: string; type: string | null; distanceM: number; source: "analyze" | "connection-points"; // Stable structure identifier (НСПД cad_num) when available — используется для // дедупа между источниками, т.к. distanceM меряется до разных опорных точек // (analyze — до центроида, connection-points — до границы участка). cadNum: string | null; // #2111 — расширенные поля из connection-points (EngineeringStructure). // analyze-источник их не отдаёт → null; рендерим вторичной строкой только когда есть. purpose: string | null; characteristics: string | null; readableAddress: string | null; } export function NspdEngineeringNearbyBlock({ nearby, cadNum }: Props) { const { data: cpData, isPending: cpLoading } = useConnectionPoints(cadNum); // Merge and sort by distance const rows: MergedRow[] = []; for (const item of nearby) { if (item.distance_m !== null) { rows.push({ label: item.name ?? item.type ?? "Объект", type: item.type, distanceM: item.distance_m, source: "analyze", cadNum: null, purpose: null, characteristics: null, readableAddress: null, }); } } if (cpData) { for (const s of cpData.engineering_structures) { rows.push({ label: s.name ?? s.type ?? "Объект", type: s.type, distanceM: s.distance_to_boundary_m, source: "connection-points", cadNum: s.cad_num, purpose: s.purpose ?? null, characteristics: s.characteristics ?? null, readableAddress: s.readable_address, }); } } // Dedup. distanceM меряется до разных опорных точек (analyze — до центроида, // connection-points — до границы), поэтому label+round(distance) пропускает // дубли одного физического сооружения. Дедупим по стабильному cad_num, когда он // есть; иначе (analyze без cad_num) — по label + округлённому расстоянию. const seen = new Set(); const deduped = rows.filter((r) => { const key = r.cadNum !== null ? `cad:${r.cadNum}` : `lbl:${r.label}|${Math.round(r.distanceM)}`; if (seen.has(key)) return false; seen.add(key); return true; }); deduped.sort((a, b) => a.distanceM - b.distanceM); if (deduped.length === 0 && !cpLoading) { return (
Инженерных объектов поблизости не найдено
); } return (
{deduped.length > 0 && ( {deduped.map((row, idx) => { // #2111 — расширенные поля (НСПД-дамп) одной вторичной строкой под // основной; рендерим только присутствующие. const hasDetail = !!row.purpose || !!row.characteristics || !!row.readableAddress || !!row.cadNum; const isLast = idx === deduped.length - 1; return ( ); })}
Объект Тип Расстояние
{row.label} {row.type ?? "—"} {Math.round(row.distanceM)} м
{hasDetail && (
{row.purpose && (
Назначение: {" "} {row.purpose}
)} {row.characteristics && (
Характеристики: {" "} {row.characteristics}
)} {row.readableAddress && (
Адрес:{" "} {row.readableAddress}
)} {row.cadNum && (
№ ЕГРН:{" "} {row.cadNum}
)}
)}
)} {cpLoading && (
Загружаем данные точек подключения…
)} {cpData?.summary && (
{cpData.summary.in_protection_zone && ( В охранной зоне )} {cpData.summary.nearest_structure_distance_m !== null && ( Ближайший:{" "} {Math.round(cpData.summary.nearest_structure_distance_m)} м )}
)}
); }