"use client"; import { useEffect } from "react"; import { useParcelAnalyzeQuery } from "@/lib/site-finder-api"; import type { ParcelAnalysis } from "@/types/site-finder"; import type { CompareColumn } from "./CompareTable"; interface Props { cad: string; onResult: (col: CompareColumn) => void; } /** * Headless loader: runs `useParcelAnalyzeQuery` for a single cad and lifts the * flattened metrics up to the compare page via `onResult`. Rendered one-per-cad * inside a `.map`, so each instance owns a stable hook order (rules-of-hooks * safe) — the page itself never calls the hook in a loop. Reuses the exact same * analyze endpoint + 202-poll logic as the single-parcel analysis page, so a * parcel already analyzed there is served warm from the shared query cache. * * Renders nothing; `useEffect` here only mirrors query state into parent state, * it does not perform HTTP (the hook does, via TanStack Query). */ export function ParcelCompareLoader({ cad, onResult }: Props) { const { data, isLoading, error } = useParcelAnalyzeQuery(cad); useEffect(() => { if (isLoading) { onResult({ cad, status: "loading" }); return; } if (error || !data) { onResult({ cad, status: "error", errorMsg: error instanceof Error ? error.message : "Ошибка загрузки анализа", }); return; } // ParcelAnalyzeResponse is a structural subset of ParcelAnalysis (same // /analyze endpoint); the richer fields (velocity, gate_verdict, confidence, // success_recommendation) are optional and may be absent on thin parcels. const a = data as unknown as ParcelAnalysis; onResult({ cad, status: "ready", districtName: a.district?.district_name ?? null, verdictLabel: a.gate_verdict?.verdict_label ?? null, score: a.score ?? null, scoreLabel: a.score_label ?? null, velocityScore: a.velocity?.velocity_score ?? null, // SF#17 / issue #1422: explicit false (конкуренты есть, данных Objective // нет → velocity_score=0 — sentinel) гасит ячейку и исключает колонку из // подсветки «лучшее». undefined/null трактуется как «данные есть». velocityDataAvailable: a.velocity?.velocity_data_available ?? null, medianPricePerM2: a.district?.median_price_per_m2 ?? null, pipeline24mo: a.pipeline_24mo?.flats_total ?? null, confidenceLabel: a.confidence_label ?? null, confidenceValue: a.confidence ?? null, }); }, [cad, data, isLoading, error, onResult]); return null; }