feat(web): add property comparison page with side-by-side view

Build a complete property comparison feature at /compare:
- Zustand store with localStorage persistence for selected listings (2-5)
- Side-by-side comparison table (price, area, price/m², amenities, location, etc.)
- Summary statistics banner (price range, area range, price/m² range)
- "Add to Compare" button on property cards and detail pages
- Floating comparison bar for quick access when listings are selected
- Bilingual i18n support (Vietnamese + English)
- 18 unit tests for store logic and comparison stats computation
- Mobile-responsive layout with horizontal scroll on comparison table

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-10 23:55:50 +07:00
parent 55a01c5738
commit 37fab515b7
13 changed files with 1092 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
import { listingsApi, type ListingDetail } from './listings-api';
/**
* Fetch multiple listing details in parallel for comparison.
* Returns only successfully fetched listings (silently skips 404s).
*/
export async function fetchListingsForComparison(
ids: string[],
): Promise<ListingDetail[]> {
const results = await Promise.allSettled(ids.map((id) => listingsApi.getById(id)));
return results
.filter((r): r is PromiseFulfilledResult<ListingDetail> => r.status === 'fulfilled')
.map((r) => r.value);
}