From 84804a59a77db6ab9e1c63ac304231c036f85d7e Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Thu, 4 Sep 2025 16:40:07 +0300 Subject: [PATCH] completed till otp receiving --- lib/core/api/api_client.dart | 247 +++++----- lib/core/api_consts.dart | 66 +-- lib/core/app_state.dart | 80 ++-- lib/core/dependencies.dart | 4 +- lib/core/enums.dart | 9 +- lib/core/exceptions/api_failure.dart | 17 +- lib/core/post_params_model.dart | 14 +- lib/core/utils/loading_utils.dart | 4 +- lib/core/utils/request_utils.dart | 89 ++-- lib/core/utils/validation_utils.dart | 8 +- .../authentication/authentication_repo.dart | 59 +-- .../authentication_view_model.dart | 115 +++-- .../send_activation_request_model.dart | 60 +-- lib/features/lab/lab_repo.dart | 2 +- .../prescriptions/prescriptions_repo.dart | 4 +- lib/features/radiology/radiology_repo.dart | 6 +- lib/main.dart | 13 + lib/presentation/authentication/login.dart | 10 +- lib/presentation/authentication/register.dart | 1 + lib/presentation/home/landing_page.dart | 440 +++++++++--------- lib/services/dialog_service.dart | 4 +- lib/services/error_handler_service.dart | 6 +- lib/services/logger_service.dart | 6 +- .../bottomsheet/generic_bottom_sheet.dart | 6 +- lib/widgets/input_widget.dart | 6 +- 25 files changed, 650 insertions(+), 626 deletions(-) diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 6e64543..a6f033c 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -1,7 +1,6 @@ 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'; @@ -9,7 +8,6 @@ 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; @@ -19,7 +17,7 @@ abstract class ApiClient { Future post( String endPoint, { required Map body, - required Function(dynamic response, int statusCode, {int? messageStatus}) onSuccess, + required Function(dynamic response, int statusCode, {int? messageStatus, String? errorMessage}) onSuccess, required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure, bool isAllowAny, bool isExternal, @@ -77,29 +75,26 @@ abstract class ApiClient { class ApiClientImp implements ApiClient { final _analytics = getIt(); - - final LoggerService loggerService; - final AppState appState; - final DialogService dialogService; + final LoggerService _loggerService; + final AppState _appState; ApiClientImp({ - required this.loggerService, - required this.dialogService, - required this.appState, - }); + required LoggerService loggerService, + required AppState appState, + }) : _appState = appState, + _loggerService = loggerService; @override post( String endPoint, { required Map body, - required Function(dynamic response, int statusCode, {int? messageStatus}) onSuccess, + required Function(dynamic response, int statusCode, {int? messageStatus, String? errorMessage}) onSuccess, required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure, - bool isAllowAny = false, + bool isAllowAny = true, bool isExternal = false, bool isRCService = false, bool bypassConnectionCheck = false, }) async { - AppState appState = getIt.get(); String url; if (isExternal) { url = endPoint; @@ -111,39 +106,19 @@ class ApiClientImp implements ApiClient { } } try { - var user = appState.getAuthenticatedUser; + var user = _appState.getAuthenticatedUser; Map headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}; if (!isExternal) { - String? token = appState.appAuthToken; - String? languageID = (appState.postParamsObject?.languageID == 1 ? 'ar' : 'en'); - if (endPoint == ApiConsts.sendActivationCode) { - languageID = 'en'; - } + String? token = _appState.appAuthToken; + if (body.containsKey('SetupID')) { body['SetupID'] = body.containsKey('SetupID') ? body['SetupID'] ?? body[''] : SETUP_ID; } else {} - if (body.containsKey('LanguageID')) { - if (body['LanguageID'] != null) { - body['LanguageID'] = body['LanguageID'] == 'ar' - ? 1 - : body['LanguageID'] == 'en' - ? 2 - : body['LanguageID']; - } - } - if (body.containsKey('isDentalAllowedBackend')) { body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND; } - //Todo: I have converted it to string - body['DeviceTypeID'] = Platform.isIOS - ? "1" - : await Utils.isGoogleServicesAvailable() - ? "2" - : "3"; - if (!body.containsKey('IsPublicRequest')) { // if (!body.containsKey('PatientType')) { if (user != null && user.patientType != null) { @@ -158,6 +133,7 @@ class ApiClientImp implements ApiClient { body['PatientType'] = PATIENT_TYPE_ID.toString(); } + // TODO : These should be from the appState if (user != null) { body['TokenID'] = body['TokenID'] ?? token; body['PatientID'] = body['PatientID'] ?? user.patientID; @@ -175,129 +151,134 @@ class ApiClientImp implements ApiClient { // 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'] ?? "50.0"; - 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"); - body['TokenID'] = "@dm!n"; + body['VersionID'] = ApiConsts.appVersionID.toString(); + body['Channel'] = ApiConsts.appChannelId.toString(); + body['IPAdress'] = ApiConsts.appIpAddress; + body['generalid'] = ApiConsts.appGeneralId; + + body['LanguageID'] = _appState.getLanguageID().toString(); + body['Latitude'] = _appState.userLat.toString(); + body['Longitude'] = _appState.userLong.toString(); + body['DeviceTypeID'] = _appState.deviceTypeID; + if (_appState.appLoginTokenID.isNotEmpty) { + body['LogInTokenID'] = _appState.appLoginTokenID; + } + body.removeWhere((key, value) => value == null); 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 bool networkStatus = await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck); + + if (!networkStatus) { + onFailure( + 'Please Check The Internet Connection 1', + -1, + failureType: ConnectivityFailure("Please Check The Internet Connection 1"), + ); + _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); + return; + } - final int statusCode = response.statusCode; - if (statusCode < 200 || statusCode >= 400) { - onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data")); - logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); + final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers); + final int statusCode = response.statusCode; + log("response.body: ${response.body}"); + if (statusCode < 200 || statusCode >= 400) { + var parsed = json.decode(utf8.decode(response.bodyBytes)); + 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)); + if (isAllowAny) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); } else { - var parsed = json.decode(utf8.decode(response.bodyBytes)); - log("parsed: ${jsonEncode(parsed)}"); - if (isAllowAny) { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); + if (parsed['Response_Message'] != null) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); } else { - if (parsed['Response_Message'] != null) { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); - } else { - if (parsed['ErrorType'] == 4) { - //TODO : handle app update + if (parsed['ErrorType'] == 4) { + //TODO : handle app update + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + } + if (parsed['ErrorType'] == 2) { + // todo: handle Logout + logApiEndpointError(endPoint, "session logged out", statusCode); + } + if (isAllowAny) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + } else if (parsed['IsAuthenticated'] == null) { + if (parsed['isSMSSent'] == true) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + } else if (parsed['MessageStatus'] == 1) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + } else if (parsed['Result'] == 'OK') { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + } else { + onFailure( + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode, + failureType: MessageStatusFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']), + ); logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } - if (parsed['ErrorType'] == 2) { - // todo: handle Logout - logApiEndpointError(endPoint, "session logged out", statusCode); - } - if (isAllowAny) { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); - } else if (parsed['IsAuthenticated'] == null) { - if (parsed['isSMSSent'] == true) { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); - } else if (parsed['MessageStatus'] == 1) { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); - } else if (parsed['Result'] == 'OK') { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); - } else { - 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, messageStatus: parsed['MessageStatus']); - } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) { - if (parsed['SameClinicApptList'] != null) { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); - } else { - if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { - if (parsed['ErrorSearchMsg'] == null) { - 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, - failureType: ServerFailure("Error While Fetching data"), - ); - logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode); - } - } else { - onFailure( - parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode, - failureType: ServerFailure("Error While Fetching data"), - ); - logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); - } - } + } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) { + if (parsed['SameClinicApptList'] != null) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); } else { - if (parsed['SameClinicApptList'] != null) { - onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus']); - } else { - if (parsed['message'] != null) { + if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { + if (parsed['ErrorSearchMsg'] == null) { onFailure( - parsed['message'] ?? parsed['message'], + "Server Error found with no available message", statusCode, failureType: ServerFailure("Error While Fetching data"), ); - logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); + logApiEndpointError(endPoint, "Server Error found with no available message", statusCode); } else { onFailure( - parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + parsed['ErrorSearchMsg'], statusCode, failureType: ServerFailure("Error While Fetching data"), ); - logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode); } + } else { + onFailure( + parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode, + failureType: UserIntimationFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']), + ); + logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); + } + } + } else { + if (parsed['SameClinicApptList'] != null) { + onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + } else { + if (parsed['message'] != null) { + 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, + failureType: ServerFailure("Error While Fetching data"), + ); + logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } } } } - } else { - onFailure( - 'Please Check The Internet Connection 1', - -1, - failureType: ConnectivityFailure("Please Check The Internet Connection 1"), - ); - _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } - } catch (e) { - loggerService.errorLogs(e.toString()); + } catch (e, stackTrace) { + _loggerService.errorLogs(stackTrace.toString()); if (e.toString().contains("ClientException")) { - onFailure('Something went wrong, plase try again', -1, failureType: InvalidCredentials('Something went wrong, plase try again')); + onFailure('ClientException: Something went wrong, Please try again', -1, failureType: InvalidCredentials('ClientException: Something went wrong, plase try again')); _analytics.errorTracking.log("internet_connectivity", error: "no internet available"); } else { onFailure(e.toString(), -1); diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index ef7656c..5fa6f5e 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -1,4 +1,4 @@ -import 'dart:io'; +import 'package:hmg_patient_app_new/core/enums.dart'; var MAX_SMALL_SCREEN = 660; final OPENTOK_API_KEY = '46209962'; @@ -350,7 +350,6 @@ var CAN_PAY_FOR_FOR_WALKIN_APPOINTMENT = 'Services/Doctors.svc/REST/CanPayForWal var CHANNEL = 3; var GENERAL_ID = 'Cs2020@2016\$2958'; var IP_ADDRESS = '10.20.10.20'; -var VERSION_ID = 18.7; var SETUP_ID = '91877'; var LANGUAGE = 2; // var PATIENT_OUT_SA = 0; @@ -702,20 +701,12 @@ var applePayMerchantId = "merchant.com.hmgwebservices"; // var payFortEnvironment = FortEnvironment.test; // var applePayMerchantId = "merchant.com.hmgwebservices.uat"; - - // Auth Provider Consts - const String INSERT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI'; const String SELECT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; const String CHECK_PATIENT_AUTH = 'Services/Authentication.svc/REST/CheckPatientAuthentication'; const GET_MOBILE_INFO = 'Services/Authentication.svc/REST/GetMobileLoginInfo'; -const SEND_ACTIVATION_CODE = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType'; - -const SEND_ACTIVATION_CODE_REGISTER = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationTypeForRegistration'; -const CHECK_ACTIVATION_CODE = 'Services/Authentication.svc/REST/CheckActivationCode'; -const CHECK_ACTIVATION_CODE_REGISTER = 'Services/Authentication.svc/REST/CheckActivationCodeForRegistration'; const FORGOT_PASSWORD = 'Services/Authentication.svc/REST/CheckActivationCodeForSendFileNo'; const CHECK_PATIENT_FOR_REGISTRATION = "Services/Authentication.svc/REST/CheckPatientForRegisteration"; @@ -731,36 +722,49 @@ const SAVE_SETTING = 'Services/Patients.svc/REST/UpdatePateintInfo'; const DEACTIVATE_ACCOUNT = 'Services/Patients.svc/REST/PatientAppleActivation_InsertUpdate'; - - class ApiConsts { static const maxSmallScreen = 660; - static bool isDevelopment = true; + static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat; // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT - static String baseUrl = 'https://hmgwebservices.com/'; // HIS API URL PROD - - static String SELECT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; - - static num VERSION_ID = 18.9; - - static final String selectDeviceImei = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; - static final String sendActivationCode = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType'; - static final String checkPatientAuth = 'Services/Authentication.svc/REST/CheckPatientAuthentication'; - + static String baseUrl = 'https://hmgwebservices.com/'; // HIS API URL PROD static setBackendURLs() { - if (isDevelopment) { - baseUrl = "https://uat.hmgwebservices.com/"; - } else { - baseUrl = "https://hmgwebservices.com/"; + switch (appEnvironmentType) { + case AppEnvironmentTypeEnum.prod: + baseUrl = "https://hmgwebservices.com/"; + break; + case AppEnvironmentTypeEnum.dev: + baseUrl = "https://uat.hmgwebservices.com/"; + break; + case AppEnvironmentTypeEnum.uat: + baseUrl = "https://uat.hmgwebservices.com/"; + break; + case AppEnvironmentTypeEnum.preProd: + baseUrl = "https://uat.hmgwebservices.com/"; + break; + case AppEnvironmentTypeEnum.qa: + baseUrl = "https://uat.hmgwebservices.com/"; + break; + case AppEnvironmentTypeEnum.staging: + baseUrl = "https://uat.hmgwebservices.com/"; + break; } } + static final String selectDeviceImei = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; + static final String checkPatientAuth = 'Services/Authentication.svc/REST/CheckPatientAuthentication'; - - static final Map packagesAuthHeader = {}; - -} \ No newline at end of file + static final String sendActivationCode = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType'; + static final String sendActivationCodeRegister = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationTypeForRegistration'; + static final String checkActivationCode = 'Services/Authentication.svc/REST/CheckActivationCode'; + static final String checkActivationCodeRegister = 'Services/Authentication.svc/REST/CheckActivationCodeForRegistration'; + + // static values for Api + static final double appVersionID = 18.7; + static final int appChannelId = 3; + static final String appIpAddress = "10.20.10.20"; + static final String appGeneralId = "Cs2020@2016\$2958"; +} diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index 4b31bab..8f1cbff 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -1,70 +1,24 @@ 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/resp_models/authenticated_user_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/navigation_service.dart'; -import 'api_consts.dart' as ApiConsts; - class AppState { NavigationService navigationService; - AppState({ - required this.navigationService, - }); - - bool isAuthenticated = false; - - set setIsAuthenticated(v) => isAuthenticated = v; - - String deviceToken = ""; - - set setDeviceToken(v) => deviceToken = v; + AppState({required this.navigationService}); - String appAuthToken = ""; - - set setAppAuthToken(v) => appAuthToken = v; + double userLat = 0.0; set setUserLat(v) => userLat = v; - set setUserLong(v) => userLong = v; - - // TODO: GETTER SETTER FOR SESSION ID - - String sessionId = ""; - - set setSessionId(v) => sessionId = v; - - final PostParamsModel _postParamsInitConfig = PostParamsModel( - channel: 3, - versionID: ApiConsts.VERSION_ID, - ipAddress: '10.20.10.20', - generalId: 'Cs2020@2016\$2958', - deviceTypeID: "2", - sessionID: 'TMRhVmkGhOsvamErw', - ); - - void setPostParamsInitConfig() { - isAuthenticated = false; - _postParams = _postParamsInitConfig; - } - - PostParamsModel? _postParams; - - PostParamsModel? get postParamsObject => _postParams; - - Map get postParamsJson => isAuthenticated ? (_postParams?.toJsonAfterLogin() ?? {}) : (_postParams?.toJson() ?? {}); - - void setPostParamsModel(PostParamsModel _postParams) { - this._postParams = _postParams; - } - - double userLat = 0.0; double userLong = 0.0; + set setUserLong(v) => userLong = v; + bool isArabic() => EasyLocalization.of(navigationService.navigatorKey.currentContext!)?.locale.languageCode == "ar"; - int getLanguageID(context) => EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2; + int getLanguageID() => EasyLocalization.of(navigationService.navigatorKey.currentContext!)?.locale.languageCode == "ar" ? 1 : 2; AuthenticatedUser? _authenticatedUser; @@ -82,7 +36,27 @@ class AppState { SelectDeviceByImeiRespModelElement? get getSelectDeviceByImeiRespModelElement => _selectDeviceByImeiRespModelElement; - String appLoginToken = ""; + String appLoginTokenID = ""; + + set setAppLoginTokenID(v) => appLoginTokenID = v; + + String deviceToken = ""; + + set setDeviceToken(v) => deviceToken = v; + + String appAuthToken = ""; + + set setAppAuthToken(v) => appAuthToken = v; + + String sessionId = ""; + + set setSessionId(v) => sessionId = v; + + bool isAuthenticated = false; + + set setIsAuthenticated(v) => isAuthenticated = v; + + String deviceTypeID = ""; - set setAppLoginToken(v) => appLoginToken = v; + set setDeviceTypeID(v) => deviceTypeID = v; } diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index 721d01d..77088af 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -32,7 +32,7 @@ class AppDependencies { printer: PrettyPrinter( methodCount: 2, errorMethodCount: 5, - lineLength: 100, + lineLength: 1000, colors: true, printEmojis: true, ), @@ -63,7 +63,7 @@ class AppDependencies { final sharedPreferences = await SharedPreferences.getInstance(); getIt.registerLazySingleton(() => CacheServiceImp(sharedPreferences: sharedPreferences, loggerService: getIt())); - getIt.registerLazySingleton(() => ApiClientImp(loggerService: getIt(), dialogService: getIt(), appState: getIt())); + getIt.registerLazySingleton(() => ApiClientImp(loggerService: getIt(), appState: getIt())); // Repositories getIt.registerLazySingleton(() => CommonRepoImp(loggerService: getIt())); diff --git a/lib/core/enums.dart b/lib/core/enums.dart index 874dff4..ab5cac1 100644 --- a/lib/core/enums.dart +++ b/lib/core/enums.dart @@ -22,13 +22,6 @@ enum ViewStateEnum { errorLocal, } -enum LoginTypeEnum { - fromLogin, - silentLogin, - silentWithOTP, -} - - enum CountryEnum { saudiArabia, unitedArabEmirates } enum SelectionTypeEnum { dropdown, calendar } @@ -43,6 +36,8 @@ enum OTPTypeEnum { sms, whatsapp } enum LoginTypeEnum { sms, whatsapp, face, fingerprint } +enum AppEnvironmentTypeEnum { dev, uat, preProd, qa, staging, prod } + extension LoginTypeExtension on LoginTypeEnum { int get toInt { switch (this) { diff --git a/lib/core/exceptions/api_failure.dart b/lib/core/exceptions/api_failure.dart index 4bc5097..c950195 100644 --- a/lib/core/exceptions/api_failure.dart +++ b/lib/core/exceptions/api_failure.dart @@ -13,6 +13,20 @@ class ServerFailure extends Failure { List get props => [message]; } +class UserIntimationFailure extends Failure { + const UserIntimationFailure(super.message); + + @override + List get props => [message]; +} + +class MessageStatusFailure extends Failure { + const MessageStatusFailure(super.message); + + @override + List get props => [message]; +} + class StatusCodeFailure extends Failure { const StatusCodeFailure(super.message); @@ -48,7 +62,6 @@ class UnknownFailure extends Failure { List get props => [message]; } - class DuplicateUsername extends Failure { const DuplicateUsername(String? message) : super(message ?? ''); @@ -62,5 +75,3 @@ class InvalidCredentials extends Failure { @override List get props => [message]; } - - diff --git a/lib/core/post_params_model.dart b/lib/core/post_params_model.dart index 2f981f6..cf52306 100644 --- a/lib/core/post_params_model.dart +++ b/lib/core/post_params_model.dart @@ -14,7 +14,19 @@ class PostParamsModel { String? sessionID; String? setupID; - PostParamsModel({this.versionID, this.channel, this.languageID, this.logInTokenID, this.tokenID, this.language, this.ipAddress, this.generalId, this.latitude, this.longitude, this.deviceTypeID, this.sessionID}); + PostParamsModel( + {this.versionID, + this.channel, + this.languageID, + this.logInTokenID, + this.tokenID, + this.language, + this.ipAddress, + this.generalId, + this.latitude, + this.longitude, + this.deviceTypeID, + this.sessionID}); PostParamsModel.fromJson(Map json) { versionID = json['VersionID']; diff --git a/lib/core/utils/loading_utils.dart b/lib/core/utils/loading_utils.dart index 1dd0410..7390d56 100644 --- a/lib/core/utils/loading_utils.dart +++ b/lib/core/utils/loading_utils.dart @@ -13,11 +13,11 @@ class LoadingUtils { static bool get isLoading => _isLoadingVisible; - static showFullScreenLoading({bool barrierDismissible = true}) { + static showFullScreenLoader({bool barrierDismissible = true}) { if (!_isLoadingVisible) { _isLoadingVisible = true; final context = _navigationService.navigatorKey.currentContext; - log("context:$context"); + log("got the context in showFullScreenLoading"); if (context == null) return; showDialog( diff --git a/lib/core/utils/request_utils.dart b/lib/core/utils/request_utils.dart index 7e02ae2..e83dd46 100644 --- a/lib/core/utils/request_utils.dart +++ b/lib/core/utils/request_utils.dart @@ -1,9 +1,48 @@ -import 'dart:developer'; - 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 getPatientAuthenticationRequest({ + required String phoneNumber, + required String nationId, + required OTPTypeEnum otpTypeEnum, + required bool patientOutSA, + required bool isForRegister, + required int? patientId, + required String zipCode, + }) { + bool fileNo = false; + if (nationId.isNotEmpty) { + fileNo = nationId.length < 10; + } + var request = SendActivationRequest(); + if (phoneNumber.isNotEmpty) { + request.patientMobileNumber = int.parse(phoneNumber); + } + request.oTPSendType = otpTypeEnum.toInt(); // could map OTPTypeEnum if needed + request.zipCode = zipCode; // or countryCode if defined elsewhere + + if (isForRegister) { + // 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(nationId); + request.patientIdentificationID = request.nationalID = ""; + request.searchType = 2; + } else { + request.patientID = 0; + request.searchType = 1; + request.patientIdentificationID = request.nationalID = nationId.isNotEmpty ? nationId : '0'; + } + request.isRegister = false; + } + return request; + } + static dynamic getCommonRequestWelcome({ required String phoneNumber, required OTPTypeEnum otpTypeEnum, @@ -19,7 +58,6 @@ class RequestUtils { if (nationIdText.isNotEmpty) { fileNo = nationIdText.length < 10; } - log("phoneNumber: ${phoneNumber}"); var request = SendActivationRequest(); request.patientMobileNumber = int.parse(phoneNumber); request.mobileNo = '0$phoneNumber'; @@ -53,39 +91,38 @@ class RequestUtils { return request; } - static getCommonRequestAuthProvider({ + static getCommonRequestSendActivationCode({ required OTPTypeEnum otpTypeEnum, - required registeredData, - required deviceToken, - required mobileNumber, - required zipCode, - required patientOutSA, - required loginTokenID, - required selectedOption, + required String mobileNumber, + required String zipCode, required int? patientId, + required String? nationalId, + required bool patientOutSA, + required int selectedLoginType, + required bool isForRegister, + required bool isFileNo, }) { var request = SendActivationRequest(); - request.patientMobileNumber = mobileNumber; + if (mobileNumber.isNotEmpty) { + request.patientMobileNumber = int.parse(mobileNumber); + } request.mobileNo = '0$mobileNumber'; - request.deviceToken = deviceToken; - request.projectOutSA = patientOutSA == true ? true : false; - request.loginType = selectedOption; + request.projectOutSA = patientOutSA; + request.loginType = selectedLoginType; 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; + if (isForRegister) { + // 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.searchType = isFileNo ? 2 : 1; request.patientID = patientId ?? 0; - request.nationalID = request.nationalID ?? '0'; - request.patientIdentificationID = request.patientIdentificationID ?? '0'; + request.nationalID = nationalId ?? '0'; + request.patientIdentificationID = nationalId ?? '0'; request.isRegister = false; } request.deviceTypeID = request.searchType; diff --git a/lib/core/utils/validation_utils.dart b/lib/core/utils/validation_utils.dart index 5472b66..cb54af5 100644 --- a/lib/core/utils/validation_utils.dart +++ b/lib/core/utils/validation_utils.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; @@ -5,13 +7,15 @@ class ValidationUtils { static final DialogService _dialogService = getIt.get(); static bool isValidatePhoneAndId({String? nationalId, String? phoneNumber}) { + log("phoneNumber: $phoneNumber"); + log("nationalId: $nationalId"); if (nationalId == null || nationalId.isEmpty) { - _dialogService.showErrorDialog(message: "Please enter a valid national ID or file number", onOkPressed: () {}); + _dialogService.showErrorBottomSheet(message: "Please enter a valid national ID or file number", onOkPressed: () {}); return false; } if (phoneNumber == null || phoneNumber.isEmpty) { - _dialogService.showErrorDialog(message: "Please enter a valid phone number", onOkPressed: () {}); + _dialogService.showErrorBottomSheet(message: "Please enter a valid phone number", onOkPressed: () {}); return false; } return true; diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index 6059331..f8ceff4 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -1,12 +1,10 @@ import 'dart:async'; -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/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/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'; @@ -18,7 +16,7 @@ abstract class AuthenticationRepo { Future>> checkPatientAuthentication({required dynamic checkPatientAuthenticationReq}); Future>> sendActivationCodeRepo({ - required dynamic checkPatientAuthenticationReq, + required dynamic sendActivationCodeReq, String? languageID, bool isRegister = false, }); @@ -48,7 +46,7 @@ class AuthenticationRepoImp implements AuthenticationRepo { onFailure: (error, statusCode, {messageStatus, failureType}) { failure = failureType; }, - onSuccess: (response, statusCode, {messageStatus}) { + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { final list = response['Patient_SELECTDeviceIMEIbyIMEIList']; if (list == null || list.isEmpty) { @@ -59,7 +57,7 @@ class AuthenticationRepoImp implements AuthenticationRepo { apiResponse = GenericApiModel( messageStatus: messageStatus, statusCode: statusCode, - errorMessage: null, + errorMessage: errorMessage, data: model, ); } catch (e) { @@ -81,13 +79,6 @@ class AuthenticationRepoImp implements AuthenticationRepo { 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; @@ -98,12 +89,12 @@ class AuthenticationRepoImp implements AuthenticationRepo { onFailure: (error, statusCode, {messageStatus, failureType}) { failure = failureType; }, - onSuccess: (response, statusCode, {messageStatus}) { + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { apiResponse = GenericApiModel( messageStatus: messageStatus, statusCode: statusCode, - errorMessage: null, + errorMessage: errorMessage, data: response, ); } catch (e) { @@ -121,41 +112,31 @@ class AuthenticationRepoImp implements AuthenticationRepo { @override Future>> sendActivationCodeRepo({ - required dynamic checkPatientAuthenticationReq, + required dynamic sendActivationCodeReq, String? languageID, bool isRegister = false, }) 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 = isRegister ? (languageID == 'ar' ? 1 : 2) : 2; - checkPatientAuthenticationReq.deviceTypeID = Platform.isIOS ? 1 : 2; - checkPatientAuthenticationReq.patientOutSA = isOutKsa; - checkPatientAuthenticationReq.isDentalAllowedBackend = false; - - // Pick correct endpoint + int isOutKsa = (sendActivationCodeReq.zipCode == '966' || sendActivationCodeReq.zipCode == '+966') ? 0 : 1; + sendActivationCodeReq.patientOutSA = isOutKsa; + sendActivationCodeReq.isDentalAllowedBackend = false; try { GenericApiModel? apiResponse; Failure? failure; await apiClient.post( - isRegister ? SEND_ACTIVATION_CODE_REGISTER : SEND_ACTIVATION_CODE, - body: checkPatientAuthenticationReq.toJson(), + isRegister ? ApiConsts.sendActivationCodeRegister : ApiConsts.sendActivationCode, + body: sendActivationCodeReq.toJson(), onFailure: (error, statusCode, {messageStatus, failureType}) { failure = failureType; }, - onSuccess: (response, statusCode, {messageStatus}) { + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { apiResponse = GenericApiModel( messageStatus: messageStatus, statusCode: statusCode, - errorMessage: null, - data: CheckActivationCode.fromJson(response), + errorMessage: errorMessage, + data: response, ); } catch (e) { failure = DataParsingFailure(e.toString()); @@ -179,18 +160,12 @@ class AuthenticationRepoImp implements AuthenticationRepo { }) async { newRequest.activationCode = activationCode ?? "0000"; newRequest.isSilentLogin = activationCode != null ? false : true; - - newRequest.versionID = VERSION_ID; - newRequest.channel = CHANNEL; - newRequest.iPAdress = IP_ADDRESS; - newRequest.generalid = GENERAL_ID; - newRequest.deviceTypeID = Platform.isIOS ? 1 : 2; newRequest.projectOutSA = newRequest.zipCode == '966' ? false : true; newRequest.isDentalAllowedBackend = false; newRequest.forRegisteration = newRequest.isRegister ?? false; newRequest.isRegister = false; - final endpoint = isRegister ? CHECK_ACTIVATION_CODE_REGISTER : CHECK_ACTIVATION_CODE; + final endpoint = isRegister ? ApiConsts.checkActivationCodeRegister : ApiConsts.checkActivationCode; try { GenericApiModel? apiResponse; @@ -202,12 +177,12 @@ class AuthenticationRepoImp implements AuthenticationRepo { onFailure: (error, statusCode, {messageStatus, failureType}) { failure = failureType; }, - onSuccess: (response, statusCode, {messageStatus}) { + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { apiResponse = GenericApiModel( messageStatus: messageStatus, statusCode: statusCode, - errorMessage: null, + errorMessage: errorMessage, data: response, ); } catch (e) { diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index beb3c74..f1606bf 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -61,7 +61,7 @@ class AuthenticationViewModel extends ChangeNotifier { Future onLoginPressed() async { try { - LoadingUtils.showFullScreenLoading(); + LoadingUtils.showFullScreenLoader(); //TODO: We will remove this delay await Future.delayed(Duration(seconds: 3)); var data = _appState.getSelectDeviceByImeiRespModelElement; @@ -74,7 +74,7 @@ class AuthenticationViewModel extends ChangeNotifier { } catch (e) { log("Error in onLoginPressed: $e"); LoadingUtils.hideFullScreenLoader(); - _dialogService.showErrorDialog(message: "An unexpected error occurred. Please try again.", onOkPressed: () {}); + _dialogService.showErrorBottomSheet(message: "An unexpected error occurred. Please try again.", onOkPressed: () {}); } } @@ -97,7 +97,7 @@ class AuthenticationViewModel extends ChangeNotifier { if (apiResponse.messageStatus == 1) { onSuccess(apiResponse.data); } else if (apiResponse.messageStatus == 2) { - _dialogService.showErrorDialog(message: "Message Status = 2", onOkPressed: () {}); + _dialogService.showErrorBottomSheet(message: "Message Status = 2", onOkPressed: () {}); } }, ); @@ -144,70 +144,84 @@ class AuthenticationViewModel extends ChangeNotifier { } }, onError: (String error) { LoadingUtils.hideFullScreenLoader(); - _dialogService.showErrorDialog(message: error, onOkPressed: () {}); + _dialogService.showErrorBottomSheet(message: error, onOkPressed: () {}); }); } Future checkUserAuthentication({required OTPTypeEnum otpTypeEnum, Function(dynamic)? onSuccess, Function(String)? onError}) async { // TODO: THIS SHOULD BE REMOVED LATER ON AND PASSED FROM APP STATE DIRECTLY INTO API CLIENT. BECAUSE THIS API ONLY NEEDS FEW PARAMS FROM USER + if (phoneNumberController.text.isEmpty) { + phoneNumberController.text = "504278212"; + } bool isValidated = ValidationUtils.isValidatePhoneAndId( phoneNumber: phoneNumberController.text, nationalId: nationalIdController.text, ); - if (!isValidated) return; - dynamic checkPatientAuthenticationReq = RequestUtils.getCommonRequestWelcome( + if (!isValidated) { + return; + } + + LoadingUtils.showFullScreenLoader(); + + dynamic checkPatientAuthenticationReq = RequestUtils.getPatientAuthenticationRequest( phoneNumber: phoneNumberController.text, - nationIdText: nationalIdController.text, + nationId: nationalIdController.text, + isForRegister: false, + patientOutSA: false, otpTypeEnum: otpTypeEnum, - deviceToken: 'dummyDeviceToken123', - patientOutSA: true, - loginTokenID: 'dummyLoginToken456', - registeredData: null, - patientId: 12345, - countryCode: 'SA', + patientId: 0, + zipCode: '966', ); final result = await _authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq); + LoadingUtils.hideFullScreenLoader(); result.fold( (failure) async => await _errorHandlerService.handleError(failure: failure), - (apiResponse) { - if (apiResponse.data['isSMSSent']) { - // TODO: set this in AppState - _appState.setAppLoginToken = apiResponse.data['LogInTokenID']; - - // sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']); - // loginTokenID = value['LogInTokenID'], - // sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), - sendActivationCode(otpTypeEnum: otpTypeEnum); - } else { - if (apiResponse.data['IsAuthenticated']) { - checkActivationCode( - onWrongActivationCode: (String? message) {}, - activationCode: 0000, + (apiResponse) async { + if (apiResponse.messageStatus == 2) { + await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty", onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + if (apiResponse.data['isSMSSent']) { + _appState.setAppLoginTokenID = apiResponse.data['LogInTokenID']; + sendActivationCode( + otpTypeEnum: otpTypeEnum, + phoneNumber: phoneNumberController.text, + nationalIdOrFileNumber: nationalIdController.text, ); + } else { + if (apiResponse.data['IsAuthenticated']) { + await checkActivationCode( + onWrongActivationCode: (String? message) {}, + activationCode: 0000, + ); + } } } }, ); } - Future sendActivationCode({required OTPTypeEnum otpTypeEnum}) async { - var request = RequestUtils.getCommonRequestAuthProvider( + Future sendActivationCode({ + required OTPTypeEnum otpTypeEnum, + required String nationalIdOrFileNumber, + required String phoneNumber, + }) async { + var request = RequestUtils.getCommonRequestSendActivationCode( otpTypeEnum: otpTypeEnum, - registeredData: null, - deviceToken: "dummyLoginToken456", - mobileNumber: "0567184134", - zipCode: "SA", - patientOutSA: true, - loginTokenID: "dummyLoginToken456", - selectedOption: otpTypeEnum.toInt(), - patientId: 12345, + mobileNumber: phoneNumber, + selectedLoginType: otpTypeEnum.toInt(), + zipCode: "966", + nationalId: nationalIdOrFileNumber, + isFileNo: false, + patientId: 0, + isForRegister: false, + patientOutSA: false, ); // TODO: GET APP SMS SIGNATURE HERE - request.sMSSignature = ""; + request.sMSSignature = "enKTDcqbOVd"; // GifLoaderDialogUtils.showMyDialog(context); bool isForRegister = healthId != null || isDubai; @@ -218,22 +232,28 @@ class AuthenticationViewModel extends ChangeNotifier { request.healthId = healthId; request.isHijri = isHijri; } else { - request.dob = ""; - request.healthId = ""; - request.isHijri = 0; + // request.dob = ""; + // request.healthId = ""; + // request.isHijri = 0; } final resultEither = await _authenticationRepo.sendActivationCodeRepo( - checkPatientAuthenticationReq: request, + sendActivationCodeReq: request, isRegister: isForRegister, languageID: 'er', ); + resultEither.fold( (failure) async => await _errorHandlerService.handleError(failure: failure), - (apiResponse) { - if (apiResponse.data != null && apiResponse.data['isSMSSent'] == true) { - // startSMSService(otpTypeEnum.toInt()); - navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: request.mobileNumber); + (apiResponse) async { + if (apiResponse.messageStatus == 2) { + await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty"); + } else { + if (apiResponse.data != null && apiResponse.data['isSMSSent'] == true) { + navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber); + } else { + navigateToOTPScreen(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber); + } } }, ); @@ -254,7 +274,6 @@ class AuthenticationViewModel extends ChangeNotifier { nationIdText: '1234567890', countryCode: 'SA', ).toJson(); - dynamic res; bool isForRegister = healthId != null || isDubai; if (isForRegister) { @@ -267,7 +286,6 @@ class AuthenticationViewModel extends ChangeNotifier { activationCode: activationCode.toString(), isRegister: true, ); - res = resultEither; resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) { final activation = CheckActivationCode.fromJson(apiResponse.data as Map); @@ -283,7 +301,6 @@ class AuthenticationViewModel extends ChangeNotifier { activationCode: activationCode.toString(), isRegister: false, ); - res = resultEither; resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) { final activation = CheckActivationCode.fromJson(resultEither as Map); 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 index dc3d55d..360efd4 100644 --- a/lib/features/authentication/models/request_models/send_activation_request_model.dart +++ b/lib/features/authentication/models/request_models/send_activation_request_model.dart @@ -29,38 +29,38 @@ class SendActivationRequest { 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 - }); + 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']; diff --git a/lib/features/lab/lab_repo.dart b/lib/features/lab/lab_repo.dart index 326379c..d746c69 100644 --- a/lib/features/lab/lab_repo.dart +++ b/lib/features/lab/lab_repo.dart @@ -45,7 +45,7 @@ class LabRepoImp implements LabRepo { onFailure: (error, statusCode, {messageStatus, failureType}) { failure = failureType; }, - onSuccess: (response, statusCode, {messageStatus}) { + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { final list = response['ListPLO']; if (list == null || list.isEmpty) { diff --git a/lib/features/prescriptions/prescriptions_repo.dart b/lib/features/prescriptions/prescriptions_repo.dart index de7bc4b..f584f7b 100644 --- a/lib/features/prescriptions/prescriptions_repo.dart +++ b/lib/features/prescriptions/prescriptions_repo.dart @@ -48,7 +48,7 @@ class PrescriptionsRepoImp implements PrescriptionsRepo { onFailure: (error, statusCode, {messageStatus, failureType}) { failure = failureType; }, - onSuccess: (response, statusCode, {messageStatus}) { + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { final list = response['PatientPrescriptionList']; if (list == null || list.isEmpty) { @@ -111,7 +111,7 @@ class PrescriptionsRepoImp implements PrescriptionsRepo { onFailure: (error, statusCode, {messageStatus, failureType}) { failure = failureType; }, - onSuccess: (response, statusCode, {messageStatus}) { + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { final list = prescriptionsResponseModel.isInOutPatient! ? response['ListPRM'] : response['INP_GetPrescriptionReport_List']; if (list == null || list.isEmpty) { diff --git a/lib/features/radiology/radiology_repo.dart b/lib/features/radiology/radiology_repo.dart index d3e4f3d..2917dfd 100644 --- a/lib/features/radiology/radiology_repo.dart +++ b/lib/features/radiology/radiology_repo.dart @@ -1,8 +1,8 @@ +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_failure.dart'; import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart'; -import 'package:dartz/dartz.dart'; +import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; import 'package:hmg_patient_app_new/features/radiology/models/resp_models/patient_radiology_response_model.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; @@ -45,7 +45,7 @@ class RadiologyRepoImp implements RadiologyRepo { onFailure: (error, statusCode, {messageStatus, failureType}) { failure = failureType; }, - onSuccess: (response, statusCode, {messageStatus}) { + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { final radOrders; try { if (response['FinalRadiologyList'] != null && response['FinalRadiologyList'].length != 0) { diff --git a/lib/main.dart b/lib/main.dart index e57d960..29c8943 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,7 +5,9 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.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/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; @@ -33,6 +35,16 @@ class MyHttpOverrides extends HttpOverrides { } } +Future callAppStateInitializations() async { + final String deviceTypeId = (Platform.isIOS + ? "1" + : await Utils.isGoogleServicesAvailable() + ? "2" + : "3"); + AppState appState = getIt.get(); + appState.setDeviceTypeID = deviceTypeId; +} + Future callInitializations() async { WidgetsFlutterBinding.ensureInitialized(); await EasyLocalization.ensureInitialized(); @@ -40,6 +52,7 @@ Future callInitializations() async { AppDependencies.addDependencies(); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); HttpOverrides.global = MyHttpOverrides(); + await callAppStateInitializations(); } void main() async { diff --git a/lib/presentation/authentication/login.dart b/lib/presentation/authentication/login.dart index 3c8fa15..c3948a1 100644 --- a/lib/presentation/authentication/login.dart +++ b/lib/presentation/authentication/login.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -86,7 +88,7 @@ class _LoginScreen extends State { icon: AppAssets.login1, iconColor: Colors.white, onPressed: () { - showLoginModelSheet(context: context, textController: authVm.phoneNumberController, authViewModel: authVm); + showLoginModelSheet(context: context, phoneNumberController: authVm.phoneNumberController, authViewModel: authVm); // if (nationIdController.text.isNotEmpty) { // } else { @@ -145,7 +147,7 @@ class _LoginScreen extends State { void showLoginModelSheet({ required BuildContext context, - required TextEditingController? textController, + required TextEditingController? phoneNumberController, required AuthenticationViewModel authViewModel, }) { context.showBottomSheet( @@ -160,7 +162,7 @@ class _LoginScreen extends State { child: GenericBottomSheet( countryCode: "966", initialPhoneNumber: "", - textController: textController, + textController: phoneNumberController, isEnableCountryDropdown: true, onCountryChange: (value) {}, onChange: (String? value) {}, @@ -193,6 +195,8 @@ class _LoginScreen extends State { child: CustomButton( text: LocaleKeys.sendOTPWHATSAPP.tr(), onPressed: () async { + log("phoneNumberController: ${phoneNumberController == null}"); + log("phoneNumberControllerVa: ${phoneNumberController?.text}"); await authViewModel.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp); }, backgroundColor: Colors.white, diff --git a/lib/presentation/authentication/register.dart b/lib/presentation/authentication/register.dart index af90758..a97c7ad 100644 --- a/lib/presentation/authentication/register.dart +++ b/lib/presentation/authentication/register.dart @@ -206,6 +206,7 @@ class _RegisterNew extends State { child: GenericBottomSheet( countryCode: "966", initialPhoneNumber: "", + isEnableCountryDropdown: true, textController: TextEditingController(), onChange: (String? value) {}, buttons: [ diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 3592acd..febde89 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -16,10 +16,8 @@ import 'package:hmg_patient_app_new/presentation/home/widgets/habib_wallet_card. 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/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; -import 'package:hmg_patient_app_new/widgets/bottom_navigation/bottom_navigation.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'; @@ -37,246 +35,244 @@ class _LandingPageState extends State { AppState appState = getIt.get(); NavigationService navigationService = getIt.get(); final AuthenticationViewModel authenticationViewModel = context.read(); - return Consumer(builder: (context, navigationProvider, child) { - return Scaffold( - backgroundColor: AppColors.bgScaffoldColor, - body: Padding( - padding: EdgeInsets.all(24.h), - child: SingleChildScrollView( - child: Column( - children: [ - Padding( - padding: EdgeInsets.only(top: 50.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CustomButton( - text: LocaleKeys.loginOrRegister.tr(context: context), - onPressed: () async { - await authenticationViewModel.onLoginPressed(); - }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), - fontSize: 16, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 50, - ), - Utils.buildSvgWithAssets( - icon: AppAssets.contact_icon, - width: 24, - height: 24, - ).onPress(() { - Navigator.of(context).push( - FadePage( - page: MedicalFilePage(), - // page: LoginScreen(), - ), - ); - }), - ], - ), + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + body: Padding( + padding: EdgeInsets.all(24.h), + child: SingleChildScrollView( + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(top: 50.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CustomButton( + text: LocaleKeys.loginOrRegister.tr(context: context), + onPressed: () async { + await authenticationViewModel.onLoginPressed(); + }, + backgroundColor: Color(0xffFEE9EA), + borderColor: Color(0xffFEE9EA), + textColor: Color(0xffED1C2B), + fontSize: 16, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 50, + ), + Utils.buildSvgWithAssets( + icon: AppAssets.contact_icon, + width: 24, + height: 24, + ).onPress(() { + Navigator.of(context).push( + FadePage( + page: MedicalFilePage(), + // page: LoginScreen(), + ), + ); + }), + ], ), - SizedBox(height: 16.h), - appState.isAuthenticated - ? Column( - children: [ - Container( - width: double.infinity, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24, - ), - child: Padding( - padding: EdgeInsets.all(12.h), - child: Column( - children: [ - Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), - SizedBox(height: 12.h), - "You do not have any upcoming appointment. Please book an appointment".toText12(isCenter: true), - SizedBox(height: 12.h), - CustomButton( - text: LocaleKeys.bookAppo.tr(context: context), - onPressed: () { - Navigator.of(context).pushReplacement( - MaterialPageRoute(builder: (BuildContext context) => LandingPage()), - ); - }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), - fontSize: 14, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40, - icon: AppAssets.add_icon, - iconColor: AppColors.primaryRedColor, - ), - ], - ), - ), + ), + SizedBox(height: 16.h), + appState.isAuthenticated + ? Column( + children: [ + Container( + width: double.infinity, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24, ), - SizedBox(height: 12.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Quick Links".toText16(isBold: true), - Row( - children: [ - "View medical file".toText12(color: AppColors.primaryRedColor), - SizedBox(width: 2.h), - Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), - ], - ), - ], + child: Padding( + padding: EdgeInsets.all(12.h), + child: Column( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), + SizedBox(height: 12.h), + "You do not have any upcoming appointment. Please book an appointment".toText12(isCenter: true), + SizedBox(height: 12.h), + CustomButton( + text: LocaleKeys.bookAppo.tr(context: context), + onPressed: () { + Navigator.of(context).pushReplacement( + MaterialPageRoute(builder: (BuildContext context) => LandingPage()), + ); + }, + backgroundColor: Color(0xffFEE9EA), + borderColor: Color(0xffFEE9EA), + textColor: Color(0xffED1C2B), + fontSize: 14, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40, + icon: AppAssets.add_icon, + iconColor: AppColors.primaryRedColor, + ), + ], + ), ), - SizedBox(height: 12.h), - Container( - height: 127.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24, + ), + SizedBox(height: 12.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Quick Links".toText16(isBold: true), + Row( + children: [ + "View medical file".toText12(color: AppColors.primaryRedColor), + SizedBox(width: 2.h), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), + ], ), - child: Padding( - padding: EdgeInsets.all(16.h), - child: Column( - children: [ - Expanded( - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getLoggedInServiceCardsList.length, - shrinkWrap: true, - padding: const EdgeInsets.only(left: 0, right: 8), - itemBuilder: (context, index) { - return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: SmallServiceCard( - icon: LandingPageData.getLoggedInServiceCardsList[index].icon, - title: LandingPageData.getLoggedInServiceCardsList[index].title, - subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle, - iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor, - textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor, - backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor, - isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold, - ), + ], + ), + SizedBox(height: 12.h), + Container( + height: 127.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24, + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + children: [ + Expanded( + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getLoggedInServiceCardsList.length, + shrinkWrap: true, + padding: const EdgeInsets.only(left: 0, right: 8), + itemBuilder: (context, index) { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 1000), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: SmallServiceCard( + icon: LandingPageData.getLoggedInServiceCardsList[index].icon, + title: LandingPageData.getLoggedInServiceCardsList[index].title, + subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle, + iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor, + textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor, + backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor, + isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold, ), ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 0.width, - ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 0.width, ), - ], - ), + ), + ], ), - ) - ], - ) - : Container( - height: 127.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24, - ), - child: Padding( - padding: EdgeInsets.all(16.h), - child: Column( - children: [ - Expanded( - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getNotLoggedInServiceCardsList.length, - shrinkWrap: true, - padding: const EdgeInsets.only(left: 0, right: 8), - itemBuilder: (context, index) { - return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: SmallServiceCard( - icon: LandingPageData.getNotLoggedInServiceCardsList[index].icon, - title: LandingPageData.getNotLoggedInServiceCardsList[index].title, - subtitle: LandingPageData.getNotLoggedInServiceCardsList[index].subtitle, - iconColor: LandingPageData.getNotLoggedInServiceCardsList[index].iconColor, - textColor: LandingPageData.getNotLoggedInServiceCardsList[index].textColor, - backgroundColor: LandingPageData.getNotLoggedInServiceCardsList[index].backgroundColor, - isBold: LandingPageData.getNotLoggedInServiceCardsList[index].isBold, - ), + ), + ) + ], + ) + : Container( + height: 127.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24, + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + children: [ + Expanded( + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getNotLoggedInServiceCardsList.length, + shrinkWrap: true, + padding: const EdgeInsets.only(left: 0, right: 8), + itemBuilder: (context, index) { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 1000), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: SmallServiceCard( + icon: LandingPageData.getNotLoggedInServiceCardsList[index].icon, + title: LandingPageData.getNotLoggedInServiceCardsList[index].title, + subtitle: LandingPageData.getNotLoggedInServiceCardsList[index].subtitle, + iconColor: LandingPageData.getNotLoggedInServiceCardsList[index].iconColor, + textColor: LandingPageData.getNotLoggedInServiceCardsList[index].textColor, + backgroundColor: LandingPageData.getNotLoggedInServiceCardsList[index].backgroundColor, + isBold: LandingPageData.getNotLoggedInServiceCardsList[index].isBold, ), ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 0.width, - ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 0.width, ), - ], - ), + ), + ], ), ), - SizedBox(height: 16.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Services".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), - SizedBox( - height: 325.h, - child: Column( + SizedBox(height: 16.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Services".toText16(isBold: true), + Row( children: [ - Expanded( - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getServiceCardsList.length, - shrinkWrap: true, - padding: const EdgeInsets.only(left: 0, right: 8), - itemBuilder: (context, index) { - return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: LargeServiceCard( - image: LandingPageData.getServiceCardsList[index].icon, - title: LandingPageData.getServiceCardsList[index].title, - subtitle: LandingPageData.getServiceCardsList[index].subtitle, - icon: LandingPageData.getServiceCardsList[index].largeCardIcon, - ), + "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), + SizedBox( + height: 325.h, + child: Column( + children: [ + Expanded( + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getServiceCardsList.length, + shrinkWrap: true, + padding: const EdgeInsets.only(left: 0, right: 8), + itemBuilder: (context, index) { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 1000), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: LargeServiceCard( + image: LandingPageData.getServiceCardsList[index].icon, + title: LandingPageData.getServiceCardsList[index].title, + subtitle: LandingPageData.getServiceCardsList[index].subtitle, + icon: LandingPageData.getServiceCardsList[index].largeCardIcon, ), ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 0.width, - ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 0.width, ), - ], - ), + ), + ], ), - SizedBox(height: 16.h), - appState.isAuthenticated ? HabibWalletCard() : SizedBox(), - ], - ), + ), + SizedBox(height: 16.h), + appState.isAuthenticated ? HabibWalletCard() : SizedBox(), + ], ), ), - ); - }); + ), + ); } } diff --git a/lib/services/dialog_service.dart b/lib/services/dialog_service.dart index af5af9c..28b77e1 100644 --- a/lib/services/dialog_service.dart +++ b/lib/services/dialog_service.dart @@ -3,7 +3,7 @@ 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}); + Future showErrorBottomSheet({required String message, Function()? onOkPressed}); } class DialogServiceImp implements DialogService { @@ -12,7 +12,7 @@ class DialogServiceImp implements DialogService { DialogServiceImp({required this.navigationService}); @override - Future showErrorDialog({required String message, Function()? onOkPressed}) async { + Future showErrorBottomSheet({required String message, Function()? onOkPressed}) async { final context = navigationService.navigatorKey.currentContext; if (context == null) return; diff --git a/lib/services/error_handler_service.dart b/lib/services/error_handler_service.dart index 344e59e..59a0205 100644 --- a/lib/services/error_handler_service.dart +++ b/lib/services/error_handler_service.dart @@ -2,6 +2,7 @@ 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/core/utils/loading_utils.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'; @@ -51,6 +52,9 @@ class ErrorHandlerServiceImp implements ErrorHandlerService { } Future _showDialog(Failure failure, {String title = "Error", Function()? onOkPressed}) async { - await dialogService.showErrorDialog(message: failure.message, onOkPressed: onOkPressed); + if (LoadingUtils.isLoading) { + LoadingUtils.hideFullScreenLoader(); + } + await dialogService.showErrorBottomSheet(message: failure.message, onOkPressed: onOkPressed); } } diff --git a/lib/services/logger_service.dart b/lib/services/logger_service.dart index 0b33c52..9df6633 100644 --- a/lib/services/logger_service.dart +++ b/lib/services/logger_service.dart @@ -1,8 +1,6 @@ - import 'package:logger/logger.dart'; abstract class LoggerService { - void errorLogs(String message); void logInfo(String message); @@ -13,8 +11,6 @@ class LoggerServiceImp implements LoggerService { LoggerServiceImp({required this.logger}); - - @override void errorLogs(String message) { logger.e(message); @@ -22,6 +18,6 @@ class LoggerServiceImp implements LoggerService { @override void logInfo(String message) { - logger.i(message); + logger.d(message); } } diff --git a/lib/widgets/bottomsheet/generic_bottom_sheet.dart b/lib/widgets/bottomsheet/generic_bottom_sheet.dart index 1d07099..6ca2014 100644 --- a/lib/widgets/bottomsheet/generic_bottom_sheet.dart +++ b/lib/widgets/bottomsheet/generic_bottom_sheet.dart @@ -1,4 +1,5 @@ import 'dart:io'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; @@ -25,6 +26,7 @@ class GenericBottomSheet extends StatefulWidget { // FocusNode myFocusNode; GenericBottomSheet({ + super.key, this.countryCode = "", this.initialPhoneNumber = "", required this.buttons, @@ -46,8 +48,8 @@ class _GenericBottomSheetState extends State { void initState() { super.initState(); - if (!widget.isForEmail) { - widget.textController = TextEditingController(text: widget.initialPhoneNumber); + if (!widget.isForEmail && widget.textController != null) { + widget.textController!.text = widget.initialPhoneNumber ?? ""; } } diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart index b8d36e7..e34ba0c 100644 --- a/lib/widgets/input_widget.dart +++ b/lib/widgets/input_widget.dart @@ -80,14 +80,12 @@ class TextInputWidget extends StatelessWidget { ? CustomCountryDropdown( countryList: CountryEnum.values, onCountryChange: (CountryEnum? value) { - print(value); + }, isRtl: Directionality.of(context) == TextDirection.rtl, isFromBottomSheet: isCountryDropDown, isEnableTextField: true, - onPhoneNumberChanged: (value) { - print(value); - }, + onPhoneNumberChanged:(val){}, textField: _buildTextField(context), ) : Expanded(