229 lines
6.8 KiB
Dart
229 lines
6.8 KiB
Dart
import 'package:dio/dio.dart';
|
|
|
|
import '../config/api_config.dart';
|
|
import '../models/models.dart';
|
|
|
|
class ApiException implements Exception {
|
|
ApiException(this.message, {this.statusCode});
|
|
|
|
final String message;
|
|
final int? statusCode;
|
|
|
|
@override
|
|
String toString() => message;
|
|
}
|
|
|
|
class ApiClient {
|
|
ApiClient() {
|
|
dio = Dio(
|
|
BaseOptions(
|
|
baseUrl: resolveApiBaseUrl(),
|
|
connectTimeout: const Duration(seconds: 15),
|
|
receiveTimeout: const Duration(seconds: 15),
|
|
headers: const {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
},
|
|
),
|
|
);
|
|
dio.interceptors.add(
|
|
InterceptorsWrapper(
|
|
onRequest: (options, handler) {
|
|
if (token != null && token!.isNotEmpty) {
|
|
options.headers['Authorization'] = 'Bearer $token';
|
|
}
|
|
handler.next(options);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
late final Dio dio;
|
|
String? token;
|
|
|
|
Future<({String token, AppUser user})> staffLogin(String phone, String password) {
|
|
return _send(
|
|
dio.post('/auth/staff-login', data: {'phone': phone, 'password': password}),
|
|
(data) {
|
|
final map = data as Map<String, dynamic>;
|
|
return (
|
|
token: map['token'] as String,
|
|
user: AppUser.fromJson(map['user'] as Map<String, dynamic>),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Future<({String requestId, String secret})> dealerLogin(String phone) {
|
|
return _send(dio.post('/auth/dealer-login', data: {'phone': phone}), (data) {
|
|
final map = data as Map<String, dynamic>;
|
|
return (requestId: map['requestId'] as String, secret: map['secret'] as String);
|
|
});
|
|
}
|
|
|
|
Future<DealerLoginStatus> dealerLoginStatus(String requestId, String secret) {
|
|
return _send(
|
|
dio.get('/auth/dealer-login/$requestId', queryParameters: {'secret': secret}),
|
|
(data) => DealerLoginStatus.fromJson(data as Map<String, dynamic>),
|
|
);
|
|
}
|
|
|
|
Future<List<LoginRequestItem>> loginRequests() {
|
|
return _send(dio.get('/auth/login-requests'), (data) => _list(data, LoginRequestItem.fromJson));
|
|
}
|
|
|
|
Future<void> approveLogin(String id) {
|
|
return _send(dio.post('/auth/login-requests/$id/approve'), (_) {});
|
|
}
|
|
|
|
Future<void> rejectLogin(String id) {
|
|
return _send(dio.post('/auth/login-requests/$id/reject'), (_) {});
|
|
}
|
|
|
|
Future<AppUser> me() {
|
|
return _send(
|
|
dio.get('/auth/me'),
|
|
(data) => AppUser.fromJson(data as Map<String, dynamic>),
|
|
);
|
|
}
|
|
|
|
Future<List<Dealer>> dealers() {
|
|
return _send(dio.get('/dealers'), (data) => _list(data, Dealer.fromJson));
|
|
}
|
|
|
|
Future<List<StockItem>> stocks({String? dealerId}) {
|
|
return _send(
|
|
dio.get(
|
|
'/stocks',
|
|
queryParameters: {
|
|
if (dealerId != null && dealerId.isNotEmpty) 'dealerId': dealerId,
|
|
},
|
|
),
|
|
(data) => _list(data, StockItem.fromJson),
|
|
);
|
|
}
|
|
|
|
Future<StockItem> createStock(Map<String, dynamic> body) {
|
|
return _send(
|
|
dio.post('/stocks', data: body),
|
|
(data) => StockItem.fromJson((data as Map<String, dynamic>)['data'] as Map<String, dynamic>),
|
|
);
|
|
}
|
|
|
|
Future<StockItem> updateStage(String chassisNumber, Map<String, dynamic> body) {
|
|
return _send(
|
|
dio.patch('/stocks/$chassisNumber/stage', data: body),
|
|
(data) => StockItem.fromJson((data as Map<String, dynamic>)['data'] as Map<String, dynamic>),
|
|
);
|
|
}
|
|
|
|
Future<StockItem> transferStock(String chassisNumber, String dealerId) {
|
|
return _send(
|
|
dio.post('/stocks/$chassisNumber/transfer', data: {'dealerId': dealerId}),
|
|
(data) => StockItem.fromJson((data as Map<String, dynamic>)['data'] as Map<String, dynamic>),
|
|
);
|
|
}
|
|
|
|
Future<List<EventPlan>> events({String? dealerId, String? planType}) {
|
|
return _send(
|
|
dio.get(
|
|
'/events',
|
|
queryParameters: {
|
|
if (dealerId != null && dealerId.isNotEmpty) 'dealerId': dealerId,
|
|
if (planType != null && planType.isNotEmpty) 'planType': planType,
|
|
},
|
|
),
|
|
(data) => _list(data, EventPlan.fromJson),
|
|
);
|
|
}
|
|
|
|
Future<EventPlan> createEvent(Map<String, dynamic> body) {
|
|
return _send(
|
|
dio.post('/events', data: body),
|
|
(data) => EventPlan.fromJson((data as Map<String, dynamic>)['data'] as Map<String, dynamic>),
|
|
);
|
|
}
|
|
|
|
Future<List<ServicePoint>> servicePoints({String? district, String? search}) {
|
|
return _send(
|
|
dio.get(
|
|
'/service-points',
|
|
queryParameters: {
|
|
if (district != null && district.isNotEmpty) 'district': district,
|
|
if (search != null && search.isNotEmpty) 'search': search,
|
|
},
|
|
),
|
|
(data) => _list(data, ServicePoint.fromJson),
|
|
);
|
|
}
|
|
|
|
Future<ServicePoint> createServicePoint(Map<String, dynamic> body) {
|
|
return _send(
|
|
dio.post('/service-points', data: body),
|
|
(data) => ServicePoint.fromJson((data as Map<String, dynamic>)['data'] as Map<String, dynamic>),
|
|
);
|
|
}
|
|
|
|
Future<Dealer> createDealer(Map<String, dynamic> body) {
|
|
return _send(
|
|
dio.post('/admin/dealers', data: body),
|
|
(data) => Dealer.fromJson((data as Map<String, dynamic>)['data'] as Map<String, dynamic>),
|
|
);
|
|
}
|
|
|
|
Future<void> deleteDealer(String id) {
|
|
return _send(dio.delete('/admin/dealers/$id'), (_) {});
|
|
}
|
|
|
|
Future<List<Dealer>> adminDealers() {
|
|
return _send(dio.get('/admin/dealers'), (data) => _list(data, Dealer.fromJson));
|
|
}
|
|
|
|
Future<List<AppUser>> salesReps() {
|
|
return _send(dio.get('/admin/sales-reps'), (data) => _list(data, AppUser.fromJson));
|
|
}
|
|
|
|
Future<AppUser> createSalesRep(Map<String, dynamic> body) {
|
|
return _send(
|
|
dio.post('/admin/sales-reps', data: body),
|
|
(data) => AppUser.fromJson((data as Map<String, dynamic>)['data'] as Map<String, dynamic>),
|
|
);
|
|
}
|
|
|
|
Future<AppUser> assignDealer({
|
|
required String salesRepId,
|
|
required String dealerId,
|
|
required bool assigned,
|
|
}) {
|
|
return _send(
|
|
dio.patch(
|
|
'/admin/assign-dealer',
|
|
data: {
|
|
'salesRepId': salesRepId,
|
|
'dealerId': dealerId,
|
|
'assigned': assigned,
|
|
},
|
|
),
|
|
(data) => AppUser.fromJson((data as Map<String, dynamic>)['data'] as Map<String, dynamic>),
|
|
);
|
|
}
|
|
|
|
Future<T> _send<T>(Future<Response<dynamic>> request, T Function(dynamic data) parse) async {
|
|
try {
|
|
final response = await request;
|
|
return parse(response.data);
|
|
} on DioException catch (error) {
|
|
final data = error.response?.data;
|
|
final message = data is Map && data['message'] is String
|
|
? data['message'] as String
|
|
: 'Network request failed';
|
|
throw ApiException(message, statusCode: error.response?.statusCode);
|
|
}
|
|
}
|
|
|
|
List<T> _list<T>(dynamic data, T Function(Map<String, dynamic>) parse) {
|
|
final raw = (data as Map<String, dynamic>)['data'] as List<dynamic>;
|
|
return raw.map((item) => parse(item as Map<String, dynamic>)).toList();
|
|
}
|
|
}
|