- Vintage Modell hinzugefuegt - Equipment Multi-Select (Neue Buchung + Bearbeitung) - Kundenadresse in Formularen - Bearbeiten-Seite fuer Buchungen - Abbau-Zeiten in Formularen und Uebersicht - Vertrag PDF nur bei Privatkunden - LexOffice Kontakt-Erstellung Fix (BUSINESS) - Zurueck-Pfeil auf Touren-Seite
89 lines
2.3 KiB
TypeScript
89 lines
2.3 KiB
TypeScript
interface Coordinates {
|
|
lat: number;
|
|
lon: number;
|
|
}
|
|
|
|
interface DistanceResult {
|
|
distance: number;
|
|
duration: number;
|
|
}
|
|
|
|
export class DistanceCalculator {
|
|
private static readonly OSRM_API = 'https://router.project-osrm.org/route/v1/driving';
|
|
|
|
static async geocodeAddress(address: string): Promise<Coordinates | null> {
|
|
try {
|
|
const nominatimUrl = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(address)}&limit=1`;
|
|
|
|
const response = await fetch(nominatimUrl, {
|
|
headers: {
|
|
'User-Agent': 'SaveTheMoment-Atlas/1.0',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Geocoding failed: ${response.statusText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (!data || data.length === 0) {
|
|
console.warn(`No results found for address: ${address}`);
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
lat: parseFloat(data[0].lat),
|
|
lon: parseFloat(data[0].lon),
|
|
};
|
|
} catch (error) {
|
|
console.error('Geocoding error:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static async calculateDistance(
|
|
fromAddress: string,
|
|
toAddress: string
|
|
): Promise<DistanceResult | null> {
|
|
try {
|
|
const fromCoords = await this.geocodeAddress(fromAddress);
|
|
const toCoords = await this.geocodeAddress(toAddress);
|
|
|
|
if (!fromCoords || !toCoords) {
|
|
console.error('Failed to geocode one or both addresses');
|
|
return null;
|
|
}
|
|
|
|
const url = `${this.OSRM_API}/${fromCoords.lon},${fromCoords.lat};${toCoords.lon},${toCoords.lat}?overview=false`;
|
|
|
|
const response = await fetch(url);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`OSRM API failed: ${response.statusText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (!data.routes || data.routes.length === 0) {
|
|
console.error('No route found');
|
|
return null;
|
|
}
|
|
|
|
const route = data.routes[0];
|
|
|
|
return {
|
|
distance: Math.round(route.distance / 1000 * 100) / 100,
|
|
duration: Math.round(route.duration / 60),
|
|
};
|
|
} catch (error) {
|
|
console.error('Distance calculation error:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static formatAddress(address: string, zip: string, city: string): string {
|
|
return `${address}, ${zip} ${city}`.trim();
|
|
}
|
|
}
|