gendesign/frontend/src/lib/analytics-api.ts
2026-04-27 20:26:55 +03:00

208 lines
5.6 KiB
TypeScript

"use client";
import { keepPreviousData, useQuery } from "@tanstack/react-query";
import { apiFetch } from "./api";
import type {
DeveloperDetail,
DeveloperHistoryPoint,
DeveloperPortfolioObject,
DeveloperTopRow,
DistrictRow,
MarketPulsePoint,
ObjectDetail,
ObjectInfraPoi,
ObjectPhoto,
ObjectSaleGraphPoint,
ObjectSalesAggRow,
PipelineRow,
PrinzipDistrictRow,
PrinzipInsights,
PrinzipObjectRow,
QuartirographyDealsRow,
QuartirographyPortfolioRow,
YandexListingsSummary,
} from "@/types/analytics";
const BASE = "/api/v1/analytics";
export function useMarketPulse() {
return useQuery({
queryKey: ["analytics", "market-pulse"],
queryFn: () => apiFetch<MarketPulsePoint[]>(`${BASE}/sverdl/market-pulse`),
});
}
export function useQuartirographyPortfolio() {
return useQuery({
queryKey: ["analytics", "quartirography", "portfolio"],
queryFn: () =>
apiFetch<QuartirographyPortfolioRow[]>(
`${BASE}/sverdl/quartirography?source=portfolio`,
),
});
}
export function useQuartirographyDeals() {
return useQuery({
queryKey: ["analytics", "quartirography", "deals"],
queryFn: () =>
apiFetch<QuartirographyDealsRow[]>(
`${BASE}/sverdl/quartirography?source=deals`,
),
});
}
export function usePipeline() {
return useQuery({
queryKey: ["analytics", "pipeline"],
queryFn: () => apiFetch<PipelineRow[]>(`${BASE}/sverdl/pipeline`),
});
}
export function useDistricts() {
return useQuery({
queryKey: ["analytics", "districts"],
queryFn: () => apiFetch<DistrictRow[]>(`${BASE}/sverdl/districts`),
});
}
export function useYandexListings() {
return useQuery({
queryKey: ["analytics", "yandex"],
queryFn: () =>
apiFetch<YandexListingsSummary>(`${BASE}/sverdl/yandex-listings`),
});
}
export function useTopDevelopers(limit = 15) {
return useQuery({
queryKey: ["analytics", "top-devs", limit],
queryFn: () =>
apiFetch<DeveloperTopRow[]>(`${BASE}/developers/top?limit=${limit}`),
});
}
export function useDeveloperDetail(developerId: string) {
return useQuery({
queryKey: ["analytics", "dev", developerId],
queryFn: () =>
apiFetch<DeveloperDetail>(`${BASE}/developers/${developerId}`),
enabled: !!developerId,
});
}
export function useDeveloperHistory(developerIds: string[]) {
const idsParam = developerIds.join(",");
return useQuery({
queryKey: ["analytics", "dev-history", idsParam],
queryFn: () =>
apiFetch<DeveloperHistoryPoint[]>(
`${BASE}/developers/history?ids=${encodeURIComponent(idsParam)}`,
),
enabled: developerIds.length > 0,
});
}
export function useDeveloperPortfolio(developerId: string) {
return useQuery({
queryKey: ["analytics", "dev-portfolio", developerId],
queryFn: () =>
apiFetch<DeveloperPortfolioObject[]>(
`${BASE}/developers/${developerId}/portfolio`,
),
enabled: !!developerId,
});
}
export function usePrinzipInsights() {
return useQuery({
queryKey: ["analytics", "prinzip-insights"],
queryFn: () => apiFetch<PrinzipInsights>(`${BASE}/prinzip/insights`),
staleTime: Infinity,
});
}
export function usePrinzipDistricts() {
return useQuery({
queryKey: ["analytics", "prinzip-districts"],
queryFn: () => apiFetch<PrinzipDistrictRow[]>(`${BASE}/prinzip/districts`),
});
}
export function usePrinzipObjects() {
return useQuery({
queryKey: ["analytics", "prinzip-objects"],
queryFn: () => apiFetch<PrinzipObjectRow[]>(`${BASE}/prinzip/objects`),
});
}
// Funnel hooks moved to /admin/leads page (CRM data is admin-only).
// ── Per-object drill-in ─────────────────────────────────────────────────────
export function useObjectDetail(objId: number | string) {
return useQuery({
queryKey: ["analytics", "object", objId],
queryFn: () => apiFetch<ObjectDetail>(`${BASE}/object/${objId}`),
enabled: !!objId,
});
}
export function useObjectSaleGraph(objId: number | string, type?: string) {
return useQuery({
queryKey: ["analytics", "object-sale-graph", objId, type],
queryFn: () => {
const q = type ? `?type=${type}` : "";
return apiFetch<ObjectSaleGraphPoint[]>(
`${BASE}/object/${objId}/sale_graph${q}`,
);
},
enabled: !!objId,
});
}
export function useObjectSalesAgg(objId: number | string) {
return useQuery({
queryKey: ["analytics", "object-sales-agg", objId],
queryFn: () =>
apiFetch<ObjectSalesAggRow[]>(`${BASE}/object/${objId}/sales_agg`),
enabled: !!objId,
});
}
export function useObjectInfrastructure(
objId: number | string,
opts?: { category?: string; max_distance?: number },
) {
return useQuery({
queryKey: [
"analytics",
"object-infra",
objId,
opts?.category,
opts?.max_distance,
],
queryFn: () => {
const params = new URLSearchParams();
if (opts?.category) params.set("category", opts.category);
if (opts?.max_distance != null)
params.set("max_distance", String(opts.max_distance));
const qs = params.toString();
return apiFetch<ObjectInfraPoi[]>(
`${BASE}/object/${objId}/infrastructure${qs ? "?" + qs : ""}`,
);
},
enabled: !!objId,
placeholderData: keepPreviousData,
});
}
export function useObjectPhotos(objId: number | string, limit = 100) {
return useQuery({
queryKey: ["analytics", "object-photos", objId, limit],
queryFn: () =>
apiFetch<ObjectPhoto[]>(`${BASE}/object/${objId}/photos?limit=${limit}`),
enabled: !!objId,
});
}