Files
Siro/siro_rider/lib/controller/food/food_service.dart
T

200 lines
6.9 KiB
Dart

// food_service.dart — طبقة الاتصال بـ backend/food (جهة الراكب)
import 'dart:convert';
import '../functions/crud.dart';
import '../../constant/links.dart';
import 'food_models.dart';
class FoodApiResult<T> {
final bool success;
final T? data;
final String message;
final int? code;
FoodApiResult(this.success, this.data, this.message, {this.code});
}
class FoodService {
static String get _base => '${AppLink.server}/food';
static Future<FoodApiResult<List<FoodMerchant>>> browseMerchants({
required String city,
String? category,
}) async {
final payload = <String, dynamic>{'city': city};
if (category != null && category.isNotEmpty) payload['category'] = category;
final res = await CRUD().post(link: '$_base/merchant/browse.php', payload: payload);
if (res is Map && res['status'] == 'success') {
final msg = res['message'];
final list = (msg is Map && msg['merchants'] is List)
? (msg['merchants'] as List)
.map((m) => FoodMerchant.fromJson(Map<String, dynamic>.from(m)))
.toList()
: <FoodMerchant>[];
return FoodApiResult(true, list, 'ok');
}
return FoodApiResult(false, null, _errMsg(res));
}
static Future<FoodApiResult<List<FoodMerchant>>> searchMerchants({
required String city,
required String query,
}) async {
final res = await CRUD().post(
link: '$_base/merchant/search.php',
payload: {'city': city, 'q': query},
);
if (res is Map && res['status'] == 'success') {
final msg = res['message'];
final list = (msg is Map && msg['merchants'] is List)
? (msg['merchants'] as List)
.map((m) => FoodMerchant.fromJson(Map<String, dynamic>.from(m)))
.toList()
: <FoodMerchant>[];
return FoodApiResult(true, list, 'ok');
}
return FoodApiResult(false, null, _errMsg(res));
}
static Future<FoodApiResult<Map<String, dynamic>>> merchantDetails(int merchantId) async {
final res = await CRUD().post(
link: '$_base/merchant/details.php',
payload: {'merchant_id': merchantId.toString()},
);
if (res is Map && res['status'] == 'success') {
final msg = res['message'];
if (msg is Map) {
final merchant = FoodMerchant.fromJson(Map<String, dynamic>.from(msg['merchant']));
final categories = (msg['categories'] is List)
? (msg['categories'] as List)
.map((c) => FoodMenuCategory.fromJson(Map<String, dynamic>.from(c)))
.toList()
: <FoodMenuCategory>[];
return FoodApiResult(true, {'merchant': merchant, 'categories': categories}, 'ok');
}
}
return FoodApiResult(false, null, _errMsg(res));
}
static Future<FoodApiResult<FoodQuote>> getQuote({
required int merchantId,
required List<FoodCartLine> lines,
}) async {
final res = await CRUD().post(
link: '$_base/cart/quote.php',
payload: {
'merchant_id': merchantId.toString(),
'items': jsonEncode(lines.map((l) => l.toQuotePayload()).toList()),
},
);
if (res is Map && res['status'] == 'success') {
final msg = res['message'];
if (msg is Map) return FoodApiResult(true, FoodQuote.fromJson(Map<String, dynamic>.from(msg)), 'ok');
}
return FoodApiResult(false, null, _errMsg(res), code: _errCode(res));
}
static Future<FoodApiResult<int>> createOrder({
required String quoteToken,
required String clientOrderUuid,
required String deliveryAddress,
required double deliveryLat,
required double deliveryLng,
required String paymentMethod, // wallet | cash
String? customerNote,
}) async {
final res = await CRUD().post(
link: '$_base/order/create.php',
payload: {
'quote_token': quoteToken,
'client_order_uuid': clientOrderUuid,
'delivery_address': deliveryAddress,
'delivery_lat': deliveryLat.toString(),
'delivery_lng': deliveryLng.toString(),
'payment_method': paymentMethod,
if (customerNote != null && customerNote.isNotEmpty) 'customer_note': customerNote,
},
);
if (res is Map && res['status'] == 'success') {
final msg = res['message'];
if (msg is Map && msg['order_id'] != null) {
return FoodApiResult(true, int.tryParse(msg['order_id'].toString()) ?? 0, 'ok');
}
}
return FoodApiResult(false, null, _errMsg(res), code: _errCode(res));
}
static Future<FoodApiResult<FoodOrder>> getOrderStatus(int orderId) async {
final res = await CRUD().post(
link: '$_base/order/status.php',
payload: {'order_id': orderId.toString()},
);
if (res is Map && res['status'] == 'success') {
final msg = res['message'];
if (msg is Map && msg['order'] is Map) {
return FoodApiResult(true, FoodOrder.fromJson(Map<String, dynamic>.from(msg['order'])), 'ok');
}
}
return FoodApiResult(false, null, _errMsg(res));
}
static Future<FoodApiResult<void>> cancelOrder(int orderId, {String? reason}) async {
final res = await CRUD().post(
link: '$_base/order/cancel.php',
payload: {'order_id': orderId.toString(), if (reason != null) 'reason': reason},
);
if (res is Map && res['status'] == 'success') return FoodApiResult(true, null, 'ok');
return FoodApiResult(false, null, _errMsg(res));
}
static Future<FoodApiResult<void>> rateOrder(int orderId, int rating, {String? comment}) async {
final res = await CRUD().post(
link: '$_base/order/rate.php',
payload: {
'order_id': orderId.toString(),
'rating': rating.toString(),
if (comment != null && comment.isNotEmpty) 'comment': comment,
},
);
if (res is Map && res['status'] == 'success') return FoodApiResult(true, null, 'ok');
return FoodApiResult(false, null, _errMsg(res));
}
static Future<FoodApiResult<List<FoodOrder>>> getHistory({int page = 1}) async {
final res = await CRUD().post(
link: '$_base/order/history.php',
payload: {'page': page.toString()},
);
if (res is Map && res['status'] == 'success') {
final msg = res['message'];
final list = (msg is Map && msg['orders'] is List)
? (msg['orders'] as List)
.map((o) => FoodOrder.fromJson(Map<String, dynamic>.from(o)))
.toList()
: <FoodOrder>[];
return FoodApiResult(true, list, 'ok');
}
return FoodApiResult(false, null, _errMsg(res));
}
static int? _errCode(dynamic res) {
if (res is Map && res['code'] != null) return int.tryParse(res['code'].toString());
return null;
}
static String _errMsg(dynamic res) {
if (res == 'no_internet') return 'تحقق من اتصالك بالإنترنت';
if (res == 'token_expired') return 'انتهت الجلسة، حاول مجدداً';
if (res is Map && res['message'] is String) return res['message'];
return 'حدث خطأ، حاول مجدداً';
}
}