'use client'; import { Plus, Trash2, BarChart3 } from 'lucide-react'; import { useState } from 'react'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select } from '@/components/ui/select'; import { formatPrice, formatPricePerM2 } from '@/lib/currency'; import { useValuationBatch } from '@/lib/hooks/use-valuation'; import { VALUATION_PROPERTY_TYPES, CITIES, } from '@/lib/validations/valuation'; import type { ValuationRequest, ValuationResult } from '@/lib/valuation-api'; interface PropertySlot { id: string; propertyType: string; area: string; district: string; city: string; bedrooms: string; label: string; } function createEmptySlot(index: number): PropertySlot { return { id: crypto.randomUUID(), propertyType: 'APARTMENT', area: '', district: '', city: 'Ho Chi Minh', bedrooms: '', label: `BĐS ${index + 1}`, }; } function getConfidenceColor(c: number): string { if (c >= 0.8) return 'text-green-600'; if (c >= 0.5) return 'text-yellow-600'; return 'text-red-600'; } function getConfidenceVariant(c: number): 'success' | 'warning' | 'destructive' { if (c >= 0.8) return 'success'; if (c >= 0.5) return 'warning'; return 'destructive'; } export function ValuationCompare() { const [slots, setSlots] = useState([ createEmptySlot(0), createEmptySlot(1), ]); const [results, setResults] = useState(null); const batchMutation = useValuationBatch(); const updateSlot = (id: string, field: keyof PropertySlot, value: string) => { setSlots((prev) => prev.map((s) => (s.id === id ? { ...s, [field]: value } : s)), ); }; const addSlot = () => { if (slots.length >= 5) return; setSlots((prev) => [...prev, createEmptySlot(prev.length)]); }; const removeSlot = (id: string) => { if (slots.length <= 2) return; setSlots((prev) => prev.filter((s) => s.id !== id)); }; const handleCompare = () => { const validSlots = slots.filter((s) => s.area && s.district); if (validSlots.length < 2) return; const properties: ValuationRequest[] = validSlots.map((s) => ({ propertyType: s.propertyType, area: Number(s.area), district: s.district, city: s.city, bedrooms: s.bedrooms ? Number(s.bedrooms) : undefined, })); batchMutation.mutate( { properties }, { onSuccess: (data) => { setResults(data.results); }, }, ); }; const bestValue = results && results.length > 0 ? results.reduce((best, r) => r.pricePerM2 < best.pricePerM2 ? r : best, ) : null; return (
So sánh định giá
So sánh giá trị ước tính của nhiều bất động sản cùng lúc (2-5 BĐS)
{slots.map((slot) => (
{slots.length > 2 && ( )}
updateSlot(slot.id, 'area', e.target.value)} /> updateSlot(slot.id, 'district', e.target.value) } /> updateSlot(slot.id, 'bedrooms', e.target.value) } />
))}
{slots.length < 5 && ( )}
{/* Comparison results */} {results && results.length > 0 && (
{results.map((result, i) => { const isBest = bestValue && result.id === bestValue.id; return (
{slots[i]?.label ?? `BĐS ${i + 1}`} {isBest && ( Giá/m² tốt nhất )}
{slots[i]?.district}, {slots[i]?.city}

{formatPrice(result.estimatedPriceVND)} VNĐ

{formatPricePerM2(result.pricePerM2)}/m²

Độ tin cậy {Math.round(result.confidence * 100)}%
= 0.8 ? 'bg-green-500' : result.confidence >= 0.5 ? 'bg-yellow-500' : 'bg-red-500' }`} style={{ width: `${result.confidence * 100}%` }} />
Khoảng giá: {formatPrice(result.priceRangeLow)} -{' '} {formatPrice(result.priceRangeHigh)}
{result.priceDrivers.length > 0 && (
{result.priceDrivers.slice(0, 3).map((d) => ( {d.direction === 'positive' ? '+' : '-'} {Math.abs(d.impact).toFixed(0)}% {d.feature} ))}
)} ); })}
)} {batchMutation.isError && (
Không thể so sánh. Vui lòng thử lại sau.
)}
); }