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:
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -7,14 +7,12 @@ import {
|
||||
CONDITION_COLORS,
|
||||
CONDITION_LABELS,
|
||||
} from '@/lib/chuyen-nhuong-api';
|
||||
import { formatVNDFull } from '@/lib/currency';
|
||||
|
||||
interface TransferItemTableProps {
|
||||
items: TransferItemData[];
|
||||
}
|
||||
|
||||
function formatVND(value: string): string {
|
||||
return new Intl.NumberFormat('vi-VN').format(Number(value)) + ' \u20ab';
|
||||
}
|
||||
|
||||
export function TransferItemTable({ items }: TransferItemTableProps) {
|
||||
if (items.length === 0) {
|
||||
@@ -59,12 +57,12 @@ export function TransferItemTable({ items }: TransferItemTableProps) {
|
||||
</td>
|
||||
<td className="px-3 py-2 text-right">{item.quantity}</td>
|
||||
<td className="px-3 py-2 text-right font-medium">
|
||||
{formatVND(item.askingPriceVND)}
|
||||
{formatVNDFull(item.askingPriceVND)}
|
||||
</td>
|
||||
<td className="px-3 py-2 text-right text-muted-foreground">
|
||||
{item.aiEstimatePriceVND ? (
|
||||
<span title={item.aiConfidence ? `Độ tin cậy: ${Math.round(item.aiConfidence * 100)}%` : undefined}>
|
||||
{formatVND(item.aiEstimatePriceVND)}
|
||||
{formatVNDFull(item.aiEstimatePriceVND)}
|
||||
</span>
|
||||
) : '—'}
|
||||
</td>
|
||||
|
||||
@@ -10,14 +10,12 @@ import {
|
||||
CATEGORY_LABELS,
|
||||
STATUS_LABELS,
|
||||
} from '@/lib/chuyen-nhuong-api';
|
||||
import { formatVNDFull } from '@/lib/currency';
|
||||
|
||||
interface TransferListingCardProps {
|
||||
listing: TransferListingListItem;
|
||||
}
|
||||
|
||||
function formatVND(value: string): string {
|
||||
return new Intl.NumberFormat('vi-VN').format(Number(value)) + ' \u20ab';
|
||||
}
|
||||
|
||||
export function TransferListingCard({ listing }: TransferListingCardProps) {
|
||||
const statusColor =
|
||||
@@ -62,7 +60,7 @@ export function TransferListingCard({ listing }: TransferListingCardProps) {
|
||||
{/* Price */}
|
||||
<div className="mb-3">
|
||||
<p className="text-lg font-bold text-primary">
|
||||
{formatVND(listing.askingPriceVND)}
|
||||
{formatVNDFull(listing.askingPriceVND)}
|
||||
</p>
|
||||
{listing.isNegotiable && (
|
||||
<span className="text-xs text-muted-foreground">Thương lượng</span>
|
||||
|
||||
Reference in New Issue
Block a user