Files
kashilo/js/services/locations.js

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()