fix(tradein/v2): audit #2081 residual — 404 short-circuit, disabled-tab tooltips, stale hex token, ДКП decode
All checks were successful
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m5s
All checks were successful
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m5s
L3: sibling dashboard hooks (analytics/location-coef/placement-history/ sell-time) now short-circuit once restore-by-id confirms 404, instead of each firing their own doomed request against the same dead estimate id. L5: dimmed non-interactive user-menu items (Профиль/Настройки/Помощь) get a hover title explaining why they're disabled. L7: TopNav logo subtitle used a stale literal #6f8195 predating the C1 contrast sweep; now references tokens.muted. M12: HistoryView's "ДКП-сделки" card gets the same one-time ДКП decode convention ObjectSummary already uses. H2/M8/M9/M10/M11 re-verified live/by-code — already correct, no changes needed (see issue comment). L4 (HistoryView outlier clamp) and L6 (blueprint-grid background-image) left as follow-ups (mapper-level change / no contrast payoff respectively). Refs #2081
This commit is contained in:
parent
2538fc02e2
commit
08cedad1bf
3 changed files with 50 additions and 11 deletions
|
|
@ -439,9 +439,24 @@ export default function TradeInV2Page() {
|
||||||
// Skip the restore fetch once we already hold a fresh result.
|
// Skip the restore fetch once we already hold a fresh result.
|
||||||
const restored = useEstimate(freshResult === null ? urlId : null);
|
const restored = useEstimate(freshResult === null ? urlId : null);
|
||||||
|
|
||||||
|
// L3 — once the restore-by-id fetch has confirmed the estimate does not
|
||||||
|
// exist (404), `currentEstimateId` below drops to null so the sibling
|
||||||
|
// dashboard hooks (analytics/location-coef/placement-history/sell-time,
|
||||||
|
// all `enabled: estimate_id !== null`) don't each fire their own doomed
|
||||||
|
// request against the same dead id. Hoisted above the sub-hooks (was
|
||||||
|
// computed further down, after they'd already fired on the stale id).
|
||||||
|
const restoreActive = urlId !== null && freshResult === null;
|
||||||
|
const restoreError = restoreActive && restored.isError;
|
||||||
|
const restoreNotFound =
|
||||||
|
restoreError &&
|
||||||
|
restored.error instanceof HTTPError &&
|
||||||
|
restored.error.status === 404;
|
||||||
|
|
||||||
const estimate: AggregatedEstimate | null =
|
const estimate: AggregatedEstimate | null =
|
||||||
freshResult ?? restored.data ?? null;
|
freshResult ?? restored.data ?? null;
|
||||||
const currentEstimateId = freshResult?.estimate_id ?? urlId;
|
const currentEstimateId = restoreNotFound
|
||||||
|
? null
|
||||||
|
: (freshResult?.estimate_id ?? urlId);
|
||||||
|
|
||||||
// Per-user side data, independent of the current estimate. Both fail-soft
|
// Per-user side data, independent of the current estimate. Both fail-soft
|
||||||
// (retry:false): history feeds the «Предыдущие оценки» overlay (04), quota
|
// (retry:false): history feeds the «Предыдущие оценки» overlay (04), quota
|
||||||
|
|
@ -486,13 +501,7 @@ export default function TradeInV2Page() {
|
||||||
const sellTimeData = sellTime.data ?? null;
|
const sellTimeData = sellTime.data ?? null;
|
||||||
|
|
||||||
// ── Derived state flags ───────────────────────────────────────────────────
|
// ── Derived state flags ───────────────────────────────────────────────────
|
||||||
const restoreActive = urlId !== null && freshResult === null;
|
|
||||||
const restoreLoading = restoreActive && restored.isPending;
|
const restoreLoading = restoreActive && restored.isPending;
|
||||||
const restoreError = restoreActive && restored.isError;
|
|
||||||
const restoreNotFound =
|
|
||||||
restoreError &&
|
|
||||||
restored.error instanceof HTTPError &&
|
|
||||||
restored.error.status === 404;
|
|
||||||
|
|
||||||
const loading = mutation.isPending || restoreLoading;
|
const loading = mutation.isPending || restoreLoading;
|
||||||
const insufficient =
|
const insufficient =
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,19 @@ export default function HistoryView({
|
||||||
>
|
>
|
||||||
{data.dkpHeader.title}
|
{data.dkpHeader.title}
|
||||||
</div>
|
</div>
|
||||||
|
{/* M12 — расшифровка «ДКП» один раз на секцию, тем же lowercase
|
||||||
|
hint-стилем что ObjectSummary.rowHint() (fontSize 8/letterSpacing
|
||||||
|
0.2/muted3), а не uppercase ResultPanel §M8 стилем. */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: "8px",
|
||||||
|
letterSpacing: 0.2,
|
||||||
|
color: tokens.muted3,
|
||||||
|
marginTop: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
ДКП · договор купли-продажи
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,9 @@ export default function TopNav({
|
||||||
fontSize="27"
|
fontSize="27"
|
||||||
fontWeight="400"
|
fontWeight="400"
|
||||||
letterSpacing="11"
|
letterSpacing="11"
|
||||||
fill="#6f8195"
|
// L7 — stale literal from before the C1 contrast sweep darkened
|
||||||
|
// the muted scale; token keeps this logo subtitle in sync.
|
||||||
|
fill={tokens.muted}
|
||||||
>
|
>
|
||||||
ОЦЕНКА НЕДВИЖИМОСТИ
|
ОЦЕНКА НЕДВИЖИМОСТИ
|
||||||
</text>
|
</text>
|
||||||
|
|
@ -370,7 +372,14 @@ export default function TopNav({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={menuItemDisabledStyle} aria-disabled="true">
|
{/* L5 — `title` gives the dimmed/non-interactive item a hover
|
||||||
|
tooltip explaining WHY it's disabled, instead of a silent dead
|
||||||
|
row (mirrored on Настройки/Помощь below). */}
|
||||||
|
<div
|
||||||
|
style={menuItemDisabledStyle}
|
||||||
|
aria-disabled="true"
|
||||||
|
title="Раздел «Профиль» скоро появится"
|
||||||
|
>
|
||||||
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" aria-hidden="true">
|
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" aria-hidden="true">
|
||||||
<circle
|
<circle
|
||||||
cx="7.5"
|
cx="7.5"
|
||||||
|
|
@ -412,7 +421,11 @@ export default function TopNav({
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={menuItemDisabledStyle} aria-disabled="true">
|
<div
|
||||||
|
style={menuItemDisabledStyle}
|
||||||
|
aria-disabled="true"
|
||||||
|
title="Раздел «Настройки» скоро появится"
|
||||||
|
>
|
||||||
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" aria-hidden="true">
|
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" aria-hidden="true">
|
||||||
<circle
|
<circle
|
||||||
cx="7.5"
|
cx="7.5"
|
||||||
|
|
@ -430,7 +443,11 @@ export default function TopNav({
|
||||||
Настройки
|
Настройки
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={menuItemDisabledStyle} aria-disabled="true">
|
<div
|
||||||
|
style={menuItemDisabledStyle}
|
||||||
|
aria-disabled="true"
|
||||||
|
title="Раздел «Помощь» скоро появится"
|
||||||
|
>
|
||||||
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" aria-hidden="true">
|
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" aria-hidden="true">
|
||||||
<circle
|
<circle
|
||||||
cx="7.5"
|
cx="7.5"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue