Files
projet_gestion_commande/frontend-admin/src/api/tomtom.ts
T
Xor290 22a8d5026c
Frontend Admin - EAS Build / build (push) Canceled after 0s
Frontend Client - EAS Build / build (push) Canceled after 0s
Backend - Build & Lint / build (push) Failing after 25m18s
Frontend Web - Build & Lint / build (push) Failing after 9m58s
chore: build
2026-08-06 12:06:05 +02:00

195 lines
6.3 KiB
TypeScript

import axios from "axios";
const TOMTOM_API_KEY = "MERY8I7LMeYVSLKO5WuV73W9rKJpBLoB";
export interface LatLng {
latitude: number;
longitude: number;
}
export interface RouteInfo {
distance: string;
duration: string;
distanceMeters: number;
durationSeconds: number;
coordinates: LatLng[];
}
export interface NavigationInstruction {
instruction: string;
distance: string;
maneuver: string;
streetName?: string;
isActive: boolean;
}
export const maneuverTranslations: Record<string, string> = {
TURN_LEFT: "Tournez à gauche",
TURN_RIGHT: "Tournez à droite",
TURN_SLIGHT_LEFT: "Tournez légèrement à gauche",
TURN_SLIGHT_RIGHT: "Tournez légèrement à droite",
TURN_SHARP_LEFT: "Tournez fortement à gauche",
TURN_SHARP_RIGHT: "Tournez fortement à droite",
KEEP_LEFT: "Restez à gauche",
KEEP_RIGHT: "Restez à droite",
STRAIGHT: "Continuez tout droit",
ENTER_ROUNDABOUT: "Entrez dans le rond-point",
EXIT_ROUNDABOUT: "Sortez du rond-point",
MOTORWAY_ENTER: "Entrez sur l'autoroute",
MOTORWAY_EXIT: "Sortez de l'autoroute",
ARRIVE: "Vous êtes arrivé",
ARRIVE_LEFT: "Destination à gauche",
ARRIVE_RIGHT: "Destination à droite",
DEPART: "Départ",
U_TURN: "Faites demi-tour",
FOLLOW: "Suivez",
WAYPOINT_REACHED: "Point de passage atteint",
};
export const maneuverIcons: Record<string, string> = {
TURN_LEFT: "arrow-back",
TURN_RIGHT: "arrow-forward",
TURN_SLIGHT_LEFT: "arrow-up",
TURN_SLIGHT_RIGHT: "arrow-up",
TURN_SHARP_LEFT: "return-down-back",
TURN_SHARP_RIGHT: "return-down-forward",
KEEP_LEFT: "arrow-back",
KEEP_RIGHT: "arrow-forward",
STRAIGHT: "arrow-up",
ENTER_ROUNDABOUT: "sync",
EXIT_ROUNDABOUT: "arrow-forward",
MOTORWAY_ENTER: "speedometer",
MOTORWAY_EXIT: "exit-outline",
ARRIVE: "flag",
ARRIVE_LEFT: "flag",
ARRIVE_RIGHT: "flag",
DEPART: "car",
U_TURN: "return-up-back",
FOLLOW: "arrow-up",
WAYPOINT_REACHED: "location",
DEFAULT: "arrow-up",
};
// ---- Helpers ----
function formatDistance(meters: number): string {
if (meters < 1000) return `${Math.round(meters)} m`;
return `${(meters / 1000).toFixed(1)} km`;
}
export async function geocodeAddress(address: string): Promise<LatLng | null> {
try {
const url = `https://api.tomtom.com/search/2/geocode/${encodeURIComponent(address)}.json?key=${TOMTOM_API_KEY}&limit=1`;
const { data } = await axios.get(url);
if (data.results && data.results.length > 0) {
const pos = data.results[0].position;
if (pos?.lat != null && pos?.lon != null) {
return { latitude: pos.lat, longitude: pos.lon };
}
}
} catch {
/* silent */
}
return null;
}
export async function calculateRoute(
origin: LatLng,
destination: LatLng,
): Promise<{ route: RouteInfo; instructions: NavigationInstruction[] } | null> {
try {
const start = `${origin.latitude},${origin.longitude}`;
const end = `${destination.latitude},${destination.longitude}`;
const url = `https://api.tomtom.com/routing/1/calculateRoute/${start}:${end}/json?key=${TOMTOM_API_KEY}&instructionsType=text&language=fr-FR&traffic=true&travelMode=car`;
const { data } = await axios.get(url);
if (!data.routes || data.routes.length === 0) return null;
const route = data.routes[0];
const summary = route.summary;
// Extract polyline coordinates
const coordinates: LatLng[] = [];
if (route.legs) {
for (const leg of route.legs) {
if (leg.points) {
for (const pt of leg.points) {
coordinates.push({
latitude: pt.latitude,
longitude: pt.longitude,
});
}
}
}
}
// Fallback: straight line
if (coordinates.length === 0) {
coordinates.push(origin, destination);
}
const distanceKm = (summary.lengthInMeters / 1000).toFixed(1);
const durationMin = Math.round(summary.travelTimeInSeconds / 60);
const routeInfo: RouteInfo = {
distance: `${distanceKm} km`,
duration: `${durationMin} min`,
distanceMeters: summary.lengthInMeters,
durationSeconds: summary.travelTimeInSeconds,
coordinates,
};
// Extract instructions
const instructions: NavigationInstruction[] = [];
if (route.guidance?.instructions) {
for (let i = 0; i < route.guidance.instructions.length; i++) {
const inst = route.guidance.instructions[i];
const maneuver = inst.maneuver || "STRAIGHT";
const text =
inst.message ||
maneuverTranslations[maneuver] ||
"Continuez";
instructions.push({
instruction: text,
distance: formatDistance(inst.routeOffsetInMeters || 0),
maneuver,
streetName: inst.street,
isActive: i === 0,
});
}
}
if (instructions.length === 0) {
instructions.push({
instruction: "Dirigez-vous vers votre destination",
distance: formatDistance(summary.lengthInMeters || 0),
maneuver: "DEPART",
isActive: true,
});
instructions.push({
instruction: "Vous êtes arrivé à destination",
distance: "0 m",
maneuver: "ARRIVE",
isActive: false,
});
}
return { route: routeInfo, instructions };
} catch {
/* silent */
}
return null;
}
// ---- Bearing calculation ----
export function calculateBearing(from: LatLng, to: LatLng): number {
const φ1 = (from.latitude * Math.PI) / 180;
const φ2 = (to.latitude * Math.PI) / 180;
const Δλ = ((to.longitude - from.longitude) * Math.PI) / 180;
const y = Math.sin(Δλ) * Math.cos(φ2);
const x =
Math.cos(φ1) * Math.sin(φ2) -
Math.sin(φ1) * Math.cos(φ2) * Math.cos(Δλ);
return ((Math.atan2(y, x) * 180) / Math.PI + 360) % 360;
}