feat(osm): user-facing UX — POI sidebar + search filter + docs

* Listing detail: drop the new <NearbyPoiSidebar> below the price card
  with default 1.5km radius and 6 categories (school/secondary/hospital/
  market/bank/metro). Reads property.lat/lng — no-op when unset.
* KCN detail: same component but 3km radius with the categories that
  matter for industrial parks (hospital/bank/gas/bus/metro/police).
* New <PoiSearchFilter> widget for the search page: pill button →
  popover with radius dropdown (300m..5km), 3 quick presets ("Family",
  "Commute", "Convenience"), and 6 grouped category checkboxes. Wires
  to a `PoiNearbyConstraint` value so callers can pass it into search
  filters when they're ready.
* docs/osm-data-model.md: canonical reference for every OSM-sourced
  table, sync cadence, quality gates, runbook for ops, and a clear
  "how to add a new POI category" guide.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ho Ngoc Hai
2026-05-01 12:06:52 +07:00
parent fba536406d
commit a9770a5f93
4 changed files with 286 additions and 0 deletions

View File

@@ -14,6 +14,7 @@ import {
} from 'lucide-react';
import * as React from 'react';
import { ParkMap } from '@/components/khu-cong-nghiep/park-map';
import { NearbyPoiSidebar } from '@/components/poi/nearby-poi-sidebar';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import {
@@ -252,6 +253,16 @@ export function KhuCongNghiepDetailClient({ park }: KhuCongNghiepDetailClientPro
{/* Sidebar */}
<div className="space-y-6">
{/* OSM POI nearby (schools, hospitals, banks, transport, …) */}
{park.latitude != null && park.longitude != null && (
<NearbyPoiSidebar
lat={park.latitude}
lng={park.longitude}
radius={3000}
categories={['HOSPITAL', 'BANK', 'GAS_STATION', 'BUS_STATION', 'METRO_STATION', 'POLICE']}
/>
)}
{/* Rent info */}
<Card>
<CardHeader>