fix(tradein): error/not-found/loading UI при restore по ?id=
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
This commit is contained in:
parent
1a733302c2
commit
b8aa77dbe2
1 changed files with 41 additions and 0 deletions
|
|
@ -12,6 +12,7 @@ import { useQueryClient } from "@tanstack/react-query";
|
||||||
import "@/components/trade-in/trade-in.css";
|
import "@/components/trade-in/trade-in.css";
|
||||||
import type { AggregatedEstimate, TradeInEstimateInput, HouseType, RepairState } from "@/types/trade-in";
|
import type { AggregatedEstimate, TradeInEstimateInput, HouseType, RepairState } from "@/types/trade-in";
|
||||||
import { useEstimateMutation, useEstimate } from "@/lib/trade-in-api";
|
import { useEstimateMutation, useEstimate } from "@/lib/trade-in-api";
|
||||||
|
import { HTTPError } from "@/lib/api";
|
||||||
import { EstimateForm } from "@/components/trade-in/EstimateForm";
|
import { EstimateForm } from "@/components/trade-in/EstimateForm";
|
||||||
import { Topbar } from "@/components/trade-in/Topbar";
|
import { Topbar } from "@/components/trade-in/Topbar";
|
||||||
import { SourcesProgress } from "@/components/trade-in/SourcesProgress";
|
import { SourcesProgress } from "@/components/trade-in/SourcesProgress";
|
||||||
|
|
@ -127,6 +128,16 @@ export default function TradeInPage() {
|
||||||
}
|
}
|
||||||
: null);
|
: null);
|
||||||
|
|
||||||
|
// #822: restore по ?id= — отражаем загрузку/ошибку вместо молчаливого
|
||||||
|
// empty-state. Backend отдаёт 404 на missing/owner-mismatch/expired.
|
||||||
|
const restoreActive = urlEstimateId !== null && freshResult === null;
|
||||||
|
const restoreError = restoreActive && restoredEstimate.isError;
|
||||||
|
const restoreLoading = restoreActive && restoredEstimate.isPending;
|
||||||
|
const restoreNotFound =
|
||||||
|
restoreError &&
|
||||||
|
restoredEstimate.error instanceof HTTPError &&
|
||||||
|
restoredEstimate.error.status === 404;
|
||||||
|
|
||||||
// Надёжный input для «Что-если»: предпочитаем поля самой оценки (есть и при
|
// Надёжный input для «Что-если»: предпочитаем поля самой оценки (есть и при
|
||||||
// restore по ?id=, где resultData.input — stub с нулями), откатываемся на input.
|
// restore по ?id=, где resultData.input — stub с нулями), откатываемся на input.
|
||||||
// address/rooms обязательны для payload — берём из estimate, иначе из input.
|
// address/rooms обязательны для payload — берём из estimate, иначе из input.
|
||||||
|
|
@ -275,6 +286,36 @@ export default function TradeInPage() {
|
||||||
<ExposureCard estimate={resultData.estimate} />
|
<ExposureCard estimate={resultData.estimate} />
|
||||||
<OfferCard estimate={resultData.estimate} brandSlug={activeBrandSlug} />
|
<OfferCard estimate={resultData.estimate} brandSlug={activeBrandSlug} />
|
||||||
</>
|
</>
|
||||||
|
) : restoreError ? (
|
||||||
|
<article className="card">
|
||||||
|
<div className="card-body" style={{ padding: "48px 24px", textAlign: "center" }}>
|
||||||
|
<h3 style={{ fontSize: 16, fontWeight: 600, marginBottom: 6 }}>
|
||||||
|
{restoreNotFound
|
||||||
|
? "Отчёт не найден или недоступен"
|
||||||
|
: "Не удалось загрузить отчёт"}
|
||||||
|
</h3>
|
||||||
|
<p style={{ color: "var(--muted)", fontSize: 14, marginBottom: 16 }}>
|
||||||
|
{restoreNotFound
|
||||||
|
? "Ссылка устарела, отчёт удалён или у вас нет к нему доступа."
|
||||||
|
: "Произошла ошибка при загрузке отчёта. Попробуйте ещё раз."}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-primary"
|
||||||
|
onClick={() => router.replace("/")}
|
||||||
|
>
|
||||||
|
Новая оценка
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
) : restoreLoading ? (
|
||||||
|
<article className="card">
|
||||||
|
<div className="card-body" style={{ padding: "48px 24px", textAlign: "center" }}>
|
||||||
|
<p style={{ color: "var(--muted)", fontSize: 14 }}>
|
||||||
|
Загрузка отчёта…
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
) : (
|
) : (
|
||||||
<article className="card">
|
<article className="card">
|
||||||
<div className="card-body" style={{ padding: "48px 24px", textAlign: "center" }}>
|
<div className="card-body" style={{ padding: "48px 24px", textAlign: "center" }}>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue