70 lines
3.3 KiB
TypeScript
70 lines
3.3 KiB
TypeScript
"use client";
|
||
|
||
import { useQuery } from "@tanstack/react-query";
|
||
import type { FeatureCollection, MultiPolygon, Polygon } from "geojson";
|
||
|
||
import { apiFetch } from "@/lib/api";
|
||
|
||
/**
|
||
* Радиус поиска соседних зданий вокруг участка для 3D-сцены / 2D-плана §7
|
||
* («Размещение застройки»). Дефолт 300 м — согласован с бэком
|
||
* (GET /neighbor-buildings?radius_m=…, диапазон 50–1000). Держим отдельной
|
||
* константой, чтобы подпись и запрос не расходились.
|
||
*/
|
||
export const NEIGHBOR_BUILDINGS_RADIUS_M = 300;
|
||
|
||
/**
|
||
* properties одной соседней постройки. Форма — единственный источник истины
|
||
* бэкенд (parcels.py::get_parcel_neighbor_buildings): endpoint отдаёт plain
|
||
* GeoJSON FeatureCollection (handler-return `dict[str, Any]`, НЕ Pydantic-модель),
|
||
* поэтому в api-types.ts codegen'ом он не попадает — типизуем вручную, как и
|
||
* соседний `NeighborBuilding` в types/site-finder.ts.
|
||
*/
|
||
export interface NeighborBuildingProps {
|
||
cad_num: string | null;
|
||
/** Этажность НСПД (int) либо null, если не заполнена в кадастре. */
|
||
floors: number | null;
|
||
/** Высота = floors × 3 м (бэк), либо null при неизвестной этажности. */
|
||
height_m: number | null;
|
||
building_name: string | null;
|
||
year_built: number | null;
|
||
is_neighbor: true;
|
||
}
|
||
|
||
export interface NeighborBuildingsResponse extends FeatureCollection<
|
||
Polygon | MultiPolygon,
|
||
NeighborBuildingProps
|
||
> {
|
||
/** Число возвращённых фич (после cap на бэке). */
|
||
count: number;
|
||
/** Радиус, по которому реально искали (echo query-параметра). */
|
||
radius_m: number;
|
||
/** true, если в радиусе зданий было больше лимита (300) и выборку обрезали. */
|
||
truncated: boolean;
|
||
}
|
||
|
||
/**
|
||
* Соседние здания (footprint'ы) вокруг участка для сцены «Размещение застройки»
|
||
* (§7 отчёта ПТИЦА, Forgejo #2180): существующая застройка контекста, чтобы
|
||
* концепция читалась в окружении квартала.
|
||
*
|
||
* Зеркалит useConnectionCapacity: apiFetch, queryKey-массив, staleTime 5 мин,
|
||
* enabled по cadNum. Пустой / отсутствующий cadNum (например standalone-страница
|
||
* /concept без кадастра) → запрос не идёт (enabled=false), сцена работает как
|
||
* раньше без соседей.
|
||
*/
|
||
export function useNeighborBuildings(
|
||
cadNum: string | null | undefined,
|
||
radiusM: number = NEIGHBOR_BUILDINGS_RADIUS_M,
|
||
enabled = true,
|
||
) {
|
||
return useQuery<NeighborBuildingsResponse>({
|
||
queryKey: ["neighbor-buildings", cadNum, radiusM],
|
||
queryFn: () =>
|
||
apiFetch<NeighborBuildingsResponse>(
|
||
`/api/v1/parcels/${encodeURIComponent(cadNum!)}/neighbor-buildings?radius_m=${radiusM}`,
|
||
),
|
||
enabled: !!cadNum && enabled,
|
||
staleTime: 5 * 60 * 1000,
|
||
});
|
||
}
|