157 lines
4.5 KiB
JavaScript
157 lines
4.5 KiB
JavaScript
/**
|
|
* Locations Service - Handles location data and geosearch
|
|
*/
|
|
|
|
import { directus } from './directus.js'
|
|
|
|
class LocationsService {
|
|
constructor() {
|
|
this.cache = new Map()
|
|
this.cacheTimeout = 30 * 60 * 1000 // 30 minutes
|
|
}
|
|
|
|
async getAll() {
|
|
const cacheKey = 'all_locations'
|
|
const cached = this.getFromCache(cacheKey)
|
|
if (cached) return cached
|
|
|
|
const locations = await directus.getLocations()
|
|
this.setCache(cacheKey, locations)
|
|
return locations
|
|
}
|
|
|
|
async getById(id) {
|
|
return directus.getLocation(id)
|
|
}
|
|
|
|
async search(query) {
|
|
if (!query || query.length < 2) return []
|
|
return directus.searchLocations(query)
|
|
}
|
|
|
|
async getByRegion(region) {
|
|
const cacheKey = `region_${region}`
|
|
const cached = this.getFromCache(cacheKey)
|
|
if (cached) return cached
|
|
|
|
const locations = await directus.getLocationsByRegion(region)
|
|
this.setCache(cacheKey, locations)
|
|
return locations
|
|
}
|
|
|
|
async getByCountry(country) {
|
|
const cacheKey = `country_${country}`
|
|
const cached = this.getFromCache(cacheKey)
|
|
if (cached) return cached
|
|
|
|
const locations = await directus.getLocationsByCountry(country)
|
|
this.setCache(cacheKey, locations)
|
|
return locations
|
|
}
|
|
|
|
async getRegions(country = 'DE') {
|
|
const locations = await this.getByCountry(country)
|
|
const regions = [...new Set(locations.map(l => l.region).filter(Boolean))]
|
|
return regions.sort()
|
|
}
|
|
|
|
async getNearby(latitude, longitude, radiusKm = 50, limit = 10) {
|
|
const locations = await this.getAll()
|
|
|
|
const withDistance = locations
|
|
.filter(loc => loc.latitude && loc.longitude)
|
|
.map(loc => ({
|
|
...loc,
|
|
distance: this.calculateDistance(latitude, longitude, loc.latitude, loc.longitude)
|
|
}))
|
|
.filter(loc => loc.distance <= radiusKm)
|
|
.sort((a, b) => a.distance - b.distance)
|
|
.slice(0, limit)
|
|
|
|
return withDistance
|
|
}
|
|
|
|
calculateDistance(lat1, lon1, lat2, lon2) {
|
|
const R = 6371 // Earth radius in km
|
|
const dLat = this.toRad(lat2 - lat1)
|
|
const dLon = this.toRad(lon2 - lon1)
|
|
const a =
|
|
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
|
Math.cos(this.toRad(lat1)) * Math.cos(this.toRad(lat2)) *
|
|
Math.sin(dLon / 2) * Math.sin(dLon / 2)
|
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
|
|
return R * c
|
|
}
|
|
|
|
toRad(deg) {
|
|
return deg * (Math.PI / 180)
|
|
}
|
|
|
|
formatLocation(location) {
|
|
if (!location) return ''
|
|
|
|
const parts = [location.name]
|
|
if (location.postal_code) parts.unshift(location.postal_code)
|
|
if (location.region && location.region !== location.name) {
|
|
parts.push(location.region)
|
|
}
|
|
|
|
return parts.join(', ')
|
|
}
|
|
|
|
formatDistance(distanceKm) {
|
|
if (distanceKm < 1) {
|
|
return `${Math.round(distanceKm * 1000)} m`
|
|
}
|
|
return `${distanceKm.toFixed(1)} km`
|
|
}
|
|
|
|
async getCurrentLocation() {
|
|
return new Promise((resolve, reject) => {
|
|
if (!navigator.geolocation) {
|
|
reject(new Error('Geolocation not supported'))
|
|
return
|
|
}
|
|
|
|
navigator.geolocation.getCurrentPosition(
|
|
pos => resolve({
|
|
latitude: pos.coords.latitude,
|
|
longitude: pos.coords.longitude,
|
|
accuracy: pos.coords.accuracy
|
|
}),
|
|
err => reject(err),
|
|
{ enableHighAccuracy: false, timeout: 10000 }
|
|
)
|
|
})
|
|
}
|
|
|
|
async findNearestLocation() {
|
|
try {
|
|
const coords = await this.getCurrentLocation()
|
|
const nearby = await this.getNearby(coords.latitude, coords.longitude, 100, 1)
|
|
return nearby[0] || null
|
|
} catch (e) {
|
|
console.warn('Could not get location:', e)
|
|
return null
|
|
}
|
|
}
|
|
|
|
getFromCache(key) {
|
|
const cached = this.cache.get(key)
|
|
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
|
|
return cached.data
|
|
}
|
|
return null
|
|
}
|
|
|
|
setCache(key, data) {
|
|
this.cache.set(key, { data, timestamp: Date.now() })
|
|
}
|
|
|
|
clearCache() {
|
|
this.cache.clear()
|
|
}
|
|
}
|
|
|
|
export const locationsService = new LocationsService()
|