diff --git a/assets/images/png/Apple_Pay.png b/assets/images/png/Apple_Pay.png new file mode 100644 index 0000000..1dc7504 Binary files /dev/null and b/assets/images/png/Apple_Pay.png differ diff --git a/assets/images/png/Mada.png b/assets/images/png/Mada.png new file mode 100644 index 0000000..905a5ba Binary files /dev/null and b/assets/images/png/Mada.png differ diff --git a/assets/images/png/Mastercard.png b/assets/images/png/Mastercard.png new file mode 100644 index 0000000..5d8b1fa Binary files /dev/null and b/assets/images/png/Mastercard.png differ diff --git a/assets/images/png/male_img.png b/assets/images/png/male_img.png new file mode 100644 index 0000000..21932cd Binary files /dev/null and b/assets/images/png/male_img.png differ diff --git a/assets/images/png/tamara_en.png b/assets/images/png/tamara_en.png new file mode 100644 index 0000000..84d85b2 Binary files /dev/null and b/assets/images/png/tamara_en.png differ diff --git a/assets/images/png/visa.png b/assets/images/png/visa.png new file mode 100644 index 0000000..3a6d90d Binary files /dev/null and b/assets/images/png/visa.png differ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 5249fe5..c62a44f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -41,11 +41,20 @@ PODS: - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter + - Firebase/Analytics (11.15.0): + - Firebase/Core + - Firebase/Core (11.15.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 11.15.0) - Firebase/CoreOnly (11.15.0): - FirebaseCore (~> 11.15.0) - Firebase/Messaging (11.15.0): - Firebase/CoreOnly - FirebaseMessaging (~> 11.15.0) + - firebase_analytics (11.6.0): + - Firebase/Analytics (= 11.15.0) + - firebase_core + - Flutter - firebase_core (3.15.2): - Firebase/CoreOnly (= 11.15.0) - Flutter @@ -53,6 +62,24 @@ PODS: - Firebase/Messaging (= 11.15.0) - firebase_core - Flutter + - FirebaseAnalytics (11.15.0): + - FirebaseAnalytics/Default (= 11.15.0) + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - FirebaseAnalytics/Default (11.15.0): + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleAppMeasurement/Default (= 11.15.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) - FirebaseCore (11.15.0): - FirebaseCoreInternal (~> 11.15.0) - GoogleUtilities/Environment (~> 8.1) @@ -371,14 +398,16 @@ SPEC CHECKSUMS: DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49 Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e + firebase_analytics: bf93e20703c95030404d6ddbb1adf05bf5c3885b firebase_core: 99a37263b3c27536063a7b601d9e2a49400a433c firebase_messaging: bf6697c61f31c7cc0f654131212ff04c0115c2c7 + FirebaseAnalytics: 6433dfd311ba78084fc93bdfc145e8cb75740eae FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09 FLAnimatedImage: bbf914596368867157cc71b38a8ec834b3eeb32b - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 flutter_ios_voip_kit_karmm: 7ea37381a8841c92d186edf1f4604df5cc437579 flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f @@ -387,6 +416,8 @@ SPEC CHECKSUMS: geolocator_apple: 66b711889fd333205763b83c9dcf0a57a28c7afd Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321 google_maps_flutter_ios: e31555a04d1986ab130f2b9f24b6cdc861acc6d3 + GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64 + GoogleAppMeasurement: 700dce7541804bec33db590a5c496b663fbe2539 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 @@ -423,4 +454,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 5df9d8aa8f2c105eacd5ad7a310503d93c68c86b -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index fbf63b2..92a7e6c 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -2,21 +2,25 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'dart:io' show Platform; + import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; +import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:http/http.dart' as http; +import '../exceptions/api_failure.dart'; + abstract class ApiClient { Future post( String endPoint, { required Map body, - required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, + required Function(dynamic response, int statusCode, {int? messageStatus}) onSuccess, + required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure, bool isAllowAny, bool isExternal, bool isRCService, @@ -32,61 +36,69 @@ abstract class ApiClient { bool isRCService, }); - Future simplePost( - String fullUrl, { - required Map body, - required Map headers, - required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, - }); - - Future simpleGet( - String fullUrl, { - Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - Map? queryParams, - Map? headers, - }); - - Future simplePut( - String fullUrl, { - Map? body, - Map? headers, - Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - }); - - Future simpleDelete( - String fullUrl, { - Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - Map? queryParams, - Map? headers, - }); - - Future handleUnauthorized(int statusCode, {required String forUrl}); - String getSessionId(String id); - Future generatePackagesToken(); +// Future simplePost( +// String fullUrl, { +// required Map body, +// required Map headers, +// required Function(dynamic response, int statusCode) onSuccess, +// required Function(String error, int statusCode) onFailure, +// }); + +// +// Future simpleGet( +// String fullUrl, { +// Function(dynamic response, int statusCode)? onSuccess, +// Function(String error, int statusCode)? onFailure, +// Map? queryParams, +// Map? headers, +// }); +// +// Future simplePut( +// String fullUrl, { +// Map? body, +// Map? headers, +// Function(dynamic response, int statusCode)? onSuccess, +// Function(String error, int statusCode)? onFailure, +// }); +// +// Future simpleDelete( +// String fullUrl, { +// Function(dynamic response, int statusCode)? onSuccess, +// Function(String error, int statusCode)? onFailure, +// Map? queryParams, +// Map? headers, +// }); + +// Future handleUnauthorized(int statusCode, {required String forUrl}); +// Future generatePackagesToken(); } class ApiClientImp implements ApiClient { final _analytics = getIt(); final LoggerService loggerService; + final AppState appState; + final DialogService dialogService; - ApiClientImp({required this.loggerService}); + ApiClientImp({ + required this.loggerService, + required this.dialogService, + required this.appState, + }); @override - post(String endPoint, - {required Map body, - required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, - bool isAllowAny = false, - bool isExternal = false, - bool isRCService = false, - bool bypassConnectionCheck = false}) async { + post( + String endPoint, { + required Map body, + required Function(dynamic response, int statusCode, {int? messageStatus}) onSuccess, + required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure, + bool isAllowAny = false, + bool isExternal = false, + bool isRCService = false, + bool bypassConnectionCheck = false, + }) async { AppState appState = getIt.get(); String url; if (isExternal) { @@ -103,7 +115,7 @@ class ApiClientImp implements ApiClient { Map headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}; if (!isExternal) { String? token = appState.appAuthToken; - String? languageID = (appState.postParamsObject?.languageID == 1 ? 'ar' : 'en') ?? 'ar'; + String? languageID = (appState.postParamsObject?.languageID == 1 ? 'ar' : 'en'); if (endPoint == ApiConsts.sendActivationCode) { languageID = 'en'; } @@ -113,7 +125,6 @@ class ApiClientImp implements ApiClient { if (body.containsKey('LanguageID')) { if (body['LanguageID'] != null) { - //change this line because language issue happened on dental body['LanguageID'] = body['LanguageID'] == 'ar' ? 1 : body['LanguageID'] == 'en' @@ -128,7 +139,6 @@ class ApiClientImp implements ApiClient { : IS_DENTAL_ALLOWED_BACKEND; } - //Todo: I have converted it to string body['DeviceTypeID'] = Platform.isIOS ? "1" @@ -160,40 +170,46 @@ class ApiClientImp implements ApiClient { } } - - body['LanguageID'] = body['LanguageID'] ?? "2"; - body['VersionID'] = body['VersionID'] ?? "18.7"; - body['Channel'] = body['Channel'] ?? "3"; - body['IPAdress'] = body['IPAdress'] ?? "10.20.10.20"; - body['generalid'] = body['generalid'] ?? "Cs2020@2016\$2958"; - body['Latitude'] = body['Latitude'] ?? "0.0"; - body['Longitude'] = body['Longitude'] ?? "0.0"; + // request.versionID = VERSION_ID; + // request.channel = CHANNEL; + // request.iPAdress = IP_ADDRESS; + // request.generalid = GENERAL_ID; + // request.languageID = (languageID == 'ar' ? 1 : 2); + // request.patientOutSA = (request.zipCode == '966' || request.zipCode == '+966') ? 0 : 1; + + // TODO : we will use all these from appState + body['LanguageID'] = body['LanguageID'] ?? "2"; + body['VersionID'] = body['VersionID'] ?? "18.7"; + body['Channel'] = body['Channel'] ?? "3"; + body['IPAdress'] = body['IPAdress'] ?? "10.20.10.20"; + body['generalid'] = body['generalid'] ?? "Cs2020@2016\$2958"; + body['Latitude'] = body['Latitude'] ?? "0.0"; + body['Longitude'] = body['Longitude'] ?? "0.0"; body['DeviceTypeID'] = body['DeviceTypeID'] ?? - - - (Platform.isIOS ? "1" : await Utils.isGoogleServicesAvailable() ? "2" : "3"); - //"LanguageID":1,"VersionID":18.7,"Channel":3,"IPAdress":"10.20.10.20","generalid":"Cs2020@2016$2958","Latitude":0.0,"Longitude":0.0,"DeviceTypeID":2,"PatientType":1} + (Platform.isIOS + ? "1" + : await Utils.isGoogleServicesAvailable() + ? "2" + : "3"); body.removeWhere((key, value) => value == null); - - log("bodi: ${json.encode(body)}"); - log("bodi: ${Uri.parse(url.trim())}"); + log("body: ${json.encode(body)}"); + log("uri: ${Uri.parse(url.trim())}"); if (await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck)) { - final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers); final int statusCode = response.statusCode; if (statusCode < 200 || statusCode >= 400) { - onFailure('Error While Fetching data', statusCode); + onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data")); logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); } else { - var parsed = json.decode(utf8.decode(response.bodyBytes)); + var parsed = json.decode(utf8.decode(response.bodyBytes)); log("parsed: ${parsed.toString()}"); if (isAllowAny) { onSuccess(parsed, statusCode); } else { if (parsed['Response_Message'] != null) { - onSuccess(parsed, statusCode); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); } else { if (parsed['ErrorType'] == 4) { //TODO : handle app update @@ -204,19 +220,18 @@ class ApiClientImp implements ApiClient { logApiEndpointError(endPoint, "session logged out", statusCode); } if (isAllowAny) { - onSuccess(parsed, statusCode); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); } else if (parsed['IsAuthenticated'] == null) { if (parsed['isSMSSent'] == true) { - onSuccess(parsed, statusCode); + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); } else if (parsed['MessageStatus'] == 1) { onSuccess(parsed, statusCode); } else if (parsed['Result'] == 'OK') { onSuccess(parsed, statusCode); } else { - - onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode, + failureType: ServerFailure("Error While Fetching data")); logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); - } } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { onSuccess(parsed, statusCode); @@ -226,28 +241,46 @@ class ApiClientImp implements ApiClient { } else { if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { if (parsed['ErrorSearchMsg'] == null) { - onFailure("Server Error found with no available message", statusCode); + onFailure( + "Server Error found with no available message", + statusCode, + failureType: ServerFailure("Error While Fetching data"), + ); logApiEndpointError(endPoint, "Server Error found with no available message", statusCode); } else { - onFailure(parsed['ErrorSearchMsg'], statusCode); + onFailure( + parsed['ErrorSearchMsg'], + statusCode, + failureType: ServerFailure("Error While Fetching data"), + ); logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode); } } else { - onFailure(parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + onFailure( + parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode, + failureType: ServerFailure("Error While Fetching data"), + ); logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); } } - } - - else { + } else { if (parsed['SameClinicApptList'] != null) { onSuccess(parsed, statusCode); } else { if (parsed['message'] != null) { - onFailure(parsed['message'] ?? parsed['message'], statusCode); + onFailure( + parsed['message'] ?? parsed['message'], + statusCode, + failureType: ServerFailure("Error While Fetching data"), + ); logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); } else { - onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + onFailure( + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode, + failureType: ServerFailure("Error While Fetching data"), + ); logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } @@ -256,13 +289,17 @@ class ApiClientImp implements ApiClient { } } } else { - onFailure('Please Check The Internet Connection 1', -1); + onFailure( + 'Please Check The Internet Connection 1', + -1, + failureType: ConnectivityFailure("Error While Fetching data"), + ); _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } catch (e) { loggerService.errorLogs(e.toString()); if (e.toString().contains("ClientException")) { - onFailure('Something went wrong, plase try again', -1); + onFailure('Something went wrong, plase try again', -1, failureType: InvalidCredentials('Something went wrong, plase try again')); _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } else { onFailure(e.toString(), -1); @@ -271,6 +308,7 @@ class ApiClientImp implements ApiClient { } } + @override get(String endPoint, {required Function(dynamic response, int statusCode) onSuccess, required Function(String error, int statusCode) onFailure, @@ -304,203 +342,173 @@ class ApiClientImp implements ApiClient { // print("statusCode :$statusCode"); if (statusCode < 200 || statusCode >= 400) { - onFailure!('Error While Fetching data', statusCode); + onFailure('Error While Fetching data', statusCode); logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); } else { var parsed = json.decode(utf8.decode(response.bodyBytes)); - onSuccess!(parsed, statusCode); - } - } else { - onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); - } - } - - simplePost( - String fullUrl, { - required Map body, - required Map headers, - required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, - }) async { - String url = fullUrl; - // print("URL Query String: $url"); - // print("body: $body"); - - if (await Utils.checkConnection()) { - headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); - final response = await http.post( - Uri.parse(url.trim()), - body: json.encode(body), - headers: headers, - ); - final int statusCode = response.statusCode; - // print("statusCode :$statusCode"); - if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simplePost(fullUrl, onFailure: onFailure, onSuccess: onSuccess, body: body, headers: headers); - - // print(response.body.toString()); - - if (statusCode < 200 || statusCode >= 400) { - onFailure!('Error While Fetching data', statusCode); - logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); - } else { - onSuccess!(response.body.toString(), statusCode); + onSuccess(parsed, statusCode); } } else { - onFailure!('Please Check The Internet Connection', -1); + onFailure('Please Check The Internet Connection', -1); _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } } - simpleGet(String fullUrl, - {Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - Map? queryParams, - Map? headers}) async { - headers = headers ?? {}; - String url = fullUrl; - - var haveParams = (queryParams != null); - if (haveParams) { - String queryString = Uri(queryParameters: queryParams).query; - url += '?$queryString'; - // print("URL Query String: $url"); - } - - if (await Utils.checkConnection()) { - headers.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); - final response = await http.get( - Uri.parse(url.trim()), - headers: headers, - ); - - final int statusCode = response.statusCode; - // print("statusCode :$statusCode"); - if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simpleGet(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, queryParams: queryParams); - - if (statusCode < 200 || statusCode >= 400) { - onFailure!('Error While Fetching data', statusCode); - logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); - } else { - onSuccess!(response.body.toString(), statusCode); - } - } else { - onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); - } - } - - simplePut(String fullUrl, - {Map? body, - Map? headers, - Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure}) async { - String url = fullUrl; - // print("URL Query String: $url"); - - if (await Utils.checkConnection()) { - headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); - final response = await http.put( - Uri.parse(url.trim()), - body: json.encode(body), - headers: headers, - ); - - final int statusCode = response.statusCode; - // print("statusCode :$statusCode"); - if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simplePut(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, body: body); - - if (statusCode < 200 || statusCode >= 400) { - onFailure!('Error While Fetching data', statusCode); - logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); - } else { - onSuccess!(response.body.toString(), statusCode); - } - } else { - onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); - } - } - - simpleDelete(String fullUrl, - {Function(dynamic response, int statusCode)? onSuccess, - Function(String error, int statusCode)? onFailure, - Map? queryParams, - Map? headers}) async { - String url = fullUrl; - // print("URL Query String: $url"); - - var haveParams = (queryParams != null); - if (haveParams) { - String queryString = Uri(queryParameters: queryParams).query; - url += '?$queryString'; - // print("URL Query String: $url"); - } - - if (await Utils.checkConnection()) { - headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); - final response = await http.delete( - Uri.parse(url.trim()), - headers: headers, - ); - - final int statusCode = response.statusCode; - // print("statusCode :$statusCode"); - if (await handleUnauthorized(statusCode, forUrl: fullUrl)) - simpleDelete(fullUrl, onFailure: onFailure, onSuccess: onSuccess, queryParams: queryParams, headers: headers); - - if (statusCode < 200 || statusCode >= 400) { - onFailure!('Error While Fetching data', statusCode); - logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); - } else { - onSuccess!(response.body.toString(), statusCode); - } - } else { - onFailure!('Please Check The Internet Connection', -1); - _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); - } - } - - Future handleUnauthorized(int statusCode, {required String forUrl}) async { - if (forUrl.startsWith(EXA_CART_API_BASE_URL) && statusCode == 401) { - final token = await generatePackagesToken(); - ApiConsts.packagesAuthHeader['Authorization'] = 'Bearer $token'; - return (token is String); - } - return false; - } + // @override + // simplePost( + // String fullUrl, { + // required Map body, + // required Map headers, + // required Function(dynamic response, int statusCode) onSuccess, + // required Function(String error, int statusCode) onFailure, + // }) async { + // String url = fullUrl; + // // print("URL Query String: $url"); + // // print("body: $body"); + // + // if (await Utils.checkConnection()) { + // headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); + // final response = await http.post( + // Uri.parse(url.trim()), + // body: json.encode(body), + // headers: headers, + // ); + // final int statusCode = response.statusCode; + // // print("statusCode :$statusCode"); + // if (await handleUnauthorized(statusCode, forUrl: fullUrl)) { + // simplePost(fullUrl, onFailure: onFailure, onSuccess: onSuccess, body: body, headers: headers); + // } + // + // // print(response.body.toString()); + // + // if (statusCode < 200 || statusCode >= 400) { + // onFailure!('Error While Fetching data', statusCode); + // logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); + // } else { + // onSuccess!(response.body.toString(), statusCode); + // } + // } else { + // onFailure!('Please Check The Internet Connection', -1); + // _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); + // } + // } + + // simpleGet(String fullUrl, + // {Function(dynamic response, int statusCode)? onSuccess, + // Function(String error, int statusCode)? onFailure, + // Map? queryParams, + // Map? headers}) async { + // headers = headers ?? {}; + // String url = fullUrl; + // + // var haveParams = (queryParams != null); + // if (haveParams) { + // String queryString = Uri(queryParameters: queryParams).query; + // url += '?$queryString'; + // // print("URL Query String: $url"); + // } + // + // if (await Utils.checkConnection()) { + // headers.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); + // final response = await http.get( + // Uri.parse(url.trim()), + // headers: headers, + // ); + // + // final int statusCode = response.statusCode; + // // print("statusCode :$statusCode"); + // if (await handleUnauthorized(statusCode, forUrl: fullUrl)) + // simpleGet(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, queryParams: queryParams); + // + // if (statusCode < 200 || statusCode >= 400) { + // onFailure!('Error While Fetching data', statusCode); + // logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); + // } else { + // onSuccess!(response.body.toString(), statusCode); + // } + // } else { + // onFailure!('Please Check The Internet Connection', -1); + // _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); + // } + // } + + // simplePut(String fullUrl, + // {Map? body, + // Map? headers, + // Function(dynamic response, int statusCode)? onSuccess, + // Function(String error, int statusCode)? onFailure}) async { + // String url = fullUrl; + // // print("URL Query String: $url"); + // + // if (await Utils.checkConnection()) { + // headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); + // final response = await http.put( + // Uri.parse(url.trim()), + // body: json.encode(body), + // headers: headers, + // ); + // + // final int statusCode = response.statusCode; + // // print("statusCode :$statusCode"); + // if (await handleUnauthorized(statusCode, forUrl: fullUrl)) + // simplePut(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, body: body); + // + // if (statusCode < 200 || statusCode >= 400) { + // onFailure!('Error While Fetching data', statusCode); + // logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); + // } else { + // onSuccess!(response.body.toString(), statusCode); + // } + // } else { + // onFailure!('Please Check The Internet Connection', -1); + // _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); + // } + // } + // + // simpleDelete(String fullUrl, + // {Function(dynamic response, int statusCode)? onSuccess, + // Function(String error, int statusCode)? onFailure, + // Map? queryParams, + // Map? headers}) async { + // String url = fullUrl; + // // print("URL Query String: $url"); + // + // var haveParams = (queryParams != null); + // if (haveParams) { + // String queryString = Uri(queryParameters: queryParams).query; + // url += '?$queryString'; + // // print("URL Query String: $url"); + // } + // + // if (await Utils.checkConnection()) { + // headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); + // final response = await http.delete( + // Uri.parse(url.trim()), + // headers: headers, + // ); + // + // final int statusCode = response.statusCode; + // // print("statusCode :$statusCode"); + // if (await handleUnauthorized(statusCode, forUrl: fullUrl)) + // simpleDelete(fullUrl, onFailure: onFailure, onSuccess: onSuccess, queryParams: queryParams, headers: headers); + // + // if (statusCode < 200 || statusCode >= 400) { + // onFailure!('Error While Fetching data', statusCode); + // logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode); + // } else { + // onSuccess!(response.body.toString(), statusCode); + // } + // } else { + // onFailure!('Please Check The Internet Connection', -1); + // _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); + // } + // } + @override String getSessionId(String id) { return id.replaceAll(RegExp('/[^a-zA-Z]'), ''); } - Future generatePackagesToken() async { - var url = EXA_CART_API_BASE_URL + PACKAGES_TOKEN; - var body = { - "api_client": { - "client_id": "a4ab6be4-424f-4836-b032-46caed88e184", - "client_secret": "3c1a3e07-4a40-4510-9fb0-ee5f0a72752c" - } - }; - String? token; - final completer = Completer(); - simplePost(url, body: body, headers: {}, onSuccess: (dynamic stringResponse, int statusCode) { - if (statusCode == 200) { - var jsonResponse = json.decode(stringResponse); - token = jsonResponse['auth_token']; - completer.complete(); - } - }, onFailure: (String error, int statusCode) { - completer.complete(); - logApiFullUrlError(url, error, statusCode); - }); - await completer.future; - return token!; - } - logApiFullUrlError(String fullUrl, error, code) { final endpoint = Uri.parse(fullUrl).pathSegments.last; logApiEndpointError(endpoint, error, code); diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index bfc1229..0e7d944 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -2,8 +2,6 @@ class AppAssets { static const String svgBasePath = 'assets/images/svg'; static const String pngBasePath = 'assets/images/png'; - - static const String hmg = '$svgBasePath/hmg.svg'; static const String arrow_back = '$svgBasePath/arrow-back.svg'; static const String calendar = '$svgBasePath/calendar.svg'; @@ -53,11 +51,25 @@ class AppAssets { static const String home_calendar_icon = '$svgBasePath/home_calendar_icon.svg'; static const String add_icon = '$svgBasePath/add_icon.svg'; static const String livecare_icon = '$svgBasePath/livecare_icon.svg'; + static const String file_icon = '$svgBasePath/file_icon.svg'; + static const String checkmark_icon = '$svgBasePath/checkmark_icon.svg'; + static const String blood_icon = '$svgBasePath/blood_icon.svg'; + static const String insurance_active_icon = '$svgBasePath/insurance_active_icon.svg'; + static const String saudi_riyal_icon = '$svgBasePath/Saudi_Riyal_Symbol.svg'; + static const String habib_background_icon = '$svgBasePath/habib_logo_background.svg'; + static const String show_icon = '$svgBasePath/show_icon.svg'; + static const String recharge_icon = '$svgBasePath/recharge_icon.svg'; // PNGS // static const String hmg_logo = '$pngBasePath/hmg_logo.png'; static const String livecare_service = '$pngBasePath/livecare_service.png'; + static const String male_img = '$pngBasePath/male_img.png'; + static const String apple_pay = '$pngBasePath/Apple_Pay.png'; + static const String mada = '$pngBasePath/Mada.png'; + static const String Mastercard = '$pngBasePath/Mastercard.png'; + static const String tamara_en = '$pngBasePath/tamara_en.png'; + static const String visa = '$pngBasePath/visa.png'; } class AppAnimations { @@ -65,5 +77,4 @@ class AppAnimations { static const String login = '$lottieBasePath/login.json'; static const String register = '$lottieBasePath/register.json'; static const String checkmark = '$lottieBasePath/checkmark.json'; - -} \ No newline at end of file +} diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index 91e200a..7c42042 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -1,15 +1,14 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:hmg_patient_app_new/core/post_params_model.dart'; -import 'package:hmg_patient_app_new/features/authentication/models/authenticated_user_model.dart'; -import 'package:hmg_patient_app_new/main.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'api_consts.dart' as ApiConsts; - class AppState { - // Simple constructor - let get_it handle the singleton behavior - AppState(); + NavigationService navigationService; + AppState({required this.navigationService}); bool isAuthenticated = true; @@ -40,9 +39,7 @@ class AppState { PostParamsModel? get postParamsObject => _postParams; - Map get postParamsJson => isAuthenticated - ? (_postParams?.toJsonAfterLogin() ?? {}) - : (_postParams?.toJson() ?? {}); + Map get postParamsJson => isAuthenticated ? (_postParams?.toJsonAfterLogin() ?? {}) : (_postParams?.toJson() ?? {}); void setPostParamsModel(PostParamsModel _postParams) { this._postParams = _postParams; @@ -51,12 +48,9 @@ class AppState { double userLat = 0.0; double userLong = 0.0; - bool isArabic() => - EasyLocalization.of(navigatorKey.currentContext!)?.locale.languageCode == - "ar"; + bool isArabic() => EasyLocalization.of(navigationService.navigatorKey.currentContext!)?.locale.languageCode == "ar"; - int getLanguageID(context) => - EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2; + int getLanguageID(context) => EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2; AuthenticatedUser? _authenticatedUser; diff --git a/lib/core/common_models/generic_api_model.dart b/lib/core/common_models/generic_api_model.dart new file mode 100644 index 0000000..1ab11db --- /dev/null +++ b/lib/core/common_models/generic_api_model.dart @@ -0,0 +1,34 @@ +class GenericApiModel { + final int? messageStatus; + final String? errorMessage; + final int? statusCode; + final T? data; + + GenericApiModel({ + this.messageStatus, + this.errorMessage, + this.statusCode, + this.data, + }); + + factory GenericApiModel.fromJson( + Map json, + T Function(Object? json)? fromJsonT, + ) { + return GenericApiModel( + messageStatus: json['messageStatus'] as int?, + errorMessage: json['errorMessage'] as String?, + statusCode: json['statusCode'] as int?, + data: fromJsonT != null ? fromJsonT(json['data']) : json['data'] as T?, + ); + } + + Map toJson(Object Function(T value)? toJsonT) { + return { + 'messageStatus': messageStatus, + 'errorMessage': errorMessage, + 'statusCode': statusCode, + 'data': toJsonT != null && data != null ? toJsonT(data as T) : data, + }; + } +} diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index 440cd26..549eeed 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -1,13 +1,18 @@ import 'package:get_it/get_it.dart'; import 'package:hmg_patient_app_new/core/api/api_client.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/location_util.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart'; +import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart'; import 'package:hmg_patient_app_new/features/common/common_repo.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; import 'package:hmg_patient_app_new/services/cache_service.dart'; +import 'package:hmg_patient_app_new/services/dialog_service.dart'; +import 'package:hmg_patient_app_new/services/error_handler_service.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:logger/web.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -15,25 +20,62 @@ GetIt getIt = GetIt.instance; class AppDependencies { static Future addDependencies() async { - // Services - getIt.registerLazySingleton(() => LoggerServiceImp(logger: Logger(printer: PrettyPrinter( - methodCount: 2, // number of stack trace lines - errorMethodCount: 5, // number of stack trace lines for errors - lineLength: 100, // wrap width - colors: true, // colorful logs - printEmojis: true, // include emojis - ),))); + Logger logger = Logger( + printer: PrettyPrinter( + methodCount: 2, + errorMethodCount: 5, + lineLength: 100, + colors: true, + printEmojis: true, + ), + ); + + // Core Services + getIt.registerLazySingleton(() => LoggerServiceImp(logger: logger)); + getIt.registerLazySingleton(() => NavigationService()); + getIt.registerLazySingleton(() => GAnalytics()); + getIt.registerLazySingleton(() => AppState(navigationService: getIt())); + getIt.registerLazySingleton(() => LocationUtils( + isShowConfirmDialog: false, + navigationService: getIt(), + appState: getIt(), + )); + getIt.registerLazySingleton(() => DialogServiceImp(navigationService: getIt())); + getIt.registerLazySingleton(() => ErrorHandlerServiceImp( + dialogService: getIt(), + loggerService: getIt(), + navigationService: getIt(), + )); + final sharedPreferences = await SharedPreferences.getInstance(); getIt.registerLazySingleton(() => CacheServiceImp(sharedPreferences: sharedPreferences)); - getIt.registerSingleton(AppState()); - getIt.registerSingleton(GAnalytics()); - getIt.registerLazySingleton(() => ApiClientImp(loggerService: getIt())); + getIt.registerLazySingleton(() => ApiClientImp(loggerService: getIt(), dialogService: getIt(), appState: getIt())); // Repositories getIt.registerLazySingleton(() => CommonRepoImp(loggerService: getIt())); getIt.registerLazySingleton(() => AuthenticationRepoImp(loggerService: getIt(), apiClient: getIt())); - getIt.registerLazySingleton(() => BookAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt())); + getIt.registerLazySingleton( + () => BookAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton(() => MyAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt())); + // ViewModels + // Global/shared VMs → LazySingleton + getIt.registerLazySingleton( + () => AuthenticationViewModel( + authenticationRepo: getIt(), + dialogService: getIt(), + appState: getIt(), + errorHandlerService: getIt(), + ), + ); + + // Screen-specific VMs → Factory + // getIt.registerFactory( + // () => BookAppointmentsViewModel( + // bookAppointmentsRepo: getIt(), + // dialogService: getIt(), + // errorHandlerService: getIt(), + // ), + // ); } } diff --git a/lib/core/enums.dart b/lib/core/enums.dart index db758f3..2fd5867 100644 --- a/lib/core/enums.dart +++ b/lib/core/enums.dart @@ -5,7 +5,7 @@ // unverified, // } -enum AuthMethodTypes { +enum AuthMethodTypesEnum { sms, whatsApp, fingerPrint, @@ -13,7 +13,7 @@ enum AuthMethodTypes { moreOptions, } -enum ViewState { +enum ViewStateEnum { hide, idle, busy, @@ -22,20 +22,44 @@ enum ViewState { errorLocal, } -enum LoginType { +enum LoginTypeEnum { fromLogin, silentLogin, silentWithOTP, } -enum OTPType { sms, whatsapp } +enum OTPTypeEnum { sms, whatsapp } -enum Country { saudiArabia, unitedArabEmirates } +enum CountryEnum { saudiArabia, unitedArabEmirates } -enum SelectionType { dropdown, calendar } +enum SelectionTypeEnum { dropdown, calendar } -enum GenderType { male, female } +enum GenderTypeEnum { male, female } -enum MaritalStatusType { single, married, divorced, widowed } +enum MaritalStatusTypeEnum { single, married, divorced, widowed } -enum ChipType { success, error, alert, info, warning } +enum ChipTypeEnum { success, error, alert, info, warning } + +extension OTPTypeEnumExtension on OTPTypeEnum { + /// Convert enum to int + int toInt() { + switch (this) { + case OTPTypeEnum.sms: + return 1; + case OTPTypeEnum.whatsapp: + return 2; + } + } + + /// Convert int to enum + static OTPTypeEnum fromInt(int value) { + switch (value) { + case 1: + return OTPTypeEnum.sms; + case 2: + return OTPTypeEnum.whatsapp; + default: + throw Exception("Invalid OTPTypeEnum value: $value"); + } + } +} diff --git a/lib/core/exceptions/api_failure.dart b/lib/core/exceptions/api_failure.dart index eaa434e..4bc5097 100644 --- a/lib/core/exceptions/api_failure.dart +++ b/lib/core/exceptions/api_failure.dart @@ -1,8 +1,8 @@ - import 'package:equatable/equatable.dart'; abstract class Failure extends Equatable implements Exception { final String message; + const Failure(this.message); } @@ -13,6 +13,13 @@ class ServerFailure extends Failure { List get props => [message]; } +class StatusCodeFailure extends Failure { + const StatusCodeFailure(super.message); + + @override + List get props => [message]; +} + class ConnectivityFailure extends Failure { const ConnectivityFailure(super.message); @@ -27,16 +34,33 @@ class LocalStorageFailure extends Failure { List get props => [message]; } +class DataParsingFailure extends Failure { + const DataParsingFailure(super.message); + + @override + List get props => [message]; +} + +class UnknownFailure extends Failure { + const UnknownFailure(super.message); + + @override + List get props => [message]; +} + + class DuplicateUsername extends Failure { - const DuplicateUsername({String? message}) : super(message ?? ''); + const DuplicateUsername(String? message) : super(message ?? ''); @override List get props => [message]; } class InvalidCredentials extends Failure { - const InvalidCredentials({String? message}) : super(message ?? ''); + const InvalidCredentials(String? message) : super(message ?? ''); @override List get props => [message]; } + + diff --git a/lib/core/location_util.dart b/lib/core/location_util.dart index d9716a9..dc6a0d6 100644 --- a/lib/core/location_util.dart +++ b/lib/core/location_util.dart @@ -1,41 +1,40 @@ import 'dart:io'; +import 'package:geolocator/geolocator.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/consts.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:geolocator/geolocator.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; - -// import 'package:huawei_location/huawei_location.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:provider/provider.dart'; class LocationUtils { + NavigationService navigationService; + AppState appState; + bool isShowConfirmDialog; bool isShowLocationTimeoutDialog; - BuildContext context; bool isHuawei; final GeolocatorPlatform _geolocatorPlatform = GeolocatorPlatform.instance; - LocationUtils({required this.isShowConfirmDialog, required this.context, this.isHuawei = false, this.isShowLocationTimeoutDialog = true}); + LocationUtils({ + required this.isShowConfirmDialog, + required this.navigationService, + required this.appState, + this.isHuawei = false, + this.isShowLocationTimeoutDialog = true, + }); void getCurrentLocation({Function(LatLng)? callBack}) async { Geolocator.isLocationServiceEnabled().then((value) async { if (value) { await Geolocator.checkPermission().then((permission) async { if (permission == LocationPermission.always || permission == LocationPermission.whileInUse) { - // Geolocator.getCurrentPosition(locationSettings: LocationSettings(accuracy: LocationAccuracy.medium, timeLimit: Duration(seconds: 5))).then((value) { Geolocator.getLastKnownPosition().then((value) { setLocation(value); if (callBack != null) callBack(LatLng(value?.latitude ?? 24.7101433, value?.longitude ?? 46.6757709)); }).catchError((err) { - print(err); - if (isShowConfirmDialog && isShowLocationTimeoutDialog) { - // showLocationTimeOutDialog(failureCallBack: () { - // Geolocator.openAppSettings(); - // }); - } + if (isShowConfirmDialog && isShowLocationTimeoutDialog) {} }); } @@ -62,15 +61,11 @@ class LocationUtils { } } } - }).catchError((err) { - print(err); - }); + }).catchError((err) {}); } else { if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {}); } - }).catchError((err) { - print(err); - }); + }).catchError((err) {}); } Future checkIfGPSIsEnabled() async { @@ -151,8 +146,8 @@ class LocationUtils { Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, position?.latitude ?? 0.0); Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, position?.longitude ?? 0.0); - AppState().setUserLat = position?.latitude ?? 0.0; - AppState().setUserLong = position?.longitude ?? 0.0; + appState.setUserLat = position?.latitude ?? 0.0; + appState.setUserLong = position?.longitude ?? 0.0; // projectViewModel.setLatitudeLongitude(position?.latitude ?? 0.0, position?.longitude ?? 0.0); } @@ -161,8 +156,8 @@ class LocationUtils { Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, 0.0); Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, 0.0); - AppState().setUserLat = 0.0; - AppState().setUserLong = 0.0; + appState.setUserLat = 0.0; + appState.setUserLong = 0.0; } Future requestPermissions() async { diff --git a/lib/core/utils/CalendarUtils.dart b/lib/core/utils/calendar_utils.dart similarity index 100% rename from lib/core/utils/CalendarUtils.dart rename to lib/core/utils/calendar_utils.dart diff --git a/lib/core/utils/LocalNotification.dart b/lib/core/utils/local_notifications.dart similarity index 100% rename from lib/core/utils/LocalNotification.dart rename to lib/core/utils/local_notifications.dart diff --git a/lib/core/utils/push-notification-handler.dart b/lib/core/utils/push_notification_handler.dart similarity index 97% rename from lib/core/utils/push-notification-handler.dart rename to lib/core/utils/push_notification_handler.dart index d71bdcf..b5a816e 100644 --- a/lib/core/utils/push-notification-handler.dart +++ b/lib/core/utils/push_notification_handler.dart @@ -3,19 +3,17 @@ import 'dart:developer'; import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; -import 'package:firebase_messaging/firebase_messaging.dart'; -import 'package:firebase_messaging/firebase_messaging.dart' as fir; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart' as fir; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; // import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; -import 'package:hmg_patient_app_new/core/utils/LocalNotification.dart'; +import 'package:hmg_patient_app_new/core/utils/local_notifications.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:uuid/uuid.dart'; import '../consts.dart'; @@ -365,7 +363,9 @@ class PushNotificationHandler { Future requestPermissions() async { try { if (Platform.isIOS) { - await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation() + ?.requestPermissions(alert: true, badge: true, sound: true); } else if (Platform.isAndroid) { Map statuses = await [ Permission.notification, diff --git a/lib/core/utils/request_utils.dart b/lib/core/utils/request_utils.dart new file mode 100644 index 0000000..1869923 --- /dev/null +++ b/lib/core/utils/request_utils.dart @@ -0,0 +1,91 @@ +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/request_models/send_activation_request_model.dart'; + +class RequestUtils { + static dynamic getCommonRequestWelcome({ + required String phoneNumber, + required OTPTypeEnum otpTypeEnum, + required String? deviceToken, + required bool patientOutSA, + required String? loginTokenID, + required var registeredData, + required int? patientId, + required String nationIdText, + required String countryCode, + }) { + bool fileNo = false; + if (nationIdText.isNotEmpty) { + fileNo = nationIdText.length < 10; + } + var request = SendActivationRequest(); + request.patientMobileNumber = int.parse(phoneNumber); + request.mobileNo = '0$phoneNumber'; + request.deviceToken = deviceToken; + request.projectOutSA = patientOutSA; + request.loginType = otpTypeEnum.toInt(); + request.oTPSendType = otpTypeEnum.toInt(); // could map OTPTypeEnum if needed + request.zipCode = countryCode; // or countryCode if defined elsewhere + request.logInTokenID = loginTokenID ?? ""; + + if (registeredData != null) { + request.searchType = registeredData.searchType ?? 1; + request.patientID = registeredData.patientID ?? 0; + request.patientIdentificationID = request.nationalID = registeredData.patientIdentificationID ?? '0'; + request.dob = registeredData.dob; + request.isRegister = registeredData.isRegister; + } else { + if (fileNo) { + request.patientID = patientId ?? int.parse(nationIdText); + request.patientIdentificationID = request.nationalID = ""; + request.searchType = 2; + } else { + request.patientID = 0; + request.searchType = 1; + request.patientIdentificationID = request.nationalID = nationIdText.isNotEmpty ? nationIdText : '0'; + } + request.isRegister = false; + } + + request.deviceTypeID = request.searchType; + return request; + } + + static getCommonRequestAuthProvider({ + required OTPTypeEnum otpTypeEnum, + required registeredData, + required deviceToken, + required mobileNumber, + required zipCode, + required patientOutSA, + required loginTokenID, + required selectedOption, + required int? patientId, + }) { + var request = SendActivationRequest(); + request.patientMobileNumber = mobileNumber; + request.mobileNo = '0$mobileNumber'; + request.deviceToken = deviceToken; + request.projectOutSA = patientOutSA == true ? true : false; + request.loginType = selectedOption; + request.oTPSendType = otpTypeEnum.toInt(); //this.selectedOption == 1 ? 1 : 2; + request.zipCode = zipCode; + + request.logInTokenID = loginTokenID ?? ""; + + if (registeredData != null) { + request.searchType = registeredData.searchType ?? 1; + request.patientID = registeredData.patientID ?? 0; + request.patientIdentificationID = request.nationalID = registeredData.patientIdentificationID ?? '0'; + request.dob = registeredData.dob; + request.isRegister = registeredData.isRegister; + } else { + request.searchType = request.searchType ?? 2; + request.patientID = patientId ?? 0; + request.nationalID = request.nationalID ?? '0'; + request.patientIdentificationID = request.patientIdentificationID ?? '0'; + request.isRegister = false; + } + request.deviceTypeID = request.searchType; + return request; + } +} diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index 4f7b398..bdca5ff 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -1,24 +1,29 @@ import 'dart:convert'; -import 'package:crypto/crypto.dart' as crypto; import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:crypto/crypto.dart' as crypto; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:google_api_availability/google_api_availability.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; -import 'package:hmg_patient_app_new/main.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/dialogs/confirm_dialog.dart'; import 'package:hmg_patient_app_new/widgets/loading_dialog.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:lottie/lottie.dart'; import 'package:shared_preferences/shared_preferences.dart'; class Utils { + static AppState appState = getIt.get(); + static NavigationService navigationService = getIt.get(); + static bool _isLoadingVisible = false; static bool get isLoading => _isLoadingVisible; @@ -47,14 +52,16 @@ class Utils { } static String getFreeSlotsTimeText(String startTime, {bool isAddHours = false}) { - // return DateFormat('hh:mm a', AppState().isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime)!.add( + // return DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime)!.add( // Duration( // hours: isAddHours ? 3 : 0, // ), // )); return !isAddHours - ? DateFormat('hh:mm a', AppState().isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.toLocal()) - : DateFormat('hh:mm a', AppState().isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.add( + ? DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US") + .format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.toLocal()) + : DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US") + .format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.add( Duration( hours: isAddHours ? 3 : 0, ), @@ -82,12 +89,9 @@ class Utils { } static String getMonthDayYearDateFormatted(DateTime dateTime) { - if (dateTime != null) - return AppState().isArabic() - ? getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString() - : getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString(); - else - return ""; + return appState.isArabic() + ? getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString() + : getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString(); } /// get month by @@ -200,7 +204,7 @@ class Utils { static void showLoadingDialog() { _isLoadingVisible = true; showDialog( - context: navigatorKey.currentContext!, + context: navigationService.navigatorKey.currentContext!, barrierColor: Colors.black.withOpacity(0.5), builder: (BuildContext context) => LoadingDialog(), ) @@ -217,7 +221,7 @@ class Utils { try { if (_isLoadingVisible) { _isLoadingVisible = false; - Navigator.of(navigatorKey.currentContext!).pop(); + Navigator.of(navigationService.navigatorKey.currentContext!).pop(); } _isLoadingVisible = false; } catch (e) {} @@ -242,9 +246,6 @@ class Utils { static bool isSAUDIIDValid(String id, type) { if (type == 1) { - if (id == null) { - return false; - } try { id = id.toString(); id = id.trim(); @@ -304,13 +305,15 @@ class Utils { } static String removeHtmlTags(String htmlString) { - if (htmlString == null || htmlString.isEmpty) { + if (htmlString.isEmpty) { return ''; } // Replace HTML line breaks with newlines - var withLineBreaks = - htmlString.replaceAll(RegExp(r'', multiLine: true), '\n').replaceAll(RegExp(r'<\/p>', multiLine: true), '\n').replaceAll(RegExp(r'', multiLine: true), '\n'); + var withLineBreaks = htmlString + .replaceAll(RegExp(r'', multiLine: true), '\n') + .replaceAll(RegExp(r'<\/p>', multiLine: true), '\n') + .replaceAll(RegExp(r'', multiLine: true), '\n'); // Remove all other HTML tags var withoutTags = withLineBreaks.replaceAll(RegExp(r'<[^>]*>'), ''); @@ -376,7 +379,20 @@ class Utils { final year = parts[0]; // Map month number to short month name (Hijri months) - const hijriMonthNames = ['Muharram', 'Safar', 'Rabi I', 'Rabi II', 'Jumada I', 'Jumada II', 'Rajab', 'Sha\'ban', 'Ramadan', 'Shawwal', 'Dhu al-Qi\'dah', 'Dhu al-Hijjah']; + const hijriMonthNames = [ + 'Muharram', + 'Safar', + 'Rabi I', + 'Rabi II', + 'Jumada I', + 'Jumada II', + 'Rajab', + 'Sha\'ban', + 'Ramadan', + 'Shawwal', + 'Dhu al-Qi\'dah', + 'Dhu al-Hijjah' + ]; final monthIndex = int.tryParse(parts[1]) ?? 1; final month = hijriMonthNames[monthIndex - 1]; @@ -458,13 +474,21 @@ class Utils { ); } - - - + static Widget getPaymentMethods() { + return Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Image.asset(AppAssets.mada, width: 25, height: 25), + Image.asset(AppAssets.tamara_en, width: 25, height: 25), + Image.asset(AppAssets.visa, width: 25, height: 25), + Image.asset(AppAssets.Mastercard, width: 25, height: 25), + Image.asset(AppAssets.apple_pay, width: 25, height: 25), + ], + ); + } static Future isGoogleServicesAvailable() async { - GooglePlayServicesAvailability availability = await GoogleApiAvailability - .instance - .checkGooglePlayServicesAvailability(); + GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability(); String status = availability.toString().split('.').last; if (status == "success") { return true; @@ -472,26 +496,17 @@ class Utils { return false; } - - - - - static Future checkConnection( - {bool bypassConnectionCheck = false}) async { + static Future checkConnection({bool bypassConnectionCheck = false}) async { if (bypassConnectionCheck) return true; - List connectivityResult = - await (Connectivity().checkConnectivity()); - if (connectivityResult.contains(ConnectivityResult.mobile) || - connectivityResult.contains(ConnectivityResult.wifi)) { + List connectivityResult = await (Connectivity().checkConnectivity()); + if (connectivityResult.contains(ConnectivityResult.mobile) || connectivityResult.contains(ConnectivityResult.wifi)) { return true; } else { return false; } } - static String generateMd5Hash(String input) { return crypto.md5.convert(utf8.encode(input)).toString(); } - } diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 8b8c796..e6913d2 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -193,33 +193,33 @@ Widget widthSpacer5per() => SizedBox(height: 5.w); -extension ChipTypeExtension on ChipType { +extension ChipTypeEnumExtension on ChipTypeEnum { Color get color { switch (this) { - case ChipType.success: + case ChipTypeEnum.success: return AppColors.successColor; // Replace with your actual color - case ChipType.error: + case ChipTypeEnum.error: return AppColors.errorColor; // Replace with your actual color - case ChipType.alert: + case ChipTypeEnum.alert: return AppColors.alertColor; // Replace with your actual color - case ChipType.info: + case ChipTypeEnum.info: return AppColors.infoColor; // Replace with your actual color - case ChipType.warning: + case ChipTypeEnum.warning: return AppColors.warningColor; // Replace with your actual color } } Color get backgroundColor { switch (this) { - case ChipType.success: + case ChipTypeEnum.success: return AppColors.successLightColor; // Replace with your actual color - case ChipType.error: + case ChipTypeEnum.error: return AppColors.errorLightColor; // Replace with your actual color - case ChipType.alert: + case ChipTypeEnum.alert: return AppColors.alertLightColor; // Replace with your actual color - case ChipType.info: + case ChipTypeEnum.info: return AppColors.infoLightColor; // Replace with your actual color - case ChipType.warning: + case ChipTypeEnum.warning: return AppColors.warningLightColor; // Replace with your actual color } } diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index e544638..7307013 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -1,16 +1,27 @@ import 'dart:async'; -import 'dart:developer'; +import 'dart:io'; import 'package:dartz/dartz.dart'; import 'package:hmg_patient_app_new/core/api/api_client.dart'; import 'package:hmg_patient_app_new/core/api_consts.dart'; -import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; +import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; -import 'package:hmg_patient_app_new/features/authentication/models/select_device_by_imei.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/request_models/check_patient_authentication_request_model.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/check_activation_code_resp_model.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/select_device_by_imei.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; abstract class AuthenticationRepo { - Future> selectDeviceByImei({required String firebaseToken}); + Future>> selectDeviceByImei({ + required String firebaseToken, + }); + + Future>> checkPatientAuthentication({ + required CheckPatientAuthenticationReq checkPatientAuthenticationReq, + }); + + Future>> sendActivationCodeRegister( + {required CheckPatientAuthenticationReq checkPatientAuthenticationReq, String? languageID}); } class AuthenticationRepoImp implements AuthenticationRepo { @@ -20,38 +31,130 @@ class AuthenticationRepoImp implements AuthenticationRepo { AuthenticationRepoImp({required this.loggerService, required this.apiClient}); @override - Future> selectDeviceByImei({ - required String firebaseToken, - }) async { + Future>> selectDeviceByImei({required String firebaseToken}) async { final mapDevice = {"IMEI": firebaseToken}; try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + ApiConsts.selectDeviceImei, + body: mapDevice, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus}) { + try { + final list = response['Patient_SELECTDeviceIMEIbyIMEIList']; + if (list == null || list.isEmpty) { + throw Exception("Device list is empty"); + } - final completer = Completer>(); - await apiClient.post( - ApiConsts.selectDeviceImei, - body: mapDevice, - onSuccess: (response, statusCode) { - try { - final SelectDeviceByImeiRespModelElement model = - SelectDeviceByImeiRespModelElement.fromJson(response['Patient_SELECTDeviceIMEIbyIMEIList'][0]); - completer.complete(Right(model)); - } catch (e) { - completer.complete(Left(ServerFailure(e.toString()))); - } - }, - onFailure: (error, statusCode) { - loggerService.logInfo(("$error - $statusCode").toString()); - completer.complete(Left(ServerFailure(error))); - }, - ); - - return await completer.future; - } on APIException catch (e) { - loggerService.errorLogs(e.toString()); - return Left(ServerFailure(e.message)); + final model = SelectDeviceByImeiRespModelElement.fromJson(list[0] as Map); + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: model, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } + + @override + Future>> checkPatientAuthentication({ + required CheckPatientAuthenticationReq checkPatientAuthenticationReq, + String? languageID, + }) async { + int isOutKsa = (checkPatientAuthenticationReq.zipCode == '966' || checkPatientAuthenticationReq.zipCode == '+966') ? 0 : 1; + //TODO : We will use all these from AppState directly in the ApiClient + + checkPatientAuthenticationReq.versionID = VERSION_ID; + checkPatientAuthenticationReq.channel = CHANNEL; + checkPatientAuthenticationReq.iPAdress = IP_ADDRESS; + checkPatientAuthenticationReq.generalid = GENERAL_ID; + checkPatientAuthenticationReq.languageID = (languageID == 'ar' ? 1 : 2); + checkPatientAuthenticationReq.patientOutSA = isOutKsa; + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + ApiConsts.selectDeviceImei, + body: checkPatientAuthenticationReq.toJson(), + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: response, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } + + @override + Future>> sendActivationCodeRegister( + {required CheckPatientAuthenticationReq checkPatientAuthenticationReq, String? languageID}) async { + int isOutKsa = (checkPatientAuthenticationReq.zipCode == '966' || checkPatientAuthenticationReq.zipCode == '+966') ? 0 : 1; + //TODO : We will use all these from AppState directly in the ApiClient + + checkPatientAuthenticationReq.versionID = VERSION_ID; + checkPatientAuthenticationReq.channel = CHANNEL; + checkPatientAuthenticationReq.iPAdress = IP_ADDRESS; + checkPatientAuthenticationReq.generalid = GENERAL_ID; + checkPatientAuthenticationReq.languageID = (languageID == 'ar' ? 1 : 2); + checkPatientAuthenticationReq.deviceTypeID = Platform.isIOS ? 1 : 2; + checkPatientAuthenticationReq.patientOutSA = isOutKsa; + checkPatientAuthenticationReq.isDentalAllowedBackend = false; + + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + SEND_ACTIVATION_CODE_REGISTER, + body: checkPatientAuthenticationReq.toJson(), + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: CheckActivationCode.fromJson(response), + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); } catch (e) { - loggerService.errorLogs(e.toString()); - return Left(ServerFailure(e.toString())); + return Left(UnknownFailure(e.toString())); } } } diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index 8269c72..ed77aca 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -1,47 +1,135 @@ -import 'dart:developer'; -import 'dart:io'; - import 'package:flutter/material.dart'; -import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; -import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/core/utils/request_utils.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart'; -import 'package:hmg_patient_app_new/features/authentication/models/check_activation_code_request_register.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/request_models/check_patient_authentication_request_model.dart'; +import 'package:hmg_patient_app_new/services/dialog_service.dart'; +import 'package:hmg_patient_app_new/services/error_handler_service.dart'; class AuthenticationViewModel extends ChangeNotifier { AuthenticationRepo authenticationRepo; AppState appState; + ErrorHandlerService errorHandlerService; + DialogService dialogService; AuthenticationViewModel({ required this.appState, required this.authenticationRepo, + required this.errorHandlerService, + required this.dialogService, }); final TextEditingController nationalIdController = TextEditingController(); final TextEditingController phoneNumberController = TextEditingController(); - Future selectDeviceImei({ - Function(dynamic)? onSuccess, - Function(String)? onError - }) async { - final String firebaseToken = - "cIkkB7h7Q7uoFkC4Qv82xG:APA91bEb53Z9XzqymCIctaLxCoMX6bm9fuKlWILQ59uUqfwhCoD42AOP1-jWGB1WYd9BVN5PT2pUUFxrT07vcNg1KH9OH39mrPgCl0m21XVIgWrzNnCkufg"; - - final resultEither = - await authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken); + Future selectDeviceImei({Function(dynamic)? onSuccess, Function(String)? onError}) async { + String firebaseToken = + "dOGRRszQQMGe_9wA5Hx3kO:APA91bFV5IcIJXvcCXXk0tc2ddtZgWwCPq7sGSuPr-YW7iiJpQZKgFGN9GAzCVOWL8MfheaP1slE8MdxB7lczdPBGdONQ7WbMmhgHcsUCUktq-hsapGXXqc"; + final result = await authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken); - resultEither.fold( - (failure) { - notifyListeners(); - if (onError != null) onError(failure.message); - }, - (data) { - - log("resultEither: ${data.toString()} "); - - notifyListeners(); - if (onSuccess != null) onSuccess(data); + result.fold( + (failure) async => await errorHandlerService.handleError(failure: failure), + (apiResponse) { + if (apiResponse.messageStatus == 2) { + dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + //todo: move to next api call + } }, ); } + + // Future checkUserAuthentication({Function(dynamic)? onSuccess, Function(String)? onError}) async { + // CheckPatientAuthenticationReq checkPatientAuthenticationReq = RequestUtils.getCommonRequestWelcome( + // phoneNumber: '0567184134', + // otpTypeEnum: OTPTypeEnum.sms, + // deviceToken: 'dummyDeviceToken123', + // patientOutSA: true, + // loginTokenID: 'dummyLoginToken456', + // registeredData: null, + // patientId: 12345, + // nationIdText: '1234567890', + // countryCode: 'SA', + // ); + // + // final result = await authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq); + // result.fold( + // (failure) async => await errorHandlerService.handleError(failure: failure), + // (apiResponse) { + // if (apiResponse.data['isSMSSent']) { + // // TODO: set this in AppState + // // sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']); + // // loginTokenID = value['LogInTokenID'], + // // sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), + // sendActivationCode(type); + // } else { + // if (apiResponse.data['IsAuthenticated']) { + // checkActivationCode(onWrongActivationCode: (String? message) {}); + // } + // } + // }, + // ); + // } + + // Future sendActivationCode({required OTPTypeEnum otpTypeEnum}) async { + // var request = RequestUtils.getCommonRequestAuthProvider( + // otpTypeEnum: otpTypeEnum, + // registeredData: null, + // deviceToken: "dummyLoginToken456", + // mobileNumber: "0567184134", + // zipCode: "SA", + // patientOutSA: true, + // loginTokenID: "dummyLoginToken456", + // selectedOption: selectedOption, + // patientId: 12345, + // ); + // + // request.sMSSignature = await SMSOTP.getSignature(); + // selectedOption = type; + // // GifLoaderDialogUtils.showMyDialog(context); + // if (healthId != null || isDubai) { + // if (!isDubai) { + // request.dob = dob; //isHijri == 1 ? dob : dateFormat2.format(dateFormat.parse(dob)); + // } + // request.healthId = healthId; + // request.isHijri = isHijri; + // await this.apiClient.sendActivationCodeRegister(request).then((result) { + // // GifLoaderDialogUtils.hideDialog(context); + // if (result != null && result['isSMSSent'] == true) { + // this.startSMSService(type); + // } + // }).catchError((r) { + // GifLoaderDialogUtils.hideDialog(context); + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: r.toString(), + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // )); + // // AppToast.showErrorToast(message: r); + // }); + // } else { + // request.dob = ""; + // request.healthId = ""; + // request.isHijri = 0; + // await this.authService.sendActivationCode(request).then((result) { + // GifLoaderDialogUtils.hideDialog(context); + // if (result != null && result['isSMSSent'] == true) { + // this.startSMSService(type); + // } + // }).catchError((r) { + // GifLoaderDialogUtils.hideDialog(context); + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: r.toString(), + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // )); + // // AppToast.showErrorToast(message: r.toString()); + // }); + // } + // } } diff --git a/lib/features/authentication/models/check_activation_code_request_register.dart b/lib/features/authentication/models/check_activation_code_request_register.dart deleted file mode 100644 index 85e1f56..0000000 --- a/lib/features/authentication/models/check_activation_code_request_register.dart +++ /dev/null @@ -1,121 +0,0 @@ -class CheckActivationCodeRegisterReq { - int? patientMobileNumber; - String? mobileNo; - String? deviceToken; - bool? projectOutSA; - int? loginType; - String? zipCode; - bool? isRegister; - String? logInTokenID; - int? searchType; - int? patientID; - String? nationalID; - String? patientIdentificationID; - String? activationCode; - bool? isSilentLogin; - double? versionID; - int? channel; - int? languageID; - String? iPAdress; - String? generalid; - int? patientOutSA; - dynamic sessionID; - bool? isDentalAllowedBackend; - int? deviceTypeID; - bool? forRegisteration; - String? dob; - int? isHijri; - String? healthId; - - CheckActivationCodeRegisterReq({ - this.patientMobileNumber, - this.mobileNo, - this.deviceToken, - this.projectOutSA, - this.loginType, - this.zipCode, - this.isRegister, - this.logInTokenID, - this.searchType, - this.patientID, - this.nationalID, - this.patientIdentificationID, - this.activationCode, - this.isSilentLogin, - this.versionID, - this.channel, - this.languageID, - this.iPAdress, - this.generalid, - this.patientOutSA, - this.sessionID, - this.isDentalAllowedBackend, - this.deviceTypeID, - this.forRegisteration, - this.dob, - this.isHijri, - this.healthId, - }); - - CheckActivationCodeRegisterReq.fromJson(Map json) { - patientMobileNumber = json['PatientMobileNumber']; - mobileNo = json['MobileNo']; - deviceToken = json['DeviceToken']; - projectOutSA = json['ProjectOutSA']; - loginType = json['LoginType']; - zipCode = json['ZipCode']; - isRegister = json['isRegister']; - logInTokenID = json['LogInTokenID']; - searchType = json['SearchType']; - patientID = json['PatientID']; - nationalID = json['NationalID']; - patientIdentificationID = json['PatientIdentificationID']; - activationCode = json['activationCode']; - isSilentLogin = json['IsSilentLogin']; - versionID = json['VersionID']; - channel = json['Channel']; - languageID = json['LanguageID']; - iPAdress = json['IPAdress']; - generalid = json['generalid']; - patientOutSA = json['PatientOutSA']; - sessionID = json['SessionID']; - isDentalAllowedBackend = json['isDentalAllowedBackend']; - deviceTypeID = json['DeviceTypeID']; - forRegisteration = json['ForRegisteration']; - dob = json['DOB']; - isHijri = json['IsHijri']; - healthId = json['HealthId']; - } - - Map toJson() { - final Map data = new Map(); - data['PatientMobileNumber'] = this.patientMobileNumber; - data['MobileNo'] = this.mobileNo; - data['DeviceToken'] = this.deviceToken; - data['ProjectOutSA'] = this.projectOutSA; - data['LoginType'] = this.loginType; - data['ZipCode'] = this.zipCode; - data['isRegister'] = this.isRegister; - data['LogInTokenID'] = this.logInTokenID; - data['SearchType'] = this.searchType; - data['PatientID'] = this.patientID; - data['NationalID'] = this.nationalID; - data['PatientIdentificationID'] = this.patientIdentificationID; - data['activationCode'] = this.activationCode; - data['IsSilentLogin'] = this.isSilentLogin; - data['VersionID'] = this.versionID; - data['Channel'] = this.channel; - data['LanguageID'] = this.languageID; - data['IPAdress'] = this.iPAdress; - data['generalid'] = this.generalid; - data['PatientOutSA'] = this.patientOutSA; - data['SessionID'] = this.sessionID; - data['isDentalAllowedBackend'] = this.isDentalAllowedBackend; - data['DeviceTypeID'] = this.deviceTypeID; - data['ForRegisteration'] = this.forRegisteration; - data['DOB'] = dob; - data['IsHijri'] = isHijri; - data['HealthId'] = healthId; - return data; - } -} diff --git a/lib/features/authentication/models/request_models/check_activation_code_request_register.dart b/lib/features/authentication/models/request_models/check_activation_code_request_register.dart new file mode 100644 index 0000000..167c8ec --- /dev/null +++ b/lib/features/authentication/models/request_models/check_activation_code_request_register.dart @@ -0,0 +1,121 @@ +// class CheckActivationCodeRegisterReq { +// int? patientMobileNumber; +// String? mobileNo; +// String? deviceToken; +// bool? projectOutSA; +// int? loginType; +// String? zipCode; +// bool? isRegister; +// String? logInTokenID; +// int? searchType; +// int? patientID; +// String? nationalID; +// String? patientIdentificationID; +// String? activationCode; +// bool? isSilentLogin; +// double? versionID; +// int? channel; +// int? languageID; +// String? iPAdress; +// String? generalid; +// int? patientOutSA; +// dynamic sessionID; +// bool? isDentalAllowedBackend; +// int? deviceTypeID; +// bool? forRegisteration; +// String? dob; +// int? isHijri; +// String? healthId; +// +// CheckActivationCodeRegisterReq({ +// this.patientMobileNumber, +// this.mobileNo, +// this.deviceToken, +// this.projectOutSA, +// this.loginType, +// this.zipCode, +// this.isRegister, +// this.logInTokenID, +// this.searchType, +// this.patientID, +// this.nationalID, +// this.patientIdentificationID, +// this.activationCode, +// this.isSilentLogin, +// this.versionID, +// this.channel, +// this.languageID, +// this.iPAdress, +// this.generalid, +// this.patientOutSA, +// this.sessionID, +// this.isDentalAllowedBackend, +// this.deviceTypeID, +// this.forRegisteration, +// this.dob, +// this.isHijri, +// this.healthId, +// }); +// +// CheckActivationCodeRegisterReq.fromJson(Map json) { +// patientMobileNumber = json['PatientMobileNumber']; +// mobileNo = json['MobileNo']; +// deviceToken = json['DeviceToken']; +// projectOutSA = json['ProjectOutSA']; +// loginType = json['LoginType']; +// zipCode = json['ZipCode']; +// isRegister = json['isRegister']; +// logInTokenID = json['LogInTokenID']; +// searchType = json['SearchType']; +// patientID = json['PatientID']; +// nationalID = json['NationalID']; +// patientIdentificationID = json['PatientIdentificationID']; +// activationCode = json['activationCode']; +// isSilentLogin = json['IsSilentLogin']; +// versionID = json['VersionID']; +// channel = json['Channel']; +// languageID = json['LanguageID']; +// iPAdress = json['IPAdress']; +// generalid = json['generalid']; +// patientOutSA = json['PatientOutSA']; +// sessionID = json['SessionID']; +// isDentalAllowedBackend = json['isDentalAllowedBackend']; +// deviceTypeID = json['DeviceTypeID']; +// forRegisteration = json['ForRegisteration']; +// dob = json['DOB']; +// isHijri = json['IsHijri']; +// healthId = json['HealthId']; +// } +// +// Map toJson() { +// final Map data = new Map(); +// data['PatientMobileNumber'] = this.patientMobileNumber; +// data['MobileNo'] = this.mobileNo; +// data['DeviceToken'] = this.deviceToken; +// data['ProjectOutSA'] = this.projectOutSA; +// data['LoginType'] = this.loginType; +// data['ZipCode'] = this.zipCode; +// data['isRegister'] = this.isRegister; +// data['LogInTokenID'] = this.logInTokenID; +// data['SearchType'] = this.searchType; +// data['PatientID'] = this.patientID; +// data['NationalID'] = this.nationalID; +// data['PatientIdentificationID'] = this.patientIdentificationID; +// data['activationCode'] = this.activationCode; +// data['IsSilentLogin'] = this.isSilentLogin; +// data['VersionID'] = this.versionID; +// data['Channel'] = this.channel; +// data['LanguageID'] = this.languageID; +// data['IPAdress'] = this.iPAdress; +// data['generalid'] = this.generalid; +// data['PatientOutSA'] = this.patientOutSA; +// data['SessionID'] = this.sessionID; +// data['isDentalAllowedBackend'] = this.isDentalAllowedBackend; +// data['DeviceTypeID'] = this.deviceTypeID; +// data['ForRegisteration'] = this.forRegisteration; +// data['DOB'] = dob; +// data['IsHijri'] = isHijri; +// data['HealthId'] = healthId; +// return data; +// } +// } diff --git a/lib/features/authentication/models/request_models/check_patient_authentication_request_model.dart b/lib/features/authentication/models/request_models/check_patient_authentication_request_model.dart new file mode 100644 index 0000000..483e416 --- /dev/null +++ b/lib/features/authentication/models/request_models/check_patient_authentication_request_model.dart @@ -0,0 +1,88 @@ +class CheckPatientAuthenticationReq { + int? patientMobileNumber; + String? zipCode; + bool? isRegister; + String? tokenID; + int? searchType; + String? patientIdentificationID; + int? patientID; + double? versionID; + int? channel; + int? languageID; + String? iPAdress; + String? generalid; + int? patientOutSA; + dynamic sessionID; + bool? isDentalAllowedBackend; + int? deviceTypeID; + String? dob; + int? isHijri; + String? healthId; + + CheckPatientAuthenticationReq( + {this.patientMobileNumber, + this.zipCode, + this.isRegister, + this.tokenID, + this.searchType, + this.patientIdentificationID, + this.patientID, + this.versionID, + this.channel, + this.languageID, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID, + this.dob, + this.isHijri, + this.healthId}); + + CheckPatientAuthenticationReq.fromJson(Map json) { + patientMobileNumber = json['PatientMobileNumber']; + zipCode = json['ZipCode']; + isRegister = json['isRegister']; + tokenID = json['TokenID']; + searchType = json['SearchType']; + patientIdentificationID = json['PatientIdentificationID']; + patientID = json['PatientID']; + versionID = json['VersionID']; + channel = json['Channel']; + languageID = json['LanguageID']; + iPAdress = json['IPAdress']; + generalid = json['generalid']; + patientOutSA = json['PatientOutSA']; + sessionID = json['SessionID']; + isDentalAllowedBackend = json['isDentalAllowedBackend']; + deviceTypeID = json['DeviceTypeID']; + dob = json['dob']; + isHijri = json['isHijri']; + healthId = json['HealthId']; + } + + Map toJson() { + final Map data = {}; + data['PatientMobileNumber'] = patientMobileNumber; + data['ZipCode'] = zipCode; + data['isRegister'] = isRegister; + data['TokenID'] = tokenID; + data['SearchType'] = searchType; + data['PatientIdentificationID'] = patientIdentificationID; + data['PatientID'] = patientID; + data['VersionID'] = versionID; + data['Channel'] = channel; + data['LanguageID'] = languageID; + data['IPAdress'] = iPAdress; + data['generalid'] = generalid; + data['PatientOutSA'] = patientOutSA; + data['SessionID'] = sessionID; + data['isDentalAllowedBackend'] = isDentalAllowedBackend; + data['DeviceTypeID'] = deviceTypeID; + data['dob'] = dob; + data['isHijri'] = isHijri; + data['HealthId'] = healthId; + return data; + } +} diff --git a/lib/features/authentication/models/request_models/send_activation_request_model.dart b/lib/features/authentication/models/request_models/send_activation_request_model.dart new file mode 100644 index 0000000..dc3d55d --- /dev/null +++ b/lib/features/authentication/models/request_models/send_activation_request_model.dart @@ -0,0 +1,132 @@ +class SendActivationRequest { + int? patientMobileNumber; + String? mobileNo; + String? deviceToken; + bool? projectOutSA; + int? loginType; + String? zipCode; + bool? isRegister; + String? logInTokenID; + int? searchType; + int? patientID; + String? nationalID; + String? patientIdentificationID; + int? oTPSendType; + int? languageID; + double? versionID; + int? channel; + String? iPAdress; + String? generalid; + int? patientOutSA; + dynamic sessionID; + bool? isDentalAllowedBackend; + int? deviceTypeID; + String? sMSSignature; + String? dob; + int? isHijri; + String? healthId; + int? responseID; + int? status; + int? familyRegionID; + bool? isPatientExcluded; + SendActivationRequest( + {this.patientMobileNumber, + this.mobileNo, + this.deviceToken, + this.projectOutSA, + this.loginType, + this.zipCode, + this.isRegister, + this.logInTokenID, + this.searchType, + this.patientID, + this.nationalID, + this.patientIdentificationID, + this.oTPSendType, + this.languageID, + this.versionID, + this.channel, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID, + this.sMSSignature, + this.dob, + this.isHijri, + this.healthId, + this.responseID, + this.status, + this.familyRegionID, + this.isPatientExcluded + }); + + SendActivationRequest.fromJson(Map json) { + patientMobileNumber = json['PatientMobileNumber']; + mobileNo = json['MobileNo']; + deviceToken = json['DeviceToken']; + projectOutSA = json['ProjectOutSA']; + loginType = json['LoginType']; + zipCode = json['ZipCode']; + isRegister = json['isRegister']; + logInTokenID = json['LogInTokenID']; + searchType = json['SearchType']; + patientID = json['PatientID']; + nationalID = json['NationalID']; + patientIdentificationID = json['PatientIdentificationID']; + oTPSendType = json['OTP_SendType']; + languageID = json['LanguageID']; + versionID = json['VersionID']; + channel = json['Channel']; + iPAdress = json['IPAdress']; + generalid = json['generalid']; + patientOutSA = json['PatientOutSA']; + sessionID = json['SessionID']; + isDentalAllowedBackend = json['isDentalAllowedBackend']; + deviceTypeID = json['DeviceTypeID']; + sMSSignature = json['SMSSignature']; + dob = json['DOB']; + isHijri = json['IsHijri']; + healthId = json['HealthId']; + responseID = json['ReponseID']; + status = json['Status']; + familyRegionID = json['FamilyRegionID']; + isPatientExcluded = json['IsPatientExcluded']; + } + + Map toJson() { + final Map data = new Map(); + data['PatientMobileNumber'] = patientMobileNumber; + data['MobileNo'] = mobileNo; + data['DeviceToken'] = deviceToken; + data['ProjectOutSA'] = projectOutSA; + data['LoginType'] = loginType; + data['ZipCode'] = zipCode; + data['isRegister'] = isRegister; + data['LogInTokenID'] = logInTokenID; + data['SearchType'] = searchType; + data['PatientID'] = patientID; + data['NationalID'] = nationalID; + data['PatientIdentificationID'] = patientIdentificationID; + data['OTP_SendType'] = oTPSendType; + data['LanguageID'] = languageID; + data['VersionID'] = versionID; + data['Channel'] = channel; + data['IPAdress'] = iPAdress; + data['generalid'] = generalid; + data['PatientOutSA'] = patientOutSA; + data['SessionID'] = sessionID; + data['isDentalAllowedBackend'] = isDentalAllowedBackend; + data['DeviceTypeID'] = deviceTypeID; + data['SMSSignature'] = sMSSignature; + data['DOB'] = dob; + data['IsHijri'] = isHijri; + data['HealthId'] = healthId; + data['ResponseID'] = responseID; + data['Status'] = status; + data['FamilyRegionID'] = familyRegionID; + data['IsPatientExcluded'] = isPatientExcluded; + return data; + } +} diff --git a/lib/features/authentication/models/authenticated_user_model.dart b/lib/features/authentication/models/resp_models/authenticated_user_resp_model.dart similarity index 100% rename from lib/features/authentication/models/authenticated_user_model.dart rename to lib/features/authentication/models/resp_models/authenticated_user_resp_model.dart diff --git a/lib/features/authentication/models/resp_models/check_activation_code_resp_model.dart b/lib/features/authentication/models/resp_models/check_activation_code_resp_model.dart new file mode 100644 index 0000000..8610e08 --- /dev/null +++ b/lib/features/authentication/models/resp_models/check_activation_code_resp_model.dart @@ -0,0 +1,546 @@ +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart'; + +class CheckActivationCode { + dynamic date; + int? languageID; + int? serviceName; + dynamic time; + dynamic androidLink; + String? authenticationTokenID; + dynamic data; + bool? dataw; + int? dietType; + dynamic errorCode; + dynamic errorEndUserMessage; + dynamic errorEndUserMessageN; + dynamic errorMessage; + int? errorType; + int? foodCategory; + dynamic iOSLink; + bool? isAuthenticated; + int? mealOrderStatus; + int? mealType; + int? messageStatus; + int? numberOfResultRecords; + dynamic patientBlodType; + dynamic successMsg; + dynamic successMsgN; + dynamic doctorInformationList; + dynamic getAllPendingRecordsList; + dynamic getAllSharedRecordsByStatusList; + dynamic getResponseFileList; + bool? isHMGPatient; + bool? isLoginSuccessfully; + bool? isNeedUpdateIdintificationNo; + bool? kioskSendSMS; + AuthenticatedUser? list; + dynamic listAskHabibMobileLoginInfo; + dynamic listAskHabibPatientFile; + dynamic listMergeFiles; + dynamic listMobileLoginInfo; + dynamic listPatientCount; + dynamic logInTokenID; + dynamic mohemmPrivilegeList; + int? pateintID; + String? patientBloodType; + bool? patientHasFile; + dynamic patientMergedIDs; + bool? patientOutSA; + int? patientShareRequestID; + int? patientType; + int? projectIDOut; + dynamic returnMessage; + bool? sMSLoginRequired; + dynamic servicePrivilegeList; + dynamic sharePatientName; + dynamic verificationCode; + dynamic email; + dynamic errorList; + bool? hasFile; + bool? isActiveCode; + bool? isMerged; + bool? isNeedUserAgreement; + bool? isSMSSent; + dynamic memberList; + dynamic message; + int? statusCode; + + CheckActivationCode( + {this.date, + this.languageID, + this.serviceName, + this.time, + this.androidLink, + this.authenticationTokenID, + this.data, + this.dataw, + this.dietType, + this.errorCode, + this.errorEndUserMessage, + this.errorEndUserMessageN, + this.errorMessage, + this.errorType, + this.foodCategory, + this.iOSLink, + this.isAuthenticated, + this.mealOrderStatus, + this.mealType, + this.messageStatus, + this.numberOfResultRecords, + this.patientBlodType, + this.successMsg, + this.successMsgN, + this.doctorInformationList, + this.getAllPendingRecordsList, + this.getAllSharedRecordsByStatusList, + this.getResponseFileList, + this.isHMGPatient, + this.isLoginSuccessfully, + this.isNeedUpdateIdintificationNo, + this.kioskSendSMS, + this.list, + this.listAskHabibMobileLoginInfo, + this.listAskHabibPatientFile, + this.listMergeFiles, + this.listMobileLoginInfo, + this.listPatientCount, + this.logInTokenID, + this.mohemmPrivilegeList, + this.pateintID, + this.patientBloodType, + this.patientHasFile, + this.patientMergedIDs, + this.patientOutSA, + this.patientShareRequestID, + this.patientType, + this.projectIDOut, + this.returnMessage, + this.sMSLoginRequired, + this.servicePrivilegeList, + this.sharePatientName, + this.verificationCode, + this.email, + this.errorList, + this.hasFile, + this.isActiveCode, + this.isMerged, + this.isNeedUserAgreement, + this.isSMSSent, + this.memberList, + this.message, + this.statusCode}); + + CheckActivationCode.fromJson(Map json) { + date = json['Date']; + languageID = json['LanguageID']; + serviceName = json['ServiceName']; + time = json['Time']; + androidLink = json['AndroidLink']; + authenticationTokenID = json['AuthenticationTokenID']; + data = json['Data']; + dataw = json['Dataw']; + dietType = json['DietType']; + errorCode = json['ErrorCode']; + errorEndUserMessage = json['ErrorEndUserMessage']; + errorEndUserMessageN = json['ErrorEndUserMessageN']; + errorMessage = json['ErrorMessage']; + errorType = json['ErrorType']; + foodCategory = json['FoodCategory']; + iOSLink = json['IOSLink']; + isAuthenticated = json['IsAuthenticated']; + mealOrderStatus = json['MealOrderStatus']; + mealType = json['MealType']; + messageStatus = json['MessageStatus']; + numberOfResultRecords = json['NumberOfResultRecords']; + patientBlodType = json['PatientBlodType']; + successMsg = json['SuccessMsg']; + successMsgN = json['SuccessMsgN']; + doctorInformationList = json['DoctorInformation_List']; + getAllPendingRecordsList = json['GetAllPendingRecordsList']; + getAllSharedRecordsByStatusList = json['GetAllSharedRecordsByStatusList']; + getResponseFileList = json['GetResponseFileList']; + isHMGPatient = json['IsHMGPatient']; + isLoginSuccessfully = json['IsLoginSuccessfully']; + isNeedUpdateIdintificationNo = json['IsNeedUpdateIdintificationNo']; + kioskSendSMS = json['KioskSendSMS']; + if (json['List'] != null) { + list = AuthenticatedUser.fromJson(json['List'][0]); + } + listAskHabibMobileLoginInfo = json['List_AskHabibMobileLoginInfo']; + listAskHabibPatientFile = json['List_AskHabibPatientFile']; + listMergeFiles = json['List_MergeFiles']; + listMobileLoginInfo = json['List_MobileLoginInfo']; + listPatientCount = json['List_PatientCount']; + logInTokenID = json['LogInTokenID']; + mohemmPrivilegeList = json['MohemmPrivilege_List']; + pateintID = json['PateintID']; + patientBloodType = json['PatientBloodType']; + patientHasFile = json['PatientHasFile']; + patientMergedIDs = json['PatientMergedIDs']; + patientOutSA = json['PatientOutSA']; + patientShareRequestID = json['PatientShareRequestID']; + patientType = json['PatientType']; + projectIDOut = json['ProjectIDOut']; + returnMessage = json['ReturnMessage']; + sMSLoginRequired = json['SMSLoginRequired']; + servicePrivilegeList = json['ServicePrivilege_List']; + sharePatientName = json['SharePatientName']; + verificationCode = json['VerificationCode']; + email = json['email']; + errorList = json['errorList']; + hasFile = json['hasFile']; + isActiveCode = json['isActiveCode']; + isMerged = json['isMerged']; + isNeedUserAgreement = json['isNeedUserAgreement']; + isSMSSent = json['isSMSSent']; + memberList = json['memberList']; + message = json['message']; + statusCode = json['statusCode']; + } + + Map toJson() { + final Map data = {}; + data['Date'] = date; + data['LanguageID'] = languageID; + data['ServiceName'] = serviceName; + data['Time'] = time; + data['AndroidLink'] = androidLink; + data['AuthenticationTokenID'] = authenticationTokenID; + data['Data'] = this.data; + data['Dataw'] = dataw; + data['DietType'] = dietType; + data['ErrorCode'] = errorCode; + data['ErrorEndUserMessage'] = errorEndUserMessage; + data['ErrorEndUserMessageN'] = errorEndUserMessageN; + data['ErrorMessage'] = errorMessage; + data['ErrorType'] = errorType; + data['FoodCategory'] = foodCategory; + data['IOSLink'] = iOSLink; + data['IsAuthenticated'] = isAuthenticated; + data['MealOrderStatus'] = mealOrderStatus; + data['MealType'] = mealType; + data['MessageStatus'] = messageStatus; + data['NumberOfResultRecords'] = numberOfResultRecords; + data['PatientBlodType'] = patientBlodType; + data['SuccessMsg'] = successMsg; + data['SuccessMsgN'] = successMsgN; + data['DoctorInformation_List'] = doctorInformationList; + data['GetAllPendingRecordsList'] = getAllPendingRecordsList; + data['GetAllSharedRecordsByStatusList'] = getAllSharedRecordsByStatusList; + data['GetResponseFileList'] = getResponseFileList; + data['IsHMGPatient'] = isHMGPatient; + data['IsLoginSuccessfully'] = isLoginSuccessfully; + data['IsNeedUpdateIdintificationNo'] = isNeedUpdateIdintificationNo; + data['KioskSendSMS'] = kioskSendSMS; + if (list != null) { + data['List'] = list; + } + data['List_AskHabibMobileLoginInfo'] = listAskHabibMobileLoginInfo; + data['List_AskHabibPatientFile'] = listAskHabibPatientFile; + data['List_MergeFiles'] = listMergeFiles; + data['List_MobileLoginInfo'] = listMobileLoginInfo; + data['List_PatientCount'] = listPatientCount; + data['LogInTokenID'] = logInTokenID; + data['MohemmPrivilege_List'] = mohemmPrivilegeList; + data['PateintID'] = pateintID; + data['PatientBloodType'] = patientBloodType; + data['PatientHasFile'] = patientHasFile; + data['PatientMergedIDs'] = patientMergedIDs; + data['PatientOutSA'] = patientOutSA; + data['PatientShareRequestID'] = patientShareRequestID; + data['PatientType'] = patientType; + data['ProjectIDOut'] = projectIDOut; + data['ReturnMessage'] = returnMessage; + data['SMSLoginRequired'] = sMSLoginRequired; + data['ServicePrivilege_List'] = servicePrivilegeList; + data['SharePatientName'] = sharePatientName; + data['VerificationCode'] = verificationCode; + data['email'] = email; + data['errorList'] = errorList; + data['hasFile'] = hasFile; + data['isActiveCode'] = isActiveCode; + data['isMerged'] = isMerged; + data['isNeedUserAgreement'] = isNeedUserAgreement; + data['isSMSSent'] = isSMSSent; + data['memberList'] = memberList; + data['message'] = message; + data['statusCode'] = statusCode; + return data; + } +} + +class List { + String? setupID; + int? patientType; + int? patientID; + String? firstName; + String? middleName; + String? lastName; + String? firstNameN; + String? middleNameN; + String? lastNameN; + int? relationshipID; + int? gender; + String? dateofBirth; + dynamic dateofBirthN; + String? nationalityID; + dynamic phoneResi; + dynamic phoneOffice; + String? mobileNumber; + dynamic faxNumber; + String? emailAddress; + dynamic bloodGroup; + dynamic rHFactor; + bool? isEmailAlertRequired; + bool? isSMSAlertRequired; + String? preferredLanguage; + bool? isPrivilegedMember; + dynamic memberID; + dynamic expiryDate; + dynamic isHmgEmployee; + dynamic employeeID; + dynamic emergencyContactName; + dynamic emergencyContactNo; + int? patientPayType; + dynamic dHCCPatientRefID; + bool? isPatientDummy; + int? status; + dynamic isStatusCleared; + int? patientIdentificationType; + String? patientIdentificationNo; + int? projectID; + int? infoSourceID; + dynamic address; + int? age; + String? ageDesc; + int? areaID; + int? createdBy; + String? genderDescription; + dynamic iR; + dynamic iSOCityID; + dynamic iSOCountryID; + ListPrivilege? listPrivilege; + dynamic marital; + int? outSA; + dynamic pOBox; + bool? receiveHealthSummaryReport; + int? sourceType; + dynamic strDateofBirth; + dynamic tempAddress; + dynamic zipCode; + + List({ + this.setupID, + this.patientType, + this.patientID, + this.firstName, + this.middleName, + this.lastName, + this.firstNameN, + this.middleNameN, + this.lastNameN, + this.relationshipID, + this.gender, + this.dateofBirth, + this.dateofBirthN, + this.nationalityID, + this.phoneResi, + this.phoneOffice, + this.mobileNumber, + this.faxNumber, + this.emailAddress, + this.bloodGroup, + this.rHFactor, + this.isEmailAlertRequired, + this.isSMSAlertRequired, + this.preferredLanguage, + this.isPrivilegedMember, + this.memberID, + this.expiryDate, + this.isHmgEmployee, + this.employeeID, + this.emergencyContactName, + this.emergencyContactNo, + this.patientPayType, + this.dHCCPatientRefID, + this.isPatientDummy, + this.status, + this.isStatusCleared, + this.patientIdentificationType, + this.patientIdentificationNo, + this.projectID, + this.infoSourceID, + this.address, + this.age, + this.ageDesc, + this.areaID, + this.createdBy, + this.genderDescription, + this.iR, + this.iSOCityID, + this.iSOCountryID, + this.listPrivilege, + this.marital, + this.outSA, + this.pOBox, + this.receiveHealthSummaryReport, + this.sourceType, + this.strDateofBirth, + this.tempAddress, + this.zipCode, + }); + + List.fromJson(Map json) { + setupID = json['SetupID']; + patientType = json['PatientType']; + patientID = json['PatientID']; + firstName = json['FirstName']; + middleName = json['MiddleName']; + lastName = json['LastName']; + firstNameN = json['FirstNameN']; + middleNameN = json['MiddleNameN']; + lastNameN = json['LastNameN']; + relationshipID = json['RelationshipID']; + gender = json['Gender']; + dateofBirth = json['DateofBirth']; + dateofBirthN = json['DateofBirthN']; + nationalityID = json['NationalityID']; + phoneResi = json['PhoneResi']; + phoneOffice = json['PhoneOffice']; + mobileNumber = json['MobileNumber']; + faxNumber = json['FaxNumber']; + emailAddress = json['EmailAddress']; + bloodGroup = json['BloodGroup']; + rHFactor = json['RHFactor']; + isEmailAlertRequired = json['IsEmailAlertRequired']; + isSMSAlertRequired = json['IsSMSAlertRequired']; + preferredLanguage = json['PreferredLanguage']; + isPrivilegedMember = json['IsPrivilegedMember']; + memberID = json['MemberID']; + expiryDate = json['ExpiryDate']; + isHmgEmployee = json['IsHmgEmployee']; + employeeID = json['EmployeeID']; + emergencyContactName = json['EmergencyContactName']; + emergencyContactNo = json['EmergencyContactNo']; + patientPayType = json['PatientPayType']; + dHCCPatientRefID = json['DHCCPatientRefID']; + isPatientDummy = json['IsPatientDummy']; + status = json['Status']; + isStatusCleared = json['IsStatusCleared']; + patientIdentificationType = json['PatientIdentificationType']; + patientIdentificationNo = json['PatientIdentificationNo']; + projectID = json['ProjectID']; + infoSourceID = json['InfoSourceID']; + address = json['Address']; + age = json['Age']; + ageDesc = json['AgeDesc']; + areaID = json['AreaID']; + createdBy = json['CreatedBy']; + genderDescription = json['GenderDescription']; + iR = json['IR']; + iSOCityID = json['ISOCityID']; + iSOCountryID = json['ISOCountryID']; + if (json['ListPrivilege'] != null) { + listPrivilege = ListPrivilege.fromJson(json['ListPrivilege']); + } + marital = json['Marital']; + outSA = json['OutSA']; + pOBox = json['POBox']; + receiveHealthSummaryReport = json['ReceiveHealthSummaryReport']; + sourceType = json['SourceType']; + strDateofBirth = json['StrDateofBirth']; + tempAddress = json['TempAddress']; + zipCode = json['ZipCode']; + } + + Map toJson() { + final Map data = {}; + data['SetupID'] = setupID; + data['PatientType'] = patientType; + data['PatientID'] = patientID; + data['FirstName'] = firstName; + data['MiddleName'] = middleName; + data['LastName'] = lastName; + data['FirstNameN'] = firstNameN; + data['MiddleNameN'] = middleNameN; + data['LastNameN'] = lastNameN; + data['RelationshipID'] = relationshipID; + data['Gender'] = gender; + data['DateofBirth'] = dateofBirth; + data['DateofBirthN'] = dateofBirthN; + data['NationalityID'] = nationalityID; + data['PhoneResi'] = phoneResi; + data['PhoneOffice'] = phoneOffice; + data['MobileNumber'] = mobileNumber; + data['FaxNumber'] = faxNumber; + data['EmailAddress'] = emailAddress; + data['BloodGroup'] = bloodGroup; + data['RHFactor'] = rHFactor; + data['IsEmailAlertRequired'] = isEmailAlertRequired; + data['IsSMSAlertRequired'] = isSMSAlertRequired; + data['PreferredLanguage'] = preferredLanguage; + data['IsPrivilegedMember'] = isPrivilegedMember; + data['MemberID'] = memberID; + data['ExpiryDate'] = expiryDate; + data['IsHmgEmployee'] = isHmgEmployee; + data['EmployeeID'] = employeeID; + data['EmergencyContactName'] = emergencyContactName; + data['EmergencyContactNo'] = emergencyContactNo; + data['PatientPayType'] = patientPayType; + data['DHCCPatientRefID'] = dHCCPatientRefID; + data['IsPatientDummy'] = isPatientDummy; + data['Status'] = status; + data['IsStatusCleared'] = isStatusCleared; + data['PatientIdentificationType'] = patientIdentificationType; + data['PatientIdentificationNo'] = patientIdentificationNo; + data['ProjectID'] = projectID; + data['InfoSourceID'] = infoSourceID; + data['Address'] = address; + data['Age'] = age; + data['AgeDesc'] = ageDesc; + data['AreaID'] = areaID; + data['CreatedBy'] = createdBy; + data['GenderDescription'] = genderDescription; + data['IR'] = iR; + data['ISOCityID'] = iSOCityID; + data['ISOCountryID'] = iSOCountryID; + if (listPrivilege != null) { + data['ListPrivilege'] = listPrivilege; + } + data['Marital'] = marital; + data['OutSA'] = outSA; + data['POBox'] = pOBox; + data['ReceiveHealthSummaryReport'] = receiveHealthSummaryReport; + data['SourceType'] = sourceType; + data['StrDateofBirth'] = strDateofBirth; + data['TempAddress'] = tempAddress; + data['ZipCode'] = zipCode; + + return data; + } +} + +class ListPrivilege { + int? iD; + String? serviceName; + bool? previlege; + dynamic region; + + ListPrivilege({this.iD, this.serviceName, this.previlege, this.region}); + + ListPrivilege.fromJson(Map json) { + iD = json['ID']; + serviceName = json['ServiceName']; + previlege = json['Previlege']; + region = json['Region']; + } + + Map toJson() { + final Map data = {}; + data['ID'] = iD; + data['ServiceName'] = serviceName; + data['Previlege'] = previlege; + data['Region'] = region; + return data; + } +} diff --git a/lib/features/authentication/models/get_patient_last_login_details_response_model.dart b/lib/features/authentication/models/resp_models/get_patient_last_login_details_response_model.dart similarity index 100% rename from lib/features/authentication/models/get_patient_last_login_details_response_model.dart rename to lib/features/authentication/models/resp_models/get_patient_last_login_details_response_model.dart diff --git a/lib/features/authentication/models/resp_models/select_device_by_imei.dart b/lib/features/authentication/models/resp_models/select_device_by_imei.dart new file mode 100644 index 0000000..398f791 --- /dev/null +++ b/lib/features/authentication/models/resp_models/select_device_by_imei.dart @@ -0,0 +1,73 @@ +import 'dart:convert'; + +Map selectDeviceByImeiRespModelFromJson(String str) => Map.from(json.decode(str)); + +String selectDeviceByImeiRespModelToJson(Map data) => json.encode(Map.from(data)); + +class SelectDeviceByImeiRespModelElement { + int? id; + String? imei; + int? logInType; + int? patientId; + bool? outSa; + String? mobile; + String? identificationNo; + String? name; + String? nameN; + String? createdOn; + String? editedOn; + bool? biometricEnabled; + int? patientType; + int? preferredLanguage; + + SelectDeviceByImeiRespModelElement({ + this.id, + this.imei, + this.logInType, + this.patientId, + this.outSa, + this.mobile, + this.identificationNo, + this.name, + this.nameN, + this.createdOn, + this.editedOn, + this.biometricEnabled, + this.patientType, + this.preferredLanguage, + }); + + factory SelectDeviceByImeiRespModelElement.fromJson(Map json) => SelectDeviceByImeiRespModelElement( + id: json["ID"] as int?, + imei: json["IMEI"] as String?, + logInType: json["LogInType"] as int?, + patientId: json["PatientID"] as int?, + outSa: json["OutSA"] as bool?, + mobile: json["Mobile"] as String?, + identificationNo: json["IdentificationNo"] as String?, + name: json["Name"] as String?, + nameN: json["NameN"] as String?, + createdOn: json["CreatedOn"] as String?, + editedOn: json["EditedOn"] as String?, + biometricEnabled: json["BiometricEnabled"] as bool?, + patientType: json["PatientType"] as int?, + preferredLanguage: json["PreferredLanguage"] as int?, + ); + + Map toJson() => { + "ID": id, + "IMEI": imei, + "LogInType": logInType, + "PatientID": patientId, + "OutSA": outSa, + "Mobile": mobile, + "IdentificationNo": identificationNo, + "Name": name, + "NameN": nameN, + "CreatedOn": createdOn, + "EditedOn": editedOn, + "BiometricEnabled": biometricEnabled, + "PatientType": patientType, + "PreferredLanguage": preferredLanguage, + }; +} diff --git a/lib/features/authentication/models/select_device_by_imei.dart b/lib/features/authentication/models/select_device_by_imei.dart deleted file mode 100644 index 2ab669e..0000000 --- a/lib/features/authentication/models/select_device_by_imei.dart +++ /dev/null @@ -1,77 +0,0 @@ -// To parse this JSON data, do -// -// final selectDeviceByImeiRespModel = selectDeviceByImeiRespModelFromJson(jsonString); - -import 'dart:convert'; - -Map selectDeviceByImeiRespModelFromJson(String str) => Map.from(json.decode(str)).map((k, v) => MapEntry(k, v)); - -String selectDeviceByImeiRespModelToJson(Map data) => json.encode(Map.from(data).map((k, v) => MapEntry(k, v))); - -class SelectDeviceByImeiRespModelElement { - int id; - String imei; - int logInType; - int patientId; - bool outSa; - String mobile; - String identificationNo; - String name; - String nameN; - String createdOn; - String editedOn; - bool biometricEnabled; - int patientType; - int preferredLanguage; - - SelectDeviceByImeiRespModelElement({ - required this.id, - required this.imei, - required this.logInType, - required this.patientId, - required this.outSa, - required this.mobile, - required this.identificationNo, - required this.name, - required this.nameN, - required this.createdOn, - required this.editedOn, - required this.biometricEnabled, - required this.patientType, - required this.preferredLanguage, - }); - - factory SelectDeviceByImeiRespModelElement.fromJson(Map json) => SelectDeviceByImeiRespModelElement( - id: json["ID"], - imei: json["IMEI"], - logInType: json["LogInType"], - patientId: json["PatientID"], - outSa: json["OutSA"], - mobile: json["Mobile"], - identificationNo: json["IdentificationNo"], - name: json["Name"], - nameN: json["NameN"], - createdOn: json["CreatedOn"], - editedOn: json["EditedOn"], - biometricEnabled: json["BiometricEnabled"], - patientType: json["PatientType"], - preferredLanguage: json["PreferredLanguage"], - ); - - Map toJson() => { - "ID": id, - "IMEI": imei, - "LogInType": logInType, - "PatientID": patientId, - "OutSA": outSa, - "Mobile": mobile, - "IdentificationNo": identificationNo, - "Name": name, - "NameN": nameN, - "CreatedOn": createdOn, - "EditedOn": editedOn, - "BiometricEnabled": biometricEnabled, - "PatientType": patientType, - "PreferredLanguage": preferredLanguage, - }; -} diff --git a/lib/main.dart b/lib/main.dart index a9afd60..bb4332b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,19 +7,17 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; -import 'package:hmg_patient_app_new/core/utils/size_config.dart'; import 'package:hmg_patient_app_new/providers/bottom_navigation_provider.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/app_theme.dart'; import 'package:provider/provider.dart'; import 'package:provider/single_child_widget.dart'; + import 'core/utils/size_utils.dart'; import 'firebase_options.dart'; -var globalMessengerKey = GlobalKey(); -final navigatorKey = GlobalKey(); - @pragma('vm:entry-point') Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); @@ -57,7 +55,12 @@ void main() async { create: (_) => BottomNavigationProvider(), ), ChangeNotifierProvider( - create: (_) => AuthenticationViewModel(authenticationRepo: getIt(), appState: getIt()), + create: (_) => AuthenticationViewModel( + authenticationRepo: getIt(), + appState: getIt(), + dialogService: getIt(), + errorHandlerService: getIt(), + ), ), ], child: MyApp()), ), @@ -70,13 +73,13 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return SafeArea( - top: false, + top: false, // Set to true if you want to avoid the notch area as well bottom: Platform.isIOS ? false : true, child: LayoutBuilder( builder: (context, constraints) { return Sizer( builder: (context, orientation, deviceType) { - SizeConfig().init(constraints, orientation); + // SizeConfig().init(constraints, orientation); return MaterialApp( title: 'Dr. AlHabib', builder: (context, mchild) { @@ -94,7 +97,7 @@ class MyApp extends StatelessWidget { initialRoute: AppRoutes.initialRoute, routes: AppRoutes.routes, theme: AppTheme.getTheme(EasyLocalization.of(context)?.locale.languageCode == "ar"), - navigatorKey: navigatorKey, + navigatorKey: getIt.get().navigatorKey, ); }, ); diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index dd9f85c..55abb00 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -3,19 +3,24 @@ import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/int_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/authentication/login.dart'; import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart'; +import 'package:hmg_patient_app_new/presentation/home/widgets/habib_wallet_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/small_service_card.dart'; +import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; import 'package:hmg_patient_app_new/providers/bottom_navigation_provider.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; class LandingPage extends StatefulWidget { @@ -26,9 +31,10 @@ class LandingPage extends StatefulWidget { } class _LandingPageState extends State { - @override Widget build(BuildContext context) { + AppState appState = getIt.get(); + final AuthenticationViewModel authenticationViewModel = context.read(); return Consumer(builder: (context, navigationProvider, child) { return Scaffold( backgroundColor: AppColors.bgScaffoldColor, @@ -44,10 +50,8 @@ class _LandingPageState extends State { children: [ CustomButton( text: LocaleKeys.loginOrRegister.tr(context: context), - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute(builder: (BuildContext context) => LoginScreen()), - ); + onPressed: () async { + await authenticationViewModel.selectDeviceImei(); }, backgroundColor: Color(0xffFEE9EA), borderColor: Color(0xffFEE9EA), @@ -62,12 +66,19 @@ class _LandingPageState extends State { icon: AppAssets.contact_icon, width: 24, height: 24, - ), + ).onPress(() { + Navigator.of(context).push( + FadePage( + page: MedicalFilePage(), + // page: LoginScreen(), + ), + ); + }), ], ), ), SizedBox(height: 16.h), - AppState().isAuthenticated + appState.isAuthenticated ? Column( children: [ Container( @@ -110,7 +121,7 @@ class _LandingPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "Quick Links".toText14(isBold: true), + "Quick Links".toText16(isBold: true), Row( children: [ "View medical file".toText12(color: AppColors.primaryRedColor), @@ -213,7 +224,7 @@ class _LandingPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "Services".toText14(isBold: true), + "Services".toText16(isBold: true), Row( children: [ "View all services".toText12(color: AppColors.primaryRedColor), @@ -258,25 +269,7 @@ class _LandingPageState extends State { ), ), SizedBox(height: 16.h), - AppState().isAuthenticated - ? Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "My Balance".toText14(isBold: true), - Row( - children: [ - "View all services".toText12(color: AppColors.primaryRedColor), - SizedBox(width: 2.h), - Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), - ], - ), - ], - ), - ], - ) - : SizedBox(), + appState.isAuthenticated ? HabibWalletCard() : SizedBox(), ], ), ), diff --git a/lib/presentation/home/widgets/habib_wallet_card.dart b/lib/presentation/home/widgets/habib_wallet_card.dart new file mode 100644 index 0000000..9b513db --- /dev/null +++ b/lib/presentation/home/widgets/habib_wallet_card.dart @@ -0,0 +1,127 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; + +class HabibWalletCard extends StatelessWidget { + const HabibWalletCard({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "My Balance".toText16(isBold: true), + Row( + children: [ + "View all services".toText12(color: AppColors.primaryRedColor), + SizedBox(width: 2.h), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), + ], + ), + ], + ), + SizedBox(height: 16.h), + Container( + // height: 150.h, + width: double.infinity, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24, + ), + child: Stack(children: [ + Positioned( + right: 0, + child: ClipRRect(borderRadius: BorderRadius.circular(24.0), child: Utils.buildSvgWithAssets(icon: AppAssets.habib_background_icon, width: 150.h, height: 150.h)), + ), + Padding( + padding: EdgeInsets.all(14.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Habib Wallet".toText15(isBold: true), + Container( + height: 40.h, + width: 40.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.textColor, + borderRadius: 8.h, + ), + child: Padding( + padding: EdgeInsets.all(8.h), + child: Utils.buildSvgWithAssets( + icon: AppAssets.show_icon, + width: 12.h, + height: 12.h, + fit: BoxFit.contain, + ), + ), + ), + ], + ), + SizedBox(height: 4.h), + Row( + children: [ + Utils.buildSvgWithAssets( + icon: AppAssets.saudi_riyal_icon, + iconColor: AppColors.dividerColor, + width: 24.h, + height: 24.h, + fit: BoxFit.contain, + ), + SizedBox(width: 8.h), + "200.18".toText32(isBold: true), + ], + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 50.h), + child: Row( + children: [ + "View details".toText12(color: AppColors.primaryRedColor), + SizedBox(width: 2.h), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), + ], + ), + ), + SizedBox(height: 16.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 150.h, + child: Utils.getPaymentMethods(), + ), + CustomButton( + icon: AppAssets.recharge_icon, + iconSize: 18.h, + text: "Recharge", + onPressed: () {}, + backgroundColor: AppColors.infoColor, + borderColor: AppColors.infoColor, + textColor: AppColors.whiteColor, + fontSize: 12, + fontWeight: FontWeight.bold, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 35.h, + ), + ], + ), + ], + ), + ), + ]), + ) + ], + ); + } +} diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index dff7f75..55ca84b 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -1,5 +1,13 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/input_widget.dart'; class MedicalFilePage extends StatelessWidget { const MedicalFilePage({super.key}); @@ -12,12 +20,152 @@ class MedicalFilePage extends StatelessWidget { title: const Text('Appointments'), backgroundColor: AppColors.bgScaffoldColor, ), - body: const Center( - child: Text( - 'Appointments Page', - style: TextStyle(fontSize: 24), + body: Padding( + padding: EdgeInsets.all(24.h), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.medicalFile.tr(context: context).toText22(isBold: true), + SizedBox(height: 16.h), + TextInputWidget( + labelText: LocaleKeys.search.tr(context: context), + hintText: "Type any record", + controller: TextEditingController(), + keyboardType: TextInputType.number, + isEnable: true, + prefix: null, + autoFocus: false, + isBorderAllowed: false, + isAllowLeadingIcon: true, + padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h), + leadingIcon: AppAssets.student_card, + hasError: true, + ), + SizedBox(height: 16.h), + Container( + width: double.infinity, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24, + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Image.asset( + AppAssets.male_img, + width: 56.h, + height: 56.h, + ), + SizedBox(width: 8.h), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Haroon Amjad".toText18(isBold: true), + SizedBox(height: 4.h), + Row( + children: [ + CustomButton( + icon: AppAssets.file_icon, + iconColor: AppColors.blackColor, + iconSize: 12.h, + text: "File no: 3628599", + onPressed: () {}, + backgroundColor: AppColors.greyColor, + borderColor: AppColors.greyColor, + textColor: AppColors.blackColor, + fontSize: 10, + fontWeight: FontWeight.normal, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 30.h, + ), + SizedBox(width: 4.h), + CustomButton( + icon: AppAssets.checkmark_icon, + iconColor: AppColors.successColor, + iconSize: 13.h, + text: LocaleKeys.verified.tr(context: context), + onPressed: () {}, + backgroundColor: AppColors.greyColor, + borderColor: AppColors.greyColor, + textColor: AppColors.blackColor, + fontSize: 10, + fontWeight: FontWeight.normal, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 30.h, + ), + ], + ), + ], + ) + ], + ), + SizedBox(height: 16.h), + Divider(color: AppColors.dividerColor, height: 1.h), + SizedBox(height: 16.h), + Row( + children: [ + CustomButton( + text: "30 Years Old", + onPressed: () {}, + backgroundColor: AppColors.greyColor, + borderColor: AppColors.greyColor, + textColor: AppColors.blackColor, + fontSize: 10, + fontWeight: FontWeight.normal, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 30.h, + ), + SizedBox(width: 4.h), + CustomButton( + icon: AppAssets.blood_icon, + iconColor: AppColors.primaryRedColor, + iconSize: 13.h, + text: "Blood: A+", + onPressed: () {}, + backgroundColor: AppColors.greyColor, + borderColor: AppColors.greyColor, + textColor: AppColors.blackColor, + fontSize: 10, + fontWeight: FontWeight.normal, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 30.h, + ), + SizedBox(width: 4.h), + CustomButton( + icon: AppAssets.insurance_active_icon, + iconColor: AppColors.successColor, + iconSize: 13.h, + text: "Insurance Active", + onPressed: () {}, + backgroundColor: AppColors.bgGreenColor.withOpacity(0.20), + borderColor: AppColors.bgGreenColor.withOpacity(0.0), + textColor: AppColors.blackColor, + fontSize: 10, + fontWeight: FontWeight.normal, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 30.h, + ), + ], + ), + SizedBox(height: 8.h), + ], + ), + ), + ) + ], + ), ), ), ); } -} \ No newline at end of file +} diff --git a/lib/services/analytics/analytics_service.dart b/lib/services/analytics/analytics_service.dart index d4f83a4..3411157 100644 --- a/lib/services/analytics/analytics_service.dart +++ b/lib/services/analytics/analytics_service.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:geolocator/geolocator.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; -import 'package:hmg_patient_app_new/features/authentication/models/authenticated_user_model.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart'; import 'package:hmg_patient_app_new/services/analytics/flows/advance_payments.dart'; import 'package:hmg_patient_app_new/services/analytics/flows/app_nav.dart'; import 'package:hmg_patient_app_new/services/analytics/flows/appointments.dart'; diff --git a/lib/services/dialog_service.dart b/lib/services/dialog_service.dart new file mode 100644 index 0000000..af5af9c --- /dev/null +++ b/lib/services/dialog_service.dart @@ -0,0 +1,79 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; + +abstract class DialogService { + Future showErrorDialog({required String message, Function()? onOkPressed}); +} + +class DialogServiceImp implements DialogService { + final NavigationService navigationService; + + DialogServiceImp({required this.navigationService}); + + @override + Future showErrorDialog({required String message, Function()? onOkPressed}) async { + final context = navigationService.navigatorKey.currentContext; + if (context == null) return; + + await showModalBottomSheet( + context: context, + isScrollControlled: false, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (_) => _ErrorBottomSheet(message: message, onOkPressed: onOkPressed), + ); + } +} + +class _ErrorBottomSheet extends StatelessWidget { + final String message; + final Function()? onOkPressed; + + const _ErrorBottomSheet({required this.message, this.onOkPressed}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.error_outline, color: Colors.red, size: 40), + const SizedBox(height: 12), + Text( + "Error", + style: Theme.of(context).textTheme.titleLarge?.copyWith( + color: Colors.red, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + Text( + message, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyMedium, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: () { + if (onOkPressed != null) { + onOkPressed!(); + } else { + context.pop(); + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.red, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text("OK"), + ), + ], + ), + ); + } +} diff --git a/lib/services/error_handler_service.dart b/lib/services/error_handler_service.dart new file mode 100644 index 0000000..a26d264 --- /dev/null +++ b/lib/services/error_handler_service.dart @@ -0,0 +1,55 @@ +import 'dart:io'; + +import 'package:hmg_patient_app_new/core/exceptions/api_exception.dart'; +import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; +import 'package:hmg_patient_app_new/services/dialog_service.dart'; +import 'package:hmg_patient_app_new/services/logger_service.dart'; +import 'package:hmg_patient_app_new/services/navigation_service.dart'; + +abstract class ErrorHandlerService { + Future handleError({required Failure failure, Function() onOkPressed}); +} + +class ErrorHandlerServiceImp implements ErrorHandlerService { + final DialogService dialogService; + final LoggerService loggerService; + final NavigationService navigationService; + + ErrorHandlerServiceImp({ + required this.dialogService, + required this.loggerService, + required this.navigationService, + }); + + @override + Future handleError({required Failure failure, Function()? onOkPressed}) async { + if (failure is APIException) { + loggerService.errorLogs("API Exception: ${failure.message}"); + } else if (failure is ServerFailure) { + loggerService.errorLogs("Server Failure: ${failure.message}"); + await _showDialog(failure); + } else if (failure is DataParsingFailure) { + loggerService.errorLogs("Data Parsing Failure: ${failure.message}"); + await _showDialog(failure, title: "Data Error"); + } else if (failure is StatusCodeFailure) { + loggerService.errorLogs("StatusCode Failure: ${failure.message}"); + await _showDialog(failure, title: "Status Code Failure Error"); + } else if (failure is HttpException) { + loggerService.errorLogs("Http Exception: ${failure.message}"); + await _showDialog(failure, title: "Network Error"); + } else if (failure is UnknownFailure) { + loggerService.errorLogs("Unknown Failure: ${failure.message}"); + await _showDialog(failure, title: "Unknown Error"); + } else if (failure is InvalidCredentials) { + loggerService.errorLogs("Invalid Credentials : ${failure.message}"); + await _showDialog(failure, title: "Unknown Error"); + } else { + loggerService.errorLogs("Unhandled failure type: $failure"); + await _showDialog(failure, title: "Error"); + } + } + + Future _showDialog(Failure failure, {String title = "Error", Function()? onOkPressed}) async { + await dialogService.showErrorDialog(message: failure.message, onOkPressed: onOkPressed); + } +} diff --git a/lib/services/navigation_service.dart b/lib/services/navigation_service.dart new file mode 100644 index 0000000..d814cf5 --- /dev/null +++ b/lib/services/navigation_service.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class NavigationService { + final GlobalKey navigatorKey = GlobalKey(); + + BuildContext? get context => navigatorKey.currentContext; + + Future push(Route route) { + return navigatorKey.currentState!.push(route); + } + + void pop([T? result]) { + navigatorKey.currentState!.pop(result); + } +} diff --git a/lib/splashPage.dart b/lib/splashPage.dart index 85b2e80..bc3e542 100644 --- a/lib/splashPage.dart +++ b/lib/splashPage.dart @@ -16,8 +16,8 @@ import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; import 'core/consts.dart'; -import 'core/utils/LocalNotification.dart'; -import 'core/utils/push-notification-handler.dart'; +import 'core/utils/local_notifications.dart'; +import 'core/utils/push_notification_handler.dart'; class SplashPage extends StatefulWidget { @override diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index 2c8a1fc..3aefebf 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -29,6 +29,7 @@ class AppColors { static const Color bgGreenColor = Color(0xFF18C273); static const Color textColor = Color(0xFF2E3039); static const Color borderOnlyColor = Color(0xFF2E3039); + static const Color dividerColor = Color(0xFFD2D2D2); static const Color blackBgColor = Color(0xFF2E3039); static const blackColor = textColor; static const inputLabelTextColor = Color(0xff898A8D); diff --git a/lib/widgets/buttons/custom_button.dart b/lib/widgets/buttons/custom_button.dart index 8a08a5e..5413cea 100644 --- a/lib/widgets/buttons/custom_button.dart +++ b/lib/widgets/buttons/custom_button.dart @@ -20,6 +20,7 @@ class CustomButton extends StatelessWidget { final bool isDisabled; final Color iconColor; final double height; + final double iconSize; CustomButton({ Key? key, @@ -38,45 +39,56 @@ class CustomButton extends StatelessWidget { this.icon, this.iconColor = Colors.white, this.height = 56, + this.iconSize = 24, }) : super(key: key); @override Widget build(BuildContext context) { return GestureDetector( - onTap: isDisabled ? null : onPressed, - child: Container( - height: height, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: isDisabled ? Colors.transparent : backgroundColor, - borderRadius: borderRadius, - side: BorderSide( - width: borderWidth, - color: isDisabled ? borderColor.withOpacity(0.5) : borderColor, - )), - child: Padding( - padding: padding, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (icon != null) - Padding( - padding: const EdgeInsets.only(right: 8.0), - child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled), + onTap: isDisabled ? null : onPressed, + child: Container( + height: height, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: isDisabled ? Colors.transparent : backgroundColor, + borderRadius: borderRadius, + side: BorderSide( + width: borderWidth, + color: isDisabled ? borderColor.withOpacity(0.5) : borderColor, + )), + child: Padding( + padding: padding, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (icon != null) + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled, width: iconSize, height: iconSize), + ), + Text( + text, + style: context.dynamicTextStyle( + fontSize: fontSize.fSize, + color: isDisabled ? textColor.withOpacity(0.5) : textColor, + letterSpacing: -0.4, + fontWeight: fontWeight, + ), ), - Text( - text, - style: context.dynamicTextStyle( - fontSize: fontSize.fSize, - color: isDisabled ? textColor.withOpacity(0.5) : textColor, - letterSpacing: -0.4, - fontWeight: fontWeight, - ), - ), - ], + ], + ), ), - ), - ), - ); + ) + + // .toSmoothContainer( + // smoothness: 1, + // side: BorderSide(width: borderWidth, color: backgroundColor), + // borderRadius: BorderRadius.circular(borderRadius * 1.2), + // foregroundDecoration: BoxDecoration( + // color: isDisabled ? backgroundColor.withOpacity(0.5) : Colors.transparent, + // borderRadius: BorderRadius.circular(borderRadius), + // ), + // ), + ); } } diff --git a/lib/widgets/chip/custom_chip_widget.dart b/lib/widgets/chip/custom_chip_widget.dart index 9afb986..6c2f1e3 100644 --- a/lib/widgets/chip/custom_chip_widget.dart +++ b/lib/widgets/chip/custom_chip_widget.dart @@ -5,7 +5,7 @@ import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; class CustomChipWidget extends StatelessWidget { - final ChipType chipType; + final ChipTypeEnum chipType; final String chipText; final String? iconAsset; final VoidCallback? onTap; @@ -14,7 +14,7 @@ class CustomChipWidget extends StatelessWidget { final EdgeInsetsGeometry padding; const CustomChipWidget({ - Key? key, + super.key, required this.chipType, required this.chipText, this.iconAsset, @@ -22,7 +22,7 @@ class CustomChipWidget extends StatelessWidget { this.isSelected = false, this.borderRadius = 12, this.padding = const EdgeInsets.all(8), - }) : super(key: key); + }); @override Widget build(BuildContext context) {