"use client"; /** * ConfidencePanel — 6.3 «Уверенность прогноза». An overall conf-pill (from * confidence.level) + a row per confidence.factors entry, each with a high/mid/ * low pill. The factors map carries a stray non-factor boolean (advisory_capped) * in prod envelopes — narrowed out via a runtime guard (mirrors the light block). */ import styles from "@/app/site-finder/analysis/[cad]/ptica/ptica.module.css"; import type { ConfidenceFactor, ReportConfidence } from "@/types/forecast"; import { CONFIDENCE_RU, confidencePill } from "./scenario-helpers"; interface Props { confidence: ReportConfidence; } const FACTOR_RU: Record = { deal_count: "Объём данных по сделкам", analog_count: "Аналоги (ЖК)", domrf_coverage: "Покрытие ДОМ.РФ", history_months: "Глубина истории", component: "Компонент", }; const LEVEL_RANK: Record = { high: 0, medium: 1, low: 2, }; const PILL_CLASS = { high: styles.confPillHigh, medium: styles.confPillMedium, low: styles.confPillLow, } as const; function isConfidenceFactor(v: unknown): v is ConfidenceFactor { if (typeof v !== "object" || v === null) return false; const o = v as Record; return ( typeof o.note === "string" && (o.level === "high" || o.level === "medium" || o.level === "low") ); } function factorLabel(key: string, factor: ConfidenceFactor): string { if (factor.label) return factor.label; if (FACTOR_RU[key]) return FACTOR_RU[key]; const m = key.match(/^component(?:_(\d+))?$/); if (m) return m[1] ? `Компонент ${m[1]}` : "Компонент"; return key; } export function ConfidencePanel({ confidence }: Props) { const level = confidence.level; const drivers = Object.entries(confidence.factors) .filter((entry): entry is [string, ConfidenceFactor] => isConfidenceFactor(entry[1]), ) .sort((a, b) => LEVEL_RANK[a[1].level] - LEVEL_RANK[b[1].level]); return (

Уверенность прогноза

{level && ( {CONFIDENCE_RU[level]} )}
{drivers.length > 0 ? ( drivers.map(([key, factor]) => (
{factorLabel(key, factor)} {CONFIDENCE_RU[factor.level]}
)) ) : (

Факторы достоверности недоступны.

)}
); }