feat(trade-in): TI-3 frontend /trade-in page + 5 components + hooks #317
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#317
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/ti-3-frontend"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Wave B issue #314 TradeIn MVP. Frontend
/trade-inpage интегрируется с mock backend (TI-1 PR #316).Files (8 NEW)
frontend/src/types/trade-in.ts—TradeInEstimateInput,AggregatedEstimate,AnalogLot,HouseType,RepairState,ConfidenceLevelfrontend/src/lib/trade-in-api.ts— TanStack QueryuseEstimateMutation()+useEstimate(id)frontend/src/components/trade-in/EstimateForm.tsx— 9-field controlled form, client validation, spinnerfrontend/src/components/trade-in/EstimateResult.tsx— hero card + 4 sections + disabled PDF button (TI-2 placeholder)frontend/src/components/trade-in/AnalogsTable.tsx— sortable table,safeImgSrcXSS guardfrontend/src/components/trade-in/PriceRangeBar.tsx— gradient bar with median markerfrontend/src/components/trade-in/EstimateProgress.tsx— spinner indicatorfrontend/src/app/trade-in/page.tsx— route page, 2-col grid, mobile stack, URL persistence?id={uuid}Constraints respected
tsc --noEmit)frontend/src/app/trade-in/page.tsx)useEffectдля HTTP)safeImgSrcдляphoto_urlв<AnalogsTable/>Test plan
/trade-in— форма рендерится{address: "ул. Малышева 10", area: 42, rooms: 1, floor: 5, total_floors: 17}→ result card с price + range bar + analogs + actual_deals tables?id={uuid}— reload восстанавливает resultPart of issue #314 (Wave B). Depends on TI-1 #316 (merged). Next: TI-2 PDF (Wave C).
Deep review — verdict: APPROVE (с замечаниями для TI-4).
Что проверено
trade-in.ts) — match Pydantic schemas из TI-1 #316 (Literalconfidence/house_type/repair_state, area_m2 float, optional fields). OK.useEstimateMutationPOST/api/v1/trade-in/estimate+useEstimate(id)GET сenabledguard иstaleTime: 10m— корректно.safeImgSrc: allowlisthttps:///http:////prefix, fallbacknull(placeholder SVG) — XSS-безопасно, паттерн совпадает сrenderMarkdown.ts:safeUrl. OK.EstimateForm: 9 полей, client validation (area 10<x<500 совпадает сgt=10, lt=500, floor≤total_floors cross-field, year_built 1800-2100). Submit gating черезcanSubmit. OK.EstimateResult: hero + 4 секции + disabled PDF button сtitle="Генерация PDF появится в TI-2". OK.@media (max-width: 767px)stack. OK.router.replace(?id=...)после submit,useEstimateId()читает изwindow.location.search— restore работает.🟡 MINOR / TI-4 follow-ups (не блокирующее)
useEstimate(urlEstimateId)— сейчас raw param идёт в API call. Mock backend валидирует UUID через Pydantic (вернёт 422), но defense-in-depth: добавить regex/^[0-9a-f-]{36}$/iперед использованием.#1a1d23,#1d4ed8,#5b6066, etc.) — нарушает.claude/rules/ui-ux.md(design tokens HARD list). Должно бытьvar(--accent)/var(--fg-primary). ~80 occurrences по 8 файлам.🏠вEmptyState(page.tsx:174) — рулом запрещено, заменить на Lucide<Home/>.<Section>/<KpiCard>не переиспользованы —EstimateResult.tsxгородит inlineCard/SectionHeader. Поui-ux.md: «Заворачивать каждый блок в<Section>».import { ChevronDown } from "lucide-react". Функционально OK, конвенционально — нет./trade-inдостижим только прямым URL. Добавить пункт в sidebar/menu в отдельном PR.roomsselect offers 0..5+ но backend принимает 0..10 — 6-10к недоступны из UI (scope MVP limitation, отметить в TI-4).useEstimateIdreadswindow.location.searchнапрямую — не реактивно приrouter.replace, но сейчас работает черезfreshResultgate. Переделать наuseSearchParams()для consistency.Cross-file impact
schemas/trade_in.py,api/v1/trade_in.py,data/sql/115_trade_in_estimates.sql) — types matches 1:1. ✅apiFetchsignature matches (<T>(path, init)). ✅fixes/Fix_TradeIn_MVP_TI3_Frontend_May17.mdсуществует. ✅Smoke checklist (post-deploy):
/trade-inрендерится, форма видна{address: "ул. Малышева 10", area: 42, rooms: 1, floor: 5, total_floors: 17}→ result card?id={uuid}— reload восстанавливает resultWave C (TI-2 PDF) разблокирован. Inline-hex / Lucide /
<Section>cleanup — отдельным PR в рамках TI-4.Мержу через squash.