location.ts
Purpose
This module handles all device location concerns: requesting the appropriate permission scope, resolving the current GPS position, and geocoding a text address into coordinates via the Google Places API.
Its responsibilities include:
- Requesting
ACCESS_FINE_LOCATIONon Android orwhenInUse/alwaysauthorization on iOS - Wrapping
Geolocation.getCurrentPositionin a Promise with a 15-second timeout - Providing a convenience entry point for background location with
alwaysscope - Providing a separate foreground-only entry point for work area seeding with
whenInUsescope - Geocoding a free-text address by querying
workAreaAddressSearchand resolving the first suggestion
Invariants
Permission Before Position
Both getDeviceLocation and getForegroundLocationForWorkAreaSeed check permission before calling getCurrentPosition.
A denied permission throws Error("Location permission denied") and never attempts a position fix.
iOS Scope Distinction
getDeviceLocation always requests "always" authorization (required for background location used during background fetch).
getForegroundLocationForWorkAreaSeed requests "whenInUse" only, matching the foreground-only use case of seeding a new work area.
Android Geocode Permission
geocodeWorkAreaAddress requests "whenInUse" permission on Android before calling the Places API.
On iOS no additional permission check is performed for geocoding, as location is only used for context in the address search and not required for the API call itself.
Geolocation Options
All getCurrentPosition calls use the same fixed options:
| Option | Value |
|---|---|
enableHighAccuracy | true |
timeout | 15,000 ms |
maximumAge | 10,000 ms |
forceRequestLocation | true |
showLocationDialog | true |
Geocoding Address Validation
geocodeWorkAreaAddress trims the input and throws Error("Enter an address to search.") if it is empty after trimming.
If the Places API returns no suggestions, it throws Error("No matching address found.").
Variants
Address Geocoding Flow
Geocoding uses a two-step session-token flow via workAreaAddressSearch:
searchWorkAreaAddressSuggestionsfetches autocomplete predictionsresolveWorkAreaAddressSuggestionfetches full coordinates for the first result
A unique session token is generated per call as ${Date.now()}-${Math.random()}.
Exports
requestLocationPermission(...)
async function requestLocationPermission(iosScope: 'always' | 'whenInUse'): Promise<boolean>
Requests location permission for the given iOS scope. Returns true if granted, false otherwise. Always returns false on unsupported platforms.
getDeviceLocation()
async function getDeviceLocation(): Promise<{ lat: number; lon: number; elev: number }>
Requests always permission and resolves the current GPS position. Throws on denied permission or geolocation error.
getForegroundLocationForWorkAreaSeed()
async function getForegroundLocationForWorkAreaSeed(): Promise<{ lat: number; lon: number }>
Requests whenInUse permission and resolves the current GPS position for work area seeding. Throws on denied permission or geolocation error.
geocodeWorkAreaAddress(...)
async function geocodeWorkAreaAddress(address: string): Promise<{ lat: number; lon: number }>
Geocodes a free-text address to coordinates using the Google Places API. Throws on empty input, permission denial (Android), no results, or API errors.