diff --git a/tradein-mvp/frontend/src/app/v2/page.tsx b/tradein-mvp/frontend/src/app/v2/page.tsx index 87136092..cd14c8f9 100644 --- a/tradein-mvp/frontend/src/app/v2/page.tsx +++ b/tradein-mvp/frontend/src/app/v2/page.tsx @@ -10,7 +10,7 @@ // a pending or errored street-deals / analytics call degrades its section to a // fallback inside the mapper instead of blanking the page. -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import type { CSSProperties, ReactNode } from "react"; import { useRouter } from "next/navigation"; import { useQueryClient } from "@tanstack/react-query"; @@ -247,8 +247,10 @@ function PlaceholderPanel({ fontFamily: tokens.font.sans, }} > -
(preflight not loaded → reset UA margin). */} +

{title} -

+
-
(preflight not loaded → reset UA margin). */} +

СВОДКА ОБЪЕКТА -

+
Появится после оценки квартиры.
@@ -382,6 +386,13 @@ export default function TradeInV2Page() { const [nav, setNav] = useState(0); const [drawerOpen, setDrawerOpen] = useState(false); + + // #2264 C7: after a fresh estimate lands we move focus onto the result region + // (a labelled, tabIndex={-1} container in ResultPanel) so keyboard/SR users + // don't get dumped back on . `focusedEstimateRef` guards against + // re-focusing on unrelated re-renders / sub-hook updates. + const resultRegionRef = useRef(null); + const focusedEstimateRef = useRef(null); // Locally-held just-computed estimate (so we render instantly after submit // without a round-trip through the restore query). const [freshResult, setFreshResult] = useState( @@ -498,6 +509,23 @@ export default function TradeInV2Page() { [estimate, analyticsData, streetDealsData], ); + // Move focus to the result region once a user-submitted estimate is rendered. + // Gated on `freshResult` (a submit, not a restore-by-id cold load, which must + // not steal focus) and on the result actually being on screen (!loading + + // resultPanelData). Fires once per distinct estimate id. + useEffect(() => { + if ( + freshResult && + !loading && + hasEstimate && + resultPanelData && + focusedEstimateRef.current !== freshResult.estimate_id + ) { + focusedEstimateRef.current = freshResult.estimate_id; + resultRegionRef.current?.focus(); + } + }, [freshResult, loading, hasEstimate, resultPanelData]); + // ── Overlay (section) mapped data. Computed unconditionally: the mappers // accept nulls and degrade per-section, so an overlay opened before/without // an estimate shows an honest empty shell — never the design fixtures as if @@ -604,7 +632,13 @@ export default function TradeInV2Page() { /> ); } else if (estimate && !insufficient && resultPanelData) { - middleContent = ; + middleContent = ( + + ); } else if (estimate && insufficient) { middleContent = ; } else { @@ -655,6 +689,25 @@ export default function TradeInV2Page() { > + {/* #2264 C5: the page's single visible "title" is the SVG logo in TopNav, + so give the document a real, visually-hidden

(page-has-heading-one + + a top of the heading order for the overlay/panel

s). */} +

+ Мера — оценка квартиры +

+ {/* Polite, visually-hidden status announcer for SR users. */}
- +
(which, with preflight + // off, would need a UA-chrome reset and risk the row's exact box + // geometry / negative-margin hover bleed). Opens the methodology drawer. + role="button" + tabIndex={0} className="hero-coef-row" onClick={onOpenInfo} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + onOpenInfo(); + } + }} + aria-label="Пояснение к расчёту коэффициента локации" style={{ display: "flex", alignItems: "center", @@ -431,6 +444,7 @@ export default function HeroBar({ color: tokens.accent, fontWeight: 600, }} + aria-hidden="true" > ? @@ -451,7 +465,7 @@ export default function HeroBar({ color: tokens.accent, }} > - + diff --git a/tradein-mvp/frontend/src/components/trade-in/v2/ObjectSummary.tsx b/tradein-mvp/frontend/src/components/trade-in/v2/ObjectSummary.tsx index 90489be3..39d3949d 100644 --- a/tradein-mvp/frontend/src/components/trade-in/v2/ObjectSummary.tsx +++ b/tradein-mvp/frontend/src/components/trade-in/v2/ObjectSummary.tsx @@ -95,9 +95,18 @@ export function ObjectSummary({ > 03 - + {/* Panel heading — real

(preflight not loaded → reset UA margin + inline; visuals unchanged). */} +

СВОДКА ОБЪЕКТА - +

- +