'use client'; import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell, ReferenceLine, } from 'recharts'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import type { PriceDriver } from '@/lib/valuation-api'; interface ValueDriversChartProps { drivers: PriceDriver[]; } const FEATURE_LABELS: Record = { area_m2: 'Diện tích', avg_price_district_3m_vnd_m2: 'Giá TB khu vực', property_type_encoded: 'Loại BĐS', distance_to_cbd_km: 'Khoảng cách trung tâm', renovation_score: 'Cải tạo', building_age_years: 'Tuổi công trình', has_legal_paper: 'Giấy tờ pháp lý', distance_to_metro_km: 'Khoảng cách metro', interior_quality: 'Nội thất', price_momentum_30d: 'Đà tăng giá 30 ngày', view_quality: 'Chất lượng view', natural_light: 'Ánh sáng tự nhiên', noise_level: 'Mức ồn', flood_zone_risk: 'Nguy cơ ngập', park_occupancy_rate: 'Tỉ lệ lấp đầy', logistics_connectivity_score: 'Kết nối logistics', industry_demand_index: 'Nhu cầu CN', }; function getFeatureLabel(feature: string): string { return FEATURE_LABELS[feature] || feature.replace(/_/g, ' '); } interface WaterfallItem { name: string; base: number; value: number; fill: string; importance: number; direction: 'positive' | 'negative'; } function buildWaterfallData(drivers: PriceDriver[]): WaterfallItem[] { const sorted = [...drivers].sort( (a, b) => Math.abs(b.impact) - Math.abs(a.impact), ); let cumulative = 0; return sorted.map((driver) => { const isPositive = driver.direction === 'positive'; const absImpact = Math.abs(driver.impact); const item: WaterfallItem = { name: getFeatureLabel(driver.feature), base: isPositive ? cumulative : cumulative - absImpact, value: absImpact, fill: isPositive ? '#22c55e' : '#ef4444', importance: absImpact, direction: driver.direction, }; cumulative += isPositive ? absImpact : -absImpact; return item; }); } function CustomTooltip({ active, payload, }: { active?: boolean; payload?: Array<{ payload: WaterfallItem }>; }) { if (!active || !payload?.[0]) return null; const data = payload[0].payload; return (

{data.name}

{data.direction === 'positive' ? '+' : '-'} {data.importance.toFixed(1)}%

); } export function ValueDriversChart({ drivers }: ValueDriversChartProps) { if (drivers.length === 0) return null; const data = buildWaterfallData(drivers); return ( Yếu tố ảnh hưởng giá Biểu đồ thác nước thể hiện mức ảnh hưởng của từng yếu tố `${v.toFixed(0)}%`} domain={['dataMin', 'dataMax']} /> } /> {/* Invisible base bar for waterfall offset */} {/* Visible value bar */} {data.map((entry, index) => ( ))} ); }