feat(listings): phase A — surface usableAreaM2, floor/totalFloors, metroDistanceM
Some checks failed
E2E Tests / Playwright E2E (push) Failing after 9s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 46s
Security Scanning / Trivy Filesystem Scan (push) Has been cancelled
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 9s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m18s
Deploy / Build API Image (push) Failing after 28s
Deploy / Build Web Image (push) Failing after 12s
Deploy / Build AI Services Image (push) Failing after 10s
Security Scanning / Trivy Scan — Web Image (push) Failing after 31s
Deploy / Deploy to Staging (push) Has been cancelled
Deploy / Smoke Test Staging (push) Has been cancelled
Deploy / Rollback Staging (push) Has been cancelled
Deploy / Smoke Test Production (push) Has been cancelled
Deploy / Rollback Production (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled
Security Scanning / Security Gate (push) Has been cancelled
Security Scanning / Trivy Scan — AI Services Image (push) Has started running

The Property table already stores usableAreaM2, floor, totalFloors,
metroDistanceM and nearbyPOIs but the listing detail endpoint was
dropping them. Add them to ListingDetailData + the Prisma read query,
mirror the additions on the frontend ListingDetail type, and render
them on the detail page:

- Quick-specs bar now shows "Tầng X / Y" (floor/totalFloors) with a
  sensible fallback to `floors`, plus "Cách metro" when populated.
- Details card adds rows: "Diện tích sử dụng", "Tầng / Tổng tầng"
  (merges floor + totalFloors), "Cách metro gần nhất" (formatted m/km).
- New "transit" icon for the metro stat.

Purely additive surfacing — no schema change, no migration. Listings
missing these fields still render as before.

Test fixture in listing-detail-client.spec.tsx extended with the new
nullable fields so the type stays compatible.

Phase A of 4 (Listings detail enhancement plan).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ho Ngoc Hai
2026-04-19 14:41:17 +07:00
parent 98a84e9e3f
commit 6067adc095
5 changed files with 70 additions and 3 deletions

View File

@@ -28,13 +28,18 @@ export interface ListingDetailData {
latitude: number;
longitude: number;
areaM2: number;
usableAreaM2: number | null;
bedrooms: number | null;
bathrooms: number | null;
floors: number | null;
floor: number | null;
totalFloors: number | null;
direction: Direction | null;
yearBuilt: number | null;
legalStatus: string | null;
amenities: unknown;
nearbyPOIs: unknown;
metroDistanceM: number | null;
projectName: string | null;
media: ListingMediaData[];
};

View File

@@ -62,13 +62,18 @@ export async function findByIdWithProperty(
latitude: geo.latitude,
longitude: geo.longitude,
areaM2: listing.property.areaM2,
usableAreaM2: listing.property.usableAreaM2,
bedrooms: listing.property.bedrooms,
bathrooms: listing.property.bathrooms,
floors: listing.property.floors,
floor: listing.property.floor,
totalFloors: listing.property.totalFloors,
direction: listing.property.direction,
yearBuilt: listing.property.yearBuilt,
legalStatus: listing.property.legalStatus,
amenities: listing.property.amenities,
nearbyPOIs: listing.property.nearbyPOIs,
metroDistanceM: listing.property.metroDistanceM,
projectName: listing.property.projectName,
media: listing.property.media.map((m) => ({
id: m.id,