import React, { useEffect, useMemo, useRef, useState } from "react"; import { MapPin, SlidersHorizontal, X, Beer, Utensils, Search, RotateCcw, ChevronDown, Menu, Database, Wifi } from "lucide-react"; const MOCK_DATA = { bares: [ { id: 1, nombre: "Bar Laurel", lat: 42.4666, lng: -2.4455, asientos: 18, terraza: true, direccion: "Calle del Laurel, 12" }, { id: 2, nombre: "La Esquina", lat: 42.4646, lng: -2.4488, asientos: 42, terraza: false, direccion: "Calle Portales, 31" }, { id: 3, nombre: "Café Bretón", lat: 42.4627, lng: -2.4511, asientos: 70, terraza: true, direccion: "Bretón de los Herreros, 8" }, ], restaurantes: [ { id: 101, nombre: "Sabores del Ebro", lat: 42.4682, lng: -2.4496, cocina: "Riojana", precio: 2, direccion: "Calle Mayor, 18" }, { id: 102, nombre: "Verde Oliva", lat: 42.4654, lng: -2.4409, cocina: "Mediterránea", precio: 3, direccion: "Av. de la Paz, 22" }, { id: 103, nombre: "Mesa Norte", lat: 42.4609, lng: -2.4472, cocina: "Fusión", precio: 2, direccion: "Gran Vía, 44" }, ], }; const COLORS = { bar: "#2563eb", restaurante: "#f97316" }; function loadLeaflet() { return new Promise((resolve, reject) => { if (window.L) return resolve(window.L); if (!document.querySelector('link[data-leaflet]')) { const link = document.createElement("link"); link.rel = "stylesheet"; link.href = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"; link.dataset.leaflet = "true"; document.head.appendChild(link); } const existing = document.querySelector('script[data-leaflet]'); if (existing) { existing.addEventListener("load", () => resolve(window.L)); return; } const script = document.createElement("script"); script.src = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"; script.dataset.leaflet = "true"; script.onload = () => resolve(window.L); script.onerror = reject; document.head.appendChild(script); }); } function markerIcon(L, type) { const color = COLORS[type]; const symbol = type === "bar" ? "B" : "R"; return L.divIcon({ className: "custom-marker", html: `
${symbol}
`, iconSize: [42, 42], iconAnchor: [20, 39], popupAnchor: [0, -37] }); } function MapArea({ points, selected, onSelect }) { const elRef = useRef(null); const mapRef = useRef(null); const layerRef = useRef(null); useEffect(() => { let active = true; loadLeaflet().then((L) => { if (!active || mapRef.current) return; const map = L.map(elRef.current, { zoomControl: false }).setView([42.4654, -2.4470], 15); L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { maxZoom: 19, attribution: '© https://www.openstreetmap.org/copyright' }).addTo(map); L.control.zoom({ position: "bottomright" }).addTo(map); mapRef.current = map; layerRef.current = L.layerGroup().addTo(map); setTimeout(() => map.invalidateSize(), 100); }); return () => { active = false; }; }, []); useEffect(() => { if (!mapRef.current || !layerRef.current || !window.L) return; const L = window.L; layerRef.current.clearLayers(); points.forEach((p) => { const marker = L.marker([p.lat, p.lng], { icon: markerIcon(L, p.tipo) }).addTo(layerRef.current); marker.on("click", () => onSelect(p)); marker.bindTooltip(p.nombre, { direction: "top", offset: [0, -30], opacity: 0.95 }); }); }, [points, onSelect]); useEffect(() => { if (selected && mapRef.current) mapRef.current.flyTo([selected.lat, selected.lng], 17, { duration: 0.7 }); }, [selected]); return
; } function Toggle({ checked, onChange, color, children }) { return ( ); } export default function App() { const [showBars, setShowBars] = useState(true); const [showRestaurants, setShowRestaurants] = useState(true); const [minSeats, setMinSeats] = useState(0); const [terraceOnly, setTerraceOnly] = useState(false); const [cuisine, setCuisine] = useState("Todas"); const [query, setQuery] = useState(""); const [filtersOpen, setFiltersOpen] = useState(false); const [selected, setSelected] = useState(null); const points = useMemo(() => { const q = query.trim().toLowerCase(); const bars = showBars ? MOCK_DATA.bares .filter(x => x.asientos >= minSeats && (!terraceOnly || x.terraza)) .map(x => ({ ...x, tipo: "bar" })) : []; const restaurants = showRestaurants ? MOCK_DATA.restaurantes .filter(x => cuisine === "Todas" || x.cocina === cuisine) .map(x => ({ ...x, tipo: "restaurante" })) : []; return [...bars, ...restaurants].filter(x => !q || x.nombre.toLowerCase().includes(q) || x.direccion.toLowerCase().includes(q)); }, [showBars, showRestaurants, minSeats, terraceOnly, cuisine, query]); const reset = () => { setShowBars(true); setShowRestaurants(true); setMinSeats(0); setTerraceOnly(false); setCuisine("Todas"); setQuery(""); }; const Filters = () => (

Categorías

Bares Restaurantes
Propiedades de bares
Solo con terraza
Propiedades de restaurantes
); return (

Localiza+

Explora lugares en el mapa

setQuery(e.target.value)} placeholder="Buscar por nombre o dirección…" className="w-full rounded-xl border border-slate-200 bg-slate-50 py-2 pl-10 pr-3 text-sm outline-none focus:border-blue-400 focus:bg-white focus:ring-2 focus:ring-blue-100"/>
API conectada
{points.length} ubicaciones
Bares Restaurantes
{selected &&
{selected.tipo === "bar" ? : }
{selected.tipo}

{selected.nombre}

{selected.direccion}

{selected.tipo === "bar" ? <>{selected.asientos} asientos{selected.terraza ? "Con terraza" : "Sin terraza"} : <>Cocina {selected.cocina}{"€".repeat(selected.precio)}}
}
{filtersOpen &&
setQuery(e.target.value)} placeholder="Buscar localización…" className="w-full rounded-xl border border-slate-200 bg-slate-50 py-2.5 pl-10 pr-3 text-sm outline-none"/>
} ); }