feat(web): add Property Valuation UI with AVM integration
Build the valuation page at /dashboard/valuation with form input, AI-powered price estimation results, comparable properties display, and valuation history. Add "Dinh gia AI" button to listing detail sidebar for quick per-listing estimates. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
85
apps/web/lib/valuation-api.ts
Normal file
85
apps/web/lib/valuation-api.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { apiClient } from './api-client';
|
||||
|
||||
// ─── Types ──────────────────────────────────────────────
|
||||
|
||||
export interface ValuationRequest {
|
||||
propertyType: string;
|
||||
area: number;
|
||||
district: string;
|
||||
city: string;
|
||||
bedrooms?: number;
|
||||
bathrooms?: number;
|
||||
floors?: number;
|
||||
frontage?: number;
|
||||
roadWidth?: number;
|
||||
yearBuilt?: number;
|
||||
hasLegalPaper?: boolean;
|
||||
}
|
||||
|
||||
export interface ValuationComparable {
|
||||
id: string;
|
||||
title: string;
|
||||
address: string;
|
||||
district: string;
|
||||
priceVND: string;
|
||||
areaM2: number;
|
||||
pricePerM2: number;
|
||||
similarity: number;
|
||||
latitude?: number;
|
||||
longitude?: number;
|
||||
}
|
||||
|
||||
export interface PriceDriver {
|
||||
feature: string;
|
||||
impact: number;
|
||||
direction: 'positive' | 'negative';
|
||||
}
|
||||
|
||||
export interface ValuationResult {
|
||||
id: string;
|
||||
estimatedPriceVND: number;
|
||||
confidence: number;
|
||||
pricePerM2: number;
|
||||
priceRangeLow: number;
|
||||
priceRangeHigh: number;
|
||||
comparables: ValuationComparable[];
|
||||
priceDrivers: PriceDriver[];
|
||||
modelVersion: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface ValuationHistoryItem {
|
||||
id: string;
|
||||
propertyType: string;
|
||||
district: string;
|
||||
city: string;
|
||||
area: number;
|
||||
estimatedPriceVND: number;
|
||||
confidence: number;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface ValuationHistoryResponse {
|
||||
data: ValuationHistoryItem[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
// ─── API ────────────────────────────────────────────────
|
||||
|
||||
export const valuationApi = {
|
||||
predict: (data: ValuationRequest) =>
|
||||
apiClient.post<ValuationResult>('/valuation/predict', data),
|
||||
|
||||
getHistory: (page = 1, limit = 10) =>
|
||||
apiClient.get<ValuationHistoryResponse>(
|
||||
`/valuation/history?page=${page}&limit=${limit}`,
|
||||
),
|
||||
|
||||
getById: (id: string) =>
|
||||
apiClient.get<ValuationResult>(`/valuation/${id}`),
|
||||
|
||||
predictForListing: (listingId: string) =>
|
||||
apiClient.post<ValuationResult>(`/valuation/predict-listing/${listingId}`),
|
||||
};
|
||||
Reference in New Issue
Block a user