gendesign/tradein-mvp/frontend/src/components/trade-in/v2/SectionOverlay.tsx
bot-backend 267585e312
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
feat(tradein/v2): wire overlays History/Analytics/Sources to real API (#2039 #2040 #2041)
FE-2/3/4 on the FE-1 mappers architecture. Adds mapHistory/mapAnalytics/mapSources
(+helpers) to mappers.ts; HistoryView/AnalyticsView/SourcesView accept composite
data props (fixture default); SectionOverlay forwards overlay data; page.tsx adds
useEstimatePlacementHistory/useSalesVsListings/useEstimateSellTimeSensitivity and
feeds mapped data. FE-1 main dashboard untouched.

- History: house sales (placement-history); ДКП KPI/header (street-deals +
  sales-vs-listings); per-deal rows with REAL addr/date/listing-source/discount.
- Analytics: KPIs (экспозиция/торг/доля снятых), 4 sell-time tiers, price-history
  polylines computed from year×source, detail scatter.
- Sources: ad rows from analogs (real source/distance/url via safeUrl), deal rows
  from actual_deals (real source/tier/date), market KPIs.
- Un-hardcoded fabricated cells: DKP addr/date/source, deal date, deals footer count.
- FE-approx (TODO BE-1 #2043): CV, per-source counts, days_on_market->listing_date.

Verified: next build green (/v2 37.8 kB); tsx harness ran the 3 overlay mappers vs
real estimate 701795d8 (houseSales/KPIs/sellTime/priceHistory/scatter/ad+deal rows
correct). code-reviewer APPROVE after honesty fixes.
2026-06-28 15:46:07 +03:00

162 lines
4.5 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";
// Overlay wrapper for the nav-driven section panels of the /trade-in/v2
// "МЕРА Оценка" design. Faithful port of the design overlay container
// (МЕРА Оценка.dc.html lines 443-453 + 615-616): a glass/blur absolute layer
// with HUD corner brackets, a header (section number + title + "← К ОЦЕНКЕ"
// button) and a scrollable body that swaps the active view.
import { tokens } from "./tokens";
import { overlayNums, overlayTitles } from "./fixtures";
import HistoryView from "./HistoryView";
import SourcesView from "./SourcesView";
import AnalyticsView from "./AnalyticsView";
import { CacheView } from "./CacheView";
import type { HistoryData, SourcesData } from "./mappers";
import type { Analytics } from "./types";
interface SectionOverlayProps {
active: number;
onClose: () => void;
onNavigate: (i: number) => void;
// Mapped overlay data, fed by page.tsx (mapHistory / mapSources / mapAnalytics).
// Optional so unwired/storybook usage falls back to each view's fixture default.
history?: HistoryData;
sources?: SourcesData;
analytics?: Analytics;
}
export default function SectionOverlay({
active,
onClose,
onNavigate,
history,
sources,
analytics,
}: SectionOverlayProps) {
return (
<div
style={{
position: "absolute",
left: 28,
right: 28,
top: 80,
bottom: 30,
zIndex: 30,
display: "flex",
flexDirection: "column",
background:
"linear-gradient(180deg,rgba(244,248,252,.985),rgba(235,242,250,.985))",
backdropFilter: "blur(12px)",
border: `1px solid ${tokens.line3}`,
borderRadius: 8,
boxShadow: "0 22px 60px rgba(40,80,130,.18)",
overflow: "hidden",
fontFamily: tokens.font.sans,
}}
>
<style>{`
.tiv2-so-back { transition: all .15s; }
.tiv2-so-back:hover { border-color: ${tokens.accent}; color: ${tokens.accent}; }
`}</style>
{/* HUD corner brackets */}
<div
style={{
position: "absolute",
left: 12,
top: 12,
width: 15,
height: 15,
borderLeft: `1.5px solid ${tokens.accent}`,
borderTop: `1.5px solid ${tokens.accent}`,
pointerEvents: "none",
}}
/>
<div
style={{
position: "absolute",
right: 12,
bottom: 12,
width: 15,
height: 15,
borderRight: `1.5px solid ${tokens.accent}`,
borderBottom: `1.5px solid ${tokens.accent}`,
pointerEvents: "none",
}}
/>
{/* overlay header */}
<div
style={{
flex: "0 0 auto",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: "16px 24px",
borderBottom: "1px solid #cdd9e6",
}}
>
<div style={{ display: "flex", alignItems: "baseline", gap: 11 }}>
<span
style={{
fontFamily: tokens.font.mono,
fontSize: 15,
color: tokens.accent,
}}
>
{overlayNums[active]}
</span>
<span
style={{
fontSize: 14,
fontWeight: 600,
letterSpacing: 2.5,
color: tokens.ink2,
}}
>
{overlayTitles[active]}
</span>
</div>
<div
onClick={onClose}
className="tiv2-so-back"
style={{
display: "flex",
alignItems: "center",
gap: 8,
cursor: "pointer",
border: `1px solid ${tokens.line}`,
borderRadius: 6,
padding: "6px 12px",
background: tokens.surface.w60,
}}
>
<span style={{ fontSize: 13 }}></span>
<span
style={{ fontSize: 10, letterSpacing: 1.5, color: tokens.muted }}
>
К ОЦЕНКЕ
</span>
</div>
</div>
{/* overlay body */}
<div
style={{
flex: 1,
minHeight: 0,
overflowY: "auto",
padding: "22px 24px 26px",
}}
>
{active === 1 && <HistoryView data={history} />}
{active === 2 && <SourcesView data={sources} />}
{active === 3 && (
<AnalyticsView data={analytics} onNavigate={onNavigate} />
)}
{active === 4 && <CacheView />}
</div>
</div>
);
}