fix(tradein/v2): гонка при клике по строке «Предыдущие оценки» — отчёт не загружался #2428

Merged
lekss361 merged 4 commits from fix/tradein-cacheview-restore-race into main 2026-07-04 14:47:02 +00:00

4 commits

Author SHA1 Message Date
bot-backend
62e2a7ba85 style(tradein/v2): prettier (репозиторный pre-commit не покрывает tradein-mvp/frontend)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 10s
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 / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m13s
2026-07-04 17:44:48 +03:00
bot-backend
10f4f6adac fix(tradein/v2): 3-state pendingRestoreId sentinel — null и undefined разные вещи
Живая проверка в браузере (клик по строке "Предыдущие оценки" на проде)
подтвердила: router.replace() — асинхронный client-nav (RSC round-trip),
window.location.search не обновляется синхронно, а readUrlId() читает
window.location.search напрямую (useSearchParams намеренно не используется —
ломает next build через Suspense). Единственный надёжный источник urlId
в синхронном ре-рендере — override-state, выставленный в том же тике,
что и клик.

Предыдущая версия (`pendingRestoreId ?? readUrlId()`) использовала null
для двух разных смыслов сразу: "нет override" и "принудительно пусто".
handleNew() выставлял null именно во втором смысле (сброс после 404),
но ?? тут же трактовал null как "нет override" и падал обратно на
readUrlId() — который на тот момент ещё возвращал старый плохой id
(router.replace("/v2") ещё не успел домотать). Итог: "НОВАЯ ОЦЕНКА"
после битой ссылки могла не сбрасывать ошибку.

Три состояния убирают двусмысленность: undefined = нет override (readUrlId
рулит), null = принудительно пусто, string = override на конкретный id.
2026-07-04 17:43:57 +03:00
bot-backend
d3d8d15f67 fix(tradein/v2): handleNew() тоже должен сбрасывать pendingRestoreId
Иначе клик "НОВАЯ ОЦЕНКА" после ошибки восстановления (напр. 404 на битый history-id) навсегда
залипает на старом pendingRestoreId — единственный effect, который его чистит, требует
restored.data, которого в error-состоянии не будет никогда. Только F5 разлипал бы.
2026-07-04 17:25:18 +03:00
bot-backend
535c2d3855 fix(tradein/v2): гонка при клике по строке "Предыдущие оценки" — оценка не загружалась
router.replace(`/v2?id=`) — асинхронный soft-nav, а setNav(0) в том же тике вызывает
синхронный re-render ДО того как window.location реально обновится → readUrlId() читает
устаревшее значение навсегда (никто больше не форсит re-render). Добавлен pendingRestoreId —
синхронный override, аналогично тому как freshResult уже обходит эту же гонку для
post-submit пути.
2026-07-04 17:05:51 +03:00