Spaces:
Sleeping
Sleeping
| "use client" | |
| import { useEffect, useRef } from "react" | |
| import L from "leaflet" | |
| // Import Leaflet CSS | |
| import "leaflet/dist/leaflet.css" | |
| interface Property { | |
| id: number | |
| coordinates: [number, number] | |
| price: number | |
| type: string | |
| bedrooms: number | |
| bathrooms: number | |
| sqft: number | |
| address: string | |
| status: 'active' | 'pending' | 'sold' | |
| } | |
| interface SimpleLeafletMapProps { | |
| properties: Property[] | |
| onPropertySelect: (property: Property | null) => void | |
| selectedProperty: Property | null | |
| } | |
| export default function SimpleLeafletMap({ | |
| properties, | |
| onPropertySelect, | |
| selectedProperty | |
| }: SimpleLeafletMapProps) { | |
| const mapRef = useRef<L.Map | null>(null) | |
| const mapContainerRef = useRef<HTMLDivElement>(null) | |
| const markersRef = useRef<L.Marker[]>([]) | |
| const formatCurrency = (value: number) => { | |
| return new Intl.NumberFormat('en-CA', { | |
| style: 'currency', | |
| currency: 'CAD', | |
| minimumFractionDigits: 0, | |
| maximumFractionDigits: 0, | |
| }).format(value).replace('CAD', '$').trim() | |
| } | |
| const getMarkerColor = (status: string) => { | |
| switch (status) { | |
| case 'active': | |
| return '#10B981' // green | |
| case 'pending': | |
| return '#F59E0B' // orange | |
| case 'sold': | |
| return '#EF4444' // red | |
| default: | |
| return '#3B82F6' // blue | |
| } | |
| } | |
| useEffect(() => { | |
| if (!mapContainerRef.current || mapRef.current) return | |
| console.log('Initializing map with', properties.length, 'properties') | |
| // Initialize the map | |
| mapRef.current = L.map(mapContainerRef.current).setView([56.1304, -96.0000], 4) | |
| // Add OpenStreetMap tiles | |
| L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { | |
| attribution: '© OpenStreetMap contributors © CARTO', | |
| subdomains: 'abcd', | |
| maxZoom: 19 | |
| }).addTo(mapRef.current) | |
| // Clear any existing markers | |
| markersRef.current.forEach(marker => marker.remove()) | |
| markersRef.current = [] | |
| // Add property markers | |
| properties.forEach(property => { | |
| console.log('Adding marker for property:', property.address, 'at coordinates:', property.coordinates) | |
| const color = getMarkerColor(property.status) | |
| const priceText = formatCurrency(property.price) | |
| // Create custom icon | |
| const customIcon = L.divIcon({ | |
| html: ` | |
| <div style=" | |
| background: ${color}; | |
| color: white; | |
| padding: 4px 8px; | |
| border-radius: 8px; | |
| font-size: 12px; | |
| font-weight: 600; | |
| text-align: center; | |
| white-space: nowrap; | |
| border: 2px solid white; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.3); | |
| "> | |
| ${priceText} | |
| </div> | |
| `, | |
| className: 'custom-marker', | |
| iconSize: [120, 30], | |
| iconAnchor: [60, 30] | |
| }) | |
| const marker = L.marker(property.coordinates, { | |
| icon: customIcon | |
| }).addTo(mapRef.current!) | |
| marker.on('click', () => { | |
| console.log('Marker clicked:', property.address) | |
| onPropertySelect(property) | |
| mapRef.current?.setView(property.coordinates, 12, { animate: true }) | |
| }) | |
| markersRef.current.push(marker) | |
| }) | |
| console.log('Added', markersRef.current.length, 'markers to map') | |
| return () => { | |
| if (mapRef.current) { | |
| mapRef.current.remove() | |
| mapRef.current = null | |
| } | |
| markersRef.current = [] | |
| } | |
| }, [properties, onPropertySelect]) | |
| // Update marker styles when selection changes | |
| useEffect(() => { | |
| if (!selectedProperty) return | |
| markersRef.current.forEach((marker, index) => { | |
| const property = properties[index] | |
| if (property.id === selectedProperty.id) { | |
| // Highlight selected marker | |
| const element = marker.getElement() | |
| if (element) { | |
| element.style.transform = 'scale(1.1)' | |
| element.style.zIndex = '1000' | |
| } | |
| } else { | |
| // Reset other markers | |
| const element = marker.getElement() | |
| if (element) { | |
| element.style.transform = 'scale(1)' | |
| element.style.zIndex = '1' | |
| } | |
| } | |
| }) | |
| }, [selectedProperty, properties]) | |
| return ( | |
| <> | |
| <div | |
| ref={mapContainerRef} | |
| className="w-full h-full" | |
| style={{ minHeight: '400px' }} | |
| /> | |
| <style jsx global>{` | |
| .custom-marker { | |
| background: transparent ; | |
| border: none ; | |
| } | |
| `}</style> | |
| </> | |
| ) | |
| } |