gendesign/tradein-mvp/frontend/src/components/trade-in/PriceHistoryChart.tsx
lekss361 967e7185ca
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Successful in 42s
Deploy Trade-In / build-frontend (push) Successful in 1m36s
Deploy Trade-In / deploy (push) Successful in 45s
feat(tradein): cian price-change badges + split chart Avito/Yandex (#547)
2026-05-24 18:24:00 +00:00

101 lines
3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useMemo } from "react";
import {
LineChart,
Line,
XAxis,
YAxis,
Tooltip,
Legend,
ResponsiveContainer,
CartesianGrid,
} from "recharts";
import type { PriceHistoryYearPoint } from "@/types/trade-in";
type Props = { points: PriceHistoryYearPoint[] };
const fmtK = (n: number) => `${Math.round(n / 1000)}k`;
interface PivotRow {
year: number;
avito_imv?: number;
yandex_valuation?: number;
n_avito?: number;
n_yandex?: number;
}
export function PriceHistoryChart({ points }: Props) {
const pivoted = useMemo<PivotRow[]>(() => {
const byYear: Record<number, PivotRow> = {};
for (const p of points) {
if (!byYear[p.year]) byYear[p.year] = { year: p.year };
if (p.source === "avito_imv") {
byYear[p.year].avito_imv = p.median_price_per_m2;
byYear[p.year].n_avito = p.n_lots;
} else if (p.source === "yandex_valuation") {
byYear[p.year].yandex_valuation = p.median_price_per_m2;
byYear[p.year].n_yandex = p.n_lots;
}
}
return Object.values(byYear).sort((a, b) => a.year - b.year);
}, [points]);
const totalLots = points.reduce((s, p) => s + p.n_lots, 0);
return (
<article className="card" style={{ marginTop: 12, padding: 16 }}>
<header style={{ marginBottom: 8 }}>
<h4 style={{ margin: 0, fontSize: 14, fontWeight: 600 }}>
Динамика цен в доме
</h4>
<small style={{ color: "var(--muted, #6b7280)" }}>
Медиана /м² по году · Avito + Яндекс (по {totalLots} лотам)
</small>
</header>
<div style={{ width: "100%", height: 240 }}>
<ResponsiveContainer>
<LineChart
data={pivoted}
margin={{ top: 8, right: 16, left: 8, bottom: 8 }}
>
<CartesianGrid stroke="#eee" strokeDasharray="3 3" />
<XAxis dataKey="year" tick={{ fontSize: 11 }} />
<YAxis tickFormatter={fmtK} tick={{ fontSize: 11 }} />
<Tooltip
formatter={(value: number, name: string) =>
[
`${value.toLocaleString("ru-RU")} ₽/м²`,
name === "avito_imv"
? "Avito"
: name === "yandex_valuation"
? "Яндекс"
: name,
]
}
labelFormatter={(year) => `${year} год`}
/>
<Legend wrapperStyle={{ fontSize: 11 }} />
<Line
type="monotone"
dataKey="avito_imv"
stroke="#2563eb"
strokeWidth={2}
dot={{ r: 3 }}
name="Avito"
connectNulls
/>
<Line
type="monotone"
dataKey="yandex_valuation"
stroke="#ea580c"
strokeWidth={2}
dot={{ r: 3 }}
name="Яндекс"
connectNulls
/>
</LineChart>
</ResponsiveContainer>
</div>
</article>
);
}