📱 EN ROUTE STATUS - Developer Documentation

API Endpoints

// Get job details
GET /api/agentownjobs/{id}

// Mark as arrived
POST /api/agentownjobs/{id}/arrived
{
    "timestamp": "2024-12-05T11:15:00Z",
    "location": {
        "lat": 51.5074,
        "lng": -0.1278
    }
}

// Update location during travel
POST /api/agentownjobs/{id}/location
{
    "lat": 51.5074,
    "lng": -0.1278,
    "timestamp": "2024-12-05T11:00:00Z"
}

Travel Time Calculations

// Swift (iOS)
let travelStartTime = job.travelStartTime ?? Date()
let elapsedMinutes = Int(Date().timeIntervalSince(travelStartTime) / 60)
travelTimeLabel.text = "\(elapsedMinutes) min"

// Update every minute
Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { _ in
    updateTravelTime()
}

// Kotlin (Android)
val travelStartTime = job.travelStartTime ?: System.currentTimeMillis()
val elapsedMinutes = (System.currentTimeMillis() - travelStartTime) / 60000
travelTimeText.text = "$elapsedMinutes min"

// Update with Handler
handler.postDelayed({
    updateTravelTime()
}, 60000)

// Dart (Flutter)
final travelStartTime = job.travelStartTime ?? DateTime.now();
final elapsedMinutes = DateTime.now().difference(travelStartTime).inMinutes;
setState(() {
  travelTime = '$elapsedMinutes min';
});

// Update with Timer
Timer.periodic(Duration(minutes: 1), (timer) {
  updateTravelTime();
});

ETA Calculation

// Swift
let estimatedDuration = job.estimatedTravelMinutes ?? 30
let eta = travelStartTime.addingTimeInterval(Double(estimatedDuration * 60))
let formatter = DateFormatter()
formatter.timeStyle = .short
etaLabel.text = formatter.string(from: eta)

// Kotlin
val estimatedDuration = job.estimatedTravelMinutes ?: 30
val eta = travelStartTime + (estimatedDuration * 60000)
val formatter = SimpleDateFormat("h:mm a", Locale.getDefault())
etaText.text = formatter.format(Date(eta))

// Dart
final estimatedDuration = job.estimatedTravelMinutes ?? 30;
final eta = travelStartTime.add(Duration(minutes: estimatedDuration));
final formattedEta = DateFormat('h:mm a').format(eta);

Location Tracking

// Swift - Request location updates
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
locationManager.distanceFilter = 100 // Update every 100 meters

func locationManager(_ manager: CLLocationManager, 
                    didUpdateLocations locations: [CLLocation]) {
    guard let location = locations.last else { return }
    
    // Send to server
    APIClient.updateLocation(jobId: job.id, 
                           lat: location.coordinate.latitude,
                           lng: location.coordinate.longitude)
}

// Android - Location updates
if (ContextCompat.checkSelfPermission(this, 
    Manifest.permission.ACCESS_FINE_LOCATION) == 
    PackageManager.PERMISSION_GRANTED) {
    
    locationRequest = LocationRequest.create().apply {
        interval = 60000 // 1 minute
        fastestInterval = 30000
        priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        smallestDisplacement = 100f // 100 meters
    }
    
    fusedLocationClient.requestLocationUpdates(
        locationRequest,
        locationCallback,
        Looper.getMainLooper()
    )
}

// Flutter - Location tracking
final location = Location();
if (await location.hasPermission() == PermissionStatus.granted) {
  location.onLocationChanged.listen((LocationData currentLocation) {
    if (currentLocation.latitude != null && 
        currentLocation.longitude != null) {
      // Send to server
      updateJobLocation(
        jobId: job.id,
        lat: currentLocation.latitude!,
        lng: currentLocation.longitude!
      );
    }
  });
}

Status Transition

// When "I've Arrived" is clicked
async function markArrived() {
    try {
        const response = await fetch(`/api/agentownjobs/${jobId}/arrived`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            },
            body: JSON.stringify({
                timestamp: new Date().toISOString(),
                location: currentLocation
            })
        });
        
        if (response.ok) {
            // Job status changes from "EnRoute" to "InProgress"
            navigateToInProgress();
        }
    } catch (error) {
        showError('Failed to mark arrival');
    }
}

Required API Response Fields

{
    "id": "guid",
    "jobReference": "GSC-2024-1847",
    "jobType": "Meter Reading",
    "status": "EnRoute",
    "priority": "Urgent",
    "customerName": "Mr. John Smith",
    "customerPhone": "+44 20 7123 4567",
    "propertyAddress": "123 High Street, London, SW1A 1AA",
    "scheduledTime": "11:00 AM - 12:00 PM",
    "specialInstructions": "Side gate access. Ring doorbell twice.",
    "travelStartTime": "2024-12-05T10:45:00Z",
    "estimatedTravelMinutes": 30,
    "distance": 3.2,
    "distanceUnit": "miles",
    "trafficCondition": "Light",
    "location": {
        "lat": 51.5074,
        "lng": -0.1278
    }
}

En Route to Site

Started at 10:45 AM
Time Traveling
15min
ETA
11:15AM
Distance
3.2miles
Traffic
Light
Live tracking map
Meter Reading
#GSC-2024-1847
URGENT
Customer
Mr. John Smith
Address
123 High Street, London, SW1A 1AA
Scheduled Time
11:00 AM - 12:00 PM
Special Instructions
Side gate access. Ring doorbell twice.
Call
Message
Navigate