import React, { useState, useEffect, useRef } from 'react'; import { Menu, X, Plus, Search, LogIn, LogOut, Settings, User, MapPin, List, Grid, ChevronDown, ChevronUp } from 'lucide-react'; // Main App Component export default function App() { const [isLoggedIn, setIsLoggedIn] = useState(false); const [isAdmin, setIsAdmin] = useState(false); const [activeTab, setActiveTab] = useState('map'); // 'map', 'admin' const [sidebarOpen, setSidebarOpen] = useState(true); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const [locations, setLocations] = useState([]); const [filteredLocations, setFilteredLocations] = useState([]); const [selectedLocation, setSelectedLocation] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [viewMode, setViewMode] = useState('card'); // 'card' or 'list' const [loading, setLoading] = useState(true); const [mapCenter, setMapCenter] = useState([40.7128, -74.0060]); // NYC default const [mapZoom, setMapZoom] = useState(13); const [categories, setCategories] = useState([]); const [selectedCategory, setSelectedCategory] = useState('all'); const [newLocation, setNewLocation] = useState(null); const [showAddForm, setShowAddForm] = useState(false); const [formData, setFormData] = useState({ title: '', description: '', category: '', image: '', lat: '', lng: '', }); const mapRef = useRef(null); // Fetch locations from API useEffect(() => { // Simulated API call setTimeout(() => { const dummyLocations = [ { _id: '1', title: 'Central Park', description: 'A large urban park in Manhattan, New York City.', category: 'Parks', image: 'https://images.unsplash.com/photo-1534251369789-5067c8b8602a?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80', coordinates: [40.7812, -73.9665], createdAt: '2023-01-15T12:00:00Z', rating: 4.8, }, { _id: '2', title: 'Empire State Building', description: 'A 102-story Art Deco skyscraper in Midtown Manhattan.', category: 'Landmarks', image: 'https://images.unsplash.com/photo-1555109307-f7d9da25c244?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80', coordinates: [40.7484, -73.9857], createdAt: '2023-01-20T14:30:00Z', rating: 4.7, }, { _id: '3', title: 'Brooklyn Bridge', description: 'A hybrid cable-stayed/suspension bridge spanning the East River.', category: 'Bridges', image: 'https://images.unsplash.com/photo-1581373449483-37449f962b6c?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80', coordinates: [40.7061, -73.9969], createdAt: '2023-01-25T09:15:00Z', rating: 4.6, }, { _id: '4', title: 'Times Square', description: 'A major commercial intersection and tourist destination.', category: 'Entertainment', image: 'https://images.unsplash.com/photo-1534430480872-3b5e7416a3a3?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80', coordinates: [40.7580, -73.9855], createdAt: '2023-02-01T18:45:00Z', rating: 4.5, }, { _id: '5', title: 'The High Line', description: 'A 1.45-mile-long elevated linear park built on a former railroad spur.', category: 'Parks', image: 'https://images.unsplash.com/photo-1587965596700-3875ef9757e3?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80', coordinates: [40.7480, -74.0048], createdAt: '2023-02-05T11:20:00Z', rating: 4.9, }, ]; const uniqueCategories = [...new Set(dummyLocations.map(loc => loc.category))]; setCategories(uniqueCategories); setLocations(dummyLocations); setFilteredLocations(dummyLocations); setLoading(false); // Initialize map after data is loaded initMap(); }, 1000); }, []); // Initialize map using vanilla Leaflet instead of react-leaflet const initMap = () => { // Skip if not in map view or map already initialized if (activeTab !== 'map' || !document.getElementById('map')) return; // Clean up previous map instance if it exists if (mapRef.current) { mapRef.current.remove(); } // Import Leaflet dynamically to avoid SSR issues import('https://cdn.jsdelivr.net/npm/leaflet@1.9.4/+esm').then((L) => { // Create map const map = L.map('map').setView(mapCenter, mapZoom); mapRef.current = map; // Add tile layer L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map); // Create custom icon const customIcon = L.icon({ iconUrl: 'https://cdn.mapmarker.io/api/v1/pin?size=50&background=%2348A9A6&icon=fa-map-marker&color=%23FFFFFF', iconSize: [30, 30], iconAnchor: [15, 30], popupAnchor: [0, -30], }); // Add markers for locations filteredLocations.forEach(location => { const marker = L.marker(location.coordinates, { icon: customIcon }).addTo(map); marker.bindPopup(`

${location.title}

${location.description.substring(0, 50)}...

${location.category}
`); marker.on('click', () => { setSelectedLocation(location); }); }); // Add click handler for admin mode if (isAdmin && activeTab === 'admin') { map.on('click', (e) => { const { lat, lng } = e.latlng; // Remove previous new location marker if exists if (newLocation) { map.eachLayer((layer) => { if (layer._latlng && layer._latlng.lat === newLocation[0] && layer._latlng.lng === newLocation[1]) { map.removeLayer(layer); } }); } // Add new marker const newMarker = L.marker([lat, lng]).addTo(map); newMarker.bindPopup(`

New Location

Lat: ${lat.toFixed(6)}, Lng: ${lng.toFixed(6)}

`).openPopup(); setNewLocation([lat, lng]); setFormData({ ...formData, lat: lat.toFixed(6), lng: lng.toFixed(6), }); setShowAddForm(true); }); } // Update map when selected location changes if (selectedLocation) { map.setView(selectedLocation.coordinates, 15); } }); }; // Re-initialize map when filtered locations change useEffect(() => { if (activeTab === 'map') { initMap(); } }, [filteredLocations, activeTab, isAdmin]); // Clean up map on unmount useEffect(() => { return () => { if (mapRef.current) { mapRef.current.remove(); } }; }, []); // Filter locations based on search and category useEffect(() => { let filtered = [...locations]; if (searchQuery) { filtered = filtered.filter(loc => loc.title.toLowerCase().includes(searchQuery.toLowerCase()) || loc.description.toLowerCase().includes(searchQuery.toLowerCase()) ); } if (selectedCategory !== 'all') { filtered = filtered.filter(loc => loc.category === selectedCategory); } setFilteredLocations(filtered); }, [searchQuery, selectedCategory, locations]); // Handle login const handleLogin = () => { setIsLoggedIn(true); setIsAdmin(true); // For demo purposes }; // Handle logout const handleLogout = () => { setIsLoggedIn(false); setIsAdmin(false); setActiveTab('map'); }; // Handle form input changes const handleInputChange = (e) => { const { name, value } = e.target; setFormData({ ...formData, [name]: value }); }; // Handle form submission const handleSubmit = (e) => { e.preventDefault(); // Create new location const newLoc = { _id: Date.now().toString(), title: formData.title, description: formData.description, category: formData.category || 'Uncategorized', image: formData.image || 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80', coordinates: [parseFloat(formData.lat), parseFloat(formData.lng)], createdAt: new Date().toISOString(), rating: 4.0, }; // Add to locations setLocations([...locations, newLoc]); // Reset form setFormData({ title: '', description: '', category: '', image: '', lat: '', lng: '', }); setShowAddForm(false); setNewLocation(null); }; return (
{/* Header */}

GeoExplorer

{isLoggedIn ? (
{isAdmin && ( )}
) : ( )}
{/* Mobile menu */} {mobileMenuOpen && (
{isLoggedIn && isAdmin && ( )} {isLoggedIn ? ( ) : ( )}
)}
{/* Main content */}
{activeTab === 'map' ? ( <> {/* Map section */}
{/* Map container */}
{/* Add Leaflet CSS */} {/* Map controls */}
{/* Sidebar */}
{/* Sidebar header */}

Locations

{sidebarOpen && ( <> {/* Search and filters */}
setSearchQuery(e.target.value)} />
{/* Locations list */}
{loading ? (
) : filteredLocations.length === 0 ? (
No locations found matching your criteria.
) : (
{filteredLocations.map(location => (
{ setSelectedLocation(location); if (mapRef.current) { mapRef.current.setView(location.coordinates, 15); } }} > {viewMode === 'card' && (
{location.title}
)}

{location.title}

{viewMode === 'list' && ( {location.category} )}
{viewMode === 'card' && ( {location.category} )}

{location.description}

{location.coordinates[0].toFixed(2)}, {location.coordinates[1].toFixed(2)}
★ {location.rating}
))}
)}
)}
) : ( /* Admin Dashboard */

Location Management

{showAddForm ? (

Add New Location

) : (

Click on the map to add a new location, or use the button below to enter coordinates manually.

)}

Existing Locations

{locations.map(location => ( ))}
Title Category Coordinates Rating Actions
{location.title}
{location.category} {location.coordinates[0].toFixed(4)}, {location.coordinates[1].toFixed(4)} {location.rating}
)}
); }