feat: directorio más fiable y más fácil de usar
El objetivo de estos cambios es, por un lado, mantener los datos
actualizados y, por otro, mejorar la experiencia para quienes lo usan:
- Fiabilidad: los locales se pueden confirmar ("Sigue aquí") y
reportar (cerrado, datos incorrectos...), y se avisa de duplicados
antes de publicar, para que el contenido no se quede obsoleto ni
repetido.
- Usabilidad: autocompletado al proponer, favoritos, "cerca de mí",
compartir fichas, enlaces a Waze y una política de privacidad
visible, para que sea más sencillo aportar y encontrar locales.
This commit is contained in:
@@ -17,6 +17,36 @@ export function parsearEnlaceGoogleMaps(url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Enlaces para abrir la ubicación de un local directamente en Google Maps o Waze,
|
||||
// usando las coordenadas si existen (más preciso) o si no, el texto de la dirección.
|
||||
export function enlaceGoogleMapsDesdeLocal(local) {
|
||||
if (local?.lat && local?.lng) return `https://www.google.com/maps/search/?api=1&query=${local.lat},${local.lng}`;
|
||||
if (local?.direccion) return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(local.direccion)}`;
|
||||
return null;
|
||||
}
|
||||
|
||||
export function enlaceWazeDesdeLocal(local) {
|
||||
if (local?.lat && local?.lng) return `https://waze.com/ul?ll=${local.lat},${local.lng}&navigate=yes`;
|
||||
if (local?.direccion) return `https://waze.com/ul?q=${encodeURIComponent(local.direccion)}&navigate=yes`;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Distancia en kilómetros entre dos coordenadas (fórmula de Haversine),
|
||||
// usada para "cerca de mí" y para mostrar la distancia en cada tarjeta.
|
||||
export function distanciaKm(lat1, lng1, lat2, lng2) {
|
||||
const R = 6371;
|
||||
const toRad = (d) => (d * Math.PI) / 180;
|
||||
const dLat = toRad(lat2 - lat1);
|
||||
const dLng = toRad(lng2 - lng1);
|
||||
const a = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLng / 2) ** 2;
|
||||
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
}
|
||||
|
||||
export function formatearDistancia(km) {
|
||||
if (km == null) return "";
|
||||
return km < 1 ? `${Math.round(km * 1000)} m` : `${km.toFixed(1)} km`;
|
||||
}
|
||||
|
||||
export async function geocodificarDireccion(direccion) {
|
||||
const query = encodeURIComponent(`${direccion}, España`);
|
||||
const url = `https://nominatim.openstreetmap.org/search?q=${query}&format=json&limit=1&countrycodes=es`;
|
||||
@@ -27,3 +57,24 @@ export async function geocodificarDireccion(direccion) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Busca lugares/negocios por nombre (autocompletar). Usa Nominatim (OpenStreetMap),
|
||||
// que no requiere clave de API. Nota: no es el autocompletar "de Google" (eso exigiría
|
||||
// una clave de Google Places con facturación activada) pero da el mismo resultado
|
||||
// práctico: escribes un nombre y aparecen varias opciones para elegir.
|
||||
export async function buscarLugares(texto) {
|
||||
const q = (texto || "").trim();
|
||||
if (q.length < 3) return [];
|
||||
const url = `https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(`${q}, España`)}&format=json&addressdetails=1&namedetails=1&limit=6&countrycodes=es`;
|
||||
const respuesta = await fetch(url, { headers: { "Accept-Language": "es", "User-Agent": "LocalesEspanoles/1.0" } });
|
||||
const datos = await respuesta.json();
|
||||
if (!datos?.length) return [];
|
||||
return datos.map((d) => ({
|
||||
id: d.place_id,
|
||||
nombre: d.namedetails?.name || d.display_name.split(",")[0],
|
||||
direccion: d.display_name,
|
||||
provincia: d.address?.county || d.address?.province || d.address?.state || d.address?.city || "",
|
||||
lat: parseFloat(d.lat),
|
||||
lng: parseFloat(d.lon),
|
||||
}));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user