@burdenoff/microfe-housingvista 2026.929.1 → 2026.930.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/housingvista/HousingVistaRoutes.js +4 -4
- package/dist/housingvista/HousingVistaRoutes.js.map +1 -1
- package/dist/housingvista/components/PropertyCard.d.ts +5 -1
- package/dist/housingvista/components/PropertyCard.d.ts.map +1 -1
- package/dist/housingvista/components/PropertyCard.js +77 -67
- package/dist/housingvista/components/PropertyCard.js.map +1 -1
- package/dist/housingvista/components/maps/PropertyMapView.d.ts.map +1 -1
- package/dist/housingvista/components/maps/PropertyMapView.js +72 -65
- package/dist/housingvista/components/maps/PropertyMapView.js.map +1 -1
- package/dist/housingvista/pages/properties/PropertiesPage.d.ts.map +1 -1
- package/dist/housingvista/pages/properties/PropertiesPage.js +355 -324
- package/dist/housingvista/pages/properties/PropertiesPage.js.map +1 -1
- package/dist/housingvista/pages/properties/PropertyDetailPage.d.ts.map +1 -1
- package/dist/housingvista/pages/properties/PropertyDetailPage.js +220 -220
- package/dist/housingvista/pages/properties/PropertyDetailPage.js.map +1 -1
- package/dist/housingvista/pages/shortlist/ShortlistPage.d.ts.map +1 -1
- package/dist/housingvista/pages/shortlist/ShortlistPage.js +1 -0
- package/dist/housingvista/pages/shortlist/ShortlistPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -6,14 +6,14 @@ import { Popup as o } from "../../../node_modules/react-leaflet/lib/Popup.js";
|
|
|
6
6
|
import { TileLayer as s } from "../../../node_modules/react-leaflet/lib/TileLayer.js";
|
|
7
7
|
import { OSM_ATTRIBUTION as c, OSM_TILE_URL as l, boundsFromLeaflet as u, createPropertyPinIcon as d, isRealCoord as f } from "./leaflet-setup.js";
|
|
8
8
|
import { useEffect as p, useMemo as m, useRef as h, useState as g } from "react";
|
|
9
|
-
import {
|
|
10
|
-
import { Fragment as
|
|
9
|
+
import { BadgeCheck as _, Bath as v, Bed as y, RotateCcw as b, ShieldCheck as x, Square as S } from "lucide-react";
|
|
10
|
+
import { Fragment as C, jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
11
11
|
//#region src/housingvista/components/maps/PropertyMapView.tsx
|
|
12
|
-
function
|
|
12
|
+
function E() {
|
|
13
13
|
let [e, t] = g(!1);
|
|
14
14
|
return p(() => t(!0), []), e;
|
|
15
15
|
}
|
|
16
|
-
function
|
|
16
|
+
function D({ onChange: e }) {
|
|
17
17
|
let t = r({
|
|
18
18
|
moveend: () => e(t.getBounds()),
|
|
19
19
|
zoomend: () => e(t.getBounds())
|
|
@@ -22,25 +22,25 @@ function E({ onChange: e }) {
|
|
|
22
22
|
e(t.getBounds());
|
|
23
23
|
}, [t, e]), null;
|
|
24
24
|
}
|
|
25
|
-
var
|
|
26
|
-
let
|
|
27
|
-
if (!
|
|
28
|
-
let e = u(
|
|
25
|
+
var O = ({ properties: r, loading: p = !1, fallbackCenter: O = [20.5937, 78.9629], height: k = 520, className: A, selectedIds: j, onSelectProperty: M, onSearchThisArea: N }) => {
|
|
26
|
+
let P = E(), [F, I] = g(null), [L, R] = g(null), z = h(null), B = m(() => r.filter((e) => f(e.location.coordinates.latitude, e.location.coordinates.longitude)), [r]), V = B.length ? [B[0].location.coordinates.latitude, B[0].location.coordinates.longitude] : O, H = m(() => {
|
|
27
|
+
if (!F) return !1;
|
|
28
|
+
let e = u(F), t = z.current;
|
|
29
29
|
if (!t) return !0;
|
|
30
30
|
let n = 5e-4;
|
|
31
31
|
return Math.abs(e.neLat - t.neLat) > n || Math.abs(e.neLng - t.neLng) > n || Math.abs(e.swLat - t.swLat) > n || Math.abs(e.swLng - t.swLng) > n;
|
|
32
|
-
}, [
|
|
33
|
-
return /* @__PURE__ */
|
|
32
|
+
}, [F]);
|
|
33
|
+
return /* @__PURE__ */ T("div", {
|
|
34
34
|
className: "grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1.6fr)_minmax(0,1fr)]",
|
|
35
|
-
children: [/* @__PURE__ */
|
|
36
|
-
className: e("relative overflow-hidden rounded-card border border-border-seam bg-bg-sunken",
|
|
35
|
+
children: [/* @__PURE__ */ w("div", {
|
|
36
|
+
className: e("relative overflow-hidden rounded-card border border-border-seam bg-bg-sunken", A),
|
|
37
37
|
style: {
|
|
38
|
-
height:
|
|
38
|
+
height: k,
|
|
39
39
|
width: "100%"
|
|
40
40
|
},
|
|
41
|
-
children:
|
|
42
|
-
center:
|
|
43
|
-
zoom:
|
|
41
|
+
children: P ? /* @__PURE__ */ T(C, { children: [/* @__PURE__ */ T(i, {
|
|
42
|
+
center: V,
|
|
43
|
+
zoom: B.length ? 11 : 5,
|
|
44
44
|
scrollWheelZoom: !0,
|
|
45
45
|
style: {
|
|
46
46
|
height: "100%",
|
|
@@ -48,47 +48,54 @@ var D = ({ properties: r, loading: p = !1, fallbackCenter: D = [20.5937, 78.9629
|
|
|
48
48
|
},
|
|
49
49
|
className: "z-0",
|
|
50
50
|
children: [
|
|
51
|
-
/* @__PURE__ */
|
|
51
|
+
/* @__PURE__ */ w(s, {
|
|
52
52
|
url: l,
|
|
53
53
|
attribution: c
|
|
54
54
|
}),
|
|
55
|
-
/* @__PURE__ */
|
|
56
|
-
|
|
57
|
-
let n =
|
|
58
|
-
return /* @__PURE__ */
|
|
55
|
+
/* @__PURE__ */ w(D, { onChange: I }),
|
|
56
|
+
B.map((e) => {
|
|
57
|
+
let n = L === e.id || j?.has(e.id);
|
|
58
|
+
return /* @__PURE__ */ w(a, {
|
|
59
59
|
position: [e.location.coordinates.latitude, e.location.coordinates.longitude],
|
|
60
60
|
icon: d(t(e.price.amount, e.price.currency), {
|
|
61
61
|
selected: n,
|
|
62
62
|
rera: e.reraVerificationStatus === "verified"
|
|
63
63
|
}),
|
|
64
64
|
eventHandlers: {
|
|
65
|
-
click: () =>
|
|
66
|
-
mouseover: () =>
|
|
67
|
-
mouseout: () =>
|
|
65
|
+
click: () => M?.(e.id),
|
|
66
|
+
mouseover: () => R(e.id),
|
|
67
|
+
mouseout: () => R((t) => t === e.id ? null : t)
|
|
68
68
|
},
|
|
69
|
-
children: /* @__PURE__ */
|
|
69
|
+
children: /* @__PURE__ */ w(o, {
|
|
70
70
|
className: "hv-popup",
|
|
71
|
-
children: /* @__PURE__ */
|
|
71
|
+
children: /* @__PURE__ */ T("div", {
|
|
72
72
|
className: "p-3",
|
|
73
73
|
children: [
|
|
74
|
-
/* @__PURE__ */
|
|
74
|
+
/* @__PURE__ */ T("div", {
|
|
75
75
|
className: "flex items-center gap-1.5",
|
|
76
|
-
children: [
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
children: [
|
|
77
|
+
/* @__PURE__ */ w("p", {
|
|
78
|
+
className: "text-sm font-semibold text-text-primary",
|
|
79
|
+
children: e.title
|
|
80
|
+
}),
|
|
81
|
+
e.reraVerificationStatus === "verified" && /* @__PURE__ */ w(x, { className: "h-3.5 w-3.5 shrink-0 text-status-success-text" }),
|
|
82
|
+
e.verificationStatus === "verified" && /* @__PURE__ */ w(_, {
|
|
83
|
+
className: "h-3.5 w-3.5 shrink-0 text-status-success-text",
|
|
84
|
+
"aria-label": "Verified listing"
|
|
85
|
+
})
|
|
86
|
+
]
|
|
80
87
|
}),
|
|
81
|
-
/* @__PURE__ */
|
|
88
|
+
/* @__PURE__ */ w("p", {
|
|
82
89
|
className: "text-xs text-text-secondary",
|
|
83
90
|
children: [e.location.neighborhood, e.location.city].filter(Boolean).join(", ")
|
|
84
91
|
}),
|
|
85
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ T("p", {
|
|
86
93
|
className: "mt-1 text-sm font-bold text-text-primary",
|
|
87
94
|
children: [t(e.price.amount, e.price.currency), e.price.type === "rent" ? "/mo" : ""]
|
|
88
95
|
}),
|
|
89
|
-
/* @__PURE__ */
|
|
96
|
+
/* @__PURE__ */ w("button", {
|
|
90
97
|
type: "button",
|
|
91
|
-
onClick: () =>
|
|
98
|
+
onClick: () => M?.(e.id),
|
|
92
99
|
className: "mt-2 text-xs font-medium text-[var(--color-action-primary-bg)] hover:underline",
|
|
93
100
|
children: "View details"
|
|
94
101
|
})
|
|
@@ -98,62 +105,62 @@ var D = ({ properties: r, loading: p = !1, fallbackCenter: D = [20.5937, 78.9629
|
|
|
98
105
|
}, e.id);
|
|
99
106
|
})
|
|
100
107
|
]
|
|
101
|
-
}),
|
|
108
|
+
}), N && /* @__PURE__ */ w("div", {
|
|
102
109
|
className: "pointer-events-none absolute inset-x-0 top-3 z-10 flex justify-center",
|
|
103
|
-
children: /* @__PURE__ */
|
|
110
|
+
children: /* @__PURE__ */ T("button", {
|
|
104
111
|
type: "button",
|
|
105
112
|
onClick: () => {
|
|
106
|
-
if (!
|
|
107
|
-
let e = u(
|
|
108
|
-
|
|
113
|
+
if (!F || !N) return;
|
|
114
|
+
let e = u(F);
|
|
115
|
+
z.current = e, N(e);
|
|
109
116
|
},
|
|
110
|
-
disabled: !
|
|
111
|
-
className: e("pointer-events-auto inline-flex items-center gap-1.5 rounded-full border border-border-subtle bg-bg-surface px-3 py-1.5 text-xs font-medium shadow-elevation-2 transition-colors",
|
|
112
|
-
children: [/* @__PURE__ */
|
|
117
|
+
disabled: !H || p,
|
|
118
|
+
className: e("pointer-events-auto inline-flex items-center gap-1.5 rounded-full border border-border-subtle bg-bg-surface px-3 py-1.5 text-xs font-medium shadow-elevation-2 transition-colors", H && !p ? "text-text-primary hover:bg-bg-sunken" : "cursor-not-allowed text-text-secondary opacity-70"),
|
|
119
|
+
children: [/* @__PURE__ */ w(b, { className: "h-3 w-3" }), p ? "Searching…" : "Search this area"]
|
|
113
120
|
})
|
|
114
|
-
})] }) : /* @__PURE__ */
|
|
121
|
+
})] }) : /* @__PURE__ */ w("div", {
|
|
115
122
|
className: "flex h-full w-full items-center justify-center",
|
|
116
123
|
"aria-busy": "true",
|
|
117
|
-
children: /* @__PURE__ */
|
|
124
|
+
children: /* @__PURE__ */ w("div", { className: "h-full w-full motion-safe:animate-pulse bg-bg-sunken" })
|
|
118
125
|
})
|
|
119
|
-
}), /* @__PURE__ */
|
|
126
|
+
}), /* @__PURE__ */ T("div", {
|
|
120
127
|
className: "flex flex-col gap-2 overflow-y-auto rounded-card border border-border-seam bg-bg-surface p-2",
|
|
121
|
-
style: { height:
|
|
122
|
-
children: [
|
|
128
|
+
style: { height: k },
|
|
129
|
+
children: [B.length === 0 && !p && /* @__PURE__ */ w("p", {
|
|
123
130
|
className: "p-4 text-center text-sm text-text-secondary",
|
|
124
131
|
children: "No properties with a mapped location match the current filters."
|
|
125
|
-
}),
|
|
132
|
+
}), B.map((r) => /* @__PURE__ */ T("button", {
|
|
126
133
|
type: "button",
|
|
127
|
-
onMouseEnter: () =>
|
|
128
|
-
onMouseLeave: () =>
|
|
129
|
-
onClick: () =>
|
|
130
|
-
className: e("flex items-center gap-3 rounded-lg border p-2 text-left transition-colors",
|
|
131
|
-
children: [/* @__PURE__ */
|
|
134
|
+
onMouseEnter: () => R(r.id),
|
|
135
|
+
onMouseLeave: () => R((e) => e === r.id ? null : e),
|
|
136
|
+
onClick: () => M?.(r.id),
|
|
137
|
+
className: e("flex items-center gap-3 rounded-lg border p-2 text-left transition-colors", L === r.id ? "border-[var(--color-action-primary-bg)] bg-bg-sunken" : "border-transparent hover:bg-bg-sunken"),
|
|
138
|
+
children: [/* @__PURE__ */ T("div", {
|
|
132
139
|
className: "min-w-0 flex-1",
|
|
133
140
|
children: [
|
|
134
|
-
/* @__PURE__ */
|
|
141
|
+
/* @__PURE__ */ w("p", {
|
|
135
142
|
className: "truncate text-sm font-medium text-text-primary",
|
|
136
143
|
children: r.title
|
|
137
144
|
}),
|
|
138
|
-
/* @__PURE__ */
|
|
145
|
+
/* @__PURE__ */ w("p", {
|
|
139
146
|
className: "truncate text-xs text-text-secondary",
|
|
140
147
|
children: [r.location.neighborhood, r.location.city].filter(Boolean).join(", ")
|
|
141
148
|
}),
|
|
142
|
-
/* @__PURE__ */
|
|
149
|
+
/* @__PURE__ */ T("div", {
|
|
143
150
|
className: "mt-1 flex items-center gap-3 text-[11px] text-text-secondary",
|
|
144
151
|
children: [
|
|
145
|
-
r.specifications.bedrooms != null && /* @__PURE__ */
|
|
152
|
+
r.specifications.bedrooms != null && /* @__PURE__ */ T("span", {
|
|
146
153
|
className: "inline-flex items-center gap-1",
|
|
147
|
-
children: [/* @__PURE__ */
|
|
154
|
+
children: [/* @__PURE__ */ w(y, { className: "h-3 w-3" }), r.specifications.bedrooms]
|
|
148
155
|
}),
|
|
149
|
-
r.specifications.bathrooms != null && /* @__PURE__ */
|
|
156
|
+
r.specifications.bathrooms != null && /* @__PURE__ */ T("span", {
|
|
150
157
|
className: "inline-flex items-center gap-1",
|
|
151
|
-
children: [/* @__PURE__ */
|
|
158
|
+
children: [/* @__PURE__ */ w(v, { className: "h-3 w-3" }), r.specifications.bathrooms]
|
|
152
159
|
}),
|
|
153
|
-
/* @__PURE__ */
|
|
160
|
+
/* @__PURE__ */ T("span", {
|
|
154
161
|
className: "inline-flex items-center gap-1",
|
|
155
162
|
children: [
|
|
156
|
-
/* @__PURE__ */
|
|
163
|
+
/* @__PURE__ */ w(S, { className: "h-3 w-3" }),
|
|
157
164
|
n(r.specifications.totalArea),
|
|
158
165
|
" sq ft"
|
|
159
166
|
]
|
|
@@ -161,7 +168,7 @@ var D = ({ properties: r, loading: p = !1, fallbackCenter: D = [20.5937, 78.9629
|
|
|
161
168
|
]
|
|
162
169
|
})
|
|
163
170
|
]
|
|
164
|
-
}), /* @__PURE__ */
|
|
171
|
+
}), /* @__PURE__ */ w("span", {
|
|
165
172
|
className: "shrink-0 text-sm font-bold text-text-primary",
|
|
166
173
|
children: t(r.price.amount, r.price.currency)
|
|
167
174
|
})]
|
|
@@ -170,6 +177,6 @@ var D = ({ properties: r, loading: p = !1, fallbackCenter: D = [20.5937, 78.9629
|
|
|
170
177
|
});
|
|
171
178
|
};
|
|
172
179
|
//#endregion
|
|
173
|
-
export {
|
|
180
|
+
export { O as PropertyMapView };
|
|
174
181
|
|
|
175
182
|
//# sourceMappingURL=PropertyMapView.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PropertyMapView.js","names":[],"sources":["../../../../src/housingvista/components/maps/PropertyMapView.tsx"],"sourcesContent":["/**\n * PropertyMapView — the HousingVista property map (BOFF-4617 frontend half).\n *\n * Renders every property with real coordinates as a price-labeled pin using\n * react-leaflet (the same fleet-wide OSM + divIcon pattern as\n * microfe-movethewheels). Panning/zooming does NOT auto-refetch on every\n * frame — the user reviews the new viewport and explicitly presses\n * \"Search this area\", which reports the new bounds up to the caller so it\n * can be sent to the server-side `bounds` filter (`HousingVistaPropertyFilterInput`)\n * and mirrored into the URL for shareable/bookmarkable map searches.\n * @module housingvista\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { MapContainer, Marker, Popup, TileLayer, useMapEvents } from 'react-leaflet';\nimport type { LatLngBounds } from 'leaflet';\nimport { Bed, Bath, Square, RotateCcw, ShieldCheck } from 'lucide-react';\nimport { boundsFromLeaflet, createPropertyPinIcon, isRealCoord, OSM_ATTRIBUTION, OSM_TILE_URL } from './leaflet-setup';\nimport type { LeafletBoundsResult } from './leaflet-setup';\nimport { cn, formatCompactCurrency, formatNumber } from '../../utils/helpers';\nimport type { Property } from '../../types';\n\n/** SSR/lazy safety: only mount Leaflet (which touches the DOM) after mount. */\nfunction useIsMounted(): boolean {\n const [mounted, setMounted] = useState(false);\n useEffect(() => setMounted(true), []);\n return mounted;\n}\n\ninterface BoundsWatcherProps {\n onChange: (bounds: LatLngBounds) => void;\n}\n\n/** Tracks the live viewport and reports it up on every pan/zoom settle. */\nfunction BoundsWatcher({ onChange }: BoundsWatcherProps) {\n const map = useMapEvents({\n moveend: () => onChange(map.getBounds()),\n zoomend: () => onChange(map.getBounds()),\n });\n // `map` (from useMapEvents) and `onChange` (the parent's setState setter) are\n // both referentially stable across renders, so this effectively fires once\n // on mount — reporting the initial viewport — without needing to suppress\n // the exhaustive-deps rule.\n useEffect(() => {\n onChange(map.getBounds());\n }, [map, onChange]);\n return null;\n}\n\nexport interface PropertyMapViewProps {\n properties: Property[];\n loading?: boolean;\n /** Center used when no properties have coordinates yet. */\n fallbackCenter?: [number, number];\n height?: number | string;\n className?: string;\n selectedIds?: Set<string>;\n onSelectProperty?: (id: string) => void;\n /** Called only when the user presses \"Search this area\", with the map's current viewport. */\n onSearchThisArea?: (bounds: LeafletBoundsResult) => void;\n}\n\n/**\n * PropertyMapView — split layout: map on top (or left on wide screens) with a\n * scrollable list of the same matching properties alongside, so a click on\n * either a pin or a list row highlights the other.\n */\nexport const PropertyMapView = ({\n properties,\n loading = false,\n fallbackCenter = [20.5937, 78.9629], // India centroid — sensible default for an unfiltered, empty map.\n height = 520,\n className,\n selectedIds,\n onSelectProperty,\n onSearchThisArea,\n}: PropertyMapViewProps) => {\n const mounted = useIsMounted();\n const [pendingBounds, setPendingBounds] = useState<LatLngBounds | null>(null);\n const [hoveredId, setHoveredId] = useState<string | null>(null);\n const searchedBoundsRef = useRef<LeafletBoundsResult | null>(null);\n\n const plottable = useMemo(\n () => properties.filter((p) => isRealCoord(p.location.coordinates.latitude, p.location.coordinates.longitude)),\n [properties]\n );\n\n const initialCenter: [number, number] = plottable.length\n ? [plottable[0].location.coordinates.latitude, plottable[0].location.coordinates.longitude]\n : fallbackCenter;\n\n const dirtySearch = useMemo(() => {\n if (!pendingBounds) return false;\n const b = boundsFromLeaflet(pendingBounds);\n const last = searchedBoundsRef.current;\n if (!last) return true;\n const eps = 0.0005;\n return (\n Math.abs(b.neLat - last.neLat) > eps ||\n Math.abs(b.neLng - last.neLng) > eps ||\n Math.abs(b.swLat - last.swLat) > eps ||\n Math.abs(b.swLng - last.swLng) > eps\n );\n }, [pendingBounds]);\n\n const handleSearchThisArea = () => {\n if (!pendingBounds || !onSearchThisArea) return;\n const b = boundsFromLeaflet(pendingBounds);\n searchedBoundsRef.current = b;\n onSearchThisArea(b);\n };\n\n const wrapperClass = cn('relative overflow-hidden rounded-card border border-border-seam bg-bg-sunken', className);\n\n return (\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1.6fr)_minmax(0,1fr)]\">\n <div className={wrapperClass} style={{ height, width: '100%' }}>\n {!mounted ? (\n <div className=\"flex h-full w-full items-center justify-center\" aria-busy=\"true\">\n <div className=\"h-full w-full motion-safe:animate-pulse bg-bg-sunken\" />\n </div>\n ) : (\n <>\n <MapContainer\n center={initialCenter}\n zoom={plottable.length ? 11 : 5}\n scrollWheelZoom\n style={{ height: '100%', width: '100%' }}\n className=\"z-0\"\n >\n <TileLayer url={OSM_TILE_URL} attribution={OSM_ATTRIBUTION} />\n <BoundsWatcher onChange={setPendingBounds} />\n {plottable.map((property) => {\n const isSelected = hoveredId === property.id || selectedIds?.has(property.id);\n return (\n <Marker\n key={property.id}\n position={[property.location.coordinates.latitude, property.location.coordinates.longitude]}\n icon={createPropertyPinIcon(formatCompactCurrency(property.price.amount, property.price.currency), {\n selected: isSelected,\n rera: property.reraVerificationStatus === 'verified',\n })}\n eventHandlers={{\n click: () => onSelectProperty?.(property.id),\n mouseover: () => setHoveredId(property.id),\n mouseout: () => setHoveredId((cur) => (cur === property.id ? null : cur)),\n }}\n >\n <Popup className=\"hv-popup\">\n <div className=\"p-3\">\n <div className=\"flex items-center gap-1.5\">\n <p className=\"text-sm font-semibold text-text-primary\">{property.title}</p>\n {property.reraVerificationStatus === 'verified' && (\n <ShieldCheck className=\"h-3.5 w-3.5 shrink-0 text-status-success-text\" />\n )}\n </div>\n <p className=\"text-xs text-text-secondary\">\n {[property.location.neighborhood, property.location.city].filter(Boolean).join(', ')}\n </p>\n <p className=\"mt-1 text-sm font-bold text-text-primary\">\n {formatCompactCurrency(property.price.amount, property.price.currency)}\n {property.price.type === 'rent' ? '/mo' : ''}\n </p>\n <button\n type=\"button\"\n onClick={() => onSelectProperty?.(property.id)}\n className=\"mt-2 text-xs font-medium text-[var(--color-action-primary-bg)] hover:underline\"\n >\n View details\n </button>\n </div>\n </Popup>\n </Marker>\n );\n })}\n </MapContainer>\n\n {onSearchThisArea && (\n <div className=\"pointer-events-none absolute inset-x-0 top-3 z-10 flex justify-center\">\n <button\n type=\"button\"\n onClick={handleSearchThisArea}\n disabled={!dirtySearch || loading}\n className={cn(\n 'pointer-events-auto inline-flex items-center gap-1.5 rounded-full border border-border-subtle bg-bg-surface px-3 py-1.5 text-xs font-medium shadow-elevation-2 transition-colors',\n dirtySearch && !loading\n ? 'text-text-primary hover:bg-bg-sunken'\n : 'cursor-not-allowed text-text-secondary opacity-70'\n )}\n >\n <RotateCcw className=\"h-3 w-3\" />\n {loading ? 'Searching…' : 'Search this area'}\n </button>\n </div>\n )}\n </>\n )}\n </div>\n\n {/* Compact list synced with the plotted pins */}\n <div\n className=\"flex flex-col gap-2 overflow-y-auto rounded-card border border-border-seam bg-bg-surface p-2\"\n style={{ height }}\n >\n {plottable.length === 0 && !loading && (\n <p className=\"p-4 text-center text-sm text-text-secondary\">\n No properties with a mapped location match the current filters.\n </p>\n )}\n {plottable.map((property) => (\n <button\n key={property.id}\n type=\"button\"\n onMouseEnter={() => setHoveredId(property.id)}\n onMouseLeave={() => setHoveredId((cur) => (cur === property.id ? null : cur))}\n onClick={() => onSelectProperty?.(property.id)}\n className={cn(\n 'flex items-center gap-3 rounded-lg border p-2 text-left transition-colors',\n hoveredId === property.id\n ? 'border-[var(--color-action-primary-bg)] bg-bg-sunken'\n : 'border-transparent hover:bg-bg-sunken'\n )}\n >\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{property.title}</p>\n <p className=\"truncate text-xs text-text-secondary\">\n {[property.location.neighborhood, property.location.city].filter(Boolean).join(', ')}\n </p>\n <div className=\"mt-1 flex items-center gap-3 text-[11px] text-text-secondary\">\n {property.specifications.bedrooms != null && (\n <span className=\"inline-flex items-center gap-1\">\n <Bed className=\"h-3 w-3\" />\n {property.specifications.bedrooms}\n </span>\n )}\n {property.specifications.bathrooms != null && (\n <span className=\"inline-flex items-center gap-1\">\n <Bath className=\"h-3 w-3\" />\n {property.specifications.bathrooms}\n </span>\n )}\n <span className=\"inline-flex items-center gap-1\">\n <Square className=\"h-3 w-3\" />\n {formatNumber(property.specifications.totalArea)} sq ft\n </span>\n </div>\n </div>\n <span className=\"shrink-0 text-sm font-bold text-text-primary\">\n {formatCompactCurrency(property.price.amount, property.price.currency)}\n </span>\n </button>\n ))}\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PropertyMapView.js","names":[],"sources":["../../../../src/housingvista/components/maps/PropertyMapView.tsx"],"sourcesContent":["/**\n * PropertyMapView — the HousingVista property map (BOFF-4617 frontend half).\n *\n * Renders every property with real coordinates as a price-labeled pin using\n * react-leaflet (the same fleet-wide OSM + divIcon pattern as\n * microfe-movethewheels). Panning/zooming does NOT auto-refetch on every\n * frame — the user reviews the new viewport and explicitly presses\n * \"Search this area\", which reports the new bounds up to the caller so it\n * can be sent to the server-side `bounds` filter (`HousingVistaPropertyFilterInput`)\n * and mirrored into the URL for shareable/bookmarkable map searches.\n * @module housingvista\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { MapContainer, Marker, Popup, TileLayer, useMapEvents } from 'react-leaflet';\nimport type { LatLngBounds } from 'leaflet';\nimport { Bed, Bath, Square, RotateCcw, ShieldCheck, BadgeCheck } from 'lucide-react';\nimport { boundsFromLeaflet, createPropertyPinIcon, isRealCoord, OSM_ATTRIBUTION, OSM_TILE_URL } from './leaflet-setup';\nimport type { LeafletBoundsResult } from './leaflet-setup';\nimport { cn, formatCompactCurrency, formatNumber } from '../../utils/helpers';\nimport type { Property } from '../../types';\n\n/** SSR/lazy safety: only mount Leaflet (which touches the DOM) after mount. */\nfunction useIsMounted(): boolean {\n const [mounted, setMounted] = useState(false);\n useEffect(() => setMounted(true), []);\n return mounted;\n}\n\ninterface BoundsWatcherProps {\n onChange: (bounds: LatLngBounds) => void;\n}\n\n/** Tracks the live viewport and reports it up on every pan/zoom settle. */\nfunction BoundsWatcher({ onChange }: BoundsWatcherProps) {\n const map = useMapEvents({\n moveend: () => onChange(map.getBounds()),\n zoomend: () => onChange(map.getBounds()),\n });\n // `map` (from useMapEvents) and `onChange` (the parent's setState setter) are\n // both referentially stable across renders, so this effectively fires once\n // on mount — reporting the initial viewport — without needing to suppress\n // the exhaustive-deps rule.\n useEffect(() => {\n onChange(map.getBounds());\n }, [map, onChange]);\n return null;\n}\n\nexport interface PropertyMapViewProps {\n properties: Property[];\n loading?: boolean;\n /** Center used when no properties have coordinates yet. */\n fallbackCenter?: [number, number];\n height?: number | string;\n className?: string;\n selectedIds?: Set<string>;\n onSelectProperty?: (id: string) => void;\n /** Called only when the user presses \"Search this area\", with the map's current viewport. */\n onSearchThisArea?: (bounds: LeafletBoundsResult) => void;\n}\n\n/**\n * PropertyMapView — split layout: map on top (or left on wide screens) with a\n * scrollable list of the same matching properties alongside, so a click on\n * either a pin or a list row highlights the other.\n */\nexport const PropertyMapView = ({\n properties,\n loading = false,\n fallbackCenter = [20.5937, 78.9629], // India centroid — sensible default for an unfiltered, empty map.\n height = 520,\n className,\n selectedIds,\n onSelectProperty,\n onSearchThisArea,\n}: PropertyMapViewProps) => {\n const mounted = useIsMounted();\n const [pendingBounds, setPendingBounds] = useState<LatLngBounds | null>(null);\n const [hoveredId, setHoveredId] = useState<string | null>(null);\n const searchedBoundsRef = useRef<LeafletBoundsResult | null>(null);\n\n const plottable = useMemo(\n () => properties.filter((p) => isRealCoord(p.location.coordinates.latitude, p.location.coordinates.longitude)),\n [properties]\n );\n\n const initialCenter: [number, number] = plottable.length\n ? [plottable[0].location.coordinates.latitude, plottable[0].location.coordinates.longitude]\n : fallbackCenter;\n\n const dirtySearch = useMemo(() => {\n if (!pendingBounds) return false;\n const b = boundsFromLeaflet(pendingBounds);\n const last = searchedBoundsRef.current;\n if (!last) return true;\n const eps = 0.0005;\n return (\n Math.abs(b.neLat - last.neLat) > eps ||\n Math.abs(b.neLng - last.neLng) > eps ||\n Math.abs(b.swLat - last.swLat) > eps ||\n Math.abs(b.swLng - last.swLng) > eps\n );\n }, [pendingBounds]);\n\n const handleSearchThisArea = () => {\n if (!pendingBounds || !onSearchThisArea) return;\n const b = boundsFromLeaflet(pendingBounds);\n searchedBoundsRef.current = b;\n onSearchThisArea(b);\n };\n\n const wrapperClass = cn('relative overflow-hidden rounded-card border border-border-seam bg-bg-sunken', className);\n\n return (\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1.6fr)_minmax(0,1fr)]\">\n <div className={wrapperClass} style={{ height, width: '100%' }}>\n {!mounted ? (\n <div className=\"flex h-full w-full items-center justify-center\" aria-busy=\"true\">\n <div className=\"h-full w-full motion-safe:animate-pulse bg-bg-sunken\" />\n </div>\n ) : (\n <>\n <MapContainer\n center={initialCenter}\n zoom={plottable.length ? 11 : 5}\n scrollWheelZoom\n style={{ height: '100%', width: '100%' }}\n className=\"z-0\"\n >\n <TileLayer url={OSM_TILE_URL} attribution={OSM_ATTRIBUTION} />\n <BoundsWatcher onChange={setPendingBounds} />\n {plottable.map((property) => {\n const isSelected = hoveredId === property.id || selectedIds?.has(property.id);\n return (\n <Marker\n key={property.id}\n position={[property.location.coordinates.latitude, property.location.coordinates.longitude]}\n icon={createPropertyPinIcon(formatCompactCurrency(property.price.amount, property.price.currency), {\n selected: isSelected,\n rera: property.reraVerificationStatus === 'verified',\n })}\n eventHandlers={{\n click: () => onSelectProperty?.(property.id),\n mouseover: () => setHoveredId(property.id),\n mouseout: () => setHoveredId((cur) => (cur === property.id ? null : cur)),\n }}\n >\n <Popup className=\"hv-popup\">\n <div className=\"p-3\">\n <div className=\"flex items-center gap-1.5\">\n <p className=\"text-sm font-semibold text-text-primary\">{property.title}</p>\n {property.reraVerificationStatus === 'verified' && (\n <ShieldCheck className=\"h-3.5 w-3.5 shrink-0 text-status-success-text\" />\n )}\n {property.verificationStatus === 'verified' && (\n <BadgeCheck\n className=\"h-3.5 w-3.5 shrink-0 text-status-success-text\"\n aria-label=\"Verified listing\"\n />\n )}\n </div>\n <p className=\"text-xs text-text-secondary\">\n {[property.location.neighborhood, property.location.city].filter(Boolean).join(', ')}\n </p>\n <p className=\"mt-1 text-sm font-bold text-text-primary\">\n {formatCompactCurrency(property.price.amount, property.price.currency)}\n {property.price.type === 'rent' ? '/mo' : ''}\n </p>\n <button\n type=\"button\"\n onClick={() => onSelectProperty?.(property.id)}\n className=\"mt-2 text-xs font-medium text-[var(--color-action-primary-bg)] hover:underline\"\n >\n View details\n </button>\n </div>\n </Popup>\n </Marker>\n );\n })}\n </MapContainer>\n\n {onSearchThisArea && (\n <div className=\"pointer-events-none absolute inset-x-0 top-3 z-10 flex justify-center\">\n <button\n type=\"button\"\n onClick={handleSearchThisArea}\n disabled={!dirtySearch || loading}\n className={cn(\n 'pointer-events-auto inline-flex items-center gap-1.5 rounded-full border border-border-subtle bg-bg-surface px-3 py-1.5 text-xs font-medium shadow-elevation-2 transition-colors',\n dirtySearch && !loading\n ? 'text-text-primary hover:bg-bg-sunken'\n : 'cursor-not-allowed text-text-secondary opacity-70'\n )}\n >\n <RotateCcw className=\"h-3 w-3\" />\n {loading ? 'Searching…' : 'Search this area'}\n </button>\n </div>\n )}\n </>\n )}\n </div>\n\n {/* Compact list synced with the plotted pins */}\n <div\n className=\"flex flex-col gap-2 overflow-y-auto rounded-card border border-border-seam bg-bg-surface p-2\"\n style={{ height }}\n >\n {plottable.length === 0 && !loading && (\n <p className=\"p-4 text-center text-sm text-text-secondary\">\n No properties with a mapped location match the current filters.\n </p>\n )}\n {plottable.map((property) => (\n <button\n key={property.id}\n type=\"button\"\n onMouseEnter={() => setHoveredId(property.id)}\n onMouseLeave={() => setHoveredId((cur) => (cur === property.id ? null : cur))}\n onClick={() => onSelectProperty?.(property.id)}\n className={cn(\n 'flex items-center gap-3 rounded-lg border p-2 text-left transition-colors',\n hoveredId === property.id\n ? 'border-[var(--color-action-primary-bg)] bg-bg-sunken'\n : 'border-transparent hover:bg-bg-sunken'\n )}\n >\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{property.title}</p>\n <p className=\"truncate text-xs text-text-secondary\">\n {[property.location.neighborhood, property.location.city].filter(Boolean).join(', ')}\n </p>\n <div className=\"mt-1 flex items-center gap-3 text-[11px] text-text-secondary\">\n {property.specifications.bedrooms != null && (\n <span className=\"inline-flex items-center gap-1\">\n <Bed className=\"h-3 w-3\" />\n {property.specifications.bedrooms}\n </span>\n )}\n {property.specifications.bathrooms != null && (\n <span className=\"inline-flex items-center gap-1\">\n <Bath className=\"h-3 w-3\" />\n {property.specifications.bathrooms}\n </span>\n )}\n <span className=\"inline-flex items-center gap-1\">\n <Square className=\"h-3 w-3\" />\n {formatNumber(property.specifications.totalArea)} sq ft\n </span>\n </div>\n </div>\n <span className=\"shrink-0 text-sm font-bold text-text-primary\">\n {formatCompactCurrency(property.price.amount, property.price.currency)}\n </span>\n </button>\n ))}\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PropertiesPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/properties/PropertiesPage.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"PropertiesPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/properties/PropertiesPage.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AA4CH,eAAO,MAAM,cAAc,mCAqhC1B,CAAC"}
|