Files
goodgo-platform/apps/web/components/neighborhood/neighborhood-radar-chart.tsx
Ho Ngoc Hai e21e096e54 feat(web): complete du-an project pages, neighborhood components, and public notification bell
- Add grid/map view toggle on /du-an listing page with Mapbox project markers
- Enhance du-an detail with master plan viewer, neighborhood radar chart, POI map, and price history chart
- Create neighborhood component suite: radar chart (Recharts), POI map (Mapbox), score badges
- Add du-an API client, server-side fetching, and React Query hooks
- Wire NotificationBell into public layout header for authenticated users
- Fix missing PROJECT_STATUS_COLORS import in du-an detail client

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

104 lines
2.7 KiB
TypeScript

'use client';
import {
Radar,
RadarChart,
PolarGrid,
PolarAngleAxis,
PolarRadiusAxis,
ResponsiveContainer,
Tooltip,
} from 'recharts';
import { Badge } from '@/components/ui/badge';
import type { NeighborhoodCategory } from './types';
interface NeighborhoodRadarChartProps {
categories: NeighborhoodCategory[];
height?: number;
showBadges?: boolean;
className?: string;
}
function getScoreVariant(score: number): 'success' | 'warning' | 'destructive' {
if (score > 7) return 'success';
if (score >= 5) return 'warning';
return 'destructive';
}
function getScoreLabel(score: number): string {
if (score > 7) return 'Tốt';
if (score >= 5) return 'TB';
return 'Yếu';
}
export function NeighborhoodRadarChart({
categories,
height = 300,
showBadges = true,
className,
}: NeighborhoodRadarChartProps) {
const chartData = categories.map((cat) => ({
subject: cat.label,
score: cat.score,
fullMark: 10,
}));
return (
<div className={className}>
<ResponsiveContainer width="100%" height={height}>
<RadarChart cx="50%" cy="50%" outerRadius="75%" data={chartData}>
<PolarGrid
stroke="hsl(var(--border))"
strokeDasharray="3 3"
/>
<PolarAngleAxis
dataKey="subject"
tick={{
fontSize: 12,
fill: 'hsl(var(--muted-foreground))',
}}
/>
<PolarRadiusAxis
angle={90}
domain={[0, 10]}
tick={{ fontSize: 10, fill: 'hsl(var(--muted-foreground))' }}
tickCount={6}
/>
<Tooltip
contentStyle={{
backgroundColor: 'hsl(var(--card))',
border: '1px solid hsl(var(--border))',
borderRadius: '0.5rem',
fontSize: '0.875rem',
}}
formatter={(value) => [`${Number(value).toFixed(1)}/10`, 'Điểm']}
/>
<Radar
name="Điểm"
dataKey="score"
stroke="hsl(var(--primary))"
fill="hsl(var(--primary))"
fillOpacity={0.2}
strokeWidth={2}
/>
</RadarChart>
</ResponsiveContainer>
{showBadges && (
<div className="mt-3 flex flex-wrap items-center justify-center gap-2">
{categories.map((cat) => (
<Badge
key={cat.category}
variant={getScoreVariant(cat.score)}
className="gap-1 text-xs"
>
{cat.label}: {cat.score.toFixed(1)}
<span className="opacity-70">({getScoreLabel(cat.score)})</span>
</Badge>
))}
</div>
)}
</div>
);
}