From 55e0d9e174f3a4555e85791b0762fe4062526804 Mon Sep 17 00:00:00 2001 From: bot-backend Date: Wed, 16 Sep 2026 19:53:52 +0300 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20=D0=BA=D0=B0=D1=80=D1=82=D0=BE?= =?UTF-8?q?=D1=87=D0=BA=D0=B0=20=C2=AB=D0=BD=D0=B5=20=D1=85=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B0=D0=B5=D1=82=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= =?UTF-8?q?=C2=BB=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D1=82=D0=B8=D1=87=D0=BD=D0=BE=D0=B9=20=D0=B7=D0=B0=D0=B3?= =?UTF-8?q?=D0=BB=D1=83=D1=88=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Состояние уже существовало и подключалось по insufficient_data, но панель была без пропсов: один и тот же текст на любой случай, без адреса и без следующего шага. После бэкендной правки это состояние станет заметно чаще (общегородской ДКП-коридор перестаёт становиться ценой), и тестировщик упрётся именно в него. Теперь карточка показывает объяснение, которое прислал сам бэкенд (confidence_explanation), найденный геокодером адрес — он заполнен даже когда цены нет — и кнопку уточнить адрес. Предикат вынесен в именованную функцию isInsufficientEstimate и опирается на серверный флаг insufficient_data, а не на price === 0: флаг определён как «ответ успешный, но median_price_rub <= 0», то есть ровно нужное состояние, и он не путается с ещё не загруженной оценкой. --- tradein-mvp/frontend/src/app/v2/page.tsx | 63 +++++++++++++++++++++--- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/tradein-mvp/frontend/src/app/v2/page.tsx b/tradein-mvp/frontend/src/app/v2/page.tsx index 1bc3617e..4917d454 100644 --- a/tradein-mvp/frontend/src/app/v2/page.tsx +++ b/tradein-mvp/frontend/src/app/v2/page.tsx @@ -289,12 +289,63 @@ function EmptyResultPanel() { ); } -function InsufficientPanel() { +// Named predicate for the "no price at all" state — deliberately NOT +// `!estimate.median_price_rub` (a bare zero/price check): that would also +// misfire on a still-loading `estimate` or on legitimate falsy-but-present +// values. The one reliable signal is the backend's own `insufficient_data` +// flag, which is defined (see AggregatedEstimate in types/trade-in.ts / +// backend @computed_field) to mean "this IS a successful response, but +// median_price_rub <= 0 — there was nothing to price with". Only fires on a +// present, successfully-returned estimate. +function isInsufficientEstimate(estimate: AggregatedEstimate | null): boolean { + return estimate != null && estimate.insufficient_data === true; +} + +// Карточка состояния «цены нет». Показывает объяснение, которое прислал сам +// бэкенд (confidence_explanation — текст написан специально под это состояние), +// и адрес, который геокодер всё-таки нашёл: target_address и координаты +// заполнены даже когда цены нет. Плюс понятное следующее действие. +// Цена, диапазон, «−N% к рынку» и аналоги здесь не рендерятся вовсе — на +// проводе они 0/null, и показать их значило бы выдать сломанный экран «0 ₽» +// вместо честного «дом нашли, цену — нет». +function InsufficientPanel({ + estimate, + onNew, +}: { + estimate: AggregatedEstimate; + onNew: () => void; +}) { return ( + title="НЕ ХВАТАЕТ ДАННЫХ ДЛЯ ОЦЕНКИ" + body={ + estimate.confidence_explanation ?? + "По этому адресу не нашлось достаточного числа аналогов и сделок для надёжной оценки. Уточните адрес или параметры квартиры." + } + > + {estimate.target_address && ( +
+ Найденный адрес: {estimate.target_address} +
+ )} +
+ +
+
); } @@ -588,7 +639,7 @@ export default function TradeInV2Page() { // existing Серов estimates were already stuck in this state). See // mapResultPanel's `dealsOnlyPrice` for how the result panel discloses the // deals-only source instead of mislabelling it as "по объявлениям". - const insufficient = estimate != null && estimate.insufficient_data; + const insufficient = isInsufficientEstimate(estimate); const apiError = mutation.error?.message ?? null; // M4: estimate-dependent meta/controls (the «ДЕЙСТВИТЕЛЕН ДО» validity line, // «КАК РАССЧИТАНО», PDF) only render once there is a real, sufficient estimate. @@ -830,7 +881,7 @@ export default function TradeInV2Page() { ); } else if (estimate && insufficient) { - middleContent = ; + middleContent = ; } else { middleContent = ; } -- 2.45.3