import React, { useState, useRef, useEffect } from "react";
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import pinIconImage from "../images/pin.png";
import Navbar from "./Navbar";
import { useLocation, useNavigate } from 'react-router-dom';
// Utility function to introduce a delay
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const Pin = () => {
// Address search state
const [address, setAddress] = useState("");
const [suggestions, setSuggestions] = useState([]);
const [selectedLocation, setSelectedLocation] = useState(null);
const [fullAddress, setFullAddress] = useState("");
// Pin state
const [pins, setPins] = useState([]);
const [username, setUsername] = useState('');
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [pinMode, setPinMode] = useState(false);
const [showPinForm, setShowPinForm] = useState(false);
const [currentPinLocation, setCurrentPinLocation] = useState(null);
const [pinDetails, setPinDetails] = useState({
pin_name: '',
description: '',
category: '',
public: false,
x: 0,
y: 0
});
const mapRef = useRef(null);
const mapInstance = useRef(null);
const markersRef = useRef([]);
const location = useLocation();
const navigate = useNavigate();
// Custom pin icon
const pinIcon = new L.Icon({
iconUrl: pinIconImage,
iconSize: [24, 40],
iconAnchor: [15, 40],
popupAnchor: [0, -40],
});
// Initialize map and fetch user data
useEffect(() => {
// Check login status
const storedUsername = localStorage.getItem('username');
const storedLoginStatus = localStorage.getItem('login');
if (storedUsername && storedLoginStatus === 'true') {
setUsername(storedUsername);
setIsLoggedIn(true);
fetchPins(storedUsername);
} else {
fetchPins(null);
}
// Initialize map
if (!mapInstance.current) {
const initialCenter = location.state?.pinLocation || [43.7, -79.42];
const initialZoom = location.state?.pinLocation ? 14 : 10;
const map = L.map(mapRef.current, {
center: initialCenter,
zoom: initialZoom,
});
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "© OpenStreetMap contributors",
}).addTo(map);
mapInstance.current = map;
}
// Cleanup markers on unmount
return () => {
markersRef.current.forEach(marker => {
if (marker && mapInstance.current) {
mapInstance.current.removeLayer(marker);
}
});
};
}, []);
// Handle incoming pin location from state
useEffect(() => {
if (location.state?.pinLocation && mapInstance.current) {
const { lat, lng } = location.state.pinLocation;
mapInstance.current.flyTo([lat, lng], 14);
// Clear the state after handling it to prevent re-centering
navigate('/visit', { replace: true, state: {} });
}
}, [location.state, navigate]);
// Handle map click for pin placement
useEffect(() => {
if (!mapInstance.current) return;
const handleMapClick = (e) => {
if (pinMode) {
const { lat, lng } = e.latlng;
setCurrentPinLocation({ lat, lng });
setPinDetails(prev => ({
...prev,
x: lng,
y: lat
}));
setShowPinForm(true);
}
};
// Add click event listener
mapInstance.current.on('click', handleMapClick);
// Cleanup
return () => {
if (mapInstance.current) {
mapInstance.current.off('click', handleMapClick);
}
};
}, [pinMode]);
// Update pins on the map when pins state changes
useEffect(() => {
if (!mapInstance.current) return;
// Clear existing markers
markersRef.current.forEach(marker => {
if (marker) {
mapInstance.current.removeLayer(marker);
}
});
markersRef.current = [];
// Add new markers
pins.forEach((pin) => {
const marker = L.marker([pin.y, pin.x], { icon: pinIcon })
.addTo(mapInstance.current)
.bindPopup(`
${pin.pin_name || "Unnamed Pin"}
${pin.description || "No description available"}
By: ${pin.username}
Category: ${pin.category || "Unknown"}
${pin.public ?
'
X (Longitude): {pinDetails.x.toFixed(5)}
Y (Latitude): {pinDetails.y.toFixed(5)}