Some checks failed
CI / changes (push) Successful in 8s
CI / changes (pull_request) Successful in 9s
CI / frontend-tests (push) Successful in 1m1s
CI / openapi-codegen-check (push) Successful in 1m50s
CI / backend-tests (push) Failing after 9m8s
CI / frontend-tests (pull_request) Successful in 54s
CI / openapi-codegen-check (pull_request) Successful in 1m59s
CI / backend-tests (pull_request) Failing after 8m56s
Switch portfolio source from domrf_region_aggregates (room_count_type ONE/TWO/THREE/FOUR) to domrf_flat_area_distribution (area_bucket FROM_0_TO_25…FROM_100), aggregated into the same 5 area buckets as the deals series. Both series now share the same axis and are directly comparable. Frontend portfolioMap simplified to direct bucket key lookup.
76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
"use client";
|
|
|
|
import { useMemo } from "react";
|
|
|
|
import {
|
|
useQuartirographyDeals,
|
|
useQuartirographyPortfolio,
|
|
} from "@/lib/analytics-api";
|
|
|
|
import { ChartShell } from "./ChartShell";
|
|
|
|
export function QuartirographyChart() {
|
|
const portfolio = useQuartirographyPortfolio();
|
|
const deals = useQuartirographyDeals();
|
|
|
|
const option = useMemo(() => {
|
|
const portfolioRows = portfolio.data ?? [];
|
|
const dealsRows = deals.data ?? [];
|
|
const buckets = [
|
|
"Студии 15-30",
|
|
"1-к 30-45",
|
|
"2-к 45-60",
|
|
"3-к 60-80",
|
|
"80+ м²",
|
|
];
|
|
// Portfolio is now served from domrf_flat_area_distribution with the same
|
|
// area bucket keys as the deals series — direct lookup by bucket label.
|
|
// If a bucket is absent in the source (e.g. studio data gap), percent
|
|
// falls back to null so ECharts draws no bar rather than a misleading 0%.
|
|
const portfolioMap: Record<string, number | null> = Object.fromEntries(
|
|
buckets.map((b) => {
|
|
const row = portfolioRows.find((r) => r.bucket === b);
|
|
return [b, row != null ? (row.percent ?? null) : null];
|
|
}),
|
|
);
|
|
const dealsPercents = buckets.map(
|
|
(b) => dealsRows.find((r) => r.bucket === b)?.percent ?? 0,
|
|
);
|
|
const portfolioPercents = buckets.map((b) => portfolioMap[b] ?? null);
|
|
|
|
return {
|
|
tooltip: {
|
|
trigger: "axis",
|
|
axisPointer: { type: "shadow" },
|
|
valueFormatter: (v: number | null) =>
|
|
v == null ? "нет данных" : `${v}%`,
|
|
},
|
|
legend: { data: ["Что строится (портфель)", "Что покупают (ДДУ)"] },
|
|
grid: { left: 110, right: 32, top: 40, bottom: 28 },
|
|
xAxis: { type: "value", axisLabel: { formatter: "{value}%" } },
|
|
yAxis: { type: "category", data: buckets, inverse: true },
|
|
series: [
|
|
{
|
|
name: "Что строится (портфель)",
|
|
type: "bar",
|
|
data: portfolioPercents,
|
|
itemStyle: { color: "#94a3b8" },
|
|
},
|
|
{
|
|
name: "Что покупают (ДДУ)",
|
|
type: "bar",
|
|
data: dealsPercents,
|
|
itemStyle: { color: "#0a7a3a" },
|
|
},
|
|
],
|
|
};
|
|
}, [portfolio.data, deals.data]);
|
|
|
|
return (
|
|
<ChartShell
|
|
option={option}
|
|
loading={portfolio.isLoading || deals.isLoading}
|
|
height={320}
|
|
/>
|
|
);
|
|
}
|