"use client"; import type { RiskZone } from "@/types/nspd"; interface Props { riskZones: RiskZone[] | null | undefined; parcelAreaSqm?: number | null; /** * #2934: сколько объектов риск-слоёв в дампе квартала. Пустой `riskZones` без * этого признака неоднозначен, и блок рисовал по нему зелёное «Риски не * обнаружены» — то есть утверждал результат проверки, которой не было. * * `undefined`/`null` — дампа нет; `0` — слой не дал объектов на весь квартал; * `>0` — слой отработал, и отсутствие пересечений с участком уже настоящий факт. */ quarterRisksCount?: number | null; } // Severity mapping: layer key suffix → severity tier function getSeverity(layer: string): "high" | "medium" | "low" { const key = layer.replace(/^risk_/, ""); if (key === "flooding" || key === "landslide") return "high"; if (key === "flooding_underground" || key === "burns") return "medium"; return "low"; } const SEVERITY_STYLES: Record< "high" | "medium" | "low", { bg: string; badgeBg: string; color: string; label: string } > = { high: { bg: "#fff1f2", badgeBg: "#fee2e2", color: "#991b1b", label: "ВЫСОКИЙ", }, medium: { bg: "#fffbeb", badgeBg: "#fef3c7", color: "#92400e", label: "СРЕДНИЙ", }, low: { bg: "#fff7ed", badgeBg: "#ffedd5", color: "#9a3412", label: "НИЗКИЙ", }, }; function formatArea(sqm: number | null): string | null { if (sqm === null) return null; if (sqm >= 10000) return `${(sqm / 10000).toFixed(2)} га`; return `${Math.round(sqm).toLocaleString("ru-RU")} м²`; } export function NspdRiskZonesBlock({ riskZones, parcelAreaSqm, quarterRisksCount, }: Props) { const zones = riskZones ?? []; if (zones.length === 0) { // Зелёный success-стиль оставляем ТОЛЬКО когда слой реально что-то отдал по // кварталу: тогда «на участке ничего не пересекается» — измеренный факт. // Замер 19.08: risks_count = 0 у всех 669 дампов, слои risk_* не вернули ни // одного объекта, — то есть сегодня показывается нейтральная ветка. const layerAnswered = (quarterRisksCount ?? 0) > 0; if (!layerAnswered) { return (
Не проверено Слои природного риска НСПД не вернули объектов по этому кварталу — отсутствие риска не подтверждено
); } return (
Риски не обнаружены Риск-зоны НСПД на участке не выявлены
); } // Sort: high first, then medium, then low const sorted = [...zones].sort((a, b) => { const order = { high: 0, medium: 1, low: 2 }; return order[getSeverity(a.layer)] - order[getSeverity(b.layer)]; }); return (
{sorted.map((zone, idx) => { const severity = getSeverity(zone.layer); const style = SEVERITY_STYLES[severity]; const areaStr = formatArea(zone.intersection_area_sqm); const pct = parcelAreaSqm && zone.intersection_area_sqm ? Math.min( 100, Math.round((zone.intersection_area_sqm / parcelAreaSqm) * 100), ) : null; return (
{style.label}
{zone.subtype ?? zone.layer}
{(areaStr || pct !== null) && (
{areaStr && Площадь пересечения: {areaStr}} {areaStr && pct !== null && · } {pct !== null && {pct}% участка}
)}
); })}
); }