'use client'; import dynamic from 'next/dynamic'; import { useState } from 'react'; import { ComparablesTable } from '@/components/valuation/comparables-table'; import { ExportPdfButton } from '@/components/valuation/export-pdf-button'; import { MarketContextCard } from '@/components/valuation/market-context-card'; import { ValuationCompare } from '@/components/valuation/valuation-compare'; import { ValuationForm } from '@/components/valuation/valuation-form'; import { ValuationHistory } from '@/components/valuation/valuation-history'; import { ValuationResults } from '@/components/valuation/valuation-results'; import { ApiError } from '@/lib/api-client'; import { useValuationPredict, useValuationHistory, useValuationDetail, } from '@/lib/hooks/use-valuation'; import type { ValuationRequest, ValuationResult } from '@/lib/valuation-api'; function getValuationErrorMessage(error: unknown): { title: string; detail: string } { if (error instanceof ApiError) { if (error.status === 429) { return { title: 'Quá nhiều yêu cầu', detail: 'Bạn đã gửi quá nhiều yêu cầu định giá. Vui lòng đợi một lát rồi thử lại.', }; } if (error.status === 402 || /quota|subscription/i.test(error.message)) { return { title: 'Đã hết hạn mức', detail: 'Gói đăng ký hiện tại đã hết lượt định giá AI. Hãy nâng cấp hoặc thử lại vào chu kỳ sau.', }; } if (error.status === 503 || /model|unavailable/i.test(error.message)) { return { title: 'Dịch vụ AI tạm thời không khả dụng', detail: 'Mô hình định giá đang bận hoặc bảo trì. Vui lòng thử lại sau vài phút.', }; } return { title: 'Không thể định giá', detail: error.message || 'Đã xảy ra lỗi không xác định. Vui lòng thử lại sau.', }; } return { title: 'Không thể định giá', detail: 'Vui lòng kiểm tra kết nối mạng và thử lại.', }; } // Lazy-load chart components (uses Recharts, no SSR) const chartLoading = () => (
Đang tải...
); const ValuationHistoryChart = dynamic( () => import('@/components/valuation/valuation-history-chart').then( (m) => m.ValuationHistoryChart, ), { ssr: false, loading: chartLoading }, ); const ValueDriversChart = dynamic( () => import('@/components/valuation/value-drivers-chart').then( (m) => m.ValueDriversChart, ), { ssr: false, loading: chartLoading }, ); type TabKey = 'single' | 'compare'; export default function ValuationPage() { const [activeTab, setActiveTab] = useState('single'); const [historyPage, setHistoryPage] = useState(1); const [selectedId, setSelectedId] = useState(null); const predictMutation = useValuationPredict(); const { data: historyData, isLoading: historyLoading } = useValuationHistory(historyPage); const { data: selectedResult } = useValuationDetail(selectedId ?? ''); const currentResult: ValuationResult | undefined = predictMutation.data ?? selectedResult; const handleSubmit = (data: ValuationRequest) => { setSelectedId(null); predictMutation.mutate(data); }; const handleSelectHistory = (id: string) => { setActiveTab('single'); setSelectedId(id); }; return (
{/* Page header */}

Định giá AI

Sử dụng AI để ước tính giá trị bất động sản dựa trên dữ liệu thị trường

{activeTab === 'single' && currentResult && ( )}
{/* Tab switcher */}
{activeTab === 'single' ? (
{/* Form + Results (left 2 cols) */}
{predictMutation.isError && (() => { const { title, detail } = getValuationErrorMessage(predictMutation.error); return (

{title}

{detail}

); })()} {currentResult && ( <> {/* Main results with confidence badge */} {/* Value drivers waterfall chart */} {currentResult.priceDrivers.length > 0 && ( )} {/* Comparables table (TanStack Table) */} {currentResult.comparables.length > 0 && ( )} {/* Market context card */} {currentResult.marketContext && ( )} {/* Valuation history chart */} {currentResult.valuationHistory && currentResult.valuationHistory.length >= 2 && ( )} )}
{/* History sidebar (right col) */}
) : ( )}
); }