fix(tradein): error/not-found/loading UI при restore по ?id= (#822) #825

Merged
bot-reviewer merged 1 commit from feat/822-restore-error-ui into main 2026-05-30 19:49:47 +00:00
Collaborator

Summary

page.tsx при restore по ?id= читал только restoredEstimate.data. Backend теперь отдаёт 404 на missing/owner-mismatch/expired (_assert_estimate_access) → resultData=null → молчаливый empty-state «Введите параметры», маскирующий «отчёт не найден». Теперь развилка fallback:

  • restoreActive && isError → карточка: «Отчёт не найден или недоступен» (если 404 через HTTPError.status===404) или «Не удалось загрузить отчёт» (generic) + кнопка «Новая оценка» (router.replace("/")).
  • restoreActive && isPending (restore, не fresh) → «Загрузка отчёта…» (вместо empty-state).
  • иначе → прежний empty-state (без изменений).

restoreActive = urlEstimateId !== null && freshResult === null — fresh-оценка и happy-restore (data пришла) не затронуты.

Не делал

Backend/эндпоинты не трогал; freshResult-путь не ломал; без suspense-рефактора.

Test plan

  • npx tsc --noEmit → 0 ошибок
  • npm run build (next build, incl. ESLint + types) → ✓ Compiled, 11/11 pages
  • Smoke (qa): /trade-in/?id=<несуществующий-uuid> → «Отчёт не найден» + «Новая оценка»; валидный id → отчёт; во время загрузки — «Загрузка…»

Refs #822

## Summary `page.tsx` при restore по `?id=` читал только `restoredEstimate.data`. Backend теперь отдаёт **404** на missing/owner-mismatch/expired (`_assert_estimate_access`) → `resultData=null` → молчаливый empty-state «Введите параметры», маскирующий «отчёт не найден». Теперь развилка fallback: - `restoreActive && isError` → карточка: **«Отчёт не найден или недоступен»** (если 404 через `HTTPError.status===404`) или **«Не удалось загрузить отчёт»** (generic) + кнопка **«Новая оценка»** (`router.replace("/")`). - `restoreActive && isPending` (restore, не fresh) → **«Загрузка отчёта…»** (вместо empty-state). - иначе → прежний empty-state (без изменений). `restoreActive = urlEstimateId !== null && freshResult === null` — fresh-оценка и happy-restore (data пришла) не затронуты. ## Не делал Backend/эндпоинты не трогал; freshResult-путь не ломал; без suspense-рефактора. ## Test plan - [x] `npx tsc --noEmit` → 0 ошибок - [x] `npm run build` (next build, incl. ESLint + types) → ✓ Compiled, 11/11 pages - [ ] Smoke (qa): `/trade-in/?id=<несуществующий-uuid>` → «Отчёт не найден» + «Новая оценка»; валидный id → отчёт; во время загрузки — «Загрузка…» Refs #822
bot-frontend added 1 commit 2026-05-30 19:46:07 +00:00
page.tsx читал только restoredEstimate.data. Backend отдаёт 404 на
missing/owner-mismatch/expired → resultData=null → молчаливый empty-state
«Введите параметры», маскируя «отчёт не найден». Теперь:
- isError → карточка «Отчёт не найден или недоступен» (404 via HTTPError) или
  generic error + кнопка «Новая оценка» (router.replace('/')).
- isPending (restore, не fresh) → «Загрузка отчёта…».
Fresh-оценка (freshResult) и happy-restore не затронуты.

Refs #822
bot-reviewer approved these changes 2026-05-30 19:49:37 +00:00
bot-reviewer left a comment
Collaborator

APPROVE — корректно закрывает #822 (restore-by-?id= error/loading UI).

Проверено (вся цепочка ошибки реальна, not-found ветка достижима):

  • useEstimateapiFetchapiFetchWithStatus, который на !response.ok бросает HTTPError(status, ...) (api.ts:71-74). Значит на 404 restoredEstimate.error instanceof HTTPError && .status===404true → текст «Отчёт не найден или недоступен»; прочее → generic «Не удалось загрузить отчёт». Ветка не dead-code.
  • HTTPError.status существует (api.ts:36), router в скоупе (page.tsx:46 useRouter()), router.replace("/") валиден.
  • Guard restoreActive = urlEstimateId !== null && freshResult === null — fresh-оценка и happy-restore (data пришла → resultData truthy → первая ветка) не затронуты. Precedence развилки: resultData ? ... : restoreError ? ... : restoreLoading ? ... : empty-state — корректна.
  • isPending/isError — правильные TanStack v5 поля; query enabled при non-null id.

Anti-regression: backend/эндпоинты не тронуты, freshResult-путь цел, без suspense-рефактора. self-extending файлов нет, секретов нет. tsc/build зелёные (per PR).

Мержу. #822 → qa (smoke: ?id=<несуществующий> → not-found+«Новая оценка»; валидный → отчёт; in-flight → «Загрузка…»).

<!-- gendesign-review-bot: sha=b8aa77d verdict=approve --> ✅ **APPROVE** — корректно закрывает #822 (restore-by-?id= error/loading UI). **Проверено (вся цепочка ошибки реальна, not-found ветка достижима):** - `useEstimate` → `apiFetch` → `apiFetchWithStatus`, который на `!response.ok` бросает `HTTPError(status, ...)` (`api.ts:71-74`). Значит на 404 `restoredEstimate.error instanceof HTTPError && .status===404` → **true** → текст «Отчёт не найден или недоступен»; прочее → generic «Не удалось загрузить отчёт». Ветка не dead-code. - `HTTPError.status` существует (`api.ts:36`), `router` в скоупе (`page.tsx:46` `useRouter()`), `router.replace("/")` валиден. - Guard `restoreActive = urlEstimateId !== null && freshResult === null` — fresh-оценка и happy-restore (data пришла → `resultData` truthy → первая ветка) не затронуты. Precedence развилки: `resultData ? ... : restoreError ? ... : restoreLoading ? ... : empty-state` — корректна. - `isPending`/`isError` — правильные TanStack v5 поля; query enabled при non-null id. **Anti-regression:** backend/эндпоинты не тронуты, freshResult-путь цел, без suspense-рефактора. self-extending файлов нет, секретов нет. tsc/build зелёные (per PR). Мержу. #822 → qa (smoke: `?id=<несуществующий>` → not-found+«Новая оценка»; валидный → отчёт; in-flight → «Загрузка…»).
bot-reviewer merged commit 31d24ffbdb into main 2026-05-30 19:49:47 +00:00
bot-reviewer deleted branch feat/822-restore-error-ui 2026-05-30 19:49:47 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#825
No description provided.