gendesign/frontend/src/components/site-finder/ptica/ParcelPassportCard.tsx
Light1YT 95f93da83b feat(ptica): right-slider detail drawer system + 17 drawers wired (PR#4)
PticaDrawer: controlled right slider (480px / full-screen <768), scrim+Esc
close, focus-on-open, body-scroll-lock (restored on close/unmount), dialog
a11y. Deep-link ?drawer= via useSearchParams + shallow router.replace (no
render loop; unknown keys ignored). Enables the «Подробнее» buttons on scan
+ hero cards.

17 drawer contents (passport/buildability/urban/restrictions/engineering/
market[4 sub-tabs]/economy/risks/georisks/oks/potential/product/finance/legal/
environment/insolation/future3d) built from ParcelAnalysis + forecast product_tz.
Many are REAL: environment (noise/air_quality/wind/weather), georisks (geology/
hydrology/geotech_risk), market (competitors/market_trend/velocity/pipeline),
restrictions (zouit/red_lines/zoning), engineering, passport. Absent fields
(КСИТ/ОКС/финмодель/insolation) show honest «—»/«скоро» via ptica-adapt.

All field paths verified against types. Dark theme scoped. TS strict, no any.
Follow-up: drawer focus-trap + focus-restore for full modal a11y.
2026-06-20 16:16:39 +05:00

78 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"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";
import type { DrawerKey } from "@/components/site-finder/ptica/drawers/drawer-keys";
interface Props {
analysis: ParcelAnalysis;
onOpenDrawer: (key: DrawerKey) => void;
}
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, onOpenDrawer }: Props) {
const p: PticaPassport = adaptPassport(analysis);
return (
<div className={styles.panel}>
<div className={styles.cardHead}>
<h3 className={styles.cardTitle}>Паспорт участка</h3>
<button
type="button"
className={styles.detailBtn}
onClick={() => onOpenDrawer("passport")}
title="Открыть детализацию"
>
Подробнее
</button>
</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>
);
}