'use client';
import dynamic from 'next/dynamic';
import Image from 'next/image';
import Link from 'next/link';
import { ListingStatusBadge } from '@/components/listings/listing-status-badge';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { useMarketReport, useHeatmap } from '@/lib/hooks/use-analytics';
import { useListingsSearch } from '@/lib/hooks/use-listings';
const DistrictBarChart = dynamic(
() => import('@/components/charts/district-bar-chart').then((mod) => mod.DistrictBarChart),
{ ssr: false, loading: () =>
Đang tải biểu đồ...
},
);
const CITY = 'Ho Chi Minh';
const PERIOD = '2026-Q1';
function formatPrice(priceStr: string): string {
const num = Number(priceStr);
if (num >= 1_000_000_000) return `${(num / 1_000_000_000).toFixed(1)} tỷ`;
if (num >= 1_000_000) return `${(num / 1_000_000).toFixed(0)} triệu`;
return num.toLocaleString('vi-VN');
}
function formatPriceM2(price: number): string {
if (price >= 1_000_000) return `${(price / 1_000_000).toFixed(1)} tr/m²`;
return `${price.toLocaleString('vi-VN')} đ/m²`;
}
interface StatCardProps {
title: string;
value: string;
description?: string;
trend?: number | null;
}
function StatCard({ title, value, description, trend }: StatCardProps) {
return (
{title}
{value}
{(description || trend != null) && (
{trend != null && (
= 0 ? 'text-green-600' : 'text-red-600'}`}
>
{trend >= 0 ? '+' : ''}
{trend.toFixed(1)}%
)}
{description && (
{description}
)}
)}
);
}
export default function DashboardPage() {
const { data: reportData, isLoading: reportLoading } = useMarketReport(CITY, PERIOD);
const { data: heatmapData, isLoading: heatmapLoading } = useHeatmap(CITY, PERIOD);
const { data: listings, isLoading: listingsLoading } = useListingsSearch({ page: 1, limit: 6 });
const loading = reportLoading || heatmapLoading || listingsLoading;
const marketReport = reportData?.districts ?? [];
const heatmap = heatmapData?.dataPoints ?? [];
const totalListings = marketReport.reduce((sum, d) => sum + d.totalListings, 0);
const avgPriceM2 =
marketReport.length > 0
? marketReport.reduce((sum, d) => sum + d.avgPriceM2, 0) / marketReport.length
: 0;
const avgDaysOnMarket =
marketReport.length > 0
? marketReport.reduce((sum, d) => sum + d.daysOnMarket, 0) / marketReport.length
: 0;
const avgYoy =
marketReport.filter((d) => d.yoyChange != null).length > 0
? marketReport
.filter((d) => d.yoyChange != null)
.reduce((sum, d) => sum + (d.yoyChange ?? 0), 0) /
marketReport.filter((d) => d.yoyChange != null).length
: null;
const myListingsCount = listings?.total ?? 0;
const totalViews = listings?.data.reduce((s, l) => s + l.viewCount, 0) ?? 0;
const totalInquiries = listings?.data.reduce((s, l) => s + l.inquiryCount, 0) ?? 0;
const chartData = heatmap
.sort((a, b) => b.avgPriceM2 - a.avgPriceM2)
.slice(0, 8)
.map((p) => ({
district: p.district.replace(/^Quan\s*/i, 'Q.').replace(/^Huyen\s*/i, 'H.'),
'Gia/m2': Math.round(p.avgPriceM2 / 1_000_000),
listings: p.totalListings,
}));
return (
Bảng điều khiển
Tổng quan thị trường và tin đăng của bạn
{/* Stats overview */}
{/* Market overview + quick stats */}
{/* Price chart */}
Giá trung bình theo quận
{CITY} - {PERIOD} (triệu VND/m²)
{loading ? (
Đang tải...
) : chartData.length === 0 ? (
Chưa có dữ liệu
) : (
[`${value} tr/m²`, 'Giá']}
/>
)}
{/* Market summary */}
Thị trường {CITY}
Chỉ số chính - {PERIOD}
Tổng tin đăng
{loading ? '...' : totalListings.toLocaleString('vi-VN')}
Giá TB/m²
{loading ? '...' : formatPriceM2(avgPriceM2)}
Ngày TB để bán
{loading ? '...' : `${avgDaysOnMarket.toFixed(0)} ngày`}
Số quận
{loading ? '...' : new Set(marketReport.map((d) => d.district)).size}
{/* Recent listings */}
Tin đăng gần đây
Danh sách tin đăng mới nhất của bạn
{loading ? (
Đang tải...
) : !listings || listings.data.length === 0 ? (
Chưa có tin đăng nào
) : (
{listings.data.slice(0, 5).map((listing) => (
{listing.property.media.length > 0 ? (
) : (
N/A
)}
{listing.property.title}
{listing.property.district}, {listing.property.city}
{formatPrice(listing.priceVND)}
{listing.viewCount} lượt xem
{listing.inquiryCount} liên hệ
))}
)}
);
}