428 lines
12 KiB
Markdown
428 lines
12 KiB
Markdown
# 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:
|
|
|
|
```dart
|
|
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`:
|
|
|
|
```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;
|
|
}
|
|
}
|
|
```
|
|
|
|
2. Use it in `main.dart`:
|
|
|
|
```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:
|
|
|
|
```dart
|
|
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:
|
|
|
|
```dart
|
|
// 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
|
|
|
|
```dart
|
|
// 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`:
|
|
```dart
|
|
static const String baseApiUrl = 'https://your-api-url.com/api';
|
|
```
|
|
|
|
2. Remove mock data from `route_api_service.dart`
|
|
|
|
3. Ensure your API returns data in the expected format (matching the models)
|
|
|
|
4. Test with real API:
|
|
```bash
|
|
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
|
|
```json
|
|
[
|
|
{
|
|
"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
|