"use client"; /** * Section2NetworksUtilities — "3. Сети и точки подключения" * * Layout: * HeadlineBar (title «Сети» + subtitle с расстояниями) * Utilities table: 4 rows × [Иконка / Тип / Расстояние / Количество / Статус] * Warning banner if power_line_охранная_зона_flag === true * Note (caveat text) * * Data: useParcelAnalyzeQuery (B5) — field `utilities`. * If utilities absent from response — shows "нет данных" state gracefully. */ import type { ReactNode } from "react"; import { Zap, Flame, Droplet, Pipette, AlertTriangle, Info, } from "lucide-react"; import { HeadlineBar } from "@/components/ui/HeadlineBar"; import { NspdVerifyLink } from "./NspdVerifyLink"; import { useParcelAnalyzeQuery } from "@/lib/site-finder-api"; import type { UtilitySummaryItem } from "@/lib/site-finder-api"; // ── Subtype display config ──────────────────────────────────────────────────── interface UtilityDisplayConfig { label: string; icon: ReactNode; } function getUtilityConfig(subtype: string): UtilityDisplayConfig { switch (subtype) { // ── Электричество ── case "substation": return { label: "Электричество (подстанция)", icon: ( ), }; case "transformer": return { label: "Электричество (трансформатор)", icon: ( ), }; case "power_line": return { label: "Электричество (ЛЭП)", icon: ( ), }; // ── Газ ── case "gas_pipeline": return { label: "Газ (газопровод)", icon: ( ), }; case "pipeline": return { label: "Трубопровод (без вещества)", icon: ( ), }; // ── Водопровод ── case "water_main": return { label: "Водопровод (магистраль)", icon: ( ), }; case "water_works": return { label: "Водопровод (водозабор)", icon: ( ), }; case "water_tower": return { label: "Водопровод (водонапорная башня)", icon: ( ), }; case "storage_tank": return { label: "Резервуар", icon: ( ), }; // ── Канализация ── case "sewerage": return { label: "Канализация (коллектор)", icon: ( ), }; case "wastewater_plant": return { label: "Канализация (очистные)", icon: ( ), }; // ── Теплоснабжение ── case "heat_substation": return { label: "Теплоснабжение (ЦТП)", icon: ( ), }; default: return { label: subtype, icon: ( ), }; } } // ── Distance → presence status ──────────────────────────────────────────────── type PresenceStatus = "close" | "reachable" | "far" | "absent"; function getPresenceStatus(nearestM: number): PresenceStatus { if (nearestM <= 200) return "close"; if (nearestM <= 500) return "reachable"; if (nearestM <= 1000) return "far"; return "absent"; } const PRESENCE_LABEL: Record = { close: "В радиусе 200 м", reachable: "В радиусе 500 м", far: "В радиусе 1 км", absent: "Далее 1 км", }; const PRESENCE_COLOR: Record = { close: "var(--success)", reachable: "var(--accent)", far: "var(--warn)", absent: "var(--danger)", }; const PRESENCE_BG: Record = { close: "var(--success-soft)", reachable: "var(--accent-soft)", far: "var(--warn-soft)", absent: "var(--danger-soft)", }; // ── HeadlineBar subtitle helper ─────────────────────────────────────────────── function buildSubtitle(items: UtilitySummaryItem[]): string { const parts: string[] = []; const electric = items.find( (i) => i.subtype === "substation" || i.subtype === "transformer" || i.subtype === "power_line", ); const gas = items.find((i) => i.subtype === "gas_pipeline"); const water = items.find( (i) => i.subtype === "water_main" || i.subtype === "water_works" || i.subtype === "water_tower", ); if (electric) parts.push(`электричество ${electric.nearest_m.toLocaleString("ru")} м`); if (gas) parts.push(`газ ${gas.nearest_m.toLocaleString("ru")} м`); if (water) parts.push(`водопровод ${water.nearest_m.toLocaleString("ru")} м`); return parts.length > 0 ? parts.join(" · ") : "данные из НСПД об инженерной инфраструктуре"; } // ── Loading skeleton ────────────────────────────────────────────────────────── function Section2Skeleton() { return ( ); } // ── No-data state ───────────────────────────────────────────────────────────── function Section2NoData() { return ( 2. Сети и точки подключения Данные НСПД об инженерной инфраструктуре не получены для этого участка. Проверьте наличие NSPD-снимка в базе. ); } // ── Error state ─────────────────────────────────────────────────────────────── function Section2Error({ message }: { message: string }) { return ( 2. Сети и точки подключения {message} ); } // ── Utilities table ─────────────────────────────────────────────────────────── interface UtilitiesTableProps { items: UtilitySummaryItem[]; } function UtilitiesTable({ items }: UtilitiesTableProps) { return ( {/* Table header */} Тип объекта Ближайший В 2 км Статус {/* Table rows */} {items.map((item, idx) => { const config = getUtilityConfig(item.subtype); const status = getPresenceStatus(item.nearest_m); const isLast = idx === items.length - 1; return ( {/* Icon */} {config.icon} {/* Label */} {config.label} {item.name && ( {item.name} )} {/* Nearest distance */} {item.nearest_m.toLocaleString("ru")} м {/* Count within 2km */} {item.count_within_2km} шт. {/* Status badge */} {PRESENCE_LABEL[status]} ); })} ); } // ── Main component ──────────────────────────────────────────────────────────── interface Props { cad: string; } export function Section2NetworksUtilities({ cad }: Props) { const { isLoading, isError, error, data } = useParcelAnalyzeQuery(cad); if (isLoading) return ; if (isError || !data) { return ( ); } const utilities = data.utilities; // No utilities data in response (NSPD snapshot absent) if (!utilities || utilities.summary.length === 0) { return ; } const { summary, power_line_охранная_зона_flag: powerLineZone, note, } = utilities; // HeadlineBar subtitle: list distances for key utility types const headlineSubtitle = buildSubtitle(summary); return ( {/* Section title + verify-link на НСПД (#97) */} 2. Сети и точки подключения {/* HeadlineBar */} {/* Power line охранная зона warning */} {powerLineZone && ( Участок находится в охранной зоне ЛЭП ≥35 кВ. Капитальное строительство в ОЗ запрещено (СП 36.13330, ЗОУИТ тип 5). )} {/* Utilities table */} {/* Caveat note */} {note && ( {note} )} ); }
{message}