ionic-planb-logistic-app-fl.../API_MOCK_DATA.md

12 KiB

API Mock Data Guide

If you don't have a backend API ready yet, you can use mock data to test the app. This guide shows you how to create and use mock data.

Creating Mock Data

Option 1: Modify RouteApiService

Edit lib/services/api/route_api_service.dart and replace the API calls with mock data:

import 'package:uuid/uuid.dart';

Future<List<RouteModel>> getDriverRoutes(String driverId) async {
  // Simulate network delay
  await Future.delayed(const Duration(seconds: 1));

  // Return mock data
  return [
    RouteModel(
      id: 'RT001',
      driverId: driverId,
      driverName: 'John Doe',
      date: DateTime.now(),
      status: RouteStatus.notStarted,
      totalDistance: 45.5,
      estimatedDuration: 120,
      vehicleId: 'VH123',
      stops: [
        StopModel(
          id: 'ST001',
          customerId: 'C001',
          customerName: 'Acme Corporation',
          customerPhone: '+1234567890',
          location: LocationModel(
            latitude: 37.7749,
            longitude: -122.4194,
            address: '123 Market St, San Francisco, CA 94103',
          ),
          type: StopType.pickup,
          status: StopStatus.pending,
          scheduledTime: DateTime.now().add(const Duration(hours: 1)),
          items: ['Package A', 'Package B', 'Package C'],
          orderNumber: 1,
        ),
        StopModel(
          id: 'ST002',
          customerId: 'C002',
          customerName: 'Tech Solutions Inc',
          customerPhone: '+1234567891',
          location: LocationModel(
            latitude: 37.7849,
            longitude: -122.4094,
            address: '456 Mission St, San Francisco, CA 94105',
          ),
          type: StopType.dropoff,
          status: StopStatus.pending,
          scheduledTime: DateTime.now().add(const Duration(hours: 2)),
          items: ['Package A', 'Package B'],
          orderNumber: 2,
        ),
        StopModel(
          id: 'ST003',
          customerId: 'C003',
          customerName: 'Global Supplies Ltd',
          customerPhone: '+1234567892',
          location: LocationModel(
            latitude: 37.7949,
            longitude: -122.3994,
            address: '789 Howard St, San Francisco, CA 94107',
          ),
          type: StopType.dropoff,
          status: StopStatus.pending,
          scheduledTime: DateTime.now().add(const Duration(hours: 3)),
          items: ['Package C'],
          orderNumber: 3,
        ),
      ],
    ),
    RouteModel(
      id: 'RT002',
      driverId: driverId,
      driverName: 'John Doe',
      date: DateTime.now().add(const Duration(days: 1)),
      status: RouteStatus.notStarted,
      totalDistance: 32.8,
      estimatedDuration: 90,
      vehicleId: 'VH123',
      stops: [
        StopModel(
          id: 'ST004',
          customerId: 'C004',
          customerName: 'Downtown Retail',
          customerPhone: '+1234567893',
          location: LocationModel(
            latitude: 37.7649,
            longitude: -122.4294,
            address: '321 Broadway, San Francisco, CA 94133',
          ),
          type: StopType.pickup,
          status: StopStatus.pending,
          scheduledTime: DateTime.now().add(const Duration(days: 1, hours: 1)),
          items: ['Box 1', 'Box 2'],
          orderNumber: 1,
        ),
      ],
    ),
  ];
}

Future<RouteModel?> getRouteById(String routeId) async {
  await Future.delayed(const Duration(seconds: 1));

  final routes = await getDriverRoutes('driver_1');
  return routes.firstWhere(
    (route) => route.id == routeId,
    orElse: () => routes.first,
  );
}

Future<bool> updateRouteStatus(String routeId, RouteStatus status) async {
  await Future.delayed(const Duration(milliseconds: 500));
  // Simulate successful update
  return true;
}

Future<bool> updateStopStatus(
  String routeId,
  String stopId,
  StopStatus status, {
  String? signature,
  String? photo,
  String? notes,
}) async {
  await Future.delayed(const Duration(milliseconds: 500));
  // Simulate successful update
  return true;
}

Future<bool> reportIssue(String routeId, String stopId, String issue) async {
  await Future.delayed(const Duration(milliseconds: 500));
  // Simulate successful report
  return true;
}

Option 2: Create a Mock Provider

Create a separate mock service that you can easily swap:

  1. Create lib/services/api/mock_route_api_service.dart:
import 'route_api_service.dart';
import '../../features/routes/data/models/route_model.dart';
import '../../features/routes/data/models/stop_model.dart';
import '../../features/routes/data/models/location_model.dart';

class MockRouteApiService extends RouteApiService {
  final List<RouteModel> _mockRoutes = [
    // Add your mock routes here
  ];

  @override
  Future<List<RouteModel>> getDriverRoutes(String driverId) async {
    await Future.delayed(const Duration(seconds: 1));
    return _mockRoutes;
  }

  @override
  Future<RouteModel?> getRouteById(String routeId) async {
    await Future.delayed(const Duration(seconds: 1));
    return _mockRoutes.firstWhere(
      (route) => route.id == routeId,
      orElse: () => _mockRoutes.first,
    );
  }

  @override
  Future<bool> updateRouteStatus(String routeId, RouteStatus status) async {
    await Future.delayed(const Duration(milliseconds: 500));
    return true;
  }

  @override
  Future<bool> updateStopStatus(
    String routeId,
    String stopId,
    StopStatus status, {
    String? signature,
    String? photo,
    String? notes,
  }) async {
    await Future.delayed(const Duration(milliseconds: 500));
    return true;
  }

  @override
  Future<bool> reportIssue(String routeId, String stopId, String issue) async {
    await Future.delayed(const Duration(milliseconds: 500));
    return true;
  }
}
  1. Use it in main.dart:
void main() {
  // Use mock service for development
  // RouteApiService().initialize(); // Production
  // In development, the provider will use mock data automatically

  runApp(const FleetDriverApp());
}

Mock Data Generator

Here's a utility to generate random mock data for testing:

import 'dart:math';
import 'package:uuid/uuid.dart';

class MockDataGenerator {
  static final _random = Random();
  static final _uuid = Uuid();

  static final List<String> _customerNames = [
    'Acme Corporation',
    'Tech Solutions Inc',
    'Global Supplies Ltd',
    'Downtown Retail',
    'Bay Area Logistics',
    'Pacific Trading Co',
    'Metro Wholesale',
    'Summit Distribution',
  ];

  static final List<String> _addresses = [
    '123 Market St, San Francisco, CA',
    '456 Mission St, San Francisco, CA',
    '789 Howard St, San Francisco, CA',
    '321 Broadway, San Francisco, CA',
    '654 Valencia St, San Francisco, CA',
    '987 Geary Blvd, San Francisco, CA',
  ];

  static final List<String> _items = [
    'Package A',
    'Package B',
    'Package C',
    'Box 1',
    'Box 2',
    'Crate 1',
    'Pallet A',
    'Container X',
  ];

  static RouteModel generateRoute({
    required String driverId,
    int stopCount = 3,
  }) {
    final stops = List.generate(
      stopCount,
      (index) => generateStop(orderNumber: index + 1),
    );

    return RouteModel(
      id: 'RT${_random.nextInt(9999).toString().padLeft(4, '0')}',
      driverId: driverId,
      driverName: 'Driver ${_random.nextInt(100)}',
      date: DateTime.now().add(Duration(days: _random.nextInt(7))),
      status: RouteStatus.values[_random.nextInt(RouteStatus.values.length)],
      stops: stops,
      totalDistance: 20.0 + _random.nextDouble() * 80,
      estimatedDuration: 60 + _random.nextInt(180),
      vehicleId: 'VH${_random.nextInt(999)}',
    );
  }

  static StopModel generateStop({required int orderNumber}) {
    return StopModel(
      id: _uuid.v4(),
      customerId: 'C${_random.nextInt(9999)}',
      customerName: _customerNames[_random.nextInt(_customerNames.length)],
      customerPhone: '+1${_random.nextInt(999999999).toString().padLeft(9, '0')}',
      location: LocationModel(
        latitude: 37.7749 + (_random.nextDouble() - 0.5) * 0.1,
        longitude: -122.4194 + (_random.nextDouble() - 0.5) * 0.1,
        address: _addresses[_random.nextInt(_addresses.length)],
      ),
      type: _random.nextBool() ? StopType.pickup : StopType.dropoff,
      status: StopStatus.values[_random.nextInt(StopStatus.values.length)],
      scheduledTime: DateTime.now().add(Duration(hours: orderNumber)),
      items: List.generate(
        1 + _random.nextInt(4),
        (_) => _items[_random.nextInt(_items.length)],
      ),
      orderNumber: orderNumber,
    );
  }

  static List<RouteModel> generateRoutes({
    required String driverId,
    int count = 5,
  }) {
    return List.generate(
      count,
      (_) => generateRoute(driverId: driverId),
    );
  }
}

Usage:

// In route_api_service.dart
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
  await Future.delayed(const Duration(seconds: 1));
  return MockDataGenerator.generateRoutes(driverId: driverId, count: 5);
}

Testing with Mock Data

Local Testing

  1. Use mock data during development
  2. Test all UI states (loading, error, empty, success)
  3. Test edge cases (no routes, single route, many routes)

State Testing

Test different route and stop statuses:

  • Routes: notStarted, inProgress, completed, cancelled
  • Stops: pending, inProgress, completed, failed

Example Test Scenarios

// Test empty state
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
  return [];
}

// Test error state
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
  throw Exception('Network error');
}

// Test single route
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
  return [MockDataGenerator.generateRoute(driverId: driverId)];
}

// Test many routes
Future<List<RouteModel>> getDriverRoutes(String driverId) async {
  return MockDataGenerator.generateRoutes(driverId: driverId, count: 20);
}

Switching to Real API

When your backend is ready:

  1. Update API base URL in lib/core/constants/app_constants.dart:
static const String baseApiUrl = 'https://your-api-url.com/api';
  1. Remove mock data from route_api_service.dart

  2. Ensure your API returns data in the expected format (matching the models)

  3. Test with real API:

flutter run --dart-define=API_URL=https://your-api-url.com/api

API Response Format

Your backend should return JSON in this format:

Get Routes Response

[
  {
    "id": "RT001",
    "driverId": "driver_1",
    "driverName": "John Doe",
    "date": "2025-10-27T10:00:00Z",
    "status": "notStarted",
    "totalDistance": 45.5,
    "estimatedDuration": 120,
    "vehicleId": "VH123",
    "stops": [
      {
        "id": "ST001",
        "customerId": "C001",
        "customerName": "Acme Corporation",
        "customerPhone": "+1234567890",
        "location": {
          "latitude": 37.7749,
          "longitude": -122.4194,
          "address": "123 Market St, San Francisco, CA"
        },
        "type": "pickup",
        "status": "pending",
        "scheduledTime": "2025-10-27T11:00:00Z",
        "items": ["Package A", "Package B"],
        "orderNumber": 1
      }
    ]
  }
]

Tips for Mock Data

  1. Use realistic data: Coordinates, addresses, names
  2. Test edge cases: Empty lists, null values, long strings
  3. Simulate delays: Add realistic network delays
  4. Test errors: Simulate network failures and API errors
  5. Use different statuses: Test all possible states
  6. Generate varied data: Different route lengths, stop counts
  7. Include optional fields: Test with and without optional data