diff --git a/example/src/helpers/routesApi.ts b/example/src/helpers/routesApi.ts index 83702d3..422c173 100644 --- a/example/src/helpers/routesApi.ts +++ b/example/src/helpers/routesApi.ts @@ -14,169 +14,71 @@ * limitations under the License. */ -// Note: This Routes API implementation is meant to be used only to -// support the example app, and only includes the bare minimum to get -// the route tokens. +// Minimal Routes API implementation for fetching route tokens. +// Route tokens are currently only supported for DRIVE travel mode. +// See: https://developers.google.com/maps/documentation/routes/route_token -import type { LatLng, Waypoint } from '@googlemaps/react-native-navigation-sdk'; +import type { LatLng } from '@googlemaps/react-native-navigation-sdk'; -const ROUTES_API_URL = 'https://routes.googleapis.com'; -const COMPUTE_ROUTES_URL = `${ROUTES_API_URL}/directions/v2:computeRoutes`; +const COMPUTE_ROUTES_URL = + 'https://routes.googleapis.com/directions/v2:computeRoutes'; /** - * Travel modes supported by the Routes API. - */ -export type RoutesApiTravelMode = 'DRIVE' | 'BICYCLE' | 'WALK' | 'TWO_WHEELER'; - -/** - * Routing preference options for the Routes API. - */ -export type RoutingPreference = 'TRAFFIC_AWARE' | 'TRAFFIC_AWARE_OPTIMAL'; - -/** - * Options for the Routes API request. - */ -export interface RoutesApiOptions { - /** The travel mode for the route. Defaults to 'DRIVE'. */ - travelMode?: RoutesApiTravelMode; - /** The routing preference. Defaults to 'TRAFFIC_AWARE'. */ - routingPreference?: RoutingPreference; -} - -/** - * Response from the Routes API containing route tokens. - */ -export interface RoutesApiResponse { - /** List of route tokens returned by the API. */ - routeTokens: string[]; -} - -/** - * Converts a Waypoint to the Routes API waypoint format. - */ -function toRoutesApiWaypoint( - waypoint: Waypoint | LatLng, - via: boolean = false -): Record { - const output: Record = { via }; - - // Check if it's a Waypoint with placeId - if ('placeId' in waypoint && waypoint.placeId) { - output.placeId = waypoint.placeId; - } else { - // Handle LatLng or Waypoint with position - let lat: number; - let lng: number; - - if ('position' in waypoint && waypoint.position) { - lat = waypoint.position.lat; - lng = waypoint.position.lng; - } else if ('lat' in waypoint && 'lng' in waypoint) { - lat = waypoint.lat; - lng = waypoint.lng; - } else { - throw new Error( - 'Invalid waypoint: Either position or placeId must be provided.' - ); - } - - const location: Record = { - latLng: { - latitude: lat, - longitude: lng, - }, - }; - - // Add preferred heading if available - if ('preferredHeading' in waypoint && waypoint.preferredHeading != null) { - location.heading = waypoint.preferredHeading; - } - - output.location = location; - } - - return output; -} - -/** - * Queries the Google Maps Routes API and returns a list of route tokens. + * Fetches a route token from the Google Maps Routes API. + * Route tokens are only supported for DRIVE travel mode. * - * @param apiKey - The Google Maps API key with Routes API enabled. - * @param waypoints - A list of waypoints representing the route (minimum 2: origin and destination). - * @param options - Optional configuration for the route request. - * @returns A promise that resolves to a list of route tokens. - * @throws Error if the request fails or returns no route tokens. + * @param apiKey - Google Maps API key with Routes API enabled. + * @param origin - Starting location. + * @param destination - Ending location. + * @returns The route token string. * - * @example - * ```typescript - * const tokens = await getRouteToken( - * 'YOUR_API_KEY', - * [ - * { lat: 37.7749, lng: -122.4194 }, // Origin - * { lat: 37.3382, lng: -121.8863 }, // Destination - * ], - * { travelMode: 'DRIVE' } - * ); - * ``` + * @see https://developers.google.com/maps/documentation/routes/route_token */ export async function getRouteToken( apiKey: string, - waypoints: (Waypoint | LatLng)[], - options: RoutesApiOptions = {} -): Promise { + origin: LatLng, + destination: LatLng +): Promise { if (!apiKey || apiKey.trim() === '') { - throw new Error( - 'API key is required. Please provide a valid Google Maps API key.' - ); - } - - if (waypoints.length < 2) { - throw new Error( - 'At least two waypoints (origin and destination) are required.' - ); + throw new Error('API key is required.'); } - const { travelMode = 'DRIVE', routingPreference = 'TRAFFIC_AWARE' } = options; - - const origin = waypoints[0]!; - const destination = waypoints[waypoints.length - 1]!; - const intermediates = waypoints.slice(1, -1); - - const requestBody: Record = { - origin: toRoutesApiWaypoint(origin), - destination: toRoutesApiWaypoint(destination), - intermediates: intermediates.map(wp => toRoutesApiWaypoint(wp, true)), - travelMode, - routingPreference, - }; - - const headers: Record = { - 'X-Goog-Api-Key': apiKey, - 'X-Goog-FieldMask': 'routes.routeToken', - 'Content-Type': 'application/json', - }; - const response = await fetch(COMPUTE_ROUTES_URL, { method: 'POST', - headers, - body: JSON.stringify(requestBody), + headers: { + 'X-Goog-Api-Key': apiKey, + 'X-Goog-FieldMask': 'routes.routeToken', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + origin: { + location: { + latLng: { latitude: origin.lat, longitude: origin.lng }, + }, + }, + destination: { + location: { + latLng: { latitude: destination.lat, longitude: destination.lng }, + }, + }, + travelMode: 'DRIVE', + routingPreference: 'TRAFFIC_AWARE', + }), }); if (!response.ok) { const errorText = await response.text(); - throw new Error( - `Failed to get route tokens: ${response.statusText}\n${errorText}` - ); + throw new Error(`Routes API error: ${response.statusText}\n${errorText}`); } - const responseData = (await response.json()) as { - routes?: { routeToken: string }[]; + const data = (await response.json()) as { + routes?: { routeToken?: string }[]; }; - const routes = responseData.routes; - if (!routes || routes.length === 0) { - throw new Error('No routes returned from the Routes API.'); + const routeToken = data.routes?.[0]?.routeToken; + if (!routeToken) { + throw new Error('No route token returned from the Routes API.'); } - return routes.map(route => route.routeToken); + return routeToken; } diff --git a/example/src/screens/RouteTokenScreen.tsx b/example/src/screens/RouteTokenScreen.tsx index 63c3931..7c0f6e7 100644 --- a/example/src/screens/RouteTokenScreen.tsx +++ b/example/src/screens/RouteTokenScreen.tsx @@ -41,9 +41,8 @@ import { } from '@googlemaps/react-native-navigation-sdk'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import usePermissions from '../checkPermissions'; -import SelectDropdown from 'react-native-select-dropdown'; import Snackbar from 'react-native-snackbar'; -import { getRouteToken, type RoutesApiTravelMode } from '../helpers/routesApi'; +import { getRouteToken } from '../helpers/routesApi'; // Fixed locations for the route token example const ORIGIN_LOCATION: LatLng = { @@ -67,7 +66,6 @@ const RouteTokenScreen = () => { ); const [navigationViewController, setNavigationViewController] = useState(null); - const [travelMode, setTravelMode] = useState(TravelMode.DRIVING); // API key for Routes API const [apiKey, setApiKey] = useState(''); const [isFetchingToken, setIsFetchingToken] = useState(false); @@ -76,30 +74,6 @@ const RouteTokenScreen = () => { const { navigationController, addListeners, removeListeners } = useNavigation(); - const travelModeOptions = [ - { label: 'Driving', value: TravelMode.DRIVING }, - { label: 'Cycling', value: TravelMode.CYCLING }, - { label: 'Walking', value: TravelMode.WALKING }, - { label: 'Two Wheeler', value: TravelMode.TWO_WHEELER }, - { label: 'Taxi', value: TravelMode.TAXI }, - ]; - - // Map TravelMode to Routes API travel mode - const getRoutesApiTravelMode = (mode: TravelMode): RoutesApiTravelMode => { - switch (mode) { - case TravelMode.CYCLING: - return 'BICYCLE'; - case TravelMode.WALKING: - return 'WALK'; - case TravelMode.TWO_WHEELER: - return 'TWO_WHEELER'; - case TravelMode.DRIVING: - case TravelMode.TAXI: - default: - return 'DRIVE'; - } - }; - const handleFetchRouteToken = useCallback(async () => { if (apiKey.trim() === '') { Alert.alert('Missing API Key', 'Please enter your Google Maps API key.'); @@ -108,18 +82,14 @@ const RouteTokenScreen = () => { setIsFetchingToken(true); try { - const tokens = await getRouteToken( + const token = await getRouteToken( apiKey.trim(), - [ORIGIN_LOCATION, DESTINATION_LOCATION], - { travelMode: getRoutesApiTravelMode(travelMode) } + ORIGIN_LOCATION, + DESTINATION_LOCATION ); - if (tokens.length > 0) { - setRouteTokenInput(tokens[0]!); - showSnackbar('Route token fetched successfully'); - } else { - Alert.alert('No Route Found', 'The Routes API returned no routes.'); - } + setRouteTokenInput(token); + showSnackbar('Route token fetched successfully'); } catch (error) { console.error('Error fetching route token:', error); Alert.alert( @@ -129,7 +99,7 @@ const RouteTokenScreen = () => { } finally { setIsFetchingToken(false); } - }, [apiKey, travelMode]); + }, [apiKey]); const handleSetRouteToken = useCallback(() => { if (routeTokenInput.trim() === '') { @@ -159,7 +129,7 @@ const RouteTokenScreen = () => { const routeTokenOptions: RouteTokenOptions = { routeToken: confirmedRouteToken, - travelMode: travelMode, + travelMode: TravelMode.DRIVING, // Route tokens only support driving mode. }; try { @@ -175,12 +145,7 @@ const RouteTokenScreen = () => { ); } } - }, [ - navigationViewController, - confirmedRouteToken, - travelMode, - navigationController, - ]); + }, [navigationViewController, confirmedRouteToken, navigationController]); const onNavigationMapReady = useCallback(async () => { console.log( @@ -328,27 +293,6 @@ const RouteTokenScreen = () => { - - Travel Mode: - setTravelMode(selectedItem.value)} - defaultValue={travelModeOptions[0]} - renderButton={selectedItem => ( - - - {selectedItem?.label || 'Select travel mode'} - - - )} - renderItem={item => ( - - {item.label} - - )} - /> - - {isFetchingToken ? ( @@ -399,7 +343,7 @@ const RouteTokenScreen = () => { Note: - The travel mode must match what was used to generate the token. + Route tokens only support driving mode. {'\n\n'} The user location will be simulated at the origin when navigation starts. @@ -465,26 +409,6 @@ const styles = StyleSheet.create({ justifyContent: 'space-evenly', marginBottom: 10, }, - dropdownButton: { - backgroundColor: '#fff', - borderWidth: 1, - borderColor: '#ccc', - borderRadius: 8, - paddingHorizontal: 16, - paddingVertical: 12, - }, - dropdownButtonText: { - fontSize: 16, - color: '#333', - }, - dropdownItem: { - paddingHorizontal: 16, - paddingVertical: 12, - }, - dropdownItemText: { - fontSize: 16, - color: '#333', - }, sectionContainer: { marginBottom: 16, },