New non-destructive route /site-finder/analysis/[cad]/ptica rendering the existing /analyze data in the «ПТИЦА» operator-terminal cockpit. The light analysis page, Section1-6, globals.css and package.json are untouched. PR#1 scope: app-shell (topbar + 4 tabs + left rail), hero (dark Leaflet map + parcel passport KV-grid + Buildability radial gauge + invest-score block), and the Development Scan card grid — wired to useParcelAnalyzeQuery / ParcelAnalysis. Data honesty: real fields render live (passport egrn.*, district, utilities.summary, median_price, pipeline_24mo); absent fields show muted placeholders with source captions (buildability/risk = derived proxy «предв.»; invest/buy-signal «после прогноза»; КСИТ/height/ОКС/economy «—») via typed ptica-adapt.ts — no fake numbers presented as live. Dark theme is a CSS-module scoped under .pticaRoot[data-theme=dark] (cannot leak to the light app); IBM Plex Mono added via next/font (no dep/lockfile change). Leaflet via dynamic(ssr:false). TS strict, no any. Deferred to follow-up PRs: Scenarios (forecast), Reports+Compare tabs, 16 detail drawers, Three.js 3D massing.
68 lines
2.1 KiB
TypeScript
68 lines
2.1 KiB
TypeScript
"use client";
|
||
|
||
/**
|
||
* ParcelPassportCard — passport KV-grid (hero col 2). Mono cad number; every
|
||
* value flows from the adapter view-model, so placeholders render muted "—"
|
||
* with their caption rather than fake live data.
|
||
*/
|
||
|
||
import styles from "@/app/site-finder/analysis/[cad]/ptica/ptica.module.css";
|
||
import type { ParcelAnalysis } from "@/types/site-finder";
|
||
import { adaptPassport } from "@/components/site-finder/ptica/ptica-adapt";
|
||
import type {
|
||
PticaField,
|
||
PticaPassport,
|
||
} from "@/components/site-finder/ptica/ptica-adapt";
|
||
|
||
interface Props {
|
||
analysis: ParcelAnalysis;
|
||
}
|
||
|
||
function KvCell({
|
||
label,
|
||
field,
|
||
wide,
|
||
}: {
|
||
label: string;
|
||
field: PticaField;
|
||
wide?: boolean;
|
||
}) {
|
||
return (
|
||
<div className={`${styles.kv} ${wide ? styles.kvWide : ""}`}>
|
||
<span className={styles.kvK}>{label}</span>
|
||
<span
|
||
className={`${styles.kvV} ${field.isReal ? "" : styles.kvPlaceholder}`}
|
||
>
|
||
{field.value}
|
||
</span>
|
||
{field.caption && !field.isReal && (
|
||
<span className={styles.kvCaption}>{field.caption}</span>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export function ParcelPassportCard({ analysis }: Props) {
|
||
const p: PticaPassport = adaptPassport(analysis);
|
||
|
||
return (
|
||
<div className={styles.panel}>
|
||
<div className={styles.cardHead}>
|
||
<h3 className={styles.cardTitle}>Паспорт участка</h3>
|
||
</div>
|
||
<div className={styles.kvGrid}>
|
||
<div className={`${styles.kv} ${styles.kvWide}`}>
|
||
<span className={styles.kvK}>Кадастровый номер</span>
|
||
<span className={`${styles.kvV} ${styles.mono}`}>{p.cadNum}</span>
|
||
</div>
|
||
<KvCell label="Район" field={p.district} />
|
||
<KvCell label="Площадь" field={p.area} />
|
||
<KvCell label="Адрес" field={p.address} wide />
|
||
<KvCell label="Категория земель" field={p.landCategory} />
|
||
<KvCell label="ВРИ" field={p.vri} />
|
||
<KvCell label="Статус" field={p.status} />
|
||
<KvCell label="Обременения" field={p.encumbrances} />
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|