Wire analysis/[cad]/page.tsx: replace SidebarPlaceholder with AnalysisSidebar (sticky, IntersectionObserver scrollspy on sections 1/2/3/3.1/3.2/3.3/4/5), header with AnalysisBreadcrumb (SiteFinder → cad → Анализ) and UserAvatar (gd_org_id from localStorage, SSR-safe). Add lucide-react to package.json (was used in A1 but missing from deps).
182 lines
5.6 KiB
TypeScript
182 lines
5.6 KiB
TypeScript
"use client";
|
||
|
||
import { use } from "react";
|
||
import { LayoutDashboard } from "lucide-react";
|
||
|
||
import { AnalysisSidebar } from "@/components/site-finder/analysis/AnalysisSidebar";
|
||
import { AnalysisBreadcrumb } from "@/components/site-finder/analysis/AnalysisBreadcrumb";
|
||
import { UserAvatar } from "@/components/site-finder/analysis/UserAvatar";
|
||
|
||
// ── Section placeholder (Wave 3–4 refactor will replace these) ─────────────────
|
||
|
||
interface SectionPlaceholderProps {
|
||
id: string;
|
||
title: string;
|
||
note?: string;
|
||
}
|
||
|
||
function SectionPlaceholder({ id, title, note }: SectionPlaceholderProps) {
|
||
return (
|
||
<section
|
||
id={id}
|
||
style={{
|
||
background: "var(--bg-card)",
|
||
border: "1px solid var(--border-card)",
|
||
borderRadius: 12,
|
||
padding: 20,
|
||
marginBottom: 24,
|
||
}}
|
||
>
|
||
<h2
|
||
style={{
|
||
margin: "0 0 8px",
|
||
fontSize: 18,
|
||
fontWeight: 600,
|
||
color: "var(--fg-primary)",
|
||
}}
|
||
>
|
||
{title}
|
||
</h2>
|
||
{note && (
|
||
<p style={{ margin: 0, fontSize: 13, color: "var(--fg-tertiary)" }}>
|
||
{note}
|
||
</p>
|
||
)}
|
||
<div
|
||
style={{
|
||
marginTop: 16,
|
||
padding: "24px 16px",
|
||
background: "var(--bg-card-alt)",
|
||
border: "1px dashed var(--border-strong)",
|
||
borderRadius: 8,
|
||
display: "flex",
|
||
alignItems: "center",
|
||
justifyContent: "center",
|
||
color: "var(--fg-tertiary)",
|
||
fontSize: 13,
|
||
}}
|
||
>
|
||
<LayoutDashboard
|
||
size={16}
|
||
strokeWidth={1.5}
|
||
style={{ marginRight: 8, flexShrink: 0 }}
|
||
/>
|
||
Заполняется в Wave 2–4 (A5–A11)
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|
||
|
||
// ── Page ──────────────────────────────────────────────────────────────────────
|
||
|
||
interface PageProps {
|
||
params: Promise<{ cad: string }>;
|
||
}
|
||
|
||
export default function AnalysisPage({ params }: PageProps) {
|
||
// React 19: use() unwraps Promise params (app router pattern)
|
||
const { cad } = use(params);
|
||
|
||
return (
|
||
<main
|
||
style={{
|
||
minHeight: "100vh",
|
||
background: "var(--bg-app)",
|
||
display: "flex",
|
||
flexDirection: "column",
|
||
}}
|
||
>
|
||
{/* ── Header ─────────────────────────────────────────────────────────── */}
|
||
<header
|
||
style={{
|
||
background: "var(--bg-card)",
|
||
borderBottom: "1px solid var(--border-card)",
|
||
padding: "12px 24px",
|
||
display: "flex",
|
||
alignItems: "center",
|
||
gap: 12,
|
||
flexWrap: "wrap",
|
||
position: "sticky",
|
||
top: 0,
|
||
zIndex: 10,
|
||
minHeight: 56,
|
||
boxSizing: "border-box",
|
||
}}
|
||
>
|
||
<AnalysisBreadcrumb cadNum={cad} />
|
||
|
||
{/* Push avatar to the right */}
|
||
<div style={{ marginLeft: "auto" }}>
|
||
<UserAvatar />
|
||
</div>
|
||
</header>
|
||
|
||
{/* ── Body: sidebar + scrollable sections ───────────────────────────── */}
|
||
<div style={{ display: "flex", flex: 1 }}>
|
||
<AnalysisSidebar />
|
||
|
||
{/* Main scrollable content */}
|
||
<article
|
||
style={{
|
||
flex: 1,
|
||
padding: "24px 32px",
|
||
overflowY: "auto",
|
||
maxWidth: 1000,
|
||
}}
|
||
>
|
||
{/* Section 1 — TODO A5 */}
|
||
<SectionPlaceholder
|
||
id="section-1"
|
||
title="1. Объект"
|
||
note="TODO A5: HeadlineBar вердикт + 4 KPI (Площадь / Район / Медиана / Score) + mini-map + EGRN table + POI list 2GIS"
|
||
/>
|
||
|
||
{/* Section 2 — TODO A6 */}
|
||
<SectionPlaceholder
|
||
id="section-2"
|
||
title="2. Земля и риски"
|
||
note="TODO A6: reuse NspdEngineeringNearbyBlock в новом layout headline+map"
|
||
/>
|
||
|
||
{/* Section 3 — TODO A7/A8/A9 */}
|
||
<SectionPlaceholder
|
||
id="section-3"
|
||
title="3. Рынок"
|
||
note="TODO A7: WeightProfilePanel (настройки выборки) · A8: BestLayoutsBlock / Pipeline24moBlock / VelocityBlock · A9: CompetitorTable с drawer drill-in"
|
||
/>
|
||
|
||
{/* Sub-section anchor targets (invisible) for scrollspy / direct links */}
|
||
<div
|
||
id="section-3-1"
|
||
style={{ height: 0, overflow: "hidden" }}
|
||
aria-hidden="true"
|
||
/>
|
||
<div
|
||
id="section-3-2"
|
||
style={{ height: 0, overflow: "hidden" }}
|
||
aria-hidden="true"
|
||
/>
|
||
<div
|
||
id="section-3-3"
|
||
style={{ height: 0, overflow: "hidden" }}
|
||
aria-hidden="true"
|
||
/>
|
||
|
||
{/* Section 4 — TODO A10 */}
|
||
<SectionPlaceholder
|
||
id="section-4"
|
||
title="4. Инфраструктура"
|
||
note="TODO A10: ScoreBreakdownPanel + ScoreBreakdownStackedBar + GateVerdictBanner + GeologyBlock / HydrologyBlock / GeotechRiskBlock"
|
||
/>
|
||
|
||
{/* Section 5 — TODO A11 */}
|
||
<SectionPlaceholder
|
||
id="section-5"
|
||
title="5. Свежесть"
|
||
note="TODO A11: SeasonalWeatherBlock + air quality (reuse EnvironmentTab logic split на блоки)"
|
||
/>
|
||
</article>
|
||
</div>
|
||
</main>
|
||
);
|
||
}
|