gendesign/frontend/src/components/site-finder/ptica-v2/V2ScanCard.tsx
Light1YT eb7290dcf0
All checks were successful
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 53s
CI / changes (pull_request) Successful in 5s
CI / openapi-codegen-check (pull_request) Successful in 1m51s
feat(site-finder): add Site Finder v2 cockpit route (ПТИЦА v2)
Port the approved ptica-v2 prototype to a new non-destructive route
/site-finder/analysis/{cad}/v2 — dark/light cockpit shell, real Leaflet
map (reuses PticaMapInner), 6 scan cards, lower/bottom grids, 11 drawers
and grounded chat. All values flow through the existing ptica-adapt layer
(real /analyze data or honest «—»). One beta link added on the analysis page.
2026-06-21 22:29:18 +05:00

116 lines
3.2 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";
/**
* V2ScanCard — generic «scan» card for row 2 (prototype `.row2 .card`). Renders a
* PticaScanCard view-model: a title (+ optional badge), kv-rows OR status-rows
* (dot + state, used by Инженерия), an empty-state, and a "ПОДРОБНЕЕ →" link to
* the card's drawer. All values come from the ptica-adapt layer (REAL or honest
* «—»).
*/
import styles from "@/app/site-finder/analysis/[cad]/v2/v2.module.css";
import type {
PticaScanCard,
PticaScanRow,
PticaStatusTone,
} from "@/components/site-finder/ptica/ptica-adapt";
import type { V2DrawerKey } from "@/components/site-finder/ptica-v2/v2-drawer-registry";
const STATUS_COLOR: Record<PticaStatusTone, string> = {
ok: "var(--accent-green)",
warn: "var(--accent-orange)",
bad: "var(--accent-red)",
};
const STATUS_LABEL: Record<PticaStatusTone, string> = {
ok: "Доступно",
warn: "Огранич.",
bad: "Нет",
};
const STATUS_CLASS: Record<PticaStatusTone, string> = {
ok: styles.ok,
warn: styles.warnc,
bad: styles.warnc,
};
function KvRow({ row }: { row: PticaScanRow }) {
return (
<div className={styles.kv}>
<span className={styles.k}>{row.key}</span>
<span
className={`${styles.v} ${styles.mono} ${row.field.isReal ? "" : styles.dash}`}
title={row.field.isReal ? undefined : row.field.caption}
>
{row.field.value}
</span>
</div>
);
}
function StatusRow({ row }: { row: PticaScanRow }) {
const tone = row.status ?? "ok";
return (
<div className={styles.engRow}>
<span className={styles.nm}>
<span
className={styles.sd}
style={{ color: STATUS_COLOR[tone] }}
aria-hidden="true"
/>
{row.key}
</span>
<span className={styles.st}>
<span className={`${styles.stt} ${STATUS_CLASS[tone]}`}>
{STATUS_LABEL[tone]}
</span>
<span className={styles.dm} title={row.field.isReal ? undefined : row.field.caption}>
{row.field.value}
</span>
</span>
</div>
);
}
interface Props {
card: PticaScanCard;
drawer: V2DrawerKey;
onOpenDrawer: (key: V2DrawerKey) => void;
}
export function V2ScanCard({ card, drawer, onOpenDrawer }: Props) {
return (
<div className={styles.card}>
<div className={styles.cardH}>
<div className={styles.ttl}>
<span className={styles.sectionTitle}>{card.title}</span>
{card.badge && <span className={styles.badge}>{card.badge}</span>}
</div>
</div>
<div className={styles.cardB}>
{card.rows.length === 0 ? (
<div className={styles.emptyState}>
{card.emptyState ?? "Нет данных"}
</div>
) : (
card.rows.map((row) =>
row.status ? (
<StatusRow key={row.key} row={row} />
) : (
<KvRow key={row.key} row={row} />
),
)
)}
<div className={styles.moreRow}>
<button
type="button"
className={styles.more}
onClick={() => onOpenDrawer(drawer)}
>
ПОДРОБНЕЕ
</button>
</div>
</div>
</div>
);
}