Update: 2026-08-02 17:52:28
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
// 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 'حدث خطأ، حاول مجدداً';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user