Some checks failed
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been cancelled
81 lines
2.6 KiB
TypeScript
81 lines
2.6 KiB
TypeScript
"use client";
|
||
|
||
import { useQuery } from "@tanstack/react-query";
|
||
|
||
import { apiFetch } from "./api";
|
||
import type {
|
||
BuildingListing,
|
||
BuildingSaleShare,
|
||
SaleShareQuery,
|
||
SaleShareSummary,
|
||
} from "@/types/sale-share";
|
||
|
||
const BASE = "/api/v1/buildings";
|
||
|
||
/**
|
||
* GET /api/v1/buildings/sale-share/summary
|
||
* Сводка распределения sale_share_pct: coverage, max/p95, гистограмма.
|
||
* Нужна для слайдера % и баннера покрытия — кэшируем подольше.
|
||
*/
|
||
export function useSaleShareSummary() {
|
||
return useQuery<SaleShareSummary>({
|
||
queryKey: ["sale-share", "summary"],
|
||
queryFn: () => apiFetch<SaleShareSummary>(`${BASE}/sale-share/summary`),
|
||
staleTime: 10 * 60_000,
|
||
});
|
||
}
|
||
|
||
function buildParams(q: SaleShareQuery): string {
|
||
const p = new URLSearchParams();
|
||
p.set("min_pct", String(q.min_pct));
|
||
if (q.max_pct != null) p.set("max_pct", String(q.max_pct));
|
||
if (q.city) p.set("city", q.city);
|
||
if (q.price_min != null) p.set("price_min", String(q.price_min));
|
||
if (q.price_max != null) p.set("price_max", String(q.price_max));
|
||
if (q.year_min != null) p.set("year_min", String(q.year_min));
|
||
if (q.year_max != null) p.set("year_max", String(q.year_max));
|
||
if (q.house_type) p.set("house_type", q.house_type);
|
||
p.set("sort", q.sort);
|
||
if (q.limit != null) p.set("limit", String(q.limit));
|
||
return p.toString();
|
||
}
|
||
|
||
/**
|
||
* GET /api/v1/buildings/sale-share
|
||
* Список домов вторички с долей квартир в продаже >= min_pct (+ фильтры).
|
||
*/
|
||
export function useSaleShareBuildings(query: SaleShareQuery) {
|
||
return useQuery<BuildingSaleShare[]>({
|
||
queryKey: [
|
||
"sale-share",
|
||
"buildings",
|
||
query.min_pct,
|
||
query.max_pct ?? null,
|
||
query.city ?? null,
|
||
query.price_min ?? null,
|
||
query.price_max ?? null,
|
||
query.year_min ?? null,
|
||
query.year_max ?? null,
|
||
query.house_type ?? null,
|
||
query.sort,
|
||
query.limit ?? 200,
|
||
],
|
||
queryFn: () =>
|
||
apiFetch<BuildingSaleShare[]>(`${BASE}/sale-share?${buildParams(query)}`),
|
||
staleTime: 5 * 60_000,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* GET /api/v1/buildings/{house_id}/listings
|
||
* Активные вторичные объявления одного дома (для drawer). Лениво —
|
||
* enabled только когда выбран дом.
|
||
*/
|
||
export function useBuildingListings(houseId: number | null) {
|
||
return useQuery<BuildingListing[]>({
|
||
queryKey: ["sale-share", "listings", houseId],
|
||
queryFn: () => apiFetch<BuildingListing[]>(`${BASE}/${houseId}/listings`),
|
||
enabled: houseId !== null,
|
||
staleTime: 5 * 60_000,
|
||
});
|
||
}
|