fix(web): add proper Vietnamese diacritics to all dashboard and listing pages
Vietnamese text throughout the frontend was missing accent marks (diacritics), using plain ASCII instead of proper Unicode characters. Fixed all user-visible text across dashboard, analytics, listings, search, and chart components. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -16,7 +16,7 @@ import { listingsApi, type ListingDetail, type PaginatedResult } from '@/lib/lis
|
||||
|
||||
const DistrictBarChart = dynamic(
|
||||
() => import('@/components/charts/district-bar-chart').then((mod) => mod.DistrictBarChart),
|
||||
{ ssr: false, loading: () => <div className="flex h-64 items-center justify-center text-muted-foreground">Dang tai bieu do...</div> },
|
||||
{ ssr: false, loading: () => <div className="flex h-64 items-center justify-center text-muted-foreground">Đang tải biểu đồ...</div> },
|
||||
);
|
||||
|
||||
const CITY = 'Ho Chi Minh';
|
||||
@@ -24,14 +24,14 @@ 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)} ty`;
|
||||
if (num >= 1_000_000) return `${(num / 1_000_000).toFixed(0)} trieu`;
|
||||
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/m2`;
|
||||
return `${price.toLocaleString('vi-VN')} d/m2`;
|
||||
if (price >= 1_000_000) return `${(price / 1_000_000).toFixed(1)} tr/m²`;
|
||||
return `${price.toLocaleString('vi-VN')} đ/m²`;
|
||||
}
|
||||
|
||||
interface StatCardProps {
|
||||
@@ -124,35 +124,35 @@ export default function DashboardPage() {
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Bang dieu khien</h1>
|
||||
<h1 className="text-3xl font-bold">Bảng điều khiển</h1>
|
||||
<p className="mt-2 text-muted-foreground">
|
||||
Tong quan thi truong va tin dang cua ban
|
||||
Tổng quan thị trường và tin đăng của bạn
|
||||
</p>
|
||||
</div>
|
||||
<Link href="/listings/new">
|
||||
<Button>Dang tin moi</Button>
|
||||
<Button>Đăng tin mới</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Stats overview */}
|
||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
||||
<StatCard
|
||||
title="Tin dang cua toi"
|
||||
title="Tin đăng của tôi"
|
||||
value={loading ? '...' : myListingsCount.toLocaleString('vi-VN')}
|
||||
description="Tong so tin da dang"
|
||||
description="Tổng số tin đã đăng"
|
||||
/>
|
||||
<StatCard
|
||||
title="Luot xem"
|
||||
title="Lượt xem"
|
||||
value={loading ? '...' : totalViews.toLocaleString('vi-VN')}
|
||||
description="Tren tat ca tin dang"
|
||||
description="Trên tất cả tin đăng"
|
||||
/>
|
||||
<StatCard
|
||||
title="Lien he"
|
||||
title="Liên hệ"
|
||||
value={loading ? '...' : totalInquiries.toLocaleString('vi-VN')}
|
||||
description="Yeu cau tu khach hang"
|
||||
description="Yêu cầu từ khách hàng"
|
||||
/>
|
||||
<StatCard
|
||||
title="Gia TB thi truong"
|
||||
title="Giá TB thị trường"
|
||||
value={loading ? '...' : formatPriceM2(avgPriceM2)}
|
||||
trend={avgYoy}
|
||||
description="YoY"
|
||||
@@ -164,24 +164,24 @@ export default function DashboardPage() {
|
||||
{/* Price chart */}
|
||||
<Card className="lg:col-span-2">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Gia trung binh theo quan</CardTitle>
|
||||
<CardDescription>{CITY} - {PERIOD} (trieu VND/m2)</CardDescription>
|
||||
<CardTitle className="text-lg">Giá trung bình theo quận</CardTitle>
|
||||
<CardDescription>{CITY} - {PERIOD} (triệu VND/m²)</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{loading ? (
|
||||
<div className="flex h-64 items-center justify-center text-muted-foreground">
|
||||
Dang tai...
|
||||
Đang tải...
|
||||
</div>
|
||||
) : chartData.length === 0 ? (
|
||||
<div className="flex h-64 items-center justify-center text-muted-foreground">
|
||||
Chua co du lieu
|
||||
Chưa có dữ liệu
|
||||
</div>
|
||||
) : (
|
||||
<DistrictBarChart
|
||||
data={chartData}
|
||||
height={280}
|
||||
dataKey="Gia/m2"
|
||||
tooltipFormatter={(value) => [`${value} tr/m2`, 'Gia']}
|
||||
tooltipFormatter={(value) => [`${value} tr/m²`, 'Giá']}
|
||||
/>
|
||||
)}
|
||||
</CardContent>
|
||||
@@ -190,30 +190,30 @@ export default function DashboardPage() {
|
||||
{/* Market summary */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Thi truong {CITY}</CardTitle>
|
||||
<CardDescription>Chi so chinh - {PERIOD}</CardDescription>
|
||||
<CardTitle className="text-lg">Thị trường {CITY}</CardTitle>
|
||||
<CardDescription>Chỉ số chính - {PERIOD}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">Tong tin dang</span>
|
||||
<span className="text-sm text-muted-foreground">Tổng tin đăng</span>
|
||||
<span className="font-semibold">
|
||||
{loading ? '...' : totalListings.toLocaleString('vi-VN')}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">Gia TB/m2</span>
|
||||
<span className="text-sm text-muted-foreground">Giá TB/m²</span>
|
||||
<span className="font-semibold">
|
||||
{loading ? '...' : formatPriceM2(avgPriceM2)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">Ngay TB de ban</span>
|
||||
<span className="text-sm text-muted-foreground">Ngày TB để bán</span>
|
||||
<span className="font-semibold">
|
||||
{loading ? '...' : `${avgDaysOnMarket.toFixed(0)} ngay`}
|
||||
{loading ? '...' : `${avgDaysOnMarket.toFixed(0)} ngày`}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">So quan</span>
|
||||
<span className="text-sm text-muted-foreground">Số quận</span>
|
||||
<span className="font-semibold">
|
||||
{loading ? '...' : new Set(marketReport.map((d) => d.district)).size}
|
||||
</span>
|
||||
@@ -221,7 +221,7 @@ export default function DashboardPage() {
|
||||
<div className="pt-2">
|
||||
<Link href="/analytics">
|
||||
<Button variant="outline" size="sm" className="w-full">
|
||||
Xem phan tich chi tiet
|
||||
Xem phân tích chi tiết
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -233,26 +233,26 @@ export default function DashboardPage() {
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between">
|
||||
<div>
|
||||
<CardTitle className="text-lg">Tin dang gan day</CardTitle>
|
||||
<CardDescription>Danh sach tin dang moi nhat cua ban</CardDescription>
|
||||
<CardTitle className="text-lg">Tin đăng gần đây</CardTitle>
|
||||
<CardDescription>Danh sách tin đăng mới nhất của bạn</CardDescription>
|
||||
</div>
|
||||
<Link href="/listings">
|
||||
<Button variant="outline" size="sm">
|
||||
Xem tat ca
|
||||
Xem tất cả
|
||||
</Button>
|
||||
</Link>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{loading ? (
|
||||
<div className="flex h-32 items-center justify-center text-muted-foreground">
|
||||
Dang tai...
|
||||
Đang tải...
|
||||
</div>
|
||||
) : !listings || listings.data.length === 0 ? (
|
||||
<div className="flex h-32 flex-col items-center justify-center text-muted-foreground">
|
||||
<p>Chua co tin dang nao</p>
|
||||
<p>Chưa có tin đăng nào</p>
|
||||
<Link href="/listings/new" className="mt-2">
|
||||
<Button variant="outline" size="sm">
|
||||
Dang tin dau tien
|
||||
Đăng tin đầu tiên
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -292,8 +292,8 @@ export default function DashboardPage() {
|
||||
<ListingStatusBadge status={listing.status} />
|
||||
</div>
|
||||
<div className="hidden sm:flex sm:gap-3 sm:text-sm sm:text-muted-foreground">
|
||||
<span>{listing.viewCount} luot xem</span>
|
||||
<span>{listing.inquiryCount} lien he</span>
|
||||
<span>{listing.viewCount} lượt xem</span>
|
||||
<span>{listing.inquiryCount} liên hệ</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user