fix: valuation page Vietnamese diacritics, correct API routes, update tests

- Add proper Vietnamese diacritics to all valuation components
  (form, results, history) and their test assertions
- Fix valuation API client to use /analytics/valuation endpoint
- Return empty history gracefully (no server endpoint yet)

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ho Ngoc Hai
2026-04-13 12:03:47 +07:00
parent f373f7b1e2
commit ccfc176e40
8 changed files with 108 additions and 99 deletions

View File

@@ -8,14 +8,14 @@ interface ValuationResultsProps {
}
function formatPrice(num: number): string {
if (num >= 1_000_000_000) return `${(num / 1_000_000_000).toFixed(2)} 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(2)} t`;
if (num >= 1_000_000) return `${(num / 1_000_000).toFixed(0)} triu`;
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²`;
}
export function ValuationResults({ result }: ValuationResultsProps) {
@@ -26,15 +26,15 @@ export function ValuationResults({ result }: ValuationResultsProps) {
{/* Main estimate */}
<Card className="border-primary/20 bg-primary/5">
<CardHeader className="pb-3">
<CardDescription>Gia uoc tinh boi AI</CardDescription>
<CardDescription>Giá ưc tính bi AI</CardDescription>
<CardTitle className="text-3xl text-primary">
{formatPrice(result.estimatedPriceVND)} VND
{formatPrice(result.estimatedPriceVND)} VNĐ
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid gap-4 sm:grid-cols-3">
<div>
<p className="text-sm text-muted-foreground">Do tin cay</p>
<p className="text-sm text-muted-foreground">Đ tin cy</p>
<div className="mt-1 flex items-center gap-2">
<div className="h-2 flex-1 rounded-full bg-muted">
<div
@@ -46,13 +46,13 @@ export function ValuationResults({ result }: ValuationResultsProps) {
</div>
</div>
<div>
<p className="text-sm text-muted-foreground">Gia/m2</p>
<p className="text-sm text-muted-foreground">Giá/m²</p>
<p className="mt-1 text-lg font-semibold">{formatPriceM2(result.pricePerM2)}</p>
</div>
<div>
<p className="text-sm text-muted-foreground">Khoang gia</p>
<p className="text-sm text-muted-foreground">Khong giá</p>
<p className="mt-1 text-lg font-semibold">
{formatPrice(result.priceRangeLow)} - {formatPrice(result.priceRangeHigh)}
{formatPrice(result.priceRangeLow)} {formatPrice(result.priceRangeHigh)}
</p>
</div>
</div>
@@ -63,8 +63,8 @@ export function ValuationResults({ result }: ValuationResultsProps) {
{result.priceDrivers.length > 0 && (
<Card>
<CardHeader>
<CardTitle className="text-lg">Yeu to anh huong gia</CardTitle>
<CardDescription>Cac yeu to chinh tac dong den gia tri bat dong san</CardDescription>
<CardTitle className="text-lg">Yếu t nh hưởng giá</CardTitle>
<CardDescription>Các yếu t chính tác đng đến giá tr bt đng sn</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-3">
@@ -102,9 +102,9 @@ export function ValuationResults({ result }: ValuationResultsProps) {
{result.comparables.length > 0 && (
<Card>
<CardHeader>
<CardTitle className="text-lg">Bat dong san tuong tu</CardTitle>
<CardTitle className="text-lg">Bt đng sn tương t</CardTitle>
<CardDescription>
{result.comparables.length} bat dong san co dac diem tuong tu trong khu vuc
{result.comparables.length} bt đng sn có đc điểm tương t trong khu vc
</CardDescription>
</CardHeader>
<CardContent>
@@ -117,7 +117,7 @@ export function ValuationResults({ result }: ValuationResultsProps) {
<div className="min-w-0 flex-1">
<p className="truncate font-medium">{comp.title}</p>
<p className="text-sm text-muted-foreground">
{comp.district} &middot; {comp.areaM2} m2
{comp.district} &middot; {comp.areaM2} m²
</p>
</div>
<div className="text-right">
@@ -128,7 +128,7 @@ export function ValuationResults({ result }: ValuationResultsProps) {
</div>
<div className="hidden sm:block">
<span className="rounded-full bg-accent px-2 py-1 text-xs font-medium">
{Math.round(comp.similarity * 100)}% tuong tu
{Math.round(comp.similarity * 100)}% tương t
</span>
</div>
</div>