"use client"; /** * Trade-In страница в стиле gendsgn.ru/tradein.html mockup. * С basePath=/trade-in user видит её на gendsgn.ru/trade-in/. * Использует CSS из /components/trade-in/trade-in.css. */ import { useState } from "react"; import { useRouter } from "next/navigation"; import "@/components/trade-in/trade-in.css"; import type { AggregatedEstimate, TradeInEstimateInput } from "@/types/trade-in"; import { useEstimateMutation, useEstimate } from "@/lib/trade-in-api"; import { EstimateForm } from "@/components/trade-in/EstimateForm"; import { Topbar } from "@/components/trade-in/Topbar"; import { SourcesProgress } from "@/components/trade-in/SourcesProgress"; import { HeroSummary } from "@/components/trade-in/HeroSummary"; import { IMVBenchmark } from "@/components/trade-in/IMVBenchmark"; import { HouseInfoCard } from "@/components/trade-in/HouseInfoCard"; import { PhotoUpload } from "@/components/trade-in/PhotoUpload"; import { ListingsCard } from "@/components/trade-in/ListingsCard"; import { DealsCard } from "@/components/trade-in/DealsCard"; import { OfferCard } from "@/components/trade-in/OfferCard"; import { TestPresets } from "@/components/trade-in/TestPresets"; import { useEstimateImvBenchmark, useEstimateHouses } from "@/lib/trade-in-api"; function useEstimateId() { if (typeof window === "undefined") return null; const params = new URLSearchParams(window.location.search); return params.get("id"); } export default function TradeInPage() { const router = useRouter(); const [freshResult, setFreshResult] = useState<{ estimate: AggregatedEstimate; input: TradeInEstimateInput; } | null>(null); const urlEstimateId = useEstimateId(); const restoredEstimate = useEstimate( freshResult === null ? urlEstimateId : null, ); const mutation = useEstimateMutation(); const currentEstimateId = freshResult?.estimate.estimate_id ?? urlEstimateId; const imvBenchmark = useEstimateImvBenchmark(currentEstimateId); const houses = useEstimateHouses(currentEstimateId); function handleSubmit(input: TradeInEstimateInput) { mutation.mutate(input, { onSuccess: (estimate) => { setFreshResult({ estimate, input }); // basePath auto-prefixes — passing "/" returns user to /trade-in/?id=... router.replace(`/?id=${estimate.estimate_id}`, { scroll: false }); }, }); } const apiError = mutation.error?.message ?? null; const resultData = freshResult ?? (restoredEstimate.data ? { estimate: restoredEstimate.data, input: { address: restoredEstimate.data.target_address ?? "—", area_m2: 0, rooms: restoredEstimate.data.analogs[0]?.rooms ?? 0, floor: 0, total_floors: 0, } as TradeInEstimateInput, } : null); const isPending = mutation.isPending; return ( <> Главная › Trade-In › Новая оценка Оценка квартиры на вторичке Агрегируем данные из 7 источников + аналоги в продаже + фактические сделки. Время сбора — 10–30 сек. Отчёт{" "} {resultData?.estimate.estimate_id.slice(0, 8) ?? "—"} Дата{" "} {new Date().toLocaleDateString("ru-RU", { day: "2-digit", month: "2-digit", year: "numeric", })} {resultData && ( Действителен до{" "} {new Date(resultData.estimate.expires_at).toLocaleDateString("ru-RU", { day: "2-digit", month: "2-digit", year: "numeric", })} )} {/* Sticky form left */} {/* Result column */} {/* Тестовые пресеты — показываем только когда нет результата */} {!resultData && !isPending && ( handleSubmit(data)} /> )} {resultData ? ( <> > ) : ( 🏠 Введите параметры квартиры Заполните форму слева или выберите тестовую квартиру выше. )} > ); }
Агрегируем данные из 7 источников + аналоги в продаже + фактические сделки. Время сбора — 10–30 сек.
Заполните форму слева или выберите тестовую квартиру выше.