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 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 &&
}
);
}