feat: embedded interactive map in property + match detail views
Integrates react-leaflet with OpenStreetMap tiles. PropertyDetailView and MatchDetail now show property photo + zoomable/pannable map above the tabs/content — always visible on card click, no redirect. Map renders at correct lat/lng with a location marker and popup. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import { useEffect } from 'react'
|
||||
import { Box } from '@mui/material'
|
||||
import { MapContainer, TileLayer, Marker, Popup, useMap } from 'react-leaflet'
|
||||
import L from 'leaflet'
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
|
||||
// Fix default marker icons in Vite build
|
||||
delete (L.Icon.Default.prototype as unknown as Record<string, unknown>)._getIconUrl
|
||||
L.Icon.Default.mergeOptions({
|
||||
iconRetinaUrl: new URL('leaflet/dist/images/marker-icon-2x.png', import.meta.url).href,
|
||||
iconUrl: new URL('leaflet/dist/images/marker-icon.png', import.meta.url).href,
|
||||
shadowUrl: new URL('leaflet/dist/images/marker-shadow.png', import.meta.url).href,
|
||||
})
|
||||
|
||||
interface Props {
|
||||
lat: number
|
||||
lng: number
|
||||
label?: string
|
||||
height?: number
|
||||
}
|
||||
|
||||
function RecenterOnChange({ lat, lng }: { lat: number; lng: number }) {
|
||||
const map = useMap()
|
||||
useEffect(() => {
|
||||
map.setView([lat, lng])
|
||||
}, [lat, lng, map])
|
||||
return null
|
||||
}
|
||||
|
||||
export function PropertyMap({ lat, lng, label, height = 260 }: Props) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
height,
|
||||
width: '100%',
|
||||
overflow: 'hidden',
|
||||
flexShrink: 0,
|
||||
// Ensure leaflet controls appear above MUI elements
|
||||
'& .leaflet-container': { height: '100%', width: '100%', zIndex: 0 },
|
||||
'& .leaflet-control': { zIndex: 1 },
|
||||
}}
|
||||
>
|
||||
<MapContainer
|
||||
center={[lat, lng]}
|
||||
zoom={14}
|
||||
scrollWheelZoom
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
>
|
||||
<RecenterOnChange lat={lat} lng={lng} />
|
||||
<TileLayer
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>'
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
/>
|
||||
<Marker position={[lat, lng]}>
|
||||
{label && <Popup>{label}</Popup>}
|
||||
</Marker>
|
||||
</MapContainer>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export { ViewToggle } from './ViewToggle'
|
||||
export { LocationPreview } from './LocationPreview'
|
||||
export { PropertyMap } from './PropertyMap'
|
||||
export { getScoreTier, SCORE_THEME } from './scoreTheme'
|
||||
export type { ScoreTier } from './scoreTheme'
|
||||
|
||||
Reference in New Issue
Block a user