This commit is contained in:
@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useMemo } from "react";
|
||||
import { useState, useEffect, useMemo, useRef } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import toast, { Toaster } from "react-hot-toast";
|
||||
import Link from "next/link";
|
||||
@ -69,23 +69,70 @@ import { useFavorites } from "@/app/contexts/FavoritesContext";
|
||||
import { BuildingTypeKeys, PropertyStatusKeys, extractCity } from "../../enums";
|
||||
import PropertyRatingList from "@/app/components/ratings/PropertyRatingList";
|
||||
import { getPropertyAverageRating } from "../../utils/ratings";
|
||||
import dynamic from "next/dynamic";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
|
||||
const MapContainer = dynamic(
|
||||
() => import("react-leaflet").then((m) => m.MapContainer),
|
||||
{ ssr: false },
|
||||
);
|
||||
const TileLayer = dynamic(
|
||||
() => import("react-leaflet").then((m) => m.TileLayer),
|
||||
{ ssr: false },
|
||||
);
|
||||
const Marker = dynamic(() => import("react-leaflet").then((m) => m.Marker), {
|
||||
ssr: false,
|
||||
});
|
||||
const Popup = dynamic(() => import("react-leaflet").then((m) => m.Popup), {
|
||||
ssr: false,
|
||||
});
|
||||
function PropertyDetailMap({ lat, lng, title }) {
|
||||
const mapRef = useRef(null);
|
||||
const mapInstanceRef = useRef(null);
|
||||
const markerRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!mapRef.current || mapInstanceRef.current) return;
|
||||
|
||||
if (mapRef.current._leaflet_id && !mapInstanceRef.current) {
|
||||
delete mapRef.current._leaflet_id;
|
||||
}
|
||||
|
||||
const L = require("leaflet");
|
||||
|
||||
delete L.Icon.Default.prototype._getIconUrl;
|
||||
L.Icon.Default.mergeOptions({
|
||||
iconRetinaUrl:
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png",
|
||||
iconUrl:
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png",
|
||||
shadowUrl:
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png",
|
||||
});
|
||||
|
||||
const map = L.map(mapRef.current, {
|
||||
center: [lat, lng],
|
||||
zoom: 14,
|
||||
scrollWheelZoom: false,
|
||||
});
|
||||
|
||||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||
attribution:
|
||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||||
maxZoom: 19,
|
||||
}).addTo(map);
|
||||
|
||||
const marker = L.marker([lat, lng]).addTo(map).bindPopup(title);
|
||||
mapInstanceRef.current = map;
|
||||
markerRef.current = marker;
|
||||
map.invalidateSize();
|
||||
|
||||
return () => {
|
||||
markerRef.current?.remove();
|
||||
markerRef.current = null;
|
||||
if (mapInstanceRef.current) {
|
||||
mapInstanceRef.current.remove();
|
||||
mapInstanceRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [lat, lng, title]);
|
||||
|
||||
useEffect(() => {
|
||||
if (mapInstanceRef.current) {
|
||||
mapInstanceRef.current.setView([lat, lng], 14);
|
||||
markerRef.current?.setLatLng([lat, lng]);
|
||||
markerRef.current?.setPopupContent(title);
|
||||
mapInstanceRef.current.invalidateSize();
|
||||
}
|
||||
}, [lat, lng, title]);
|
||||
|
||||
return <div ref={mapRef} className="h-full w-full" />;
|
||||
}
|
||||
|
||||
function formatCurrency(amount) {
|
||||
if (!amount || isNaN(amount)) return "0";
|
||||
@ -1243,19 +1290,11 @@ export default function PropertyDetailsPage() {
|
||||
className="bg-white rounded-2xl overflow-hidden shadow-sm border border-gray-200"
|
||||
>
|
||||
<div className="h-64">
|
||||
<MapContainer
|
||||
center={[property.location.lat, property.location.lng]}
|
||||
zoom={14}
|
||||
className="h-full w-full"
|
||||
scrollWheelZoom={false}
|
||||
>
|
||||
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
|
||||
<Marker
|
||||
position={[property.location.lat, property.location.lng]}
|
||||
>
|
||||
<Popup>{property.title}</Popup>
|
||||
</Marker>
|
||||
</MapContainer>
|
||||
<PropertyDetailMap
|
||||
lat={property.location.lat}
|
||||
lng={property.location.lng}
|
||||
title={property.title}
|
||||
/>
|
||||
</div>
|
||||
<div className="p-3 bg-amber-50 text-center text-sm text-amber-700 flex items-center justify-center gap-2">
|
||||
<Info className="w-4 h-4" />
|
||||
|
||||
Reference in New Issue
Block a user