fix(web): consolidate inline currency formatters into shared lib (GOO-205)

Remove 8 inline formatPrice/formatVND/formatPriceM2 functions scattered
across components and pages, replacing them with imports from
@/lib/currency. Add formatVNDFull (full locale, no compact notation) for
chuyen-nhuong pages. Fix price-history-chart off-by-1000 bug caused by
double-dividing through priceToMillions then formatMillions. Add k/m²
branch to formatPricePerM2 for sub-million values.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
This commit is contained in:
Ho Ngoc Hai
2026-04-24 14:17:32 +07:00
parent dfb398131d
commit e850ac48d7
10 changed files with 90 additions and 87 deletions

View File

@@ -19,14 +19,12 @@ import {
STATUS_LABELS,
} from '@/lib/chuyen-nhuong-api';
import { cn } from '@/lib/utils';
import { formatVNDFull } from '@/lib/currency';
interface ChuyenNhuongDetailClientProps {
listing: TransferListingDetail;
}
function formatVND(value: string): string {
return new Intl.NumberFormat('vi-VN').format(Number(value)) + ' \u20ab';
}
export function ChuyenNhuongDetailClient({ listing }: ChuyenNhuongDetailClientProps) {
const statusColor =
@@ -69,13 +67,13 @@ export function ChuyenNhuongDetailClient({ listing }: ChuyenNhuongDetailClientPr
<div className="my-6 grid grid-cols-2 gap-4 rounded-lg border bg-card p-4 sm:grid-cols-4 lg:grid-cols-6">
<QuickStat
label="Giá yêu cầu"
value={formatVND(listing.askingPriceVND)}
value={formatVNDFull(listing.askingPriceVND)}
valueClassName="text-primary"
/>
{listing.aiEstimatePriceVND && (
<QuickStat
label="Giá AI ước tính"
value={formatVND(listing.aiEstimatePriceVND)}
value={formatVNDFull(listing.aiEstimatePriceVND)}
/>
)}
{listing.areaM2 && (
@@ -144,7 +142,7 @@ export function ChuyenNhuongDetailClient({ listing }: ChuyenNhuongDetailClientPr
{listing.monthlyRentVND && (
<div className="flex items-center justify-between">
<span className="text-sm text-muted-foreground">Tiền thuê hàng tháng</span>
<span className="font-medium">{formatVND(listing.monthlyRentVND)}</span>
<span className="font-medium">{formatVNDFull(listing.monthlyRentVND)}</span>
</div>
)}
{listing.depositMonths != null && (
@@ -181,14 +179,14 @@ export function ChuyenNhuongDetailClient({ listing }: ChuyenNhuongDetailClientPr
<div className="flex items-center justify-between">
<span className="text-sm text-muted-foreground">Giá yêu cầu</span>
<span className="text-lg font-bold text-primary">
{formatVND(listing.askingPriceVND)}
{formatVNDFull(listing.askingPriceVND)}
</span>
</div>
{listing.aiEstimatePriceVND && (
<div className="flex items-center justify-between">
<span className="text-sm text-muted-foreground">Giá AI ưc tính</span>
<span className="font-semibold">
{formatVND(listing.aiEstimatePriceVND)}
{formatVNDFull(listing.aiEstimatePriceVND)}
</span>
</div>
)}