favorite offers done

master
Sultan khan 2 weeks ago
parent 3a73ec1c2e
commit cd2703cbc5

@ -827,6 +827,9 @@
"distanceKm": "{} كم", "distanceKm": "{} كم",
"discountPercentPlus": "{}%+", "discountPercentPlus": "{}%+",
"visitMerchantWebsite": "زيارة موقع التاجر", "visitMerchantWebsite": "زيارة موقع التاجر",
"merchantWebsiteNotAvailable": "موقع التاجر غير متوفر" "merchantWebsiteNotAvailable": "موقع التاجر غير متوفر",
"favoriteAddedSuccess": "تمت إضافة التاجر إلى المفضلة بنجاح",
"favoriteRemovedSuccess": "تمت إزالة التاجر من المفضلة بنجاح",
"favoriteError": "حدث خطأ أثناء تحديث المفضلة"
} }

@ -827,6 +827,9 @@
"distanceKm": "{} km", "distanceKm": "{} km",
"discountPercentPlus": "{}%+", "discountPercentPlus": "{}%+",
"visitMerchantWebsite": "Visit Merchant Website", "visitMerchantWebsite": "Visit Merchant Website",
"merchantWebsiteNotAvailable": "Merchant website not available" "merchantWebsiteNotAvailable": "Merchant website not available",
"favoriteAddedSuccess": "Added to favorites successfully",
"favoriteRemovedSuccess": "Removed from favorites successfully",
"favoriteError": "An error occurred while updating favorites"
} }

@ -7,6 +7,7 @@ import 'package:geolocator/geolocator.dart';
import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/api/api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/get_categories_list.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_categories_list.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/wala_plus_category_model.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/wala_plus_category_model.dart';
@ -259,6 +260,7 @@ class OffersAndDiscountsApiClient {
BuildContext? context, BuildContext? context,
String? mobileNumber, String? mobileNumber,
String? query, String? query,
String? userReference,
}) async { }) async {
String url = ApiConsts.walaPlusRetailers; String url = ApiConsts.walaPlusRetailers;
String pUserName = _resolveUserName(); String pUserName = _resolveUserName();
@ -299,6 +301,13 @@ class OffersAndDiscountsApiClient {
} }
_cleanWalaPlusParams(postParams); _cleanWalaPlusParams(postParams);
// Pass WP_User_Reference: if filled then user ID, else null value
if (userReference != null && userReference.trim().isNotEmpty) {
postParams["WP_User_Reference"] = userReference.trim();
} else {
postParams["WP_User_Reference"] = null;
}
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(response) { (response) {
if (response != null) { if (response != null) {
@ -333,11 +342,17 @@ class OffersAndDiscountsApiClient {
); );
} }
Future<WalaPlusRetailerModel?> getWalaPlusRetailerById({required String retailerId, BuildContext? context, String? mobileNumber}) async { Future<WalaPlusRetailerModel?> getWalaPlusRetailerById({
required String retailerId,
BuildContext? context,
String? mobileNumber,
String? userReference,
}) async {
String url = ApiConsts.walaPlusRetailersByID; String url = ApiConsts.walaPlusRetailersByID;
String pUserName = _resolveUserName(); String pUserName = _resolveUserName();
String pMobileNumber = _resolveMobileNumber(overrideMobile: mobileNumber); String pMobileNumber = _resolveMobileNumber(overrideMobile: mobileNumber);
String pDepNationalId = _resolveDepNationalId(); String pDepNationalId = _resolveDepNationalId();
String pUserReference = _resolveUserReference(overrideUserReference: userReference);
Map<String, dynamic> postParams = _getBaseWalaPlusParams(); Map<String, dynamic> postParams = _getBaseWalaPlusParams();
postParams["WP_RetailerID"] = retailerId; postParams["WP_RetailerID"] = retailerId;
@ -352,6 +367,7 @@ class OffersAndDiscountsApiClient {
postParams["CompanyID"] = 1; postParams["CompanyID"] = 1;
if (context != null) { if (context != null) {
postParams["LanguageID"] = AppState().getLanguageID(context);
try { try {
Position? position = await _getCurrentPositionSilently(context); Position? position = await _getCurrentPositionSilently(context);
log("context position: $position"); log("context position: $position");
@ -366,7 +382,14 @@ class OffersAndDiscountsApiClient {
_cleanWalaPlusParams(postParams); _cleanWalaPlusParams(postParams);
debugPrint("getWalaPlusRetailerById: calling $url with WP_RetailerID: $retailerId"); // Pass WP_User_Reference: if filled then user ID, else null value
if (pUserReference.isNotEmpty) {
postParams["WP_User_Reference"] = pUserReference;
} else {
postParams["WP_User_Reference"] = null;
}
debugPrint("getWalaPlusRetailerById: calling $url with params: $postParams");
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(response) { (response) {
@ -396,6 +419,13 @@ class OffersAndDiscountsApiClient {
} else { } else {
model = WalaPlusRetailerModel.fromJson(map); model = WalaPlusRetailerModel.fromJson(map);
} }
if (model?.isFavorite == null) {
if (map.containsKey('isfavorite')) {
model?.isFavorite = map['isfavorite'] == true || map['isfavorite'] == 1 || map['isfavorite'] == 'true' || map['isfavorite'] == '1';
} else if (map.containsKey('is_favorite')) {
model?.isFavorite = map['is_favorite'] == true || map['is_favorite'] == 1 || map['is_favorite'] == 'true' || map['is_favorite'] == '1';
}
}
if ((model?.offers == null || model!.offers!.isEmpty) && (map.containsKey('offers') || map.containsKey('Offers'))) { if ((model?.offers == null || model!.offers!.isEmpty) && (map.containsKey('offers') || map.containsKey('Offers'))) {
model?.offers = WalaPlusRetailerModel.parseOffersList(map['offers'] ?? map['Offers']); model?.offers = WalaPlusRetailerModel.parseOffersList(map['offers'] ?? map['Offers']);
} }
@ -415,6 +445,13 @@ class OffersAndDiscountsApiClient {
if (model != null) { if (model != null) {
if (response is Map) { if (response is Map) {
if (model.isFavorite == null) {
if (response.containsKey('isfavorite')) {
model.isFavorite = response['isfavorite'] == true || response['isfavorite'] == 1 || response['isfavorite'] == 'true' || response['isfavorite'] == '1';
} else if (response.containsKey('is_favorite')) {
model.isFavorite = response['is_favorite'] == true || response['is_favorite'] == 1 || response['is_favorite'] == 'true' || response['is_favorite'] == '1';
}
}
if (model.website == null || model.website!.isEmpty || model.website == "null") { if (model.website == null || model.website!.isEmpty || model.website == "null") {
String? web = (response['website'] ?? response['merchant_website'] ?? response['website_url'] ?? response['url'] ?? response['merchant_url'])?.toString(); String? web = (response['website'] ?? response['merchant_website'] ?? response['website_url'] ?? response['url'] ?? response['merchant_url'])?.toString();
if (web != null && web.trim().isNotEmpty && web != "null") { if (web != null && web.trim().isNotEmpty && web != "null") {
@ -429,7 +466,7 @@ class OffersAndDiscountsApiClient {
model.locations = WalaPlusRetailerModel.parseLocationsList(response['locations'] ?? response['Locations'] ?? response['location'] ?? response['Location']); model.locations = WalaPlusRetailerModel.parseLocationsList(response['locations'] ?? response['Locations'] ?? response['location'] ?? response['Location']);
} }
} }
debugPrint("getWalaPlusRetailerById: parsed retailer '${model.name}', offers: ${model.offers?.length ?? 0}, locations: ${model.locations?.length ?? 0}"); debugPrint("getWalaPlusRetailerById: parsed retailer '${model.name}', isFavorite: ${model.isFavorite}, offers: ${model.offers?.length ?? 0}, locations: ${model.locations?.length ?? 0}");
return model; return model;
} }
} }
@ -440,6 +477,10 @@ class OffersAndDiscountsApiClient {
); );
} }
String resolveUserReference({String? overrideUserReference}) {
return _resolveUserReference(overrideUserReference: overrideUserReference);
}
String _resolveUserReference({String? overrideUserReference}) { String _resolveUserReference({String? overrideUserReference}) {
if (overrideUserReference != null && overrideUserReference.trim().isNotEmpty) { if (overrideUserReference != null && overrideUserReference.trim().isNotEmpty) {
return overrideUserReference.trim(); return overrideUserReference.trim();
@ -505,4 +546,134 @@ class OffersAndDiscountsApiClient {
postParams, postParams,
); );
} }
Future<GenericResponseModel?> addWalaPlusFavorite({
Object? retailerId,
List<String>? retailerIds,
BuildContext? context,
String? mobileNumber,
String? userReference,
}) async {
String url = ApiConsts.walaPlusFavoritesAdd;
String pUserName = _resolveUserName();
String pMobileNumber = _resolveMobileNumber(overrideMobile: mobileNumber);
String pUserReference = _resolveUserReference(overrideUserReference: userReference);
List<String> ids = [];
if (retailerIds != null && retailerIds.isNotEmpty) {
ids.addAll(retailerIds);
} else if (retailerId != null) {
if (retailerId is List) {
ids.addAll(retailerId.map((e) => e.toString()));
} else {
ids.add(retailerId.toString());
}
}
Map<String, dynamic> postParams = _getBaseWalaPlusParams();
postParams["P_USER_NAME"] = pUserName;
postParams["UserName"] = pUserName;
if (pMobileNumber.isNotEmpty) {
postParams["MobileNumber"] = pMobileNumber;
}
if (pUserReference.isNotEmpty) {
postParams["WP_User_Reference"] = pUserReference;
}
postParams["WP_Retailer_Ids"] = ids;
if (context != null) {
postParams["LanguageID"] = AppState().getLanguageID(context);
}
if (ApiConsts.isDependetLogin) {
String pDepNationalId = _resolveDepNationalId();
if (pDepNationalId.isNotEmpty) {
postParams["P_DEP_NATIONAL_ID"] = pDepNationalId;
}
postParams["MemberType"] = 2;
} else {
postParams["MemberType"] = 1;
}
_cleanWalaPlusParams(postParams);
debugPrint("addWalaPlusFavorite calling $url with params: $postParams");
return await ApiClient().postJsonForObject(
(response) {
if (response != null) {
debugPrint("addWalaPlusFavorite response: $response");
return GenericResponseModel.fromJson(response);
}
return null;
},
url,
postParams,
);
}
Future<GenericResponseModel?> removeWalaPlusFavorite({
Object? retailerId,
List<String>? retailerIds,
BuildContext? context,
String? mobileNumber,
String? userReference,
}) async {
String url = ApiConsts.walaPlusFavoritesRemove;
String pUserName = _resolveUserName();
String pMobileNumber = _resolveMobileNumber(overrideMobile: mobileNumber);
String pUserReference = _resolveUserReference(overrideUserReference: userReference);
List<String> ids = [];
if (retailerIds != null && retailerIds.isNotEmpty) {
ids.addAll(retailerIds);
} else if (retailerId != null) {
if (retailerId is List) {
ids.addAll(retailerId.map((e) => e.toString()));
} else {
ids.add(retailerId.toString());
}
}
Map<String, dynamic> postParams = _getBaseWalaPlusParams();
postParams["P_USER_NAME"] = pUserName;
postParams["UserName"] = pUserName;
if (pMobileNumber.isNotEmpty) {
postParams["MobileNumber"] = pMobileNumber;
}
if (pUserReference.isNotEmpty) {
postParams["WP_User_Reference"] = pUserReference;
}
postParams["WP_Retailer_Ids"] = ids;
if (context != null) {
postParams["LanguageID"] = AppState().getLanguageID(context);
}
if (ApiConsts.isDependetLogin) {
String pDepNationalId = _resolveDepNationalId();
if (pDepNationalId.isNotEmpty) {
postParams["P_DEP_NATIONAL_ID"] = pDepNationalId;
}
postParams["MemberType"] = 2;
} else {
postParams["MemberType"] = 1;
}
_cleanWalaPlusParams(postParams);
debugPrint("removeWalaPlusFavorite calling $url with params: $postParams");
return await ApiClient().postJsonForObject(
(response) {
if (response != null) {
debugPrint("removeWalaPlusFavorite response: $response");
return GenericResponseModel.fromJson(response);
}
return null;
},
url,
postParams,
);
}
} }

@ -45,6 +45,8 @@ class ApiConsts {
static String walaPlusRetailers = erpRest + "WalaPlus_Retailers"; static String walaPlusRetailers = erpRest + "WalaPlus_Retailers";
static String walaPlusRetailersByID = erpRest + "WalaPlus_RetailersByID"; static String walaPlusRetailersByID = erpRest + "WalaPlus_RetailersByID";
static String walaPlusOfferRedeem = erpRest + "WalaPlus_OfferRedeem"; static String walaPlusOfferRedeem = erpRest + "WalaPlus_OfferRedeem";
static String walaPlusFavoritesAdd = erpRest + "WalaPlus_FavoritesAdd";
static String walaPlusFavoritesRemove = erpRest + "WalaPlus_FavoritesRemove";
static String processContactMazayaAccess = erpRest + "PROCESS_CONTACT_MAZAYA_ACCESS"; static String processContactMazayaAccess = erpRest + "PROCESS_CONTACT_MAZAYA_ACCESS";
static String ssoAuthRedirection = ssoBaseUrl + "/api/auth/connect"; static String ssoAuthRedirection = ssoBaseUrl + "/api/auth/connect";

@ -812,4 +812,7 @@ abstract class LocaleKeys {
static const discountPercentPlus = 'discountPercentPlus'; static const discountPercentPlus = 'discountPercentPlus';
static const visitMerchantWebsite = 'visitMerchantWebsite'; static const visitMerchantWebsite = 'visitMerchantWebsite';
static const merchantWebsiteNotAvailable = 'merchantWebsiteNotAvailable'; static const merchantWebsiteNotAvailable = 'merchantWebsiteNotAvailable';
static const favoriteAddedSuccess = 'favoriteAddedSuccess';
static const favoriteRemovedSuccess = 'favoriteRemovedSuccess';
static const favoriteError = 'favoriteError';
} }

@ -404,6 +404,7 @@ class GenericResponseModel {
GetWalaplusDepInfoModel? getWalaplusDepInfoModel; GetWalaplusDepInfoModel? getWalaplusDepInfoModel;
dynamic getWalaplusDepInfoModelInternal; dynamic getWalaplusDepInfoModelInternal;
List<WalaPlusCategoryModel>? walaPlusCategories; List<WalaPlusCategoryModel>? walaPlusCategories;
String? wpFavoritesAddRemoveMessage;
String? businessCardQROutside; String? businessCardQROutside;
EmpBusinessCardInfoModel? empBusinessCardInfoModel; EmpBusinessCardInfoModel? empBusinessCardInfoModel;
@ -683,6 +684,7 @@ class GenericResponseModel {
this.getWalaplusDepInfoModel, this.getWalaplusDepInfoModel,
this.getWalaplusDepInfoModelInternal, this.getWalaplusDepInfoModelInternal,
this.walaPlusCategories, this.walaPlusCategories,
this.wpFavoritesAddRemoveMessage,
this.businessCardQROutside, this.businessCardQROutside,
this.empBusinessCardInfoModel, this.empBusinessCardInfoModel,
this.isEmpLastLoginToDevice this.isEmpLastLoginToDevice
@ -1493,6 +1495,7 @@ class GenericResponseModel {
walaPlusCategories!.add(WalaPlusCategoryModel.fromJson(v)); walaPlusCategories!.add(WalaPlusCategoryModel.fromJson(v));
}); });
} }
wpFavoritesAddRemoveMessage = json['WP_Favorites_AddRemove_Message'] ?? json['wp_Favorites_AddRemove_Message'];
isEmpLastLoginToDevice = json["IsEmpLastLoginToDevice"]; isEmpLastLoginToDevice = json["IsEmpLastLoginToDevice"];
} }
@ -1994,6 +1997,9 @@ class GenericResponseModel {
if (walaPlusCategories != null) { if (walaPlusCategories != null) {
data['WalaPlus_Categories'] = walaPlusCategories!.map((WalaPlusCategoryModel v) => v.toJson()).toList(); data['WalaPlus_Categories'] = walaPlusCategories!.map((WalaPlusCategoryModel v) => v.toJson()).toList();
} }
if (this.wpFavoritesAddRemoveMessage != null) {
data['WP_Favorites_AddRemove_Message'] = this.wpFavoritesAddRemoveMessage;
}
data["IsEmpLastLoginToDevice"] = this.isEmpLastLoginToDevice; data["IsEmpLastLoginToDevice"] = this.isEmpLastLoginToDevice;
return data; return data;
} }

@ -1,5 +1,4 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/wala_plus_category_model.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/wala_plus_category_model.dart';
@ -81,6 +80,10 @@ class WalaPlusRetailersByIDResponse {
if ((model.website == null || model.website!.isEmpty || model.website == "null") && (json['website'] != null || json['merchant_website'] != null || json['url'] != null)) { if ((model.website == null || model.website!.isEmpty || model.website == "null") && (json['website'] != null || json['merchant_website'] != null || json['url'] != null)) {
model.website = (json['website'] ?? json['merchant_website'] ?? json['url'])?.toString(); model.website = (json['website'] ?? json['merchant_website'] ?? json['url'])?.toString();
} }
if (model.isFavorite == null && (json.containsKey('isfavorite') || json.containsKey('is_favorite'))) {
var favVal = json['isfavorite'] ?? json['is_favorite'];
model.isFavorite = favVal == true || favVal == 1 || favVal == 'true' || favVal == '1';
}
retList.add(model); retList.add(model);
} else if (r is Map) { } else if (r is Map) {
var model = WalaPlusRetailerModel.fromJson(Map<String, dynamic>.from(r)); var model = WalaPlusRetailerModel.fromJson(Map<String, dynamic>.from(r));
@ -89,6 +92,10 @@ class WalaPlusRetailersByIDResponse {
if ((model.website == null || model.website!.isEmpty || model.website == "null") && (json['website'] != null || json['merchant_website'] != null || json['url'] != null)) { if ((model.website == null || model.website!.isEmpty || model.website == "null") && (json['website'] != null || json['merchant_website'] != null || json['url'] != null)) {
model.website = (json['website'] ?? json['merchant_website'] ?? json['url'])?.toString(); model.website = (json['website'] ?? json['merchant_website'] ?? json['url'])?.toString();
} }
if (model.isFavorite == null && (json.containsKey('isfavorite') || json.containsKey('is_favorite'))) {
var favVal = json['isfavorite'] ?? json['is_favorite'];
model.isFavorite = favVal == true || favVal == 1 || favVal == 'true' || favVal == '1';
}
retList.add(model); retList.add(model);
} }
} }
@ -99,6 +106,10 @@ class WalaPlusRetailersByIDResponse {
if ((model.website == null || model.website!.isEmpty || model.website == "null") && (json['website'] != null || json['merchant_website'] != null || json['url'] != null)) { if ((model.website == null || model.website!.isEmpty || model.website == "null") && (json['website'] != null || json['merchant_website'] != null || json['url'] != null)) {
model.website = (json['website'] ?? json['merchant_website'] ?? json['url'])?.toString(); model.website = (json['website'] ?? json['merchant_website'] ?? json['url'])?.toString();
} }
if (model.isFavorite == null && (json.containsKey('isfavorite') || json.containsKey('is_favorite'))) {
var favVal = json['isfavorite'] ?? json['is_favorite'];
model.isFavorite = favVal == true || favVal == 1 || favVal == 'true' || favVal == '1';
}
retList.add(model); retList.add(model);
} }
@ -358,6 +369,29 @@ class WalaPlusRetailerModel {
} }
} }
bool? parsedIsFavorite;
if (targetJson.containsKey('isfavorite')) {
parsedIsFavorite = targetJson['isfavorite'] == true ||
targetJson['isfavorite'] == 1 ||
targetJson['isfavorite'] == 'true' ||
targetJson['isfavorite'] == '1';
} else if (targetJson.containsKey('is_favorite')) {
parsedIsFavorite = targetJson['is_favorite'] == true ||
targetJson['is_favorite'] == 1 ||
targetJson['is_favorite'] == 'true' ||
targetJson['is_favorite'] == '1';
} else if (targetJson.containsKey('isFavorite')) {
parsedIsFavorite = targetJson['isFavorite'] == true ||
targetJson['isFavorite'] == 1 ||
targetJson['isFavorite'] == 'true' ||
targetJson['isFavorite'] == '1';
} else if (targetJson.containsKey('favorite')) {
parsedIsFavorite = targetJson['favorite'] == true ||
targetJson['favorite'] == 1 ||
targetJson['favorite'] == 'true' ||
targetJson['favorite'] == '1';
}
return WalaPlusRetailerModel( return WalaPlusRetailerModel(
id: id:
targetJson['id']?.toString() ?? targetJson['id']?.toString() ??
@ -375,11 +409,7 @@ class WalaPlusRetailerModel {
logo: targetJson['logo']?.toString(), logo: targetJson['logo']?.toString(),
logoThumb: targetJson['logo_thumb']?.toString(), logoThumb: targetJson['logo_thumb']?.toString(),
website: foundWebsite, website: foundWebsite,
isFavorite: targetJson['is_favorite'] == true || isFavorite: parsedIsFavorite,
targetJson['is_favorite'] == 1 ||
targetJson['is_favorite'] == 'true' ||
targetJson['isFavorite'] == true ||
targetJson['favorite'] == true,
type: targetJson['type']?.toString(), type: targetJson['type']?.toString(),
usage: targetJson['usage'] is String ? decodeUnicodeString(targetJson['usage']) : targetJson['usage'], usage: targetJson['usage'] is String ? decodeUnicodeString(targetJson['usage']) : targetJson['usage'],
weight: targetJson['weight'], weight: targetJson['weight'],
@ -488,6 +518,7 @@ class WalaPlusRetailerModel {
data['country_name_ar'] = countryNameAr; data['country_name_ar'] = countryNameAr;
data['country_name_en'] = countryNameEn; data['country_name_en'] = countryNameEn;
data['is_favorite'] = isFavorite; data['is_favorite'] = isFavorite;
data['isfavorite'] = isFavorite;
if (offers != null) { if (offers != null) {
data['offers'] = offers!.map((v) => v.toJson()).toList(); data['offers'] = offers!.map((v) => v.toJson()).toList();
} }

@ -52,6 +52,7 @@ class _DashboardScreenForDependetState extends State<DashboardScreenForDependet>
String _filterDistance = '5km'; String _filterDistance = '5km';
String _filterMinDiscount = 'any'; String _filterMinDiscount = 'any';
bool isNearestOffers = true; bool isNearestOffers = true;
bool isFavoriteOnly = false;
bool isLoading = true; bool isLoading = true;
bool isLoadingMore = false; bool isLoadingMore = false;
bool isCategoriesLoading = true; bool isCategoriesLoading = true;
@ -150,6 +151,14 @@ class _DashboardScreenForDependetState extends State<DashboardScreenForDependet>
return name.replaceAll(RegExp(r'\s*-\s*'), ' ').replaceAll(RegExp(r'\s+'), ' ').trim(); return name.replaceAll(RegExp(r'\s*-\s*'), ' ').replaceAll(RegExp(r'\s+'), ' ').trim();
} }
String? _getUserReferenceForFavorites() {
String ref = OffersAndDiscountsApiClient().resolveUserReference();
if (ref.trim().isNotEmpty) return ref.trim();
String? userName = AppState().getUserName;
if (userName != null && userName.trim().isNotEmpty) return userName.trim();
return null;
}
@override @override
void dispose() { void dispose() {
_debounceTimer?.cancel(); _debounceTimer?.cancel();
@ -294,7 +303,8 @@ class _DashboardScreenForDependetState extends State<DashboardScreenForDependet>
String catParam = (targetCategoryId == "all" || targetCategoryId == "0") ? "" : targetCategoryId; String catParam = (targetCategoryId == "all" || targetCategoryId == "0") ? "" : targetCategoryId;
String? offerTypeParam = OffersAndDiscountsApiClient.mapOfferTypeFilter(selectedTypeFilter); String? offerTypeParam = OffersAndDiscountsApiClient.mapOfferTypeFilter(selectedTypeFilter);
String? queryParam = searchQuery.trim().isNotEmpty ? searchQuery.trim() : null; String? queryParam = searchQuery.trim().isNotEmpty ? searchQuery.trim() : null;
print("Fetching WalaPlus retailers: category='$catParam', offerType='$offerTypeParam', query='$queryParam', page=1, per_page=$pageSize"); String? userRef = isFavoriteOnly ? _getUserReferenceForFavorites() : null;
print("Fetching WalaPlus retailers: category='$catParam', offerType='$offerTypeParam', query='$queryParam', userReference='$userRef', page=1, per_page=$pageSize");
WalaPlusRetailersResponse? response = await OffersAndDiscountsApiClient().getWalaPlusRetailers( WalaPlusRetailersResponse? response = await OffersAndDiscountsApiClient().getWalaPlusRetailers(
categoryId: catParam, categoryId: catParam,
page: 1, page: 1,
@ -302,9 +312,15 @@ class _DashboardScreenForDependetState extends State<DashboardScreenForDependet>
offerType: offerTypeParam, offerType: offerTypeParam,
query: queryParam, query: queryParam,
context: isNearestOffers ? context : null, context: isNearestOffers ? context : null,
userReference: userRef,
); );
retailersList = response?.retailers ?? <WalaPlusRetailerModel>[]; retailersList = response?.retailers ?? <WalaPlusRetailerModel>[];
if (isFavoriteOnly) {
for (var r in retailersList) {
r.isFavorite = true;
}
}
_filteredRetailersList = retailersList; _filteredRetailersList = retailersList;
currentPage = 1; currentPage = 1;
totalPages = response?.pagesCount ?? 1; totalPages = response?.pagesCount ?? 1;
@ -335,8 +351,9 @@ class _DashboardScreenForDependetState extends State<DashboardScreenForDependet>
String catParam = (currentCategoryId == "all" || currentCategoryId == "0") ? "" : currentCategoryId; String catParam = (currentCategoryId == "all" || currentCategoryId == "0") ? "" : currentCategoryId;
String? offerTypeParam = OffersAndDiscountsApiClient.mapOfferTypeFilter(selectedTypeFilter); String? offerTypeParam = OffersAndDiscountsApiClient.mapOfferTypeFilter(selectedTypeFilter);
String? queryParam = searchQuery.trim().isNotEmpty ? searchQuery.trim() : null; String? queryParam = searchQuery.trim().isNotEmpty ? searchQuery.trim() : null;
String? userRef = isFavoriteOnly ? _getUserReferenceForFavorites() : null;
print("Fetching WalaPlus retailers next page: $nextPage of $totalPages, category: '$catParam', offerType: '$offerTypeParam', query: '$queryParam'"); print("Fetching WalaPlus retailers next page: $nextPage of $totalPages, category: '$catParam', offerType: '$offerTypeParam', query: '$queryParam', userReference='$userRef'");
WalaPlusRetailersResponse? response = await OffersAndDiscountsApiClient().getWalaPlusRetailers( WalaPlusRetailersResponse? response = await OffersAndDiscountsApiClient().getWalaPlusRetailers(
categoryId: catParam, categoryId: catParam,
@ -345,10 +362,16 @@ class _DashboardScreenForDependetState extends State<DashboardScreenForDependet>
offerType: offerTypeParam, offerType: offerTypeParam,
query: queryParam, query: queryParam,
context: isNearestOffers ? context : null, context: isNearestOffers ? context : null,
userReference: userRef,
); );
List<WalaPlusRetailerModel> newRetailers = response?.retailers ?? []; List<WalaPlusRetailerModel> newRetailers = response?.retailers ?? [];
if (newRetailers.isNotEmpty) { if (newRetailers.isNotEmpty) {
if (isFavoriteOnly) {
for (var r in newRetailers) {
r.isFavorite = true;
}
}
currentPage = nextPage; currentPage = nextPage;
totalPages = response?.pagesCount ?? totalPages; totalPages = response?.pagesCount ?? totalPages;
hasMore = currentPage < totalPages; hasMore = currentPage < totalPages;
@ -385,8 +408,15 @@ class _DashboardScreenForDependetState extends State<DashboardScreenForDependet>
} }
} }
void _openRetailer(WalaPlusRetailerModel item) { void _openRetailer(WalaPlusRetailerModel item) async {
Navigator.pushNamed(context, AppRoutes.walaPlusRetailerDetails, arguments: item); await Navigator.pushNamed(context, AppRoutes.walaPlusRetailerDetails, arguments: item);
if (mounted) {
if (isFavoriteOnly) {
fetchOffers(categoryId: currentCategoryId.isEmpty ? "all" : currentCategoryId);
} else {
setState(() {});
}
}
} }
Future<void> _saveDependentSessionToPrefs() async { Future<void> _saveDependentSessionToPrefs() async {
@ -577,11 +607,18 @@ class _DashboardScreenForDependetState extends State<DashboardScreenForDependet>
child: InkWell( child: InkWell(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
onTap: () { onTap: () {
// Favorite setState(() {
isFavoriteOnly = !isFavoriteOnly;
});
fetchOffers(categoryId: currentCategoryId.isEmpty ? "all" : currentCategoryId);
}, },
child: const Padding( child: Padding(
padding: EdgeInsets.all(3), padding: const EdgeInsets.all(3),
child: Icon(Icons.favorite_border_rounded, size: 24, color: Color(0xFF1E293B)), child: Icon(
isFavoriteOnly ? Icons.favorite_rounded : Icons.favorite_border_rounded,
size: 24,
color: isFavoriteOnly ? const Color(0xFFE11D48) : const Color(0xFF1E293B),
),
), ),
), ),
), ),

@ -5,16 +5,19 @@ import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/api/api_client.dart';
import 'package:mohem_flutter_app/api/offers_and_discounts_api_client.dart'; import 'package:mohem_flutter_app/api/offers_and_discounts_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/exceptions/api_exception.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/wala_plus_retailer_model.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/wala_plus_retailer_model.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/app_in_app_webview_screen.dart'; import 'package:mohem_flutter_app/widgets/app_in_app_webview_screen.dart';
@ -28,8 +31,9 @@ import 'package:url_launcher/url_launcher.dart';
class WalaPlusRetailerDetailsScreen extends StatefulWidget { class WalaPlusRetailerDetailsScreen extends StatefulWidget {
final WalaPlusRetailerModel? retailer; final WalaPlusRetailerModel? retailer;
final String? retailerId; final String? retailerId;
final String? userReference;
const WalaPlusRetailerDetailsScreen({Key? key, this.retailer, this.retailerId}) : super(key: key); const WalaPlusRetailerDetailsScreen({Key? key, this.retailer, this.retailerId, this.userReference}) : super(key: key);
@override @override
State<WalaPlusRetailerDetailsScreen> createState() => _WalaPlusRetailerDetailsScreenState(); State<WalaPlusRetailerDetailsScreen> createState() => _WalaPlusRetailerDetailsScreenState();
@ -40,15 +44,18 @@ class _WalaPlusRetailerDetailsScreenState extends State<WalaPlusRetailerDetailsS
bool _isLoading = true; bool _isLoading = true;
bool _hasDetailsData = false; bool _hasDetailsData = false;
String? _effectiveRetailerId; String? _effectiveRetailerId;
String? _effectiveUserReference;
bool _hasFetched = false; bool _hasFetched = false;
bool _isRedeeming = false; bool _isRedeeming = false;
bool _isFavorite = false; bool _isFavorite = false;
bool _isTogglingFavorite = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_retailer = widget.retailer; _retailer = widget.retailer;
_effectiveRetailerId = widget.retailerId ?? widget.retailer?.id; _effectiveRetailerId = widget.retailerId ?? widget.retailer?.id;
_effectiveUserReference = widget.userReference;
_isFavorite = widget.retailer?.isFavorite ?? false; _isFavorite = widget.retailer?.isFavorite ?? false;
} }
@ -63,6 +70,24 @@ class _WalaPlusRetailerDetailsScreenState extends State<WalaPlusRetailerDetailsS
_isFavorite = args.isFavorite ?? _isFavorite; _isFavorite = args.isFavorite ?? _isFavorite;
} else if (args is String) { } else if (args is String) {
_effectiveRetailerId = args; _effectiveRetailerId = args;
} else if (args is Map) {
if (args['retailer'] is WalaPlusRetailerModel) {
_retailer ??= args['retailer'];
_effectiveRetailerId = _retailer?.id;
_isFavorite = _retailer?.isFavorite ?? _isFavorite;
} else if (args['retailerId'] != null) {
_effectiveRetailerId = args['retailerId']?.toString();
}
if (args['userReference'] != null) {
_effectiveUserReference = args['userReference']?.toString();
}
}
}
if (_effectiveUserReference == null || _effectiveUserReference!.isEmpty) {
String resolved = OffersAndDiscountsApiClient().resolveUserReference();
if (resolved.isNotEmpty) {
_effectiveUserReference = resolved;
} }
} }
@ -87,7 +112,11 @@ class _WalaPlusRetailerDetailsScreenState extends State<WalaPlusRetailerDetailsS
try { try {
debugPrint("WalaPlusRetailerDetailsScreen: fetching details for retailer ID: $_effectiveRetailerId"); debugPrint("WalaPlusRetailerDetailsScreen: fetching details for retailer ID: $_effectiveRetailerId");
WalaPlusRetailerModel? result = await OffersAndDiscountsApiClient().getWalaPlusRetailerById(retailerId: _effectiveRetailerId!, context: context); WalaPlusRetailerModel? result = await OffersAndDiscountsApiClient().getWalaPlusRetailerById(
retailerId: _effectiveRetailerId!,
context: context,
userReference: _effectiveUserReference,
);
if (result != null && mounted) { if (result != null && mounted) {
if ((result.image == null || result.image!.isEmpty || result.image == "null") && _retailer?.image != null) { if ((result.image == null || result.image!.isEmpty || result.image == "null") && _retailer?.image != null) {
result.image = _retailer!.image; result.image = _retailer!.image;
@ -139,6 +168,7 @@ class _WalaPlusRetailerDetailsScreenState extends State<WalaPlusRetailerDetailsS
_retailer = result; _retailer = result;
_hasDetailsData = true; _hasDetailsData = true;
_isFavorite = result.isFavorite ?? _isFavorite; _isFavorite = result.isFavorite ?? _isFavorite;
_retailer?.isFavorite = _isFavorite;
}); });
} }
} catch (e) { } catch (e) {
@ -184,6 +214,78 @@ class _WalaPlusRetailerDetailsScreenState extends State<WalaPlusRetailerDetailsS
} }
} }
Future<void> _toggleFavorite() async {
if (_isTogglingFavorite) return;
String retailerId = _retailer?.id ?? _effectiveRetailerId ?? "";
if (retailerId.isEmpty) {
return;
}
setState(() {
_isTogglingFavorite = true;
});
Utils.showLoading(context);
try {
bool targetFavorite = !_isFavorite;
GenericResponseModel? response;
if (targetFavorite) {
response = await OffersAndDiscountsApiClient().addWalaPlusFavorite(
retailerId: retailerId,
context: context,
userReference: _effectiveUserReference,
);
} else {
response = await OffersAndDiscountsApiClient().removeWalaPlusFavorite(
retailerId: retailerId,
context: context,
userReference: _effectiveUserReference,
);
}
Utils.hideLoading(context);
if (response != null && response.errorMessage == null) {
if (mounted) {
setState(() {
_isFavorite = targetFavorite;
_retailer?.isFavorite = targetFavorite;
});
}
bool isAr = Directionality.of(context) == ui.TextDirection.rtl || AppState().isArabic(context);
String? msg;
if (isAr) {
msg = targetFavorite ? LocaleKeys.favoriteAddedSuccess.tr() : LocaleKeys.favoriteRemovedSuccess.tr();
} else {
msg = response.wpFavoritesAddRemoveMessage;
if (msg == null || msg.trim().isEmpty) {
msg = targetFavorite ? LocaleKeys.favoriteAddedSuccess.tr() : LocaleKeys.favoriteRemovedSuccess.tr();
}
}
Utils.showToast(msg);
} else {
String error = response?.errorEndUserMessage ?? response?.errorMessage ?? LocaleKeys.favoriteError.tr();
Utils.showToast(error);
}
} catch (e) {
Utils.hideLoading(context);
debugPrint("Error toggling favorite: $e");
String errorMsg = LocaleKeys.favoriteError.tr();
if (e is APIException && e.error?.errorMessage != null && e.error!.errorMessage!.isNotEmpty) {
errorMsg = e.error!.errorMessage!;
}
Utils.showToast(errorMsg);
} finally {
if (mounted) {
setState(() {
_isTogglingFavorite = false;
});
} else {
_isTogglingFavorite = false;
}
}
}
Future<void> _openInAppBrowser(String url, {String? offerType}) async { Future<void> _openInAppBrowser(String url, {String? offerType}) async {
String title = _retailer?.name ?? LocaleKeys.offerDetails.tr(); String title = _retailer?.name ?? LocaleKeys.offerDetails.tr();
// Offer types seen so far: "promo", "discount", "unique_promo", "promo_unique_qr" (and // Offer types seen so far: "promo", "discount", "unique_promo", "promo_unique_qr" (and
@ -588,12 +690,7 @@ class _WalaPlusRetailerDetailsScreenState extends State<WalaPlusRetailerDetailsS
color: _isFavorite ? const Color(0xFFE11D48) : const Color(0xFF1E293B), color: _isFavorite ? const Color(0xFFE11D48) : const Color(0xFF1E293B),
), ),
tooltip: LocaleKeys.favorite.tr(), tooltip: LocaleKeys.favorite.tr(),
onPressed: () { onPressed: _isTogglingFavorite ? null : _toggleFavorite,
setState(() {
_isFavorite = !_isFavorite;
_retailer?.isFavorite = _isFavorite;
});
},
), ),
), ),
], ],

Loading…
Cancel
Save