From 3e4f97a4c1a25944f4c943deec29583bce51395d Mon Sep 17 00:00:00 2001 From: FaizHashmi Date: Mon, 12 Oct 2026 10:50:05 +0300 Subject: [PATCH 1/3] Added business card API --- lib/api/profile_api_client.dart | 504 ++++++++++-------- lib/classes/consts.dart | 2 + lib/models/generic_response_model.dart | 61 ++- lib/ui/dialogs/id/business_card_dialog.dart | 20 +- .../dashboard_screen_for_dependet.dart | 5 +- .../wala_plus_retailer_details_screen.dart | 2 +- lib/ui/landing/widget/app_drawer.dart | 20 +- lib/ui/login/verify_last_login_screen.dart | 153 +++--- 8 files changed, 441 insertions(+), 326 deletions(-) diff --git a/lib/api/profile_api_client.dart b/lib/api/profile_api_client.dart index c9d5794..ef2c189 100644 --- a/lib/api/profile_api_client.dart +++ b/lib/api/profile_api_client.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:io'; import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; @@ -35,99 +36,140 @@ class ProfileApiClient { factory ProfileApiClient() => _instance; - Future> getEmployeeContacts() async { - String url = "${ApiConsts.erpRest}GET_EMPLOYEE_CONTACTS"; + // GET_EMP_BUSINESS_CARD_INFO requires the literal TokenID below to validate the call - + // it is not the usual session TokenID, so we don't merge AppState().postParamsJson here. + Future getEmployeeBusinessCardInfo() async { + String url = "${ApiConsts.erpRest}GET_EMP_BUSINESS_CARD_INFO"; + String deviceToken = AppState().getIsHuawei ? AppState().getHuaweiPushToken : (AppState().getDeviceToken ?? ""); Map postParams = { - "P_MENU_TYPE": "E", - "P_SELECTED_RESP_ID": -999, + "VersionID": AppState().postParamsObject?.versionID, + "Channel": AppState().postParamsObject?.channel, + "LanguageID": AppState().postParamsObject?.languageID, + "TokenID": "GET_EMP_BUSINESS_CARD_INFO", + "P_USER_NAME": AppState().getUserName ?? AppState().postParamsObject?.userName ?? AppState().postParamsObject?.pUserName, + "DeviceToken": deviceToken, + "DeviceType": Platform.isAndroid ? "android" : "ios", }; + print(jsonEncode(postParams)); + return await ApiClient().postJsonForObject( + (json) { + return GenericResponseModel.fromJson(json); + }, + url, + postParams, + ); + } + + Future> getEmployeeContacts() async { + String url = "${ApiConsts.erpRest}GET_EMPLOYEE_CONTACTS"; + Map postParams = {"P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getEmployeeContactsList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getEmployeeContactsList ?? []; + }, + url, + postParams, + ); } Future> getEmployeeBasicDetails() async { String url = "${ApiConsts.erpRest}GET_EMPLOYEE_BASIC_DETAILS"; - Map postParams = { - "P_MENU_TYPE": "E", - "P_SELECTED_RESP_ID": -999, - }; + Map postParams = {"P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getEmployeeBasicDetailsList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getEmployeeBasicDetailsList ?? []; + }, + url, + postParams, + ); } Future> getEmployeePhones() async { String url = "${ApiConsts.erpRest}GET_EMPLOYEE_PHONES"; - Map postParams = { - "P_MENU_TYPE": "E", - "P_SELECTED_RESP_ID": -999, - }; + Map postParams = {"P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getEmployeePhonesList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getEmployeePhonesList ?? []; + }, + url, + postParams, + ); } Future> getEmployeeAddress() async { String url = "${ApiConsts.erpRest}GET_EMPLOYEE_ADDRESS"; - Map postParams = { - "P_MENU_TYPE": "E", - "P_SELECTED_RESP_ID": -999, - }; + Map postParams = {"P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getEmployeeAddressList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getEmployeeAddressList ?? []; + }, + url, + postParams, + ); } Future> getEmployeeDocuments() async { String url = "${ApiConsts.erpRest}GET_EMPLOYEE_DOCUMENTS"; - Map postParams = { - "P_MENU_TYPE": "E", - "P_SELECTED_RESP_ID": -999, - }; + Map postParams = {"P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.employeeDocumentsList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.employeeDocumentsList ?? []; + }, + url, + postParams, + ); } Future updateEmpImage(img) async { String url = "${ApiConsts.erpRest}UPDATE_EMPLOYEE_IMAGE"; Map postParams = {"P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999, "P_IMAGE": img}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - // GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return json['UpdateEmployeeImageList']; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + // GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return json['UpdateEmployeeImageList']; + }, + url, + postParams, + ); } Future getDffStructure(String pFunctionName, String uRL, String requestType) async { String url = ApiConsts.erpRest + uRL; Map postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E", "P_REQUEST_TYPE": pFunctionName, "P_FUNCTION_NAME": pFunctionName, "P_COUNTRY_CODE": "SA"}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future getColStructure(String pFunctionName, String uRL, String requestType) async { String url = ApiConsts.erpRest + uRL; Map postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E", "P_FUNCTION_NAME": pFunctionName, "P_REQUEST_TYPE": requestType}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future getValueSetValues(String pSegmentName, String pDescFlexContextCode, String pDescFlexName, List> list) async { @@ -144,41 +186,38 @@ class ProfileApiClient { "GetValueSetValuesTBL": list, }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getValueSetValuesList!.first; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getValueSetValuesList!.first; + }, + url, + postParams, + ); } Future> getPhoneNumberTypes() async { String url = "${ApiConsts.erpRest}GET_OBJECT_VALUES"; Map postParams = {"P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999, "P_OBJECT_NAME": "PHONE_TYPE", "P_OBJECT_TYPE": "LOOKUP"}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getObjectValuesList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getObjectValuesList ?? []; + }, + url, + postParams, + ); } - Future submetConatctTransaction( - String pFunctionName, - String actionType, - int contactRelationId, - String date, - ) async { + Future submetConatctTransaction(String pFunctionName, String actionType, int contactRelationId, String date) async { String url = "${ApiConsts.erpRest}SUBMIT_CONTACT_TRANSACTION"; Map postParams = { "P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999, "P_FUNCTION_NAME": pFunctionName, "EITTransactionTBL": [ - { - "TRANSACTION_NUMBER": 1, - "NAME": "DATE_END", - "VARCHAR2_VALUE": null, - "NUMBER_VALUE": null, - "DATE_VALUE": date, - } + {"TRANSACTION_NUMBER": 1, "NAME": "DATE_END", "VARCHAR2_VALUE": null, "NUMBER_VALUE": null, "DATE_VALUE": date}, ], "P_CONTACT_RELATIONSHIP_ID": contactRelationId, "P_ACTION": actionType, @@ -186,28 +225,29 @@ class ProfileApiClient { "LegislationCodeStr": "SA", }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.submitContactTransactionList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.submitContactTransactionList; + }, + url, + postParams, + ); } Future getApproves(String action, String comments, int transactionId, String itemKey) async { String url = "${ApiConsts.erpRest}GET_APPROVERS_LIST"; - Map postParams = { - "P_AME_TRANSACTION_TYPE": "SSHRMS", - "P_PAGE_LIMIT": 1000, - "P_PAGE_NUM": 1, - "P_TRANSACTION_ID": transactionId, - "P_ACTION_MODE": action, - "P_COMMENTS": comments, - }; + Map postParams = {"P_AME_TRANSACTION_TYPE": "SSHRMS", "P_PAGE_LIMIT": 1000, "P_PAGE_NUM": 1, "P_TRANSACTION_ID": transactionId, "P_ACTION_MODE": action, "P_COMMENTS": comments}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - // return responseData.getApprovesList; - return (responseData.getApprovesList?.length ?? 0) > 0 ? responseData.getApprovesList!.first : null; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + // return responseData.getApprovesList; + return (responseData.getApprovesList?.length ?? 0) > 0 ? responseData.getApprovesList!.first : null; + }, + url, + postParams, + ); } Future submitPhoneNumbers(List empList) async { @@ -216,50 +256,49 @@ class ProfileApiClient { "P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999, "P_FUNCTION_NAME": "HR_PERINFO_SS", - "P_MBL_PHONES_TBL": empList.map((element) { - return element.toJson(); - }).toList() + "P_MBL_PHONES_TBL": + empList.map((element) { + return element.toJson(); + }).toList(), }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return SubmitPhonesTransactionList.fromJson(responseData.submitPhonesTransactionList ?? {}); - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return SubmitPhonesTransactionList.fromJson(responseData.submitPhonesTransactionList ?? {}); + }, + url, + postParams, + ); } Future startPhoneApprovalProcess(String action, String comments, String itemKey, int transactionId) async { String url = "${ApiConsts.erpRest}START_PHONES_APPROVAL_PROCESS"; - Map postParams = { - "P_SELECTED_RESP_ID": -999, - "P_MENU_TYPE": "E", - "P_ACTION_MODE": action, - "P_COMMENTS": comments, - "P_ITEM_KEY": itemKey, - "P_TRANSACTION_ID": transactionId, - }; + Map postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E", "P_ACTION_MODE": action, "P_COMMENTS": comments, "P_ITEM_KEY": itemKey, "P_TRANSACTION_ID": transactionId}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.startPhonesApprovalProcessList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.startPhonesApprovalProcessList; + }, + url, + postParams, + ); } Future startAddressApprovalProcess(String action, String comments, String itemKey, int transactionId) async { String url = "${ApiConsts.erpRest}START_ADDRESS_APPROVAL_PROCESS"; - Map postParams = { - "P_SELECTED_RESP_ID": -999, - "P_MENU_TYPE": "E", - "P_ACTION_MODE": action, - "P_COMMENTS": comments, - "P_ITEM_KEY": itemKey, - "P_TRANSACTION_ID": transactionId, - }; + Map postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E", "P_ACTION_MODE": action, "P_COMMENTS": comments, "P_ITEM_KEY": itemKey, "P_TRANSACTION_ID": transactionId}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.startAddressApprovalProcessList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.startAddressApprovalProcessList; + }, + url, + postParams, + ); } Future submitBasicDetailsTransaction(String pDescFlexContextCode, String pFunctionName, List> list, int correctOrNew) async { @@ -275,31 +314,38 @@ class ProfileApiClient { postParams.addAll(AppState().postParamsJson); postParams["EITTransactionTBL"] = list; postParams["EITTransactionTBLModel"] = list; - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.submitBasicDetTransactionList!; //ESERVICESDV.fromJson(responseData.getDefaultValueList!.toJson()); - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.submitBasicDetTransactionList!; //ESERVICESDV.fromJson(responseData.getDefaultValueList!.toJson()); + }, + url, + postParams, + ); } Future startBasicDetailsApprovalProcess(String action, String comments, String itemKey, int transactionId) async { String url = "${ApiConsts.erpRest}START_BASIC_DET_APPR_PROCESS"; - Map postParams = { - "P_SELECTED_RESP_ID": -999, - "P_MENU_TYPE": "E", - "P_ACTION_MODE": action, - "P_COMMENTS": comments, - "P_ITEM_KEY": itemKey, - "P_TRANSACTION_ID": transactionId, - }; + Map postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E", "P_ACTION_MODE": action, "P_COMMENTS": comments, "P_ITEM_KEY": itemKey, "P_TRANSACTION_ID": transactionId}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.startAddressApprovalProcessList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.startAddressApprovalProcessList; + }, + url, + postParams, + ); } Future submitAddressTransaction( - String pDescFlexContextCode, String pFunctionName, List> list, int correctOrNew, String countryCode, String effectiveDate) async { + String pDescFlexContextCode, + String pFunctionName, + List> list, + int correctOrNew, + String countryCode, + String effectiveDate, + ) async { String url = "${ApiConsts.erpRest}SUBMIT_ADDRESS_TRANSACTION"; Map postParams = { "P_SELECTED_RESP_ID": -999, @@ -316,23 +362,28 @@ class ProfileApiClient { postParams.addAll(AppState().postParamsJson); postParams["EITTransactionTBL"] = list; // postParams["EITTransactionTBLModel"] = list; - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.submitAddressTransactionList!; //ESERVICESDV.fromJson(responseData.getDefaultValueList!.toJson()); - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.submitAddressTransactionList!; //ESERVICESDV.fromJson(responseData.getDefaultValueList!.toJson()); + }, + url, + postParams, + ); } Future> getCountriesList() async { String url = "${ApiConsts.erpRest}GET_COUNTRIES"; - Map postParams = { - "P_MENU_TYPE": "E", - "P_SELECTED_RESP_ID": -999, - }; + Map postParams = {"P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getCountriesList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getCountriesList ?? []; + }, + url, + postParams, + ); } // add & update family member @@ -340,73 +391,75 @@ class ProfileApiClient { String url = "${ApiConsts.erpRest}GET_BASIC_DET_DFF_STRUCTURE"; Map postParams = {"P_FUNCTION_NAME": "HR_PERINFO_SS", "P_MENU_TYPE": "E", "P_REQUEST_TYPE": "CONTACT", "P_SELECTED_RESP_ID": -999}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getBasicDetDffStructureList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getBasicDetDffStructureList ?? []; + }, + url, + postParams, + ); } // add & update family member Future> getContactColsStructureList(String actionType) async { String url = "${ApiConsts.erpRest}GET_CONTACT_COLS_STRUCTURE"; - Map postParams = { - "P_ACTION": actionType, - "P_FUNCTION_NAME": "HR_PERINFO_SS", - }; + Map postParams = {"P_ACTION": actionType, "P_FUNCTION_NAME": "HR_PERINFO_SS"}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getContactColsStructureList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getContactColsStructureList ?? []; + }, + url, + postParams, + ); } // update family member Future> getContactDetailsList(int contactRelationId) async { String url = "${ApiConsts.erpRest}GET_CONTACT_DETAILS"; - Map postParams = { - "P_MENU_TYPE": "E", - "P_SELECTED_RESP_ID": -999, - "P_CONTACT_RELATIONSHIP_ID": contactRelationId, - }; + Map postParams = {"P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999, "P_CONTACT_RELATIONSHIP_ID": contactRelationId}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getContactDetailsList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getContactDetailsList ?? []; + }, + url, + postParams, + ); } // add & update family member Future> getContactDffStructureList() async { String url = "${ApiConsts.erpRest}GET_CONTACT_DFF_STRUCTURE"; - Map postParams = { - "P_DESC_FLEX_CONTEXT_CODE": "HMG_ADD_CONTACT_DETAILS", - "P_FUNCTION_NAME": "HR_PERINFO_SS", - "P_MENU_TYPE": "E", - "P_SELECTED_RESP_ID": -999, - }; + Map postParams = {"P_DESC_FLEX_CONTEXT_CODE": "HMG_ADD_CONTACT_DETAILS", "P_FUNCTION_NAME": "HR_PERINFO_SS", "P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getContactDffStructureList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getContactDffStructureList ?? []; + }, + url, + postParams, + ); } Future submitContactTransactionAddAndUpdate(String actionType, relationId, List> list) async { String url = "${ApiConsts.erpRest}SUBMIT_CONTACT_TRANSACTION"; - Map postParams = { - "P_MENU_TYPE": "E", - "P_SELECTED_RESP_ID": -999, - "P_FUNCTION_NAME": "HR_PERINFO_SS", - "P_ACTION": actionType, - "P_CONTACT_RELATIONSHIP_ID": relationId, - }; + Map postParams = {"P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999, "P_FUNCTION_NAME": "HR_PERINFO_SS", "P_ACTION": actionType, "P_CONTACT_RELATIONSHIP_ID": relationId}; postParams.addAll(AppState().postParamsJson); postParams["EITTransactionTBL"] = list; - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.submitContactTransactionList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.submitContactTransactionList; + }, + url, + postParams, + ); } Future> getPerformanceAppraisal() async { @@ -414,55 +467,48 @@ class ProfileApiClient { Map postParams = {}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getPerformanceAppraisalList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getPerformanceAppraisalList ?? []; + }, + url, + postParams, + ); } - Future getPatientInfo({ - required String nationalId, - required String dob, - String? logInTokenID, - }) async { + Future getPatientInfo({required String nationalId, required String dob, String? logInTokenID}) async { // NHIC Service GetPatientInfo only works on Production (hmgwebservices.com) // String url = "https://hmgwebservices.com/Services/NHIC.svc/REST/GetPatientInfo"; String url = "${ApiConsts.erpRest}GetMemberInfo"; - String token = logInTokenID ?? - AppState().postParamsObject?.logInTokenID ?? - ""; + String token = logInTokenID ?? AppState().postParamsObject?.logInTokenID ?? ""; Map postParams = { "PatientIdentificationID": int.tryParse(nationalId.trim()) ?? nationalId.trim(), "PatientOutSA": 0, "DOB": dob.trim(), "LogInTokenID": token, - "PatientMobileNumber":AppState().postParamsObject?.mobileNumber, // added this as per e-services changed - "TokenID":AppState().postParamsObject?.tokenID,// added this as per e-services changed - "LanguageID":AppState().postParamsObject?.languageID,// added this as per e-services changed - "Channel":AppState().postParamsObject?.channel, + "PatientMobileNumber": AppState().postParamsObject?.mobileNumber, // added this as per e-services changed + "TokenID": AppState().postParamsObject?.tokenID, // added this as per e-services changed + "LanguageID": AppState().postParamsObject?.languageID, // added this as per e-services changed + "Channel": AppState().postParamsObject?.channel, "VersionID": AppState().postParamsObject?.versionID, - "UserName":AppState().postParamsObject?.userName + "UserName": AppState().postParamsObject?.userName, }; - print(jsonEncode(postParams)); - return await ApiClient().postJsonForObject((json) { - return PatientInfoModel.fromJson(json); - }, url, postParams); + print(jsonEncode(postParams)); + return await ApiClient().postJsonForObject( + (json) { + return PatientInfoModel.fromJson(json); + }, + url, + postParams, + ); } - Future processContactMazayaAccess({ - required String accessAction, - int? contactRelationshipId, - int? contactPersonId, - int? personId, - }) async { + Future processContactMazayaAccess({required String accessAction, int? contactRelationshipId, int? contactPersonId, int? personId}) async { String url = "${ApiConsts.erpRest}PROCESS_CONTACT_MAZAYA_ACCESS"; String action = accessAction.trim().toLowerCase() == "revoke" ? "Revoke" : "Grant"; - Map postParams = { - "P_MENU_TYPE": "E", - "P_SELECTED_RESP_ID": -999, - "P_ACCESS_ACTION": action, - }; + Map postParams = {"P_MENU_TYPE": "E", "P_SELECTED_RESP_ID": -999, "P_ACCESS_ACTION": action}; if (contactRelationshipId != null) { postParams["P_CONTACT_RELATIONSHIP_ID"] = contactRelationshipId; } @@ -473,8 +519,12 @@ class ProfileApiClient { postParams["P_PERSON_ID"] = personId; } postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - return GenericResponseModel.fromJson(json); - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + return GenericResponseModel.fromJson(json); + }, + url, + postParams, + ); } } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index e346378..d8d6575 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -90,6 +90,8 @@ class ApiConsts { //DummyCards for the UI + + static int tabletMinLength = 500; // Notification Center GUIDs for OTP diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index 9e2d838..0982da9 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -405,6 +405,9 @@ class GenericResponseModel { dynamic getWalaplusDepInfoModelInternal; List? walaPlusCategories; + String? businessCardQROutside; + EmpBusinessCardInfoModel? empBusinessCardInfoModel; + GenericResponseModel({ this.date, this.languageID, @@ -680,6 +683,8 @@ class GenericResponseModel { this.getWalaplusDepInfoModel, this.getWalaplusDepInfoModelInternal, this.walaPlusCategories, + this.businessCardQROutside, + this.empBusinessCardInfoModel, }); GenericResponseModel.fromJson(Map json) { @@ -1478,6 +1483,9 @@ class GenericResponseModel { getWalaplusDepInfoModel = json['GET_WALAPLUS_DEP_INFO_Model'] != null ? GetWalaplusDepInfoModel.fromJson(json['GET_WALAPLUS_DEP_INFO_Model']) : null; getWalaplusDepInfoModelInternal = json['GET_WALAPLUS_DEP_INFO_Model_Internal']; + businessCardQROutside = json['BusinessCardQR_Outside']; + empBusinessCardInfoModel = json['GET_EMP_BUSINESS_CARD_INFO_Model'] != null ? EmpBusinessCardInfoModel.fromJson(json['GET_EMP_BUSINESS_CARD_INFO_Model']) : null; + if (json['WalaPlus_Categories'] != null) { walaPlusCategories = []; json['WalaPlus_Categories'].forEach((v) { @@ -1976,6 +1984,11 @@ class GenericResponseModel { data['GET_WALAPLUS_DEP_INFO_Model'] = this.getWalaplusDepInfoModel!.toJson(); } + data['BusinessCardQR_Outside'] = this.businessCardQROutside; + if (this.empBusinessCardInfoModel != null) { + data['GET_EMP_BUSINESS_CARD_INFO_Model'] = this.empBusinessCardInfoModel!.toJson(); + } + if (walaPlusCategories != null) { data['WalaPlus_Categories'] = walaPlusCategories!.map((WalaPlusCategoryModel v) => v.toJson()).toList(); } @@ -2011,21 +2024,41 @@ class GetWalaplusDepInfoModel { String? pEmpMobileNumber; String? pDependentName; - GetWalaplusDepInfoModel({ - this.pEmpEmailAddress, - this.pEmpMobileNumber, - this.pDependentName, - }); + GetWalaplusDepInfoModel({this.pEmpEmailAddress, this.pEmpMobileNumber, this.pDependentName}); + + factory GetWalaplusDepInfoModel.fromJson(Map json) => + GetWalaplusDepInfoModel(pEmpEmailAddress: json["P_EMP_EMAIL_ADDRESS"], pEmpMobileNumber: json["P_EMP_MOBILE_NUMBER"], pDependentName: json["P_DEPENDENT_NAME"]); + + Map toJson() => {"P_EMP_EMAIL_ADDRESS": pEmpEmailAddress, "P_EMP_MOBILE_NUMBER": pEmpMobileNumber, "P_DEPENDENT_NAME": pDependentName}; +} + +class EmpBusinessCardInfoModel { + String? pEmailAddress; + String? pFirstName; + String? pLastName; + String? pMobilePhoneNumber; + String? pPositionTitle; + String? pWorkExtensionNumber; + + EmpBusinessCardInfoModel({this.pEmailAddress, this.pFirstName, this.pLastName, this.pMobilePhoneNumber, this.pPositionTitle, this.pWorkExtensionNumber}); + + String get fullName => [pFirstName, pLastName].where((e) => e != null && e.trim().isNotEmpty).join(" "); - factory GetWalaplusDepInfoModel.fromJson(Map json) => GetWalaplusDepInfoModel( - pEmpEmailAddress: json["P_EMP_EMAIL_ADDRESS"], - pEmpMobileNumber: json["P_EMP_MOBILE_NUMBER"], - pDependentName: json["P_DEPENDENT_NAME"], - ); + factory EmpBusinessCardInfoModel.fromJson(Map json) => EmpBusinessCardInfoModel( + pEmailAddress: json["P_EMAIL_ADDRESS"], + pFirstName: json["P_FIRST_NAME"], + pLastName: json["P_LAST_NAME"], + pMobilePhoneNumber: json["P_MOBILE_PHONE_NUMBER"], + pPositionTitle: json["P_POSITION_TITLE"], + pWorkExtensionNumber: json["P_WORK_EXTENSION_NUMBER"], + ); Map toJson() => { - "P_EMP_EMAIL_ADDRESS": pEmpEmailAddress, - "P_EMP_MOBILE_NUMBER": pEmpMobileNumber, - "P_DEPENDENT_NAME": pDependentName, - }; + "P_EMAIL_ADDRESS": pEmailAddress, + "P_FIRST_NAME": pFirstName, + "P_LAST_NAME": pLastName, + "P_MOBILE_PHONE_NUMBER": pMobilePhoneNumber, + "P_POSITION_TITLE": pPositionTitle, + "P_WORK_EXTENSION_NUMBER": pWorkExtensionNumber, + }; } diff --git a/lib/ui/dialogs/id/business_card_dialog.dart b/lib/ui/dialogs/id/business_card_dialog.dart index a405ccf..e24c102 100644 --- a/lib/ui/dialogs/id/business_card_dialog.dart +++ b/lib/ui/dialogs/id/business_card_dialog.dart @@ -1,15 +1,18 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.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/utils.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/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/models/generic_response_model.dart'; class BusinessCardDialog extends StatelessWidget { - const BusinessCardDialog({Key? key}) : super(key: key); + final String? qrBase64; + final EmpBusinessCardInfoModel? employeeInfo; + + const BusinessCardDialog({Key? key, this.qrBase64, this.employeeInfo}) : super(key: key); @override Widget build(BuildContext context) { @@ -40,7 +43,7 @@ class BusinessCardDialog extends StatelessWidget { ), ), Image.memory( - Utils.getPostBytes(AppState().memberInformationList!.businessCardQR ?? ""), + Utils.getPostBytes(qrBase64 ?? ""), width: 129, height: 129, ), @@ -50,28 +53,25 @@ class BusinessCardDialog extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ - (AppState().memberInformationList!.eMPLOYEENAME ?? "").toText23(isBold: true).paddingOnly(top: 15), - (AppState().memberInformationList!.getPositionName() ?? "").toText17( + (employeeInfo?.fullName ?? "").toText23(isBold: true).paddingOnly(top: 15), + (employeeInfo?.pPositionTitle ?? "").toText17( color: MyColors.grey57Color, ), 30.height, - // (AppState().memberInformationList!.eMPLOYEENUMBER ?? "").toText13(), Row( children: [ const Icon(Icons.email, size: 17.5, color: MyColors.grey3AColor).paddingOnly(right: 11.5), ("${LocaleKeys.email.tr()}: ").toText18(color: MyColors.grey57Color), - (AppState().memberInformationList!.eMPLOYEEEMAILADDRESS ?? "").toText18(), + (employeeInfo?.pEmailAddress ?? "").toText18(), ], ), Row( children: [ const Icon(Icons.call, size: 17.5, color: MyColors.grey3AColor).paddingOnly(right: 11.5), ("${LocaleKeys.mobile.tr()}: ").toText18(color: MyColors.grey57Color), - (AppState().memberInformationList!.mobileNumberWithZipCode ?? "").toText18(), + (employeeInfo?.pMobilePhoneNumber ?? "").toText18(), ], ), - // 1.height, - // (AppState().memberInformationList!.jOBNAME ?? "").toText13(), ], ), ], diff --git a/lib/ui/landing/dashboard_screen_for_dependet.dart b/lib/ui/landing/dashboard_screen_for_dependet.dart index a4ec744..9d9c7f3 100644 --- a/lib/ui/landing/dashboard_screen_for_dependet.dart +++ b/lib/ui/landing/dashboard_screen_for_dependet.dart @@ -12,6 +12,7 @@ import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/main.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_retailer_model.dart'; import 'package:mohem_flutter_app/widgets/info_chip_widget.dart'; @@ -472,7 +473,7 @@ class _DashboardScreenForDependetState extends State GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 0.85, crossAxisSpacing: 12, mainAxisSpacing: 16), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: isTablet ? 4 : 2, childAspectRatio: 0.85, crossAxisSpacing: 12, mainAxisSpacing: 16), itemCount: _filteredRetailersList.length, itemBuilder: (context, index) { return _buildOfferCard(_filteredRetailersList[index], isAr); @@ -908,7 +909,7 @@ class _DashboardScreenForDependetState extends State child: GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 0.72, crossAxisSpacing: 12, mainAxisSpacing: 16), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: isTablet ? 4 : 2, childAspectRatio: 0.85, crossAxisSpacing: 12, mainAxisSpacing: 16), itemCount: 4, itemBuilder: (_, __) { return Container( diff --git a/lib/ui/landing/wala_plus_retailer_details_screen.dart b/lib/ui/landing/wala_plus_retailer_details_screen.dart index d04600f..4f10b1a 100644 --- a/lib/ui/landing/wala_plus_retailer_details_screen.dart +++ b/lib/ui/landing/wala_plus_retailer_details_screen.dart @@ -142,7 +142,7 @@ class _WalaPlusRetailerDetailsScreenState extends State _openInAppBrowser(String url, {String? offerType}) async { String title = _retailer?.name ?? LocaleKeys.offerDetails.tr(); bool shouldStartScanning = offerType?.trim().toLowerCase() == "discount"; - + log("shouldStartScanning: ${shouldStartScanning.toString()} for offerType: ${offerType.toString()}"); await Navigator.push( context, MaterialPageRoute(builder: (BuildContext context) => AppInAppWebViewScreen(url: url, title: title, onPageLoaded: shouldStartScanning ? _clickStartScanningButton : null)), diff --git a/lib/ui/landing/widget/app_drawer.dart b/lib/ui/landing/widget/app_drawer.dart index b9bdbc4..3f9b2e4 100644 --- a/lib/ui/landing/widget/app_drawer.dart +++ b/lib/ui/landing/widget/app_drawer.dart @@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/api/profile_api_client.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/utils.dart'; @@ -11,6 +12,7 @@ import 'package:mohem_flutter_app/extensions/string_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/models/dashboard/drawer_menu_item_model.dart'; +import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/ui/dialogs/id/business_card_dialog.dart'; @@ -37,6 +39,22 @@ class _AppDrawerState extends State { chatData = Provider.of(context, listen: false); } + Future _showBusinessCard(BuildContext context) async { + Utils.showLoading(context); + try { + GenericResponseModel? response = await ProfileApiClient().getEmployeeBusinessCardInfo(); + Utils.hideLoading(context); + showMDialog( + context, + child: BusinessCardDialog(qrBase64: response?.businessCardQROutside, employeeInfo: response?.empBusinessCardInfoModel), + isBusniessCard: true, + ); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + @override Widget build(BuildContext context) { if (drawerMenuItemList.isEmpty) { @@ -119,7 +137,7 @@ class _AppDrawerState extends State { }), menuItem("assets/images/drawer/employee_id.svg", LocaleKeys.employeeDigitalID.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: EmployeeDigitialIdDialog())), if (AppState().businessCardPrivilege) - menuItem("assets/images/drawer/view_business_card.svg", LocaleKeys.viewBusinessCard.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: BusinessCardDialog(), isBusniessCard: true)), + menuItem("assets/images/drawer/view_business_card.svg", LocaleKeys.viewBusinessCard.tr(), "", closeDrawer: false, onPress: () => _showBusinessCard(context)), menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: (){Utils.performLogout(context, chatData);}), // menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: () {Navigator.pushNamed(context, AppRoutes.survey,); ], diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index 8b52c41..f43ebc6 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -8,6 +8,7 @@ import 'package:local_auth/local_auth.dart'; import 'package:local_auth_darwin/local_auth_darwin.dart'; import 'package:local_auth_android/local_auth_android.dart'; import 'package:mohem_flutter_app/api/login_api_client.dart'; +import 'package:mohem_flutter_app/api/profile_api_client.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/consts.dart'; @@ -70,14 +71,22 @@ class _VerifyLastLoginScreenState extends State { surfaceTintColor: Colors.transparent, backgroundColor: Colors.transparent, automaticallyImplyLeading: false, - title: (mobileLoginInfoListModel?.businessCardPrivilege ?? false) - ? LocaleKeys.viewBusinessCard.tr().toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() { - showMDialog(context, child: const BusinessCardDialog()); - }) - : Container(), + title: + (mobileLoginInfoListModel?.businessCardPrivilege ?? false) + ? LocaleKeys.viewBusinessCard.tr().toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() async { + Utils.showLoading(context); + try { + GenericResponseModel? response = await ProfileApiClient().getEmployeeBusinessCardInfo(); + Utils.hideLoading(context); + showMDialog(context, child: BusinessCardDialog(qrBase64: response?.businessCardQROutside, employeeInfo: response?.empBusinessCardInfoModel)); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + }) + : Container(), actions: [ Center( - child: LocaleKeys.employeeDigitalID.tr().toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() { showMDialog(context, child: EmployeeDigitialIdDialog()); }), @@ -113,7 +122,10 @@ class _VerifyLastLoginScreenState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, - children: [LocaleKeys.lastLoginDetails.tr().toText16(), DateUtil.formatDateToDate(DateUtil.convertStringToDate(mobileLoginInfoListModel!.editedOn ?? DateTime.now().toString()), false).toText12()], + children: [ + LocaleKeys.lastLoginDetails.tr().toText16(), + DateUtil.formatDateToDate(DateUtil.convertStringToDate(mobileLoginInfoListModel!.editedOn ?? DateTime.now().toString()), false).toText12(), + ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -208,8 +220,12 @@ class _VerifyLastLoginScreenState extends State { } Future loginWithFaceIDAndBiometrics() async { - - IOSAuthMessages iosStrings = const IOSAuthMessages(cancelButton: 'cancel', goToSettingsButton: 'settings', goToSettingsDescription: 'Please set up your Touch ID.', lockOut: 'Please reenable your Touch ID'); + IOSAuthMessages iosStrings = const IOSAuthMessages( + cancelButton: 'cancel', + goToSettingsButton: 'settings', + goToSettingsDescription: 'Please set up your Touch ID.', + lockOut: 'Please reenable your Touch ID', + ); // IOSAuthMessages iosStrings = const IOSAuthMessages( // cancelButton: 'cancel', @@ -220,13 +236,10 @@ class _VerifyLastLoginScreenState extends State { bool authenticated = false; try { - authenticated = await auth.authenticate(localizedReason: 'Scan your fingerprint to authenticate', options: const AuthenticationOptions( - useErrorDialogs: true, stickyAuth: true, biometricOnly: true, - ), - authMessages: [ - iosStrings, - const AndroidAuthMessages(), - ], + authenticated = await auth.authenticate( + localizedReason: 'Scan your fingerprint to authenticate', + options: const AuthenticationOptions(useErrorDialogs: true, stickyAuth: true, biometricOnly: true), + authMessages: [iosStrings, const AndroidAuthMessages()], ); } on PlatformException catch (e) { print(e); @@ -237,60 +250,58 @@ class _VerifyLastLoginScreenState extends State { } Widget _loginOptionButton(String _title, String _icon, int _flag, int? _loginIndex) { -// <<<<<<< HEAD + // <<<<<<< HEAD bool isDisable = false; - if(_flag >= 3 && _flag <= 4) { - bool isFaceEnabled = (_flag == 3 && (checkBiometricIsAvailable(BiometricType.face) || - checkBiometricIsAvailable(BiometricType.weak))); + if (_flag >= 3 && _flag <= 4) { + bool isFaceEnabled = (_flag == 3 && (checkBiometricIsAvailable(BiometricType.face) || checkBiometricIsAvailable(BiometricType.weak))); - bool isThumbEnabled = - (_flag == 4 && (checkBiometricIsAvailable(BiometricType.fingerprint) || - checkBiometricIsAvailable(BiometricType.strong))); + bool isThumbEnabled = (_flag == 4 && (checkBiometricIsAvailable(BiometricType.fingerprint) || checkBiometricIsAvailable(BiometricType.strong))); isDisable = !(isFaceEnabled || isThumbEnabled); } -// ======= -// bool isDisable = (_flag == 3 && !checkBiometricIsAvailable(BiometricType.face) || -// _flag == 4 && !checkBiometricIsAvailable(BiometricType.fingerprint) && _flag == 4 && !checkBiometricIsAvailable(BiometricType.face)); -// // >>>>>>> master + // ======= + // bool isDisable = (_flag == 3 && !checkBiometricIsAvailable(BiometricType.face) || + // _flag == 4 && !checkBiometricIsAvailable(BiometricType.fingerprint) && _flag == 4 && !checkBiometricIsAvailable(BiometricType.face)); + // // >>>>>>> master return InkWell( - onTap: isDisable - ? null - : () async { - if (_flag == 0) { - setState(() { - // isMoreOption = true; - }); - } else { - if (_flag == 3 || _flag == 4) { - bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); - if (!authenticateWithFaceAndTouchID) { - return; - } else { - if (mobileLoginInfoListModel!.loginType == 3 || mobileLoginInfoListModel!.loginType == 4) { - // bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); - // if (!authenticateWithFaceAndTouchID) { - // return; - // } else { - // performApiCall(_title, _icon, _flag, isDirectLogin: true); - // } - performApiCall(_title, _icon, _flag, _flag, isDirectLogin: true); + onTap: + isDisable + ? null + : () async { + if (_flag == 0) { + setState(() { + // isMoreOption = true; + }); + } else { + if (_flag == 3 || _flag == 4) { + bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); + if (!authenticateWithFaceAndTouchID) { + return; } else { - isNeedVerifyWithFaceIDAndBiometrics = true; - selectedFlag = _flag; - setState(() { - return; - }); + if (mobileLoginInfoListModel!.loginType == 3 || mobileLoginInfoListModel!.loginType == 4) { + // bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); + // if (!authenticateWithFaceAndTouchID) { + // return; + // } else { + // performApiCall(_title, _icon, _flag, isDirectLogin: true); + // } + performApiCall(_title, _icon, _flag, _flag, isDirectLogin: true); + } else { + isNeedVerifyWithFaceIDAndBiometrics = true; + selectedFlag = _flag; + setState(() { + return; + }); + } } + } else { + if (isNeedVerifyWithFaceIDAndBiometrics) + performApiCall(_title, _icon, selectedFlag, _flag); + else + performApiCall(_title, _icon, _flag, _flag); } - } else { - if (isNeedVerifyWithFaceIDAndBiometrics) - performApiCall(_title, _icon, selectedFlag, _flag); - else - performApiCall(_title, _icon, _flag, _flag); } - } - }, + }, child: Container( padding: const EdgeInsets.only(left: 20, right: 20, bottom: 15, top: 28), decoration: BoxDecoration( @@ -415,15 +426,15 @@ class _VerifyLastLoginScreenState extends State { } } -// -// formatDate(date) { -// return date; -// return DateFormat('MMM dd, yyy, kk:mm').format(date); -// } -// -// showLoader(bool isTrue) { -// setState(() { -// // isLoading = isTrue; -// }); -// } + // + // formatDate(date) { + // return date; + // return DateFormat('MMM dd, yyy, kk:mm').format(date); + // } + // + // showLoader(bool isTrue) { + // setState(() { + // // isLoading = isTrue; + // }); + // } } From 703f10349e45047af503c296bc9ff30a3ef73b97 Mon Sep 17 00:00:00 2001 From: FaizHashmi Date: Mon, 12 Oct 2026 11:21:32 +0300 Subject: [PATCH 2/3] tested in release mode the QR Fix --- lib/ui/landing/dashboard_screen_for_dependet.dart | 4 ++-- lib/ui/landing/wala_plus_retailer_details_screen.dart | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/ui/landing/dashboard_screen_for_dependet.dart b/lib/ui/landing/dashboard_screen_for_dependet.dart index 9d9c7f3..344b2db 100644 --- a/lib/ui/landing/dashboard_screen_for_dependet.dart +++ b/lib/ui/landing/dashboard_screen_for_dependet.dart @@ -473,7 +473,7 @@ class _DashboardScreenForDependetState extends State GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: isTablet ? 4 : 2, childAspectRatio: 0.85, crossAxisSpacing: 12, mainAxisSpacing: 16), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: isTablet ? 4 : 2, childAspectRatio: 0.7, crossAxisSpacing: 12, mainAxisSpacing: 16), itemCount: _filteredRetailersList.length, itemBuilder: (context, index) { return _buildOfferCard(_filteredRetailersList[index], isAr); @@ -909,7 +909,7 @@ class _DashboardScreenForDependetState extends State child: GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: isTablet ? 4 : 2, childAspectRatio: 0.85, crossAxisSpacing: 12, mainAxisSpacing: 16), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: isTablet ? 4 : 2, childAspectRatio: 0.7, crossAxisSpacing: 12, mainAxisSpacing: 16), itemCount: 4, itemBuilder: (_, __) { return Container( diff --git a/lib/ui/landing/wala_plus_retailer_details_screen.dart b/lib/ui/landing/wala_plus_retailer_details_screen.dart index 4f10b1a..83db56e 100644 --- a/lib/ui/landing/wala_plus_retailer_details_screen.dart +++ b/lib/ui/landing/wala_plus_retailer_details_screen.dart @@ -158,7 +158,7 @@ class _WalaPlusRetailerDetailsScreenState extends State= maxAttempts) { clearInterval(timer); } - }, 50); + }, 200); })(); """, ); From 74bb37593a97ffa46c5f8ba94b66239aa4000463 Mon Sep 17 00:00:00 2001 From: FaizHashmi Date: Mon, 12 Oct 2026 13:17:57 +0300 Subject: [PATCH 3/3] filter api added --- lib/api/offers_and_discounts_api_client.dart | 125 ++++++++++++------ .../wala_plus_retailer_model.dart | 124 +++++------------ .../dashboard_screen_for_dependet.dart | 26 ++-- .../wala_plus_retailer_details_screen.dart | 8 +- 4 files changed, 134 insertions(+), 149 deletions(-) diff --git a/lib/api/offers_and_discounts_api_client.dart b/lib/api/offers_and_discounts_api_client.dart index bd4723d..76bd1e9 100644 --- a/lib/api/offers_and_discounts_api_client.dart +++ b/lib/api/offers_and_discounts_api_client.dart @@ -1,6 +1,9 @@ +import 'dart:async'; import 'dart:convert'; +import 'dart:developer'; import 'package:flutter/material.dart'; +import 'package:geolocator/geolocator.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/classes/consts.dart'; @@ -8,6 +11,7 @@ import 'package:mohem_flutter_app/models/offers_and_discounts/get_categories_lis 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_retailer_model.dart'; +import 'package:mohem_flutter_app/widgets/location/Location.dart' as location; class OffersAndDiscountsApiClient { static final OffersAndDiscountsApiClient _instance = OffersAndDiscountsApiClient._internal(); @@ -75,13 +79,48 @@ class OffersAndDiscountsApiClient { String _resolveUserName() { String? pUserName = AppState().getUserName; if (pUserName == null || pUserName.isEmpty) { - pUserName = AppState().postParamsObject?.userName ?? - AppState().postParamsObject?.pUserName ?? - AppState().memberInformationList?.eMPLOYEENUMBER; + pUserName = AppState().postParamsObject?.userName ?? AppState().postParamsObject?.pUserName ?? AppState().memberInformationList?.eMPLOYEENUMBER; } return pUserName ?? ""; } + // Same Location.isEnabled -> Location.havePermission -> Location.getCurrentLocation pattern + // used by mark_attendance_widget.dart (e.g. Wifi attendance), wrapped as a Future since this + // is a background enrichment of the request, not a blocking user action - any failure (service + // disabled, permission denied, error) just resolves to null so the retailer fetch still proceeds + // without WP_Geo_Location rather than showing permission dialogs here. + Future _getCurrentPositionSilently(BuildContext context) async { + Completer enabledCompleter = Completer(); + location.Location.isEnabled((bool isEnabled) { + if (!enabledCompleter.isCompleted) enabledCompleter.complete(isEnabled); + }); + bool isEnabled = await enabledCompleter.future; + debugPrint("_getCurrentPositionSilently: location service isEnabled=$isEnabled"); + if (!isEnabled) return null; + + Completer permissionCompleter = Completer(); + location.Location.havePermission((bool hasPermission) { + if (!permissionCompleter.isCompleted) permissionCompleter.complete(hasPermission); + }); + bool hasPermission = await permissionCompleter.future; + debugPrint("_getCurrentPositionSilently: havePermission=$hasPermission"); + if (!hasPermission) return null; + + Completer positionCompleter = Completer(); + location.Location.getCurrentLocation( + (Position position, bool isMocked) { + debugPrint("_getCurrentPositionSilently: got position lat=${position.latitude}, lng=${position.longitude}, isMocked=$isMocked"); + if (!positionCompleter.isCompleted) positionCompleter.complete(position); + }, + () { + debugPrint("_getCurrentPositionSilently: getCurrentLocation error callback fired"); + if (!positionCompleter.isCompleted) positionCompleter.complete(null); + }, + context, + ); + return positionCompleter.future; + } + String _resolveDepNationalId() { if (!ApiConsts.isDependetLogin) { return ""; @@ -116,7 +155,6 @@ class OffersAndDiscountsApiClient { return ""; } - Map _getBaseWalaPlusParams() { Map base = {}; base.addAll(AppState().postParamsJson); @@ -164,10 +202,7 @@ class OffersAndDiscountsApiClient { (response) { List categories = []; if (response != null) { - dynamic cats = response['WalaPlus_Categories'] ?? - response['walaPlus_Categories'] ?? - response['WalaPlusCategories'] ?? - response['result']; + dynamic cats = response['WalaPlus_Categories'] ?? response['walaPlus_Categories'] ?? response['WalaPlusCategories'] ?? response['result']; if (cats is String) { try { cats = json.decode(cats); @@ -192,11 +227,30 @@ class OffersAndDiscountsApiClient { ); } + // Confirmed with backend team: WP_Offer_Type accepts "online" and "store". + static const String walaPlusOfferTypeOnline = "online"; + static const String walaPlusOfferTypeInStore = "store"; + + // Maps the screen's internal filter key ("online"/"instore"/"all") to the WP_Offer_Type value + // the backend expects. Returns null for "all" (or anything unrecognized) so callers can skip + // sending WP_Offer_Type entirely. + static String? mapOfferTypeFilter(String internalKey) { + switch (internalKey) { + case "online": + return walaPlusOfferTypeOnline; + case "instore": + return walaPlusOfferTypeInStore; + default: + return null; + } + } + Future getWalaPlusRetailers({ String? categoryId, int page = 1, int perPage = 10, String? geoLocation, + String? offerType, BuildContext? context, String? mobileNumber, }) async { @@ -216,6 +270,9 @@ class OffersAndDiscountsApiClient { postParams["MemberType"] = ApiConsts.isDependetLogin ? 2 : 1; postParams["CompanyID"] = 1; postParams["WP_CategoryID"] = effectiveCatId; + if (offerType != null && offerType.trim().isNotEmpty) { + postParams["WP_Offer_Type"] = offerType.trim(); + } postParams["WP_Page"] = page; postParams["WP_Per_page"] = perPage; @@ -227,11 +284,7 @@ class OffersAndDiscountsApiClient { return await ApiClient().postJsonForObject( (response) { if (response != null) { - dynamic val = response['WalaPlus_Retailers'] ?? - response['walaPlus_Retailers'] ?? - response['WalaPlusRetailers'] ?? - response['WP_Retailers'] ?? - response['result']; + dynamic val = response['WalaPlus_Retailers'] ?? response['walaPlus_Retailers'] ?? response['WalaPlusRetailers'] ?? response['WP_Retailers'] ?? response['result']; if (val is String) { try { val = json.decode(val); @@ -262,11 +315,7 @@ class OffersAndDiscountsApiClient { ); } - Future getWalaPlusRetailerById({ - required String retailerId, - BuildContext? context, - String? mobileNumber, - }) async { + Future getWalaPlusRetailerById({required String retailerId, BuildContext? context, String? mobileNumber}) async { String url = ApiConsts.walaPlusRetailersByID; String pUserName = _resolveUserName(); String pMobileNumber = _resolveMobileNumber(overrideMobile: mobileNumber); @@ -283,6 +332,20 @@ class OffersAndDiscountsApiClient { } postParams["MemberType"] = ApiConsts.isDependetLogin ? 2 : 1; postParams["CompanyID"] = 1; + + if (context != null) { + try { + Position? position = await _getCurrentPositionSilently(context); + log("context position: $position"); + + if (position != null) { + postParams["WP_Geo_Location"] = "${position.latitude},${position.longitude}"; + } + } catch (e) { + debugPrint("getWalaPlusRetailerById: unable to get current location: $e"); + } + } + _cleanWalaPlusParams(postParams); debugPrint("getWalaPlusRetailerById: calling $url with WP_RetailerID: $retailerId"); @@ -291,11 +354,7 @@ class OffersAndDiscountsApiClient { (response) { if (response != null) { debugPrint("getWalaPlusRetailerById response keys: ${response is Map ? response.keys.toList() : 'non-map'}"); - dynamic val = response['WalaPlus_RetailersByID'] ?? - response['walaPlus_RetailersByID'] ?? - response['WalaPlusRetailersByID'] ?? - response['WP_RetailersByID'] ?? - response['result']; + dynamic val = response['WalaPlus_RetailersByID'] ?? response['walaPlus_RetailersByID'] ?? response['WalaPlusRetailersByID'] ?? response['WP_RetailersByID'] ?? response['result']; if (val is String) { try { val = json.decode(val); @@ -324,9 +383,7 @@ class OffersAndDiscountsApiClient { } if ((model?.locations == null || model!.locations!.isEmpty) && (map.containsKey('locations') || map.containsKey('Locations') || map.containsKey('location') || map.containsKey('Location'))) { - model?.locations = WalaPlusRetailerModel.parseLocationsList( - map['locations'] ?? map['Locations'] ?? map['location'] ?? map['Location'], - ); + model?.locations = WalaPlusRetailerModel.parseLocationsList(map['locations'] ?? map['Locations'] ?? map['location'] ?? map['Location']); } } else if (response is Map && response.containsKey('name')) { model = WalaPlusRetailerModel.fromJson(response); @@ -339,9 +396,7 @@ class OffersAndDiscountsApiClient { } if ((model.locations == null || model.locations!.isEmpty) && (response.containsKey('locations') || response.containsKey('Locations') || response.containsKey('location') || response.containsKey('Location'))) { - 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}"); @@ -370,12 +425,7 @@ class OffersAndDiscountsApiClient { return ""; } - Future?> redeemWalaPlusOffer({ - required String offerId, - String? offerType, - String? userReference, - BuildContext? context, - }) async { + Future?> redeemWalaPlusOffer({required String offerId, String? offerType, String? userReference, BuildContext? context}) async { String url = ApiConsts.walaPlusOfferRedeem; String pUserName = _resolveUserName(); String pUserReference = _resolveUserReference(overrideUserReference: userReference); @@ -405,10 +455,7 @@ class OffersAndDiscountsApiClient { (response) { if (response != null) { debugPrint("redeemWalaPlusOffer response: $response"); - dynamic val = response['WalaPlus_OfferRedeem'] ?? - response['walaPlus_OfferRedeem'] ?? - response['WalaPlusOfferRedeem'] ?? - response['result']; + dynamic val = response['WalaPlus_OfferRedeem'] ?? response['walaPlus_OfferRedeem'] ?? response['WalaPlusOfferRedeem'] ?? response['result']; if (val is String) { try { val = json.decode(val); diff --git a/lib/models/offers_and_discounts/wala_plus_retailer_model.dart b/lib/models/offers_and_discounts/wala_plus_retailer_model.dart index e7f7a9c..628b3e5 100644 --- a/lib/models/offers_and_discounts/wala_plus_retailer_model.dart +++ b/lib/models/offers_and_discounts/wala_plus_retailer_model.dart @@ -9,12 +9,7 @@ class WalaPlusRetailersResponse { int? perPage; List? retailers; - WalaPlusRetailersResponse({ - this.page, - this.pagesCount, - this.perPage, - this.retailers, - }); + WalaPlusRetailersResponse({this.page, this.pagesCount, this.perPage, this.retailers}); factory WalaPlusRetailersResponse.fromJson(Map json) { List retailersList = []; @@ -35,21 +30,15 @@ class WalaPlusRetailersResponse { } return WalaPlusRetailersResponse( - page: json['page'] is int - ? json['page'] - : int.tryParse(json['page']?.toString() ?? json['WP_Page']?.toString() ?? '1'), - pagesCount: json['pages_count'] is int - ? json['pages_count'] - : int.tryParse(json['pages_count']?.toString() ?? json['pagesCount']?.toString() ?? json['totalPages']?.toString() ?? '1'), - perPage: json['per_page'] is int - ? json['per_page'] - : int.tryParse(json['per_page']?.toString() ?? json['perPage']?.toString() ?? json['WP_Per_page']?.toString() ?? '10'), + page: json['page'] is int ? json['page'] : int.tryParse(json['page']?.toString() ?? json['WP_Page']?.toString() ?? '1'), + pagesCount: json['pages_count'] is int ? json['pages_count'] : int.tryParse(json['pages_count']?.toString() ?? json['pagesCount']?.toString() ?? json['totalPages']?.toString() ?? '1'), + perPage: json['per_page'] is int ? json['per_page'] : int.tryParse(json['per_page']?.toString() ?? json['perPage']?.toString() ?? json['WP_Per_page']?.toString() ?? '10'), retailers: retailersList, ); } Map toJson() { - Map data = {}; + Map data = {}; data['page'] = page; data['pages_count'] = pagesCount; data['per_page'] = perPage; @@ -68,22 +57,11 @@ class WalaPlusRetailersByIDResponse { List? offers; List? retailer; - WalaPlusRetailersByIDResponse({ - this.page, - this.pagesCount, - this.perPage, - this.locations, - this.offers, - this.retailer, - }); + WalaPlusRetailersByIDResponse({this.page, this.pagesCount, this.perPage, this.locations, this.offers, this.retailer}); factory WalaPlusRetailersByIDResponse.fromJson(Map json) { - List locList = WalaPlusRetailerModel.parseLocationsList( - json['locations'] ?? json['Locations'] ?? json['location'] ?? json['Location'], - ); - List offList = WalaPlusRetailerModel.parseOffersList( - json['offers'] ?? json['Offers'], - ); + List locList = WalaPlusRetailerModel.parseLocationsList(json['locations'] ?? json['Locations'] ?? json['location'] ?? json['Location']); + List offList = WalaPlusRetailerModel.parseOffersList(json['offers'] ?? json['Offers']); List retList = []; dynamic retData = json['retailer'] ?? json['Retailer']; @@ -109,15 +87,9 @@ class WalaPlusRetailersByIDResponse { } return WalaPlusRetailersByIDResponse( - page: json['page'] is int - ? json['page'] - : int.tryParse(json['page']?.toString() ?? json['WP_Page']?.toString() ?? ''), - pagesCount: json['pages_count'] is int - ? json['pages_count'] - : int.tryParse(json['pages_count']?.toString() ?? json['pagesCount']?.toString() ?? ''), - perPage: json['per_page'] is int - ? json['per_page'] - : int.tryParse(json['per_page']?.toString() ?? json['perPage']?.toString() ?? ''), + page: json['page'] is int ? json['page'] : int.tryParse(json['page']?.toString() ?? json['WP_Page']?.toString() ?? ''), + pagesCount: json['pages_count'] is int ? json['pages_count'] : int.tryParse(json['pages_count']?.toString() ?? json['pagesCount']?.toString() ?? ''), + perPage: json['per_page'] is int ? json['per_page'] : int.tryParse(json['per_page']?.toString() ?? json['perPage']?.toString() ?? ''), locations: locList, offers: offList, retailer: retList, @@ -289,9 +261,7 @@ class WalaPlusRetailerModel { } List offersList = parseOffersList(offersSource ?? targetJson['offers'] ?? targetJson['Offers']); - List locationsList = parseLocationsList( - locationsSource ?? targetJson['locations'] ?? targetJson['Locations'] ?? targetJson['location'] ?? targetJson['Location'], - ); + List locationsList = parseLocationsList(locationsSource ?? targetJson['locations'] ?? targetJson['Locations'] ?? targetJson['location'] ?? targetJson['Location']); List categoriesList = []; if (targetJson['categories'] != null && targetJson['categories'] is List) { @@ -309,7 +279,8 @@ class WalaPlusRetailerModel { } } - String? foundValidity = targetJson['validity']?.toString() ?? + String? foundValidity = + targetJson['validity']?.toString() ?? targetJson['valid_to']?.toString() ?? targetJson['valid_until']?.toString() ?? targetJson['end_date']?.toString() ?? @@ -323,9 +294,7 @@ class WalaPlusRetailerModel { if (foundValidity == null || foundValidity == "null" || foundValidity.trim().isEmpty) { for (var entry in targetJson.entries) { String k = entry.key.toLowerCase(); - if ((k.contains('valid') || k.contains('expir') || k.contains('duration')) && - !k.contains('isverificationcodevalid') && - !k.contains('barcode')) { + if ((k.contains('valid') || k.contains('expir') || k.contains('duration')) && !k.contains('isverificationcodevalid') && !k.contains('barcode')) { if (entry.value != null && entry.value.toString().trim().isNotEmpty && entry.value.toString() != "null") { foundValidity = entry.value.toString().trim(); break; @@ -335,7 +304,8 @@ class WalaPlusRetailerModel { } return WalaPlusRetailerModel( - id: targetJson['id']?.toString() ?? + id: + targetJson['id']?.toString() ?? targetJson['WP_RetailerID']?.toString() ?? targetJson['retailer_id']?.toString() ?? targetJson['RetailerID']?.toString() ?? @@ -388,10 +358,7 @@ class WalaPlusRetailerModel { } } - s = s - .replaceAll(r'\/', '/') - .replaceAll(r'\"', '"') - .replaceAll(r"\'", "'"); + s = s.replaceAll(r'\/', '/').replaceAll(r'\"', '"').replaceAll(r"\'", "'"); s = s.replaceAllMapped(RegExp(r'\\u([0-9a-fA-F]{4})'), (match) { try { @@ -600,10 +567,7 @@ class WalaPlusRetailerModel { } if (locations != null && locations!.isNotEmpty) { for (var loc in locations!) { - if (loc.contact != null && - loc.contact!.trim().isNotEmpty && - loc.contact != "null" && - !loc.contact!.contains('@')) { + if (loc.contact != null && loc.contact!.trim().isNotEmpty && loc.contact != "null" && !loc.contact!.contains('@')) { return loc.contact!.trim(); } } @@ -619,11 +583,12 @@ class WalaPlusRetailerModel { bool get isOnlineStore => (type?.trim().toLowerCase() == 'online'); - bool get isInstore => (type?.trim().toLowerCase() == 'instore' || - type?.trim().toLowerCase() == 'in_store' || - type?.trim().toLowerCase() == 'in store' || - type?.trim().toLowerCase() == 'store' || - (type == null && locations != null && locations!.isNotEmpty)); + bool get isInstore => + (type?.trim().toLowerCase() == 'instore' || + type?.trim().toLowerCase() == 'in_store' || + type?.trim().toLowerCase() == 'in store' || + type?.trim().toLowerCase() == 'store' || + (type == null && locations != null && locations!.isNotEmpty)); String? get normalizedType { if (type != null && type!.trim().isNotEmpty) { @@ -659,16 +624,7 @@ class WalaPlusRetailerContact { String? instagram; String? twitter; - WalaPlusRetailerContact({ - this.email, - this.emails, - this.phone, - this.phones, - this.website, - this.address, - this.instagram, - this.twitter, - }); + WalaPlusRetailerContact({this.email, this.emails, this.phone, this.phones, this.website, this.address, this.instagram, this.twitter}); factory WalaPlusRetailerContact.fromJson(Map json) { List emailsList = []; @@ -706,16 +662,7 @@ class WalaPlusRetailerContact { } Map toJson() { - return { - 'email': email, - 'emails': emails, - 'phone': phone, - 'phones': phones, - 'website': website, - 'address': address, - 'instagram': instagram, - 'twitter': twitter, - }; + return {'email': email, 'emails': emails, 'phone': phone, 'phones': phones, 'website': website, 'address': address, 'instagram': instagram, 'twitter': twitter}; } String? get primaryEmail { @@ -748,6 +695,7 @@ class WalaPlusRetailerLocation { String? contact; String? countryNameAr; String? countryNameEn; + String? distance; double? latitude; double? longitude; dynamic placeId; @@ -761,6 +709,7 @@ class WalaPlusRetailerLocation { this.contact, this.countryNameAr, this.countryNameEn, + this.distance, this.latitude, this.longitude, this.placeId, @@ -776,6 +725,7 @@ class WalaPlusRetailerLocation { contact: json['contact']?.toString(), countryNameAr: WalaPlusRetailerModel.decodeUnicodeString(json['country_name_ar']), countryNameEn: WalaPlusRetailerModel.decodeUnicodeString(json['country_name_en']), + distance: WalaPlusRetailerModel.decodeUnicodeString(json['distance']), latitude: json['latitude'] is num ? (json['latitude'] as num).toDouble() : double.tryParse(json['latitude']?.toString() ?? ''), longitude: json['longitude'] is num ? (json['longitude'] as num).toDouble() : double.tryParse(json['longitude']?.toString() ?? ''), placeId: json['place_id'], @@ -792,6 +742,7 @@ class WalaPlusRetailerLocation { data['contact'] = contact; data['country_name_ar'] = countryNameAr; data['country_name_en'] = countryNameEn; + data['distance'] = distance; data['latitude'] = latitude; data['longitude'] = longitude; data['place_id'] = placeId; @@ -840,18 +791,7 @@ class WalaPlusOfferModel { dynamic usage; String? expiredAt; - WalaPlusOfferModel({ - this.id, - this.retailerId, - this.title, - this.image, - this.imageThumb, - this.type, - this.description, - this.price, - this.usage, - this.expiredAt, - }); + WalaPlusOfferModel({this.id, this.retailerId, this.title, this.image, this.imageThumb, this.type, this.description, this.price, this.usage, this.expiredAt}); factory WalaPlusOfferModel.fromJson(Map json) { return WalaPlusOfferModel( diff --git a/lib/ui/landing/dashboard_screen_for_dependet.dart b/lib/ui/landing/dashboard_screen_for_dependet.dart index 344b2db..f6ad458 100644 --- a/lib/ui/landing/dashboard_screen_for_dependet.dart +++ b/lib/ui/landing/dashboard_screen_for_dependet.dart @@ -240,12 +240,14 @@ class _DashboardScreenForDependetState extends State try { String catParam = (targetCategoryId == "all" || targetCategoryId == "0") ? "" : targetCategoryId; - print("Fetching WalaPlus retailers: category='$catParam', page=1, per_page=$pageSize"); + String? offerTypeParam = OffersAndDiscountsApiClient.mapOfferTypeFilter(selectedTypeFilter); + print("Fetching WalaPlus retailers: category='$catParam', offerType='$offerTypeParam', page=1, per_page=$pageSize"); WalaPlusRetailersResponse? response = await OffersAndDiscountsApiClient().getWalaPlusRetailers( categoryId: catParam, page: 1, perPage: pageSize, geoLocation: isNearestOffers ? "24.9485,46.977" : null, + offerType: offerTypeParam, context: context, ); @@ -279,14 +281,16 @@ class _DashboardScreenForDependetState extends State try { int nextPage = currentPage + 1; String catParam = (currentCategoryId == "all" || currentCategoryId == "0") ? "" : currentCategoryId; + String? offerTypeParam = OffersAndDiscountsApiClient.mapOfferTypeFilter(selectedTypeFilter); - print("Fetching WalaPlus retailers next page: $nextPage of $totalPages, category: '$catParam'"); + print("Fetching WalaPlus retailers next page: $nextPage of $totalPages, category: '$catParam', offerType: '$offerTypeParam'"); WalaPlusRetailersResponse? response = await OffersAndDiscountsApiClient().getWalaPlusRetailers( categoryId: catParam, page: nextPage, perPage: pageSize, geoLocation: isNearestOffers ? "24.9485,46.977" : null, + offerType: offerTypeParam, context: context, ); @@ -320,22 +324,10 @@ class _DashboardScreenForDependetState extends State if (query != null) { searchQuery = query; } + // Type filtering (online/in store) is done server-side via WP_Offer_Type (see fetchOffers), + // so retailersList already reflects the selected type - only search is applied locally here. List temp = retailersList; - if (selectedTypeFilter != "all" && selectedTypeFilter.isNotEmpty) { - temp = - temp.where((WalaPlusRetailerModel item) { - String? norm = item.normalizedType; - if (selectedTypeFilter == "online") { - return norm == "online"; - } else if (selectedTypeFilter == "instore") { - return norm == "instore"; - } else { - return norm == selectedTypeFilter || (item.type?.trim().toLowerCase() == selectedTypeFilter); - } - }).toList(); - } - if (searchQuery.trim().isNotEmpty) { String q = searchQuery.trim().toLowerCase(); temp = @@ -604,7 +596,7 @@ class _DashboardScreenForDependetState extends State setState(() { selectedTypeFilter = typeKey; }); - _runFilter(); + fetchOffers(categoryId: currentCategoryId.isEmpty ? "all" : currentCategoryId); } }, child: Container( diff --git a/lib/ui/landing/wala_plus_retailer_details_screen.dart b/lib/ui/landing/wala_plus_retailer_details_screen.dart index 83db56e..a9c0cbb 100644 --- a/lib/ui/landing/wala_plus_retailer_details_screen.dart +++ b/lib/ui/landing/wala_plus_retailer_details_screen.dart @@ -839,6 +839,7 @@ class _WalaPlusRetailerDetailsScreenState extends State