Files
goodgo-platform/apps/web/components/listings/price-history-chart.tsx
Ho Ngoc Hai 8e9d021465 feat: add unit tests for featured listings, neighborhood scores + price history chart
- Add unit tests for FeatureListingHandler (6 tests) and ActivateFeaturedListingHandler (6 tests)
- Add unit tests for NeighborhoodScoreServiceImpl (5 tests) and GetNeighborhoodScoreHandler (2 tests)
- Add PriceHistoryChart component with recharts LineChart for listing detail page
- Wire up price history API client and integrate chart into listing detail view

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 18:21:44 +07:00

74 lines
2.0 KiB
TypeScript

'use client';
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
} from 'recharts';
import type { PriceHistoryItem } from '@/lib/listings-api';
interface PriceHistoryChartProps {
data: PriceHistoryItem[];
height?: number;
}
function priceToMillions(priceStr: string): number {
return Math.round(Number(priceStr) / 1_000_000);
}
function formatMillions(value: number): string {
if (value >= 1000) return `${(value / 1000).toFixed(1)} tỷ`;
return `${value} tr`;
}
export function PriceHistoryChart({ data, height = 280 }: PriceHistoryChartProps) {
if (data.length === 0) return null;
const chartData = [...data]
.sort((a, b) => new Date(a.changedAt).getTime() - new Date(b.changedAt).getTime())
.map((item) => ({
date: new Date(item.changedAt).toLocaleDateString('vi-VN', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
}),
price: priceToMillions(item.newPrice),
}));
return (
<ResponsiveContainer width="100%" height={height}>
<LineChart data={chartData} margin={{ top: 5, right: 20, left: 0, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
<XAxis dataKey="date" tick={{ fontSize: 11 }} className="fill-muted-foreground" />
<YAxis
tick={{ fontSize: 11 }}
className="fill-muted-foreground"
tickFormatter={(v: number) => formatMillions(v)}
/>
<Tooltip
contentStyle={{
backgroundColor: 'hsl(var(--card))',
border: '1px solid hsl(var(--border))',
borderRadius: '0.5rem',
fontSize: '0.875rem',
}}
formatter={(value) => [formatMillions(Number(value)), 'Giá']}
/>
<Line
type="monotone"
dataKey="price"
stroke="hsl(var(--primary))"
strokeWidth={2}
dot={{ r: 4 }}
activeDot={{ r: 6 }}
/>
</LineChart>
</ResponsiveContainer>
);
}