diff --git a/assets/images/png/cc_ar.png b/assets/images/png/cc_ar.png new file mode 100644 index 0000000..e4388ba Binary files /dev/null and b/assets/images/png/cc_ar.png differ diff --git a/assets/images/png/cc_en.png b/assets/images/png/cc_en.png new file mode 100644 index 0000000..c11cf5e Binary files /dev/null and b/assets/images/png/cc_en.png differ diff --git a/assets/images/svg/comprehensive_checkup.svg b/assets/images/svg/comprehensive_checkup.svg new file mode 100644 index 0000000..885d9a7 --- /dev/null +++ b/assets/images/svg/comprehensive_checkup.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/images/svg/e-referral.svg b/assets/images/svg/e-referral.svg new file mode 100644 index 0000000..3262779 --- /dev/null +++ b/assets/images/svg/e-referral.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 162f0fd..28475ea 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -103,7 +103,7 @@ class ApiClientImp implements ApiClient { url = endPoint; } else { if (isRCService) { - url = RC_BASE_URL + endPoint; + url = ApiConsts.rcBaseUrl + endPoint; } else { url = ApiConsts.baseUrl + endPoint; } @@ -161,11 +161,10 @@ class ApiClientImp implements ApiClient { // body['VersionID'] = ApiConsts.appVersionID.toString(); if (!isExternal) { - body['VersionID'] = "50.0"; - body['Channel'] = ApiConsts.appChannelId.toString(); + body['VersionID'] = ApiConsts.appVersionID; + body['Channel'] = ApiConsts.appChannelId; body['IPAdress'] = ApiConsts.appIpAddress; body['generalid'] = ApiConsts.appGeneralId; - body['LanguageID'] = _appState.getLanguageID().toString(); body['Latitude'] = _appState.userLat.toString(); body['Longitude'] = _appState.userLong.toString(); @@ -184,9 +183,6 @@ class ApiClientImp implements ApiClient { } body.removeWhere((key, value) => value == null); - log("uri: ${Uri.parse(url.trim())}"); - - log("body: ${json.encode(body)}"); final bool networkStatus = await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck); @@ -202,6 +198,8 @@ class ApiClientImp implements ApiClient { final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers); final int statusCode = response.statusCode; + log("uri: ${Uri.parse(url.trim())}"); + log("body: ${json.encode(body)}"); log("response.body: ${response.body}"); if (statusCode < 200 || statusCode >= 400) { onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data")); @@ -213,13 +211,14 @@ class ApiClientImp implements ApiClient { onSuccess(parsed, statusCode, messageStatus: 1, errorMessage: ""); } else { onSuccess(parsed, statusCode, - messageStatus: parsed.contains('MessageStatus') ? parsed['MessageStatus'] : 1, - errorMessage: parsed.contains('ErrorEndUserMessage') ? parsed['ErrorEndUserMessage'] : ""); + messageStatus: (parsed is Map && parsed.containsKey('MessageStatus')) ? parsed['MessageStatus'] : 1, + errorMessage: (parsed is Map && parsed.containsKey('ErrorEndUserMessage')) ? parsed['ErrorEndUserMessage'] : ""); } } else { if (parsed['Response_Message'] != null) { onSuccess(parsed, statusCode, - messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']); + messageStatus: (parsed is Map && parsed.containsKey('MessageStatus')) ? parsed['MessageStatus'] : 1, + errorMessage: (parsed is Map && parsed.containsKey('ErrorEndUserMessage')) ? parsed['ErrorEndUserMessage'] : ""); } else { if (parsed['ErrorType'] == 4) { //TODO : handle app update @@ -352,9 +351,9 @@ class ApiClientImp implements ApiClient { url = endPoint; } else { if (isRCService) { - url = RC_BASE_URL + endPoint; + url = ApiConsts.rcBaseUrl + endPoint; } else { - url = BASE_URL + endPoint; + url = ApiConsts.baseUrl + endPoint; } } if (queryParams != null) { diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index b21d329..3faef34 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -14,7 +14,7 @@ var PACKAGES_ORDERS = '/api/orders'; var PACKAGES_ORDER_HISTORY = '/api/orders/items'; var PACKAGES_TAMARA_OPT = '/api/orders/paymentoptions/tamara'; // var BASE_URL = 'http://10.50.100.198:2018/'; -var BASE_URL = 'https://uat.hmgwebservices.com/'; +var BASE_URL = 'https://uat.hmgwebservices.com/'; // var BASE_URL = 'https://hmgwebservices.com/'; // var BASE_URL = 'http://10.201.204.103/'; // var BASE_URL = 'https://orash.cloudsolutions.com.sa/'; @@ -46,8 +46,6 @@ var PHARMACY_REDIRECT_URL = 'https://bit.ly/AlhabibPharmacy'; // RC API URL // var RC_BASE_URL = 'https://rc.hmg.com/'; -var RC_BASE_URL = 'https://rc.hmg.com/uat/'; - // var RC_BASE_URL = 'https://ms.hmg.com/rc/'; var PING_SERVICE = 'Services/Weather.svc/REST/CheckConnectivity'; @@ -521,12 +519,6 @@ var ADD_HHC_ORDER_RC = "api/HHC/add"; var GET_ALL_HHC_ORDERS_RC = 'api/hhc/list'; var UPDATE_HHC_ORDER_RC = 'api/hhc/update'; -// CMC RC SERVICES -var GET_ALL_CMC_SERVICES_RC = 'api/cmc/getallcmc'; -var ADD_CMC_ORDER_RC = 'api/cmc/add'; -var GET_ALL_CMC_ORDERS_RC = 'api/cmc/list'; -var UPDATE_CMC_ORDER_RC = 'api/cmc/update'; - // RRT RC SERVICES var ADD_RRT_ORDER_RC = "api/rrt/add"; var GET_ALL_RRT_ORDERS_RC = "api/rrt/list"; @@ -725,7 +717,7 @@ class ApiConsts { static String baseUrl = 'https://hmgwebservices.com/'; // HIS API URL PROD - static String RCBaseUrl = 'https://rc.hmg.com/'; // RC API URL PROD + static String rcBaseUrl = 'https://rc.hmg.com/'; // RC API URL PROD static var payFortEnvironment = FortEnvironment.production; static var applePayMerchantId = "merchant.com.hmgwebservices"; @@ -752,7 +744,7 @@ class ApiConsts { TAMARA_URL = "https://mdlaboratories.com/tamaralive/Home/Checkout"; GET_TAMARA_INSTALLMENTS_URL = "https://mdlaboratories.com/tamaralive/Home/GetInstallments"; GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid='; - RCBaseUrl = 'https://rc.hmg.com/'; + rcBaseUrl = 'https://rc.hmg.com/'; break; case AppEnvironmentTypeEnum.dev: baseUrl = "https://uat.hmgwebservices.com/"; @@ -762,7 +754,7 @@ class ApiConsts { TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; - RCBaseUrl = 'https://rc.hmg.com/test/'; + rcBaseUrl = 'https://rc.hmg.com/'; break; case AppEnvironmentTypeEnum.uat: baseUrl = "https://uat.hmgwebservices.com/"; @@ -772,7 +764,7 @@ class ApiConsts { TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; - RCBaseUrl = 'https://rc.hmg.com/test/'; + rcBaseUrl = 'https://rc.hmg.com/'; break; case AppEnvironmentTypeEnum.preProd: baseUrl = "https://webservices.hmg.com/"; @@ -782,7 +774,7 @@ class ApiConsts { TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; - RCBaseUrl = 'https://rc.hmg.com/'; + rcBaseUrl = 'https://rc.hmg.com/'; break; case AppEnvironmentTypeEnum.qa: baseUrl = "https://uat.hmgwebservices.com/"; @@ -792,7 +784,7 @@ class ApiConsts { TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; - RCBaseUrl = 'https://rc.hmg.com/test/'; + rcBaseUrl = 'https://rc.hmg.com/'; break; case AppEnvironmentTypeEnum.staging: baseUrl = "https://uat.hmgwebservices.com/"; @@ -802,7 +794,7 @@ class ApiConsts { TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments"; GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid='; - RCBaseUrl = 'https://rc.hmg.com/test/'; + rcBaseUrl = 'https://rc.hmg.com/'; break; } } @@ -846,8 +838,19 @@ class ApiConsts { static final String createAdvancePayments = 'Services/Patients.svc/REST/HIS_CreateAdvancePayment'; static final String addAdvanceNumberRequest = 'Services/PayFort_Serv.svc/REST/AddAdvancedNumberRequest'; + // RC CMC ServIces + static final String allCMCOrdersRc = 'api/cmc/list'; + static final String allCMCServicesRc = 'api/cmc/getallcmc'; + static final String updateCMCOrder = 'api/cmc/update'; + + // CMC RC SERVICES + var GET_ALL_CMC_SERVICES_RC = 'api/cmc/getallcmc'; + var ADD_CMC_ORDER_RC = 'api/cmc/add'; + var GET_ALL_CMC_ORDERS_RC = 'api/cmc/list'; + var UPDATE_CMC_ORDER_RC = 'api/cmc/update'; + // ************ static values for Api **************** - static final double appVersionID = 18.7; + static final double appVersionID = 20.0; 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_assets.dart b/lib/core/app_assets.dart index e8215ba..3f524be 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -171,7 +171,8 @@ class AppAssets { static const String to_arrow = '$svgBasePath/to_arrow.svg'; static const String dual_arrow = '$svgBasePath/to_arrow.svg'; static const String forward_arrow_medium = '$svgBasePath/forward_arrow_medium.svg'; - + static const String eReferral = '$svgBasePath/e-referral.svg'; + static const String comprehensiveCheckup = '$svgBasePath/comprehensive_checkup.svg'; //bottom navigation// static const String homeBottom = '$svgBasePath/home_bottom.svg'; @@ -200,6 +201,8 @@ class AppAssets { static const String visa = '$pngBasePath/visa.png'; static const String lockIcon = '$pngBasePath/lock-icon.png'; static const String dummy_user = '$pngBasePath/dummy_user.png'; + static const String comprehensiveCheckupEn = '$pngBasePath/cc_en.png'; + static const String comprehensiveCheckupAr = '$pngBasePath/cc_er.png'; } class AppAnimations { diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index 37d0cc4..835e9bf 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -15,6 +15,8 @@ import 'package:hmg_patient_app_new/features/emergency_services/emergency_servic import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_repo.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_repo.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_repo.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart'; import 'package:hmg_patient_app_new/features/insurance/insurance_repo.dart'; @@ -104,47 +106,30 @@ class AppDependencies { getIt.registerLazySingleton(() => InsuranceRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton(() => PayfortRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton( - () => LocalAuthService(loggerService: getIt(), localAuth: getIt())); + () => LocalAuthService(loggerService: getIt(), localAuth: getIt()), + ); getIt.registerLazySingleton(() => HabibWalletRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton(() => MedicalFileRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton(() => ImmediateLiveCareRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton(() => EmergencyServicesRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton(() => TodoSectionRepoImp(loggerService: getIt(), apiClient: getIt())); - getIt.registerLazySingleton( - () => LocationRepoImpl(apiClient: getIt())); + getIt.registerLazySingleton(() => LocationRepoImpl(apiClient: getIt())); getIt.registerLazySingleton(() => ContactUsRepoImp(loggerService: getIt(), apiClient: getIt())); + getIt.registerLazySingleton(() => HmgServicesRepoImp(loggerService: getIt(), apiClient: getIt())); // ViewModels // Global/shared VMs → LazySingleton - getIt.registerLazySingleton( - () => LabViewModel(labRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt()), - ); + getIt.registerLazySingleton(() => LabViewModel(labRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt())); - getIt.registerLazySingleton( - () => RadiologyViewModel( - radiologyRepo: getIt(), - errorHandlerService: getIt(), - ), - ); + getIt.registerLazySingleton(() => RadiologyViewModel(radiologyRepo: getIt(), errorHandlerService: getIt())); - getIt.registerLazySingleton( - () => PrescriptionsViewModel( - prescriptionsRepo: getIt(), - errorHandlerService: getIt(), - ), - ); + getIt.registerLazySingleton(() => PrescriptionsViewModel(prescriptionsRepo: getIt(), errorHandlerService: getIt())); - getIt.registerLazySingleton( - () => InsuranceViewModel( - insuranceRepo: getIt(), - errorHandlerService: getIt(), - ), - ); + getIt.registerLazySingleton(() => InsuranceViewModel(insuranceRepo: getIt(), errorHandlerService: getIt())); getIt.registerLazySingleton( - () => MyAppointmentsViewModel(myAppointmentsRepo: getIt(), errorHandlerService: getIt(), appState: getIt()), - ); + () => MyAppointmentsViewModel(myAppointmentsRepo: getIt(), errorHandlerService: getIt(), appState: getIt())); getIt.registerLazySingleton( () => PayfortViewModel( @@ -198,53 +183,39 @@ class AppDependencies { ); getIt.registerLazySingleton(() => ProfileSettingsViewModel()); - getIt.registerLazySingleton( - () => DateRangeSelectorRangeViewModel(), - ); + getIt.registerLazySingleton(() => DateRangeSelectorRangeViewModel()); - getIt.registerLazySingleton( - () => DoctorFilterViewModel(), - ); + getIt.registerLazySingleton(() => DoctorFilterViewModel()); getIt.registerLazySingleton( - () => AppointmentViaRegionViewmodel( - navigationService: getIt(), - appState: getIt(), - ), + () => AppointmentViaRegionViewmodel(navigationService: getIt(), appState: getIt()), ); getIt.registerLazySingleton( () => EmergencyServicesViewModel( - locationUtils: getIt(), - navServices: getIt(), - emergencyServicesRepo: getIt(), - appState: getIt(), - errorHandlerService: getIt(), - appointmentRepo: getIt(), - dialogService: getIt() - ), + locationUtils: getIt(), + navServices: getIt(), + emergencyServicesRepo: getIt(), + appState: getIt(), + errorHandlerService: getIt(), + appointmentRepo: getIt(), + dialogService: getIt()), ); getIt.registerLazySingleton( - () => LocationViewModel( - locationRepo: getIt(), - errorHandlerService: getIt(), - ), + () => LocationViewModel(locationRepo: getIt(), errorHandlerService: getIt()), ); getIt.registerLazySingleton( - () => ContactUsViewModel( - contactUsRepo: getIt(), - appState: getIt(), - errorHandlerService: getIt(), - ), + () => ContactUsViewModel(contactUsRepo: getIt(), appState: getIt(), errorHandlerService: getIt()), ); getIt.registerLazySingleton( - () => TodoSectionViewModel( - todoSectionRepo: getIt(), - errorHandlerService: getIt(), - ), + () => TodoSectionViewModel(todoSectionRepo: getIt(), errorHandlerService: getIt()), + ); + + getIt.registerLazySingleton( + () => HmgServicesViewModel(hmgServicesRepo: getIt(), errorHandlerService: getIt()), ); // Screen-specific VMs → Factory diff --git a/lib/core/utils/date_util.dart b/lib/core/utils/date_util.dart index d58aef6..82b9909 100644 --- a/lib/core/utils/date_util.dart +++ b/lib/core/utils/date_util.dart @@ -6,19 +6,17 @@ class DateUtil { /// convert String To Date function /// [date] String we want to convert static DateTime convertStringToDate(String? date) { - print("the date is $date"); - if (date == null) return DateTime.now(); if (date.isEmpty) return DateTime.now(); - const start = "/Date("; - const end = "+0300)"; - final startIndex = date.indexOf(start); - final endIndex = date.indexOf(end, startIndex + start.length); - return DateTime.fromMillisecondsSinceEpoch(int.parse( - date.substring(startIndex + start.length, endIndex), - )); - + const start = "/Date("; + const end = "+0300)"; + final startIndex = date.indexOf(start); + final endIndex = date.indexOf(end, startIndex + start.length); + return DateTime.fromMillisecondsSinceEpoch(int.parse( + date.substring(startIndex + start.length, endIndex), + )) + ; } static DateTime convertStringToDateSaudiTimezone(String date, int projectId) { @@ -36,10 +34,10 @@ class DateUtil { // .add(Duration(hours: 4)); // } else { return DateTime.fromMillisecondsSinceEpoch( - int.parse( - date.substring(startIndex + start.length, endIndex), - ), - isUtc: true) + int.parse( + date.substring(startIndex + start.length, endIndex), + ), + isUtc: true) .add(Duration(hours: 3)); // } } else { @@ -156,7 +154,13 @@ class DateUtil { static String getDateFormatted(String date) { DateTime dateObj = DateUtil.convertStringToDate(date); - return DateUtil.getWeekDay(dateObj.weekday) + ", " + dateObj.day.toString() + " " + DateUtil.getMonth(dateObj.month) + " " + dateObj.year.toString(); + return DateUtil.getWeekDay(dateObj.weekday) + + ", " + + dateObj.day.toString() + + " " + + DateUtil.getMonth(dateObj.month) + + " " + + dateObj.year.toString(); } static String getISODateFormat(DateTime dateTime) { @@ -352,7 +356,13 @@ class DateUtil { if (dateTime != null) { return lang == 'en' ? getWeekDayEnglish(dateTime.weekday) + ", " + getMonth(dateTime.month) + " " + dateTime.day.toString() + " " + dateTime.year.toString() - : getWeekDayArabic(dateTime.weekday) + ", " + dateTime.day.toString() + " " + getMonthArabic(dateTime.month) + " " + dateTime.year.toString(); + : getWeekDayArabic(dateTime.weekday) + + ", " + + dateTime.day.toString() + + " " + + getMonthArabic(dateTime.month) + + " " + + dateTime.year.toString(); } else { return ""; } @@ -381,7 +391,9 @@ class DateUtil { static String getMonthYearLangDateFormatted(DateTime dateTime, String lang) { if (dateTime != null) { - return lang == 'en' ? getMonth(dateTime.month) + " " + dateTime.year.toString() : getMonthArabic(dateTime.month) + " " + dateTime.year.toString(); + return lang == 'en' + ? getMonth(dateTime.month) + " " + dateTime.year.toString() + : getMonthArabic(dateTime.month) + " " + dateTime.year.toString(); } else { return ""; } @@ -488,10 +500,8 @@ class DateUtil { } } - -extension OnlyDate on DateTime{ - - DateTime provideDateOnly(){ +extension OnlyDate on DateTime { + DateTime provideDateOnly() { return DateTime(this.year, month, day); } -} \ No newline at end of file +} diff --git a/lib/features/emergency_services/emergency_services_repo.dart b/lib/features/emergency_services/emergency_services_repo.dart index c54c3d1..ccfc210 100644 --- a/lib/features/emergency_services/emergency_services_repo.dart +++ b/lib/features/emergency_services/emergency_services_repo.dart @@ -44,13 +44,11 @@ abstract class EmergencyServicesRepo { Future>>> getTransportationMethods({int? id}); - Future>> submitAmbulanceRequest(PatientER_RC request); Future>>> getTransportationOrders({int? id}); - Future>> cancelOrder(int? iD, int patientId); - + Future>> cancelOrder(int? iD, int patientId); } class EmergencyServicesRepoImp implements EmergencyServicesRepo { @@ -150,7 +148,10 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo { onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { final list = response['response']['transportationservices']; - final proceduresList = list.map((item) => PatientERTransportationMethod.fromJson(item as Map)).toList().cast(); + final proceduresList = list + .map((item) => PatientERTransportationMethod.fromJson(item as Map)) + .toList() + .cast(); apiResponse = GenericApiModel>( messageStatus: messageStatus, @@ -249,7 +250,7 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo { Failure? failure; await apiClient.post( body: {}, - "$GET_ALL_TRANSPORTATIONS_ORDERS?patientID=$id", + "$GET_ALL_TRANSPORTATIONS_ORDERS?patientID=$id", isRCService: true, onFailure: (error, statusCode, {messageStatus, failureType}) { failure = failureType; @@ -257,7 +258,8 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo { onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { final list = response['response']; - final proceduresList = list.map((item) => AmbulanceRequestOrdersModel.fromJson(item as Map)).toList().cast(); + final proceduresList = + list.map((item) => AmbulanceRequestOrdersModel.fromJson(item as Map)).toList().cast(); apiResponse = GenericApiModel>( messageStatus: messageStatus, @@ -327,13 +329,11 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo { await apiClient.post( CHECK_PATIENT_ER_ADVANCE_BALANCE, body: mapDevice, - onFailure: (error, statusCode, {messageStatus, failureType}) { - failure = failureType; - }, + onFailure: (error, statusCode, {messageStatus, failureType}) => failure = failureType, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { final bool patientHasERBalance = response['BalanceAmount'] > 0; - print(patientHasERBalance); + log(patientHasERBalance.toString()); apiResponse = GenericApiModel( messageStatus: messageStatus, statusCode: statusCode, @@ -353,7 +353,6 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo { } } - @override Future>> checkPatientERPaymentInformation({int? projectID}) async { Map mapDevice = {"ClinicID": 10, "ProjectID": projectID ?? 0}; diff --git a/lib/features/hmg_services/hmg_services_repo.dart b/lib/features/hmg_services/hmg_services_repo.dart new file mode 100644 index 0000000..39a6142 --- /dev/null +++ b/lib/features/hmg_services/hmg_services_repo.dart @@ -0,0 +1,178 @@ +import 'dart:developer'; + +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/hmg_services/models/req_models/order_update_req_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart'; +import 'package:hmg_patient_app_new/services/logger_service.dart'; + +abstract class HmgServicesRepo { + Future>>> getAllCmcOrders(); + + Future>> updateCmcPresOrder(OrderUpdateRequestModel requestModel); + + Future>>> getAllCmcServices({required int patientID}); +} + +class HmgServicesRepoImp implements HmgServicesRepo { + final ApiClient apiClient; + final LoggerService loggerService; + + HmgServicesRepoImp({required this.apiClient, required this.loggerService}); + + @override + Future>>> getAllCmcOrders() async { + Map requestBody = {}; + + try { + GenericApiModel>? apiResponse; + Failure? failure; + + await apiClient.post( + ApiConsts.allCMCOrdersRc, + isRCService: true, + body: requestBody, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + loggerService.logError("CMC Orders API Failed: $error, Status: $statusCode"); + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + List cmcOrdersList = []; + // Log the full response for debugging + // Extract MessageStatus and ErrorEndUserMessage from root level + final apiErrorMessage = response['ErrorEndUserMessage'] as String?; + // Parse the response array + if (response['response'] != null && response['response'] is List) { + final ordersList = response['response'] as List; + + for (var orderJson in ordersList) { + if (orderJson is Map) { + try { + cmcOrdersList.add(GetCMCAllOrdersResponseModel.fromJson(orderJson)); + } catch (e) { + loggerService.logError("Error parsing individual order: ${e.toString()}"); + } + } + } + } + + apiResponse = GenericApiModel>( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: apiErrorMessage ?? errorMessage, + data: cmcOrdersList, + ); + } catch (e) { + loggerService.logError("Error parsing CMC orders: ${e.toString()}"); + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + loggerService.logError("Unknown error in getAllCmcOrders: ${e.toString()}"); + return Left(UnknownFailure(e.toString())); + } + } + + @override + Future>>> getAllCmcServices({required int patientID}) async { + Map requestBody = {}; + + try { + GenericApiModel>? apiResponse; + Failure? failure; + + await apiClient.post( + '${ApiConsts.allCMCServicesRc}?patientID=$patientID', + isRCService: true, + isAllowAny: true, + body: requestBody, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + loggerService.logError("CMC Services API Failed: $error, Status: $statusCode"); + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + List cmcServicesList = []; + + if (response['response'] != null && response['response'] is List) { + final servicesList = response['response'] as List; + + for (var serviceJson in servicesList) { + if (serviceJson is Map) { + cmcServicesList.add(GetCMCServicesResponseModel.fromJson(serviceJson)); + } + } + } + + apiResponse = GenericApiModel>( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: cmcServicesList, + ); + } catch (e) { + loggerService.logError("Error parsing CMC services: ${e.toString()}"); + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + log("Unknown error in getAllCmcServices: ${e.toString()}"); + return Left(UnknownFailure(e.toString())); + } + } + + @override + Future>> updateCmcPresOrder(OrderUpdateRequestModel requestModel) async { + try { + GenericApiModel? apiResponse; + Failure? failure; + + await apiClient.post( + ApiConsts.updateCMCOrder, + isRCService: true, + body: requestModel.toJson(), + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + loggerService.logError("Update CMC Order API Failed: $error, Status: $statusCode"); + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: true, + ); + + loggerService.logInfo("CMC Order updated successfully: PresOrderID=${requestModel.presOrderID}"); + } catch (e) { + loggerService.logError("Error processing update CMC order response: ${e.toString()}"); + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + loggerService.logError("Unknown error in updateCmcPresOrder: ${e.toString()}"); + return Left(UnknownFailure(e.toString())); + } + } +} diff --git a/lib/features/hmg_services/hmg_services_view_model.dart b/lib/features/hmg_services/hmg_services_view_model.dart new file mode 100644 index 0000000..84e3bb4 --- /dev/null +++ b/lib/features/hmg_services/hmg_services_view_model.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_repo.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/order_update_req_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart'; +import 'package:hmg_patient_app_new/services/error_handler_service.dart'; + +class HmgServicesViewModel extends ChangeNotifier { + final HmgServicesRepo hmgServicesRepo; + final ErrorHandlerService errorHandlerService; + + HmgServicesViewModel({required this.hmgServicesRepo, required this.errorHandlerService}); + + bool isCmcOrdersLoading = false; + bool isCmcServicesLoading = false; + bool isUpdatingOrder = false; + + List cmcOrdersList = []; + List cmcServicesList = []; + + Future getOrdersList() async { + cmcOrdersList.clear(); + isCmcOrdersLoading = true; + notifyListeners(); + await getAllCmcOrders(); + } + + Future getAllCmcOrders({ + Function(dynamic)? onSuccess, + Function(String)? onError, + }) async { + isCmcOrdersLoading = true; + notifyListeners(); + + final result = await hmgServicesRepo.getAllCmcOrders(); + + result.fold( + (failure) async { + isCmcOrdersLoading = false; + notifyListeners(); + await errorHandlerService.handleError(failure: failure); + if (onError != null) { + onError(failure.toString()); + } + }, + (apiResponse) { + isCmcOrdersLoading = false; + if (apiResponse.messageStatus == 1) { + cmcOrdersList = apiResponse.data ?? []; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } else { + notifyListeners(); + if (onError != null) { + onError(apiResponse.errorMessage ?? 'Unknown error'); + } + } + }, + ); + } + + Future getAllCmcServices({required int patientID, Function(dynamic)? onSuccess, Function(String)? onError}) async { + isCmcServicesLoading = true; + notifyListeners(); + + final result = await hmgServicesRepo.getAllCmcServices(patientID: patientID); + + result.fold( + (failure) async { + isCmcServicesLoading = false; + notifyListeners(); + await errorHandlerService.handleError(failure: failure); + if (onError != null) { + onError(failure.toString()); + } + }, + (apiResponse) { + isCmcServicesLoading = false; + if (apiResponse.messageStatus == 1) { + cmcServicesList = apiResponse.data ?? []; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } else { + notifyListeners(); + if (onError != null) { + onError(apiResponse.errorMessage ?? 'Unknown error'); + } + } + }, + ); + } + + Future updateCmcPresOrder({ + required OrderUpdateRequestModel requestModel, + Function(dynamic)? onSuccess, + Function(String)? onError, + }) async { + isUpdatingOrder = true; + notifyListeners(); + + final result = await hmgServicesRepo.updateCmcPresOrder(requestModel); + + bool success = false; + + result.fold( + (failure) async { + isUpdatingOrder = false; + notifyListeners(); + await errorHandlerService.handleError(failure: failure); + if (onError != null) { + onError(failure.toString()); + } + }, + (apiResponse) { + isUpdatingOrder = false; + if (apiResponse.messageStatus == 1) { + success = true; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } else { + notifyListeners(); + if (onError != null) { + onError(apiResponse.errorMessage ?? 'Unknown error'); + } + } + }, + ); + + return success; + } +} diff --git a/lib/features/hmg_services/models/hmg_services.dart b/lib/features/hmg_services/models/hmg_services.dart deleted file mode 100644 index 2c33381..0000000 --- a/lib/features/hmg_services/models/hmg_services.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; - -class HmgServices { - int action; - String title; - String subTitle; - String icon; - bool isLogin; - bool isLocked; - Color bgColor; - Color textColor; - String route; - HmgServices(this.action, this.title, this.subTitle, this.icon, this.isLogin, {this.isLocked = false, this.bgColor = Colors.white, this.textColor = Colors.black, this.route=''}); -} diff --git a/lib/features/hmg_services/models/req_models/cmc_create_new_order_req_model.dart b/lib/features/hmg_services/models/req_models/cmc_create_new_order_req_model.dart new file mode 100644 index 0000000..a1fcc4b --- /dev/null +++ b/lib/features/hmg_services/models/req_models/cmc_create_new_order_req_model.dart @@ -0,0 +1,131 @@ +class CMCInsertPresOrderRequestModel { + double? versionID; + int? channel; + int? languageID; + String? iPAdress; + String? generalid; + int? patientOutSA; + String? sessionID; + bool? isDentalAllowedBackend; + int? deviceTypeID; + int? patientID; + String? tokenID; + int? patientTypeID; + int? patientType; + double? latitude; + double? longitude; + int? createdBy; + int? orderServiceID; + int? projectID; + List? patientERCMCInsertServicesList; + + CMCInsertPresOrderRequestModel( + {this.versionID, + this.channel, + this.languageID, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID, + this.patientID, + this.tokenID, + this.patientTypeID, + this.patientType, + this.latitude, + this.longitude, + this.createdBy, + this.orderServiceID, + this.projectID, + this.patientERCMCInsertServicesList}); + + CMCInsertPresOrderRequestModel.fromJson(Map json) { + 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']; + patientID = json['PatientID']; + tokenID = json['TokenID']; + patientTypeID = json['PatientTypeID']; + patientType = json['PatientType']; + latitude = json['Latitude']; + longitude = json['Longitude']; + createdBy = json['CreatedBy']; + orderServiceID = json['OrderServiceID']; + projectID = json['ProjectId']; + if (json['PatientER_CMC_InsertServicesList'] != null) { + patientERCMCInsertServicesList = []; + json['PatientER_CMC_InsertServicesList'].forEach((v) { + patientERCMCInsertServicesList!.add( + new PatientERCMCInsertServicesList.fromJson(v), + ); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['VersionID'] = this.versionID; + data['Channel'] = this.channel; + data['LanguageID'] = this.languageID; + data['IPAdress'] = this.iPAdress; + data['generalid'] = this.generalid; + data['isOutPatient'] = this.patientOutSA == 0 ? false : true; + data['SessionID'] = this.sessionID; + data['isDentalAllowedBackend'] = this.isDentalAllowedBackend; + data['DeviceTypeID'] = this.deviceTypeID; + data['TokenID'] = this.tokenID; + data['PatientTypeID'] = this.patientTypeID; + data['PatientType'] = this.patientType; + data['latitude'] = this.latitude; + data['longitude'] = this.longitude; + // data['CreatedBy'] = this.createdBy; + data['OrderServiceID'] = this.orderServiceID; + data['ProjectID'] = this.projectID; + if (this.patientERCMCInsertServicesList != null) { + data['procedures'] = this.patientERCMCInsertServicesList!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class PatientERCMCInsertServicesList { + int? recordID; + String? serviceID; + String? selectedServiceName; + String? selectedServiceNameAR; + dynamic price; + dynamic vAT; + dynamic totalPrice; + + PatientERCMCInsertServicesList( + {this.recordID, this.serviceID, this.selectedServiceName, this.selectedServiceNameAR, this.price, this.vAT, this.totalPrice}); + + PatientERCMCInsertServicesList.fromJson(Map json) { + recordID = json['RecordID']; + serviceID = json['ServiceID']; + selectedServiceName = json['selectedServiceName']; + selectedServiceNameAR = json['selectedServiceNameAR']; + price = json['Price']; + vAT = json['VAT']; + totalPrice = json['TotalPrice']; + } + + Map toJson() { + final Map data = new Map(); + data['RecordID'] = this.recordID; + data['ServiceID'] = this.serviceID; + data['selectedServiceName'] = this.selectedServiceName; + data['selectedServiceNameAR'] = this.selectedServiceNameAR; + data['Price'] = this.price; + data['VAT'] = this.vAT; + data['TotalPrice'] = this.totalPrice; + return data; + } +} diff --git a/lib/features/hmg_services/models/req_models/order_update_req_model.dart b/lib/features/hmg_services/models/req_models/order_update_req_model.dart new file mode 100644 index 0000000..0f9964f --- /dev/null +++ b/lib/features/hmg_services/models/req_models/order_update_req_model.dart @@ -0,0 +1,82 @@ +class OrderUpdateRequestModel { + double? versionID; + int? channel; + int? languageID; + String? iPAdress; + String? generalid; + int? patientOutSA; + String? sessionID; + bool? isDentalAllowedBackend; + int? deviceTypeID; + int? patientID; + String? tokenID; + int? patientTypeID; + int? patientType; + int? presOrderID; + int? presOrderStatus; + int? editedBy; + String? rejectionReason; + + OrderUpdateRequestModel({ + this.versionID, + this.channel, + this.languageID, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID, + this.patientID, + this.tokenID, + this.patientTypeID, + this.patientType, + this.presOrderID, + this.presOrderStatus, + this.editedBy, + this.rejectionReason, + }); + + OrderUpdateRequestModel.fromJson(Map json) { + 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']; + patientID = json['PatientID']; + tokenID = json['TokenID']; + patientTypeID = json['PatientTypeID']; + patientType = json['PatientType']; + presOrderID = json['PresOrderID']; + presOrderStatus = json['PresOrderStatus']; + editedBy = json['EditedBy']; + rejectionReason = json['RejectionReason']; + } + + Map toJson() { + final Map data = {}; + 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['PatientID'] = patientID; + data['TokenID'] = tokenID; + data['PatientTypeID'] = patientTypeID; + data['PatientType'] = patientType; + data['Id'] = presOrderID; + data['ClickButton'] = 14; + data['PresOrderStatus'] = presOrderStatus; + data['EditedBy'] = editedBy; + data['RejectionReason'] = rejectionReason; + return data; + } +} diff --git a/lib/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart b/lib/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart new file mode 100644 index 0000000..ddd91f4 --- /dev/null +++ b/lib/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart @@ -0,0 +1,344 @@ +import 'dart:developer'; + +class GetCMCAllOrdersResponseModel { + int? iD; + int? patientId; + int? patientOutSa; + bool? isOutPatient; + int? projectId; + int? nearestProjectId; + dynamic longitude; + dynamic latitude; + dynamic appointmentNo; + dynamic dischargeId; + int? statusId; + int? serviceId; + int? channel; + Orderpayment? orderpayment; + dynamic orderselectedservice; + dynamic wforder; + dynamic orderapprovalobj; + String? created; + dynamic createdBy; + dynamic modified; + dynamic modifiedBy; + bool? isDeleted; + String? statusText; + int? paymentStatus; + dynamic clientRequestid; + dynamic paymentStatusText; + String? projectName; + String? nearestProjectName; + dynamic paymentAmount; + WFOrder? wFOrder; + String? serviceText; + bool? isSentForApproval; + int? exaCartOrderId; + bool? isTimer; + int? timeSeconds; + int? totalPendingSeconds; + int? timeMinute; + int? timeHour; + int? timeTotalSeconds; + int? timeTotalMinute; + int? timeTotalHour; + dynamic approvalStatus; + bool? isActive; + int? clickButton; + List? procedures; + dynamic pickupLocation; + dynamic dropOffLocation; + dynamic clinicName; + dynamic doctorName; + dynamic branch; + dynamic time; + dynamic notes; + + GetCMCAllOrdersResponseModel( + {this.iD, + this.patientId, + this.patientOutSa, + this.isOutPatient, + this.projectId, + this.nearestProjectId, + this.longitude, + this.latitude, + this.appointmentNo, + this.dischargeId, + this.statusId, + this.serviceId, + this.channel, + this.orderpayment, + this.orderselectedservice, + this.wforder, + this.orderapprovalobj, + this.created, + this.createdBy, + this.modified, + this.modifiedBy, + this.isDeleted, + this.statusText, + this.paymentStatus, + this.clientRequestid, + this.paymentStatusText, + this.projectName, + this.nearestProjectName, + this.paymentAmount, + this.wFOrder, + this.serviceText, + this.isSentForApproval, + this.exaCartOrderId, + this.isTimer, + this.timeSeconds, + this.totalPendingSeconds, + this.timeMinute, + this.timeHour, + this.timeTotalSeconds, + this.timeTotalMinute, + this.timeTotalHour, + this.approvalStatus, + this.isActive, + this.clickButton, + this.procedures, + this.pickupLocation, + this.dropOffLocation, + this.clinicName, + this.doctorName, + this.branch, + this.time, + this.notes}); + + GetCMCAllOrdersResponseModel.fromJson(Map json) { + log("responseJson: $json"); + iD = json['ID']; + patientId = json['PatientId']; + patientOutSa = json['PatientOutSa']; + isOutPatient = json['IsOutPatient']; + projectId = json['ProjectId']; + nearestProjectId = json['NearestProjectId']; + longitude = json['Longitude']; + latitude = json['Latitude']; + appointmentNo = json['AppointmentNo']; + dischargeId = json['DischargeId']; + statusId = json['StatusId']; + serviceId = json['ServiceId']; + channel = json['Channel']; + orderpayment = json['orderpayment'] != null ? Orderpayment.fromJson(json['orderpayment']) : null; + orderselectedservice = json['orderselectedservice']; + wforder = json['wforder']; + orderapprovalobj = json['orderapprovalobj']; + created = json['Created']; + createdBy = json['CreatedBy']; + modified = json['Modified']; + modifiedBy = json['ModifiedBy']; + isDeleted = json['IsDeleted']; + statusText = json['StatusText']; + paymentStatus = json['PaymentStatus']; + clientRequestid = json['ClientRequestid']; + paymentStatusText = json['PaymentStatusText']; + projectName = json['ProjectName']; + nearestProjectName = json['NearestProjectName']; + paymentAmount = json['PaymentAmount']; + wFOrder = json['WF_order'] != null ? WFOrder.fromJson(json['WF_order']) : null; + serviceText = json['ServiceText']; + isSentForApproval = json['isSentForApproval']; + exaCartOrderId = json['ExaCart_OrderId']; + isTimer = json['isTimer']; + timeSeconds = json['TimeSeconds']; + totalPendingSeconds = json['TotalPendingSeconds']; + timeMinute = json['TimeMinute']; + timeHour = json['TimeHour']; + timeTotalSeconds = json['TimeTotalSeconds']; + timeTotalMinute = json['TimeTotalMinute']; + timeTotalHour = json['TimeTotalHour']; + approvalStatus = json['ApprovalStatus']; + isActive = json['isActive']; + clickButton = json['ClickButton']; + pickupLocation = json['PickupLocation']; + dropOffLocation = json['DropOffLocation']; + clinicName = json['clinicName']; + doctorName = json['DoctorName']; + branch = json['Branch']; + time = json['Time']; + notes = json['Notes']; + } + + Map toJson() { + final Map data = {}; + data['ID'] = iD; + data['PatientId'] = patientId; + data['PatientOutSa'] = patientOutSa; + data['IsOutPatient'] = isOutPatient; + data['ProjectId'] = projectId; + data['NearestProjectId'] = nearestProjectId; + data['Longitude'] = longitude; + data['Latitude'] = latitude; + data['AppointmentNo'] = appointmentNo; + data['DischargeId'] = dischargeId; + data['StatusId'] = statusId; + data['ServiceId'] = serviceId; + data['Channel'] = channel; + if (orderpayment != null) { + data['orderpayment'] = orderpayment!.toJson(); + } + data['orderselectedservice'] = orderselectedservice; + + data['wforder'] = wforder; + data['orderapprovalobj'] = orderapprovalobj; + data['Created'] = created; + data['CreatedBy'] = createdBy; + data['Modified'] = modified; + data['ModifiedBy'] = modifiedBy; + data['IsDeleted'] = isDeleted; + data['StatusText'] = statusText; + data['PaymentStatus'] = paymentStatus; + data['ClientRequestid'] = clientRequestid; + data['PaymentStatusText'] = paymentStatusText; + data['ProjectName'] = projectName; + data['NearestProjectName'] = nearestProjectName; + data['PaymentAmount'] = paymentAmount; + if (wFOrder != null) { + data['WF_order'] = wFOrder!.toJson(); + } + data['ServiceText'] = serviceText; + data['isSentForApproval'] = isSentForApproval; + data['ExaCart_OrderId'] = exaCartOrderId; + data['isTimer'] = isTimer; + data['TimeSeconds'] = timeSeconds; + data['TotalPendingSeconds'] = totalPendingSeconds; + data['TimeMinute'] = timeMinute; + data['TimeHour'] = timeHour; + data['TimeTotalSeconds'] = timeTotalSeconds; + data['TimeTotalMinute'] = timeTotalMinute; + data['TimeTotalHour'] = timeTotalHour; + data['ApprovalStatus'] = approvalStatus; + data['isActive'] = isActive; + data['ClickButton'] = clickButton; + data['PickupLocation'] = pickupLocation; + data['DropOffLocation'] = dropOffLocation; + data['clinicName'] = clinicName; + data['DoctorName'] = doctorName; + data['Branch'] = branch; + data['Time'] = time; + data['Notes'] = notes; + return data; + } +} + +class Orderpayment { + int? iD; + int? orderId; + dynamic clientRequestId; + dynamic totalAmount; + int? paymentStatus; + dynamic order; + String? created; + dynamic createdBy; + dynamic modified; + dynamic modifiedBy; + bool? isDeleted; + + Orderpayment( + {this.iD, + this.orderId, + this.clientRequestId, + this.totalAmount, + this.paymentStatus, + this.order, + this.created, + this.createdBy, + this.modified, + this.modifiedBy, + this.isDeleted}); + + Orderpayment.fromJson(Map json) { + iD = json['ID']; + orderId = json['OrderId']; + clientRequestId = json['ClientRequestId']; + totalAmount = json['TotalAmount']; + paymentStatus = json['PaymentStatus']; + order = json['Order']; + created = json['Created']; + createdBy = json['CreatedBy']; + modified = json['Modified']; + modifiedBy = json['ModifiedBy']; + isDeleted = json['IsDeleted']; + } + + Map toJson() { + final Map data = {}; + data['ID'] = iD; + data['OrderId'] = orderId; + data['ClientRequestId'] = clientRequestId; + data['TotalAmount'] = totalAmount; + data['PaymentStatus'] = paymentStatus; + data['Order'] = order; + data['Created'] = created; + data['CreatedBy'] = createdBy; + data['Modified'] = modified; + data['ModifiedBy'] = modifiedBy; + data['IsDeleted'] = isDeleted; + return data; + } +} + +class WFOrder { + dynamic wfButtonsDTO; + int? iD; + int? orderId; + int? previousStep; + int? nextStep; + int? serviceId; + dynamic order; + String? created; + dynamic createdBy; + dynamic modified; + dynamic modifiedBy; + bool? isDeleted; + + WFOrder( + {this.wfButtonsDTO, + this.iD, + this.orderId, + this.previousStep, + this.nextStep, + this.serviceId, + this.order, + this.created, + this.createdBy, + this.modified, + this.modifiedBy, + this.isDeleted}); + + WFOrder.fromJson(Map json) { + wfButtonsDTO = json['wf_ButtonsDTO']; + iD = json['ID']; + orderId = json['OrderId']; + previousStep = json['PreviousStep']; + nextStep = json['NextStep']; + serviceId = json['ServiceId']; + order = json['Order']; + created = json['Created']; + createdBy = json['CreatedBy']; + modified = json['Modified']; + modifiedBy = json['ModifiedBy']; + isDeleted = json['IsDeleted']; + } + + Map toJson() { + final Map data = {}; + data['wf_ButtonsDTO'] = wfButtonsDTO; + data['ID'] = iD; + data['OrderId'] = orderId; + data['PreviousStep'] = previousStep; + data['NextStep'] = nextStep; + data['ServiceId'] = serviceId; + data['Order'] = order; + data['Created'] = created; + data['CreatedBy'] = createdBy; + data['Modified'] = modified; + data['ModifiedBy'] = modifiedBy; + data['IsDeleted'] = isDeleted; + return data; + } +} diff --git a/lib/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart b/lib/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart new file mode 100644 index 0000000..670a582 --- /dev/null +++ b/lib/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart @@ -0,0 +1,57 @@ +class GetCMCServicesResponseModel { + int? iD; + String? serviceID; + int? orderServiceID; + String? text; + String? textN; + dynamic price; + dynamic priceVAT; + dynamic priceTotal; + bool? isEnabled; + int? orderId; + int? quantity; + + GetCMCServicesResponseModel({ + this.iD, + this.serviceID, + this.orderServiceID, + this.text, + this.textN, + this.price, + this.priceVAT, + this.priceTotal, + this.isEnabled, + this.orderId, + this.quantity, + }); + + GetCMCServicesResponseModel.fromJson(Map json) { + iD = json['ID']; + serviceID = json['ServiceID']; + orderServiceID = json['OrderServiceID']; + text = json['Text']; + textN = json['TextN']; + price = json['Price']; + priceVAT = json['PriceVAT']; + priceTotal = json['PriceTotal']; + isEnabled = json['IsEnabled']; + orderId = json['OrderId']; + quantity = json['Quantity']; + } + + Map toJson() { + final Map data = {}; + data['ID'] = this.iD; + data['ServiceID'] = this.serviceID; + data['OrderServiceID'] = this.orderServiceID; + data['Text'] = this.text; + data['TextN'] = this.textN; + data['Price'] = this.price; + data['PriceVAT'] = this.priceVAT; + data['PriceTotal'] = this.priceTotal; + data['IsEnabled'] = this.isEnabled; + data['OrderId'] = this.orderId; + data['Quantity'] = this.quantity; + return data; + } +} diff --git a/lib/features/hmg_services/models/ui_models/hmg_services_component_model.dart b/lib/features/hmg_services/models/ui_models/hmg_services_component_model.dart new file mode 100644 index 0000000..d5180ae --- /dev/null +++ b/lib/features/hmg_services/models/ui_models/hmg_services_component_model.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +class HmgServicesComponentModel { + int action; + String title; + String subTitle; + String icon; + bool isLogin; + bool isLocked; + Color bgColor; + Color textColor; + String route; + + HmgServicesComponentModel( + this.action, + this.title, + this.subTitle, + this.icon, + this.isLogin, { + this.isLocked = false, + this.bgColor = Colors.white, + this.textColor = Colors.black, + this.route = '', + }); +} diff --git a/lib/main.dart b/lib/main.dart index 20c4ece..1af80b6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -14,6 +14,7 @@ import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.da import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart'; import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart'; import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/history/lab_history_viewmodel.dart'; @@ -132,7 +133,8 @@ void main() async { ), ChangeNotifierProvider( create: (_) => getIt.get(), - ),ChangeNotifierProvider( + ), + ChangeNotifierProvider( create: (_) => getIt.get(), ), ChangeNotifierProvider( @@ -140,6 +142,9 @@ void main() async { ), ChangeNotifierProvider( create: (_) => getIt.get(), + ), + ChangeNotifierProvider( + create: (_) => getIt.get(), ) ], child: MyApp()), ), diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 79084c9..12f3589 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -30,7 +30,7 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; -import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; +import 'package:hmg_patient_app_new/widgets/shimmer/common_shimmer_widget.dart'; import 'package:maps_launcher/maps_launcher.dart'; import 'package:provider/provider.dart'; @@ -317,7 +317,7 @@ class _AppointmentDetailsPageState extends State { SizedBox(height: 16.h), Consumer(builder: (context, prescriptionVM, child) { return prescriptionVM.isPrescriptionsDetailsLoading - ? const MoviesShimmerWidget() + ? const CommonShimmerWidget() : Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: Colors.white, diff --git a/lib/presentation/comprehensive_checkup/cmc_order_detail_page.dart b/lib/presentation/comprehensive_checkup/cmc_order_detail_page.dart new file mode 100644 index 0000000..97e5e6d --- /dev/null +++ b/lib/presentation/comprehensive_checkup/cmc_order_detail_page.dart @@ -0,0 +1,344 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.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/features/hmg_services/hmg_services_view_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/order_update_req_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart'; +import 'package:hmg_patient_app_new/services/dialog_service.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import 'package:shimmer/shimmer.dart'; + +class CmcOrderDetailPage extends StatefulWidget { + const CmcOrderDetailPage({super.key}); + + @override + State createState() => _CmcOrderDetailPageState(); +} + +class _CmcOrderDetailPageState extends State { + bool _isLoading = false; + + @override + void initState() { + super.initState(); + final hmgServicesViewModel = context.read(); + scheduleMicrotask(() async { + await hmgServicesViewModel.getOrdersList(); + }); + } + + Color _getStatusColor(int? statusId) { + switch (statusId) { + case 1: // Pending + return const Color(0xffCC9B14); + case 2: // Processing + return const Color(0xff2E303A); + case 3: // Completed + return const Color(0xff359846); + case 4: // Cancelled + case 6: // Rejected + case 7: // Rejected + return const Color(0xffD02127); + default: + return AppColors.greyColor; + } + } + + String _formatDate(String? dateString) { + if (dateString == null) return ''; + try { + final date = DateTime.parse(dateString); + return DateFormat('dd MMM yyyy').format(date); + } catch (e) { + return dateString; + } + } + + Future _showCancelConfirmationDialog({ + required BuildContext context, + required HmgServicesViewModel viewModel, + required GetCMCAllOrdersResponseModel order, + }) async { + final dialogService = context.read(); + + await dialogService.showCommonBottomSheetWithoutH( + label: "Confirm Cancellation".needTranslation, + message: "Are you sure you want to cancel this order?".needTranslation, + onOkPressed: () async { + Navigator.of(context).pop(); + + // Show loading state + setState(() { + _isLoading = true; + }); + + final requestModel = OrderUpdateRequestModel( + presOrderID: order.iD, + rejectionReason: "", + presOrderStatus: 4, // Cancelled status + editedBy: 3, + ); + + final success = await viewModel.updateCmcPresOrder( + requestModel: requestModel, + onSuccess: (_) async { + setState(() { + _isLoading = false; + }); + Fluttertoast.showToast( + msg: "Order cancelled successfully".needTranslation, + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + backgroundColor: Colors.green, + textColor: Colors.white, + ); + await viewModel.getAllCmcOrders(); + }, + onError: (error) { + setState(() { + _isLoading = false; + }); + Fluttertoast.showToast( + msg: error, + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + backgroundColor: Colors.red, + textColor: Colors.white, + ); + }, + ); + + if (!success) { + setState(() { + _isLoading = false; + }); + } + }, + onCancelPressed: () { + Navigator.of(context).pop(); + }, + ); + } + + Widget _buildLoadingShimmer() { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.all(21.w), + itemCount: 3, + separatorBuilder: (_, __) => SizedBox(height: 12.h), + itemBuilder: (context, index) { + return Shimmer.fromColors( + baseColor: Colors.grey[300]!, + highlightColor: Colors.grey[100]!, + child: Container( + height: 120.h, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.r), + ), + ), + ); + }, + ); + } + + Widget _buildOrderCard(GetCMCAllOrdersResponseModel order) { + final statusColor = _getStatusColor(order.statusId); + final canCancel = order.statusId == 1 || order.statusId == 2; + + return Container( + decoration: BoxDecoration( + color: statusColor, + borderRadius: BorderRadius.circular(10.r), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withValues(alpha: 0.05), + blurRadius: 27, + offset: const Offset(0, -3), + ), + ], + ), + child: Container( + margin: EdgeInsets.only(left: 6.w), + padding: EdgeInsets.symmetric(vertical: 14.h, horizontal: 12.w), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: Colors.white, width: 1), + borderRadius: BorderRadius.only( + bottomRight: Radius.circular(10.r), + topRight: Radius.circular(10.r), + ), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + order.statusText ?? '', + style: TextStyle( + fontSize: 12.f, + fontWeight: FontWeight.w600, + color: statusColor, + letterSpacing: -0.4, + height: 16 / 10, + ), + ), + SizedBox(height: 6.h), + Text( + '${"Request ID".needTranslation}: ${order.iD}', + style: TextStyle( + fontSize: 16.f, + fontWeight: FontWeight.w600, + color: const Color(0xff2E303A), + letterSpacing: -0.64, + height: 25 / 16, + ), + ), + SizedBox(height: 4.h), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "${"Hospital".needTranslation}: ", + style: TextStyle( + fontSize: 12.f, + fontWeight: FontWeight.w600, + color: const Color(0xff575757), + letterSpacing: -0.4, + height: 16 / 10, + ), + ), + Expanded( + child: Text( + order.projectName?.trim() ?? '', + style: TextStyle( + fontSize: 14.f, + fontWeight: FontWeight.w600, + color: const Color(0xff2B353E), + letterSpacing: -0.56, + ), + ), + ), + ], + ), + ], + ), + ), + Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + _formatDate(order.created), + style: TextStyle( + fontSize: 12.f, + fontWeight: FontWeight.w600, + color: const Color(0xff2B353E), + letterSpacing: -0.4, + height: 16 / 10, + ), + ), + if (canCancel) ...[ + SizedBox(height: 12.h), + InkWell( + onTap: _isLoading + ? null + : () { + _showCancelConfirmationDialog( + context: context, + viewModel: context.read(), + order: order, + ); + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 14.w), + decoration: BoxDecoration( + color: _isLoading ? Colors.grey : const Color(0xffD02127), + border: Border.all(color: Colors.white, width: 1), + borderRadius: BorderRadius.circular(10.r), + ), + child: Text( + "Cancel".needTranslation, + style: TextStyle( + fontSize: 12.f, + fontWeight: FontWeight.w600, + color: Colors.white, + letterSpacing: -0.4, + ), + ), + ), + ), + ], + ], + ), + ], + ), + ), + ); + } + + Widget _buildEmptyState() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.inbox_outlined, size: 80.w, color: AppColors.greyColor), + SizedBox(height: 16.h), + Text( + "No orders found".needTranslation, + style: TextStyle( + fontSize: 16.f, + color: AppColors.greyTextColor, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + return CollapsingListView( + title: "CMC Orders".needTranslation, + isLeading: true, + child: Consumer( + builder: (context, viewModel, child) { + if (viewModel.isCmcOrdersLoading) { + return _buildLoadingShimmer(); + } + + if (viewModel.cmcOrdersList.isEmpty) { + return SizedBox( + height: MediaQuery.of(context).size.height * 0.6, + child: _buildEmptyState(), + ); + } + + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.all(21.w), + itemCount: viewModel.cmcOrdersList.length, + separatorBuilder: (_, __) => SizedBox(height: 12.h), + itemBuilder: (context, index) { + final order = viewModel.cmcOrdersList.reversed.toList()[index]; + return _buildOrderCard(order); + }, + ); + }, + ), + ); + } +} diff --git a/lib/presentation/comprehensive_checkup/comprehensive_checkup_page.dart b/lib/presentation/comprehensive_checkup/comprehensive_checkup_page.dart new file mode 100644 index 0000000..d242e55 --- /dev/null +++ b/lib/presentation/comprehensive_checkup/comprehensive_checkup_page.dart @@ -0,0 +1,378 @@ +import 'dart:async'; + +import 'package:flutter/material.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/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart'; +import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/cmc_order_detail_page.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/media_viewer/full_screen_image_viewer.dart'; +import 'package:hmg_patient_app_new/widgets/radio_list_tile_widget.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; +import 'package:provider/provider.dart'; +import 'package:shimmer/shimmer.dart'; + +class ComprehensiveCheckupPage extends StatefulWidget { + const ComprehensiveCheckupPage({super.key}); + + @override + State createState() => _ComprehensiveCheckupPageState(); +} + +class _ComprehensiveCheckupPageState extends State { + int? _selectedServiceId; + GetCMCServicesResponseModel? _selectedService; + + @override + void initState() { + super.initState(); + final HmgServicesViewModel hmgServicesViewModel = context.read(); + final AppState appState = getIt.get(); + + scheduleMicrotask(() async { + final user = appState.getAuthenticatedUser(); + if (user != null) { + await hmgServicesViewModel.getAllCmcOrders(); + await hmgServicesViewModel.getAllCmcServices(patientID: user.patientId ?? 0); + } + }); + } + + GetCMCAllOrdersResponseModel? _getPendingOrder(List orders) { + if (orders.isEmpty) return null; + + // Find pending or processing orders (status 1 or 2) + for (var order in orders) { + if (order.statusId == 1 || order.statusId == 2) { + return order; + } + } + + return null; + } + + Widget _buildPendingOrderCard(GetCMCAllOrdersResponseModel order) { + int status = order.statusId ?? 0; + String statusDisp = order.statusText ?? ""; + Color statusColor; + + if (status == 1) { + // pending + statusColor = const Color(0xffCC9B14); + } else if (status == 2) { + // processing + statusColor = const Color(0xff2E303A); + } else if (status == 3) { + // completed + statusColor = const Color(0xff359846); + } else { + // cancel / rejected + statusColor = const Color(0xffD02127); + } + + return Container( + width: double.infinity, + margin: EdgeInsets.all(16.h), + decoration: BoxDecoration( + color: AppColors.whiteColor, + borderRadius: BorderRadius.circular(12.h), + boxShadow: [ + BoxShadow( + color: Color.fromARGB(13, 0, 0, 0), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: Container( + padding: EdgeInsets.all(14.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + statusDisp, + style: TextStyle( + fontSize: 12.h, + fontWeight: FontWeight.w600, + color: statusColor, + letterSpacing: -0.4, + ), + ), + SizedBox(height: 6.h), + Text( + '${"Request ID".needTranslation}: ${order.iD}', + style: TextStyle( + fontSize: 16.h, + fontWeight: FontWeight.w600, + color: AppColors.blackColor, + letterSpacing: -0.64, + ), + ), + SizedBox(height: 4.h), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "${"Hospital".needTranslation}: ", + style: TextStyle( + fontSize: 12.h, + fontWeight: FontWeight.w600, + color: AppColors.greyTextColor, + letterSpacing: -0.4, + ), + ), + Expanded( + child: Text( + order.projectName ?? "", + style: TextStyle( + fontSize: 14.h, + fontWeight: FontWeight.w600, + color: const Color(0xff2B353E), + letterSpacing: -0.56, + ), + ), + ), + ], + ), + SizedBox(height: 4.h), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "${"Service Name".needTranslation}: ", + style: TextStyle( + fontSize: 12.h, + fontWeight: FontWeight.w600, + color: AppColors.greyTextColor, + letterSpacing: -0.4, + ), + ), + Expanded( + child: Text( + order.serviceText ?? "", + style: TextStyle( + fontSize: 14.h, + fontWeight: FontWeight.w600, + color: const Color(0xff2B353E), + letterSpacing: -0.56, + ), + ), + ), + ], + ), + ], + ), + ), + ], + ), + ], + ), + ), + ); + } + + Widget _buildServiceSelectionList(List services) { + if (services.isEmpty) { + return Center( + child: Padding( + padding: EdgeInsets.all(24.h), + child: Text( + 'No services available'.needTranslation, + style: TextStyle( + fontSize: 16.h, + color: AppColors.greyTextColor, + ), + ), + ), + ); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 16.h), + Text( + 'Select a Service'.needTranslation, + style: TextStyle( + fontSize: 20.h, + fontWeight: FontWeight.w700, + color: AppColors.blackColor, + letterSpacing: -0.8, + ), + ).paddingOnly(left: 16.w, right: 16.w), + ListView.builder( + padding: EdgeInsets.zero, + itemCount: services.length, + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + final service = services[index]; + final serviceName = service.text ?? service.textN ?? ''; + final price = service.priceTotal ?? 0.0; + return RadioListTileWidget( + value: service.iD ?? 0, + groupValue: _selectedServiceId, + title: serviceName, + subtitleWidget: Utils.getPaymentAmountWithSymbol( + isExpanded: false, + price.toString().toText14(), + AppColors.blackColor, + 14, + isSaudiCurrency: true, + ), + onChanged: (value) { + setState(() { + _selectedServiceId = value; + _selectedService = service; + }); + }, + ); + }, + ), + // Illustration image below the services list similar to the old implementation + SizedBox(height: 12.h), + Builder(builder: (context) { + final appStateLocal = getIt.get(); + final String imagePath = appStateLocal.isArabic() ? AppAssets.comprehensiveCheckupAr : AppAssets.comprehensiveCheckupEn; + return Stack( + children: [ + Image.asset( + imagePath, + width: double.infinity, + fit: BoxFit.cover, + ).paddingAll(16.w), + Align( + alignment: Alignment.topRight, + child: Container( + decoration: BoxDecoration( + color: Color.fromARGB(51, 0, 0, 0), + borderRadius: BorderRadius.circular(1000.r), + ), + margin: EdgeInsets.all(12.h), + child: IconButton( + icon: Icon(Icons.zoom_in, color: Colors.white), + padding: EdgeInsets.all(12.h), + onPressed: () => _showFullScreenImage(context, imagePath, isSvg: false), + ), + ), + ), + ], + ); + }), + ], + ); + } + + void _proceedWithSelectedService() { + if (_selectedService != null) { + // TODO: Navigate to next step or create order + // This will be implemented based on your flow + // For now, just show a message + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Selected: ${_selectedService!.text}'), + ), + ); + } + } + + Widget _buildLoadingShimmer() { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.all(21.w), + itemCount: 3, + separatorBuilder: (_, __) => SizedBox(height: 12.h), + itemBuilder: (context, index) { + return Shimmer.fromColors( + baseColor: Colors.grey[300]!, + highlightColor: Colors.grey[100]!, + child: Container( + height: 120.h, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.r), + ), + ), + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return CollapsingListView( + title: "Comprehensive Checkup".needTranslation, + requests: () { + Navigator.of(context).push(CustomPageRoute(page: CmcOrderDetailPage(), direction: AxisDirection.up)); + }, + // bottomChild sticks to the bottom of the scaffold; make it reactive using Consumer + bottomChild: Consumer( + builder: (context, hmgServicesViewModel, child) { + // if still loading, don't show the bottom button + if (hmgServicesViewModel.isCmcOrdersLoading || hmgServicesViewModel.isCmcServicesLoading) return SizedBox.shrink(); + + final pendingOrder = _getPendingOrder(hmgServicesViewModel.cmcOrdersList); + + // show button only when there is no pending order and a service is selected + if (pendingOrder == null && _selectedServiceId != null) { + return SafeArea( + top: false, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h), + child: CustomButton( + borderWidth: 0, + text: "Next".needTranslation, + onPressed: _proceedWithSelectedService, + textColor: AppColors.whiteColor, + borderRadius: 12.r, + borderColor: Colors.transparent, + padding: EdgeInsets.symmetric(vertical: 14.h), + ), + ), + ); + } + + return SizedBox.shrink(); + }, + ), + child: Consumer( + builder: (context, hmgServicesViewModel, child) { + if (hmgServicesViewModel.isCmcOrdersLoading || hmgServicesViewModel.isCmcServicesLoading) { + return _buildLoadingShimmer(); + } + + final pendingOrder = _getPendingOrder(hmgServicesViewModel.cmcOrdersList); + + if (pendingOrder != null) { + // Return the pending order card directly. The outer CollapsingListView's + // CustomScrollView/SliverList will provide proper scroll constraints. + return _buildPendingOrderCard(pendingOrder); + } else { + return _buildServiceSelectionList(hmgServicesViewModel.cmcServicesList); + } + }, + ), + ); + } + + void _showFullScreenImage(BuildContext context, String path, {bool isSvg = false}) { + Navigator.of(context).push(MaterialPageRoute(builder: (_) => FullScreenImageViewer(isSvg: isSvg, path: path))); + } +} diff --git a/lib/presentation/comprehensive_checkup/old_cmc_page.dart b/lib/presentation/comprehensive_checkup/old_cmc_page.dart new file mode 100644 index 0000000..042eab0 --- /dev/null +++ b/lib/presentation/comprehensive_checkup/old_cmc_page.dart @@ -0,0 +1,195 @@ +// import 'package:hmg_patient_app/core/enum/viewstate.dart'; +// import 'package:hmg_patient_app/core/model/AlHabibMedicalService/ComprehensiveMedicalCheckup/cmc_insert_pres_order_request_model.dart'; +// import 'package:hmg_patient_app/core/viewModels/AlHabibMedicalService/cmc_view_model.dart'; +// import 'package:hmg_patient_app/core/viewModels/project_view_model.dart'; +// import 'package:hmg_patient_app/pages/AlHabibMedicalService/ComprehensiveMedicalCheckup/NewCMC/new_cmc_step_three_page.dart'; +// import 'package:hmg_patient_app/uitl/translations_delegate_base.dart'; +// import 'package:hmg_patient_app/uitl/utils.dart'; +// import 'package:hmg_patient_app/uitl/utils_new.dart'; +// import 'package:hmg_patient_app/widgets/buttons/defaultButton.dart'; +// import 'package:hmg_patient_app/widgets/dragable_sheet.dart'; +// import 'package:hmg_patient_app/widgets/others/app_scaffold_widget.dart'; +// import 'package:hmg_patient_app/widgets/photo_view_page.dart'; +// import 'package:flutter/cupertino.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_svg/svg.dart'; +// import 'package:provider/provider.dart'; +// +// import 'new_cmc_step_tow_page.dart'; +// +// class NewCMCStepOnePage extends StatefulWidget { +// final CMCInsertPresOrderRequestModel cMCInsertPresOrderRequestModel; +// final Function changePageViewIndex; +// final CMCViewModel model; +// +// final double latitude; +// final double longitude; +// +// const NewCMCStepOnePage({Key? key, required this.cMCInsertPresOrderRequestModel, required this.model, required this.changePageViewIndex, required this.latitude, required this.longitude}) +// : super(key: key); +// +// @override +// _NewCMCStepOnePageState createState() => _NewCMCStepOnePageState(); +// } +// +// class _NewCMCStepOnePageState extends State { +// int selectedItem = 0; +// +// @override +// void initState() { +// super.initState(); +// } +// +// @override +// Widget build(BuildContext context) { +// ProjectViewModel projectViewModel = Provider.of(context); +// +// return AppScaffold( +// isShowAppBar: false, +// baseViewModel: widget.model, +// body: Column( +// children: [ +// Expanded( +// child: SingleChildScrollView( +// physics: BouncingScrollPhysics(), +// padding: EdgeInsets.all(21), +// child: Column( +// children: [ +// ListView.separated( +// physics: NeverScrollableScrollPhysics(), +// shrinkWrap: true, +// itemBuilder: (context, index) { +// return Row( +// children: [ +// Radio( +// value: num.tryParse(widget.model.cmcAllServicesList[index].serviceID!), +// activeColor: Colors.red[800], +// onChanged: (newValue) async { +// selectedItem = index; +// PatientERCMCInsertServicesList patientERCMCInsertServicesList = PatientERCMCInsertServicesList( +// price: widget.model.cmcAllServicesList[index].price, +// serviceID: widget.model.cmcAllServicesList[index].serviceID, +// selectedServiceName: widget.model.cmcAllServicesList[index].text, +// selectedServiceNameAR: widget.model.cmcAllServicesList[index].textN, +// recordID: 1, +// totalPrice: widget.model.cmcAllServicesList[index].priceTotal, +// vAT: widget.model.cmcAllServicesList[index].priceVAT); +// setState(() { +// widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList = [patientERCMCInsertServicesList]; +// }); +// // CMCGetItemsRequestModel cMCGetItemsRequestModel = new CMCGetItemsRequestModel(checkupType: newValue); +// // await widget.model.getCheckupItems(cMCGetItemsRequestModel: cMCGetItemsRequestModel); +// }, +// groupValue: widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList!.length > 0 +// ? int.parse(widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList![0].serviceID!) +// : 1), +// Expanded( +// child: Padding( +// padding: const EdgeInsets.only( +// left: 10, +// right: 10, +// top: 20, +// bottom: 20, +// ), +// child: Text( +// projectViewModel.isArabic ? widget.model.cmcAllServicesList[index].textN! : widget.model.cmcAllServicesList[index].text!, +// style: TextStyle( +// fontSize: 14, +// fontWeight: FontWeight.w600, +// letterSpacing: -0.45, +// ), +// ), +// ), +// ), +// ], +// ); +// }, +// separatorBuilder: (context, index) { +// return mDivider(Colors.grey); +// }, +// itemCount: widget.model.cmcAllServicesList.length), +// Stack( +// children: [ +// Image.asset( +// projectViewModel.isArabic ? "assets/images/cc_ar.png" : "assets/images/cc_en.png", +// width: double.infinity, +// ), +// Align( +// alignment: Alignment.topRight, +// child: Container( +// decoration: containerColorRadiusBorder( +// Colors.black.withOpacity(0.2), +// 1000, +// Colors.white, +// ), +// margin: EdgeInsets.all(12), +// child: IconButton( +// icon: SvgPicture.asset( +// "assets/images/new/ic_zoom.svg", +// color: Colors.white, +// ), +// padding: EdgeInsets.all(12), +// onPressed: () { +// showDraggableDialog(context, PhotoViewPage(projectViewModel.isArabic ? "assets/images/cc_ar.png" : "assets/images/cc_en.png")); +// }, +// ), +// ), +// ), +// ], +// ), +// ], +// ), +// ), +// ), +// Container( +// color: Colors.white, +// padding: EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21), +// child: DefaultButton( +// TranslationBase.of(context).next, +// () async { +// if (widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList!.length != 0 || widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList == null) { +// // int index = widget.model.cmcAllServicesList.length; +// PatientERCMCInsertServicesList patientERCMCInsertServicesList = new PatientERCMCInsertServicesList( +// price: widget.model.cmcAllServicesList[selectedItem].price, +// serviceID: widget.model.cmcAllServicesList[selectedItem].serviceID.toString(), +// selectedServiceName: widget.model.cmcAllServicesList[selectedItem].text, +// selectedServiceNameAR: widget.model.cmcAllServicesList[selectedItem].textN, +// recordID: 1, +// totalPrice: widget.model.cmcAllServicesList[selectedItem].priceTotal, +// vAT: widget.model.cmcAllServicesList[selectedItem].priceVAT, +// ); +// +// widget.cMCInsertPresOrderRequestModel.patientID = projectViewModel.user!.patientID; +// widget.cMCInsertPresOrderRequestModel.patientOutSA = projectViewModel.user!.outSA; +// +// widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList = [patientERCMCInsertServicesList]; +// navigateTo( +// context, +// NewCMCStepThreePage( +// cmcInsertPresOrderRequestModel: widget.cMCInsertPresOrderRequestModel, +// model: widget.model, +// ), +// ); +// // await widget.model.getCustomerInfo(); +// if (widget.model.state == ViewState.ErrorLocal) { +// Utils.showErrorToast(); +// } else { +// // navigateTo( +// // context, +// // NewCMCStepTowPage( +// // longitude: widget.longitude, +// // latitude: widget.latitude, +// // cmcInsertPresOrderRequestModel: widget.cMCInsertPresOrderRequestModel, +// // model: widget.model, +// // ), +// // ); +// } +// } +// }, +// ), +// ), +// ], +// ), +// ); +// } +// } diff --git a/lib/presentation/comprehensive_checkup/old_detail_page.dart b/lib/presentation/comprehensive_checkup/old_detail_page.dart new file mode 100644 index 0000000..27070fe --- /dev/null +++ b/lib/presentation/comprehensive_checkup/old_detail_page.dart @@ -0,0 +1,183 @@ +// import 'package:hmg_patient_app/core/enum/viewstate.dart'; +// import 'package:hmg_patient_app/core/model/AlHabibMedicalService/ComprehensiveMedicalCheckup/GetCMCAllOrdersResponseModel.dart'; +// import 'package:hmg_patient_app/core/model/AlHabibMedicalService/HomeHealthCare/get_hhc_all_pres_orders_response_model.dart'; +// import 'package:hmg_patient_app/core/model/AlHabibMedicalService/HomeHealthCare/update_pres_oreder_request_model.dart'; +// import 'package:hmg_patient_app/core/viewModels/AlHabibMedicalService/cmc_view_model.dart'; +// import 'package:hmg_patient_app/core/viewModels/project_view_model.dart'; +// import 'package:hmg_patient_app/uitl/app_toast.dart'; +// import 'package:hmg_patient_app/uitl/date_uitl.dart'; +// import 'package:hmg_patient_app/uitl/gif_loader_dialog_utils.dart'; +// import 'package:hmg_patient_app/uitl/translations_delegate_base.dart'; +// import 'package:hmg_patient_app/uitl/utils.dart'; +// import 'package:hmg_patient_app/uitl/utils_new.dart'; +// import 'package:hmg_patient_app/widgets/buttons/defaultButton.dart'; +// import 'package:hmg_patient_app/widgets/buttons/secondary_button.dart'; +// import 'package:hmg_patient_app/widgets/data_display/text.dart'; +// import 'package:hmg_patient_app/widgets/dialogs/ConfirmWithMessageDialog.dart'; +// import 'package:hmg_patient_app/widgets/others/app_scaffold_widget.dart'; +// import 'package:flutter/material.dart'; +// import 'package:provider/provider.dart'; +// +// import 'Dialog/confirm_cancel_order_dialog.dart'; +// +// class OrdersLogDetailsPage extends StatelessWidget { +// final CMCViewModel model; +// +// const OrdersLogDetailsPage({Key ?key, required this.model}) : super(key: key); +// +// @override +// Widget build(BuildContext context) { +// ProjectViewModel projectViewModel = Provider.of(context); +// +// void showConfirmMessage(CMCViewModel model, GetCMCAllOrdersResponseModel order) { +// showDialog( +// context: context, +// builder: (cxt) => ConfirmWithMessageDialog( +// message: TranslationBase.of(context).cancelOrderMsg, +// onTap: () { +// UpdatePresOrderRequestModel updatePresOrderRequestModel = UpdatePresOrderRequestModel(presOrderID: order.iD, rejectionReason: "", presOrderStatus: 4, editedBy: 3); +// Future.delayed(new Duration(milliseconds: 300)).then((value) async { +// GifLoaderDialogUtils.showMyDialog(context); +// await model.updateCmcPresOrder(updatePresOrderRequestModel); +// if (model.state == ViewState.ErrorLocal) { +// Utils.showErrorToast(model.error); +// GifLoaderDialogUtils.hideDialog(context); +// } else { +// AppToast.showSuccessToast(message: TranslationBase.of(context).processDoneSuccessfully); +// await model.getCmcAllPresOrders(); +// GifLoaderDialogUtils.hideDialog(context); +// } +// }); +// }, +// )); +// return; +// } +// +// return AppScaffold( +// isShowAppBar: false, +// baseViewModel: model, +// body: model.cmcAllPresOrders.length > 0 ? ListView.separated( +// padding: EdgeInsets.all(21), +// physics: BouncingScrollPhysics(), +// itemBuilder: (context, index) { +// GetCMCAllOrdersResponseModel order = model.cmcAllPresOrders.reversed.toList()[index]; +// +// int status = order.statusId!; +// String _statusDisp = order.statusText!; +// late Color _color; +// if (status == 1) { +// //pending +// _color = Color(0xffCC9B14); +// } else if (status == 2) { +// //processing +// _color = Color(0xff2E303A); +// } else if (status == 3) { +// //completed +// _color = Color(0xff359846); +// } else if (status == 4 || status == 6 || status == 7) { +// //cancel // Rejected +// _color = Color(0xffD02127); +// } +// return Container( +// decoration: BoxDecoration( +// color: _color, +// borderRadius: BorderRadius.all( +// Radius.circular(10.0), +// ), +// boxShadow: [ +// BoxShadow( +// color: Color(0xff000000).withOpacity(.05), +// blurRadius: 27, +// offset: Offset(0, -3), +// ), +// ], +// ), +// child: Container( +// margin: EdgeInsets.only(left: projectViewModel.isArabic ? 0 : 6, right: projectViewModel.isArabic ? 6 : 0), +// padding: EdgeInsets.symmetric(vertical: 14, horizontal: 12), +// decoration: BoxDecoration( +// color: Colors.white, +// border: Border.all(color: Colors.white, width: 1), +// borderRadius: BorderRadius.only( +// bottomRight: projectViewModel.isArabic ? Radius.circular(0) : Radius.circular(10.0), +// topRight: projectViewModel.isArabic ? Radius.circular(0) : Radius.circular(10.0), +// bottomLeft: projectViewModel.isArabic ? Radius.circular(10.0) : Radius.circular(0), +// topLeft: projectViewModel.isArabic ? Radius.circular(10.0) : Radius.circular(0), +// ), +// ), +// // clipBehavior: Clip.antiAlias, +// child: Row( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Expanded( +// child: Column( +// mainAxisAlignment: MainAxisAlignment.start, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Text( +// _statusDisp, +// style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: _color, letterSpacing: -0.4, height: 16 / 10), +// ), +// SizedBox(height: 6), +// Text( +// '${TranslationBase.of(context).requestID}: ${order.iD}', +// style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2E303A), letterSpacing: -0.64, height: 25 / 16), +// ), +// Row( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Text( +// TranslationBase.of(context).hospital + ": ", +// style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xff575757), letterSpacing: -0.4, height: 16 / 10), +// ), +// Expanded( +// child: Text( +// // !projectViewModel.isArabic ? order.nearestProjectDescription.trim().toString() : order.nearestProjectDescriptionN.toString(), +// order.projectName != null ? order.projectName!.trim().toString() : "", +// style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.56), +// ), +// ), +// ], +// ) +// ], +// ), +// ), +// Column( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// crossAxisAlignment: CrossAxisAlignment.end, +// children: [ +// Text( +// DateUtil.getDayMonthYearDateFormatted(DateTime.tryParse(order.created!)!), +// style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.4, height: 16 / 10), +// ), +// SizedBox(height: 12), +// if (order.statusId == 1 || order.statusId == 2) +// InkWell( +// onTap: () { +// showConfirmMessage(model, order); +// }, +// child: Container( +// padding: EdgeInsets.symmetric(vertical: 8, horizontal: 14), +// decoration: BoxDecoration( +// color: Color(0xffD02127), +// border: Border.all(color: Colors.white, width: 1), +// borderRadius: BorderRadius.circular(10), +// ), +// child: Text( +// TranslationBase.of(context).cancel_nocaps, +// style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Colors.white, letterSpacing: -0.4), +// ), +// ), +// ), +// ], +// ), +// ], +// ), +// ), +// ); +// }, +// separatorBuilder: (context, index) => SizedBox(height: 12), +// itemCount: model.cmcAllPresOrders.length) : getNoDataWidget(context), +// ); +// } +// } diff --git a/lib/presentation/emergency_services/emergency_services_page.dart b/lib/presentation/emergency_services/emergency_services_page.dart index 3cbce23..ce4ae2b 100644 --- a/lib/presentation/emergency_services/emergency_services_page.dart +++ b/lib/presentation/emergency_services/emergency_services_page.dart @@ -11,11 +11,9 @@ import 'package:hmg_patient_app_new/features/emergency_services/emergency_servic import 'package:hmg_patient_app_new/features/location/location_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/emergency_services/RRT/rrt_request_type_select.dart'; -import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/call_ambulance_page.dart'; import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/ambulance_option_selection_bottomsheet.dart'; import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/pickup_location.dart'; import 'package:hmg_patient_app_new/presentation/emergency_services/history/er_history_listing.dart'; -import 'package:hmg_patient_app_new/presentation/emergency_services/nearest_er_page.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; @@ -39,7 +37,7 @@ class EmergencyServicesPage extends StatelessWidget { return CollapsingListView( title: LocaleKeys.emergencyServices.tr(), requests: () { - Navigator.of(context).push(CustomPageRoute(page: ErHistoryListing(), direction: AxisDirection.up)); + Navigator.of(context).push(CustomPageRoute(page: ErHistoryListing(), direction: AxisDirection.up)); }, child: Padding( padding: EdgeInsets.all(24.h), @@ -62,7 +60,9 @@ class EmergencyServicesPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ "Call Ambulance".needTranslation.toText16(isBold: true, color: AppColors.blackColor), - "Request an ambulance in emergency from home or hospital".needTranslation.toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), + "Request an ambulance in emergency from home or hospital" + .needTranslation + .toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), ], ), ), @@ -70,13 +70,10 @@ class EmergencyServicesPage extends StatelessWidget { Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, width: 13.h, height: 13.h), ], ).onPress(() { - - showCommonBottomSheetWithoutHeight( context, child: Container( - decoration: - RoundedRectangleBorder().toSmoothCornerDecoration( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.primaryRedColor, borderRadius: 24.h, ), @@ -101,21 +98,13 @@ class EmergencyServicesPage extends StatelessWidget { ], ), Lottie.asset(AppAnimations.ambulance_alert, - repeat: false, - reverse: false, - frameRate: FrameRate(60), - width: 120.h, - height: 120.h, - fit: BoxFit.contain), + repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain), SizedBox(height: 8.h), - "Confirmation".needTranslation.toText28( - color: AppColors.whiteColor, isBold: true), + "Confirmation".needTranslation.toText28(color: AppColors.whiteColor, isBold: true), SizedBox(height: 8.h), "Are you sure you want to call an ambulance?" .needTranslation - .toText14( - color: AppColors.whiteColor, - weight: FontWeight.w500), + .toText14(color: AppColors.whiteColor, weight: FontWeight.w500), SizedBox(height: 24.h), CustomButton( text: LocaleKeys.confirm.tr(context: context), @@ -123,7 +112,7 @@ class EmergencyServicesPage extends StatelessWidget { // Navigator.of(context).pop(); await emergencyServicesViewModel.getTransportationOption(); - openTranportationSelectionBottomSheet(context); + openTranportationSelectionBottomSheet(context); }, backgroundColor: AppColors.whiteColor, borderColor: AppColors.whiteColor, @@ -161,7 +150,9 @@ class EmergencyServicesPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ "Nearest ER Location".needTranslation.toText16(isBold: true, color: AppColors.blackColor), - "Get the details of nearest branch including directions".needTranslation.toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), + "Get the details of nearest branch including directions" + .needTranslation + .toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), ], ), ), @@ -189,7 +180,8 @@ class EmergencyServicesPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ "Rapid Response Team (RRT)".toText16(isBold: true, color: AppColors.blackColor), - "Comprehensive medical service for all sorts of urgent and stable cases".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), + "Comprehensive medical service for all sorts of urgent and stable cases" + .toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), ], ), ), @@ -224,11 +216,14 @@ class EmergencyServicesPage extends StatelessWidget { }), ], ), - Lottie.asset(AppAnimations.ambulance_alert, repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain), + Lottie.asset(AppAnimations.ambulance_alert, + repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain), SizedBox(height: 8.h), LocaleKeys.confirm.tr().toText28(color: AppColors.whiteColor, isBold: true), SizedBox(height: 8.h), - "Are you sure you want to call Rapid Response Team (RRT)?".needTranslation.toText14(color: AppColors.whiteColor, weight: FontWeight.w500), + "Are you sure you want to call Rapid Response Team (RRT)?" + .needTranslation + .toText14(color: AppColors.whiteColor, weight: FontWeight.w500), SizedBox(height: 24.h), CustomButton( text: LocaleKeys.confirm.tr(context: context), @@ -286,7 +281,9 @@ class EmergencyServicesPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ "Emergency Check-In".needTranslation.toText16(isBold: true, color: AppColors.blackColor), - "Prior ER Check-In to skip the line & payment at the reception.".needTranslation.toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), + "Prior ER Check-In to skip the line & payment at the reception." + .needTranslation + .toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), ], ), ), @@ -321,7 +318,8 @@ class EmergencyServicesPage extends StatelessWidget { }), ], ), - Lottie.asset(AppAnimations.ambulance_alert, repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain), + Lottie.asset(AppAnimations.ambulance_alert, + repeat: false, reverse: false, frameRate: FrameRate(60), width: 120.h, height: 120.h, fit: BoxFit.contain), SizedBox(height: 8.h), LocaleKeys.confirm.tr().toText28(color: AppColors.whiteColor, isBold: true), SizedBox(height: 8.h), @@ -362,14 +360,12 @@ class EmergencyServicesPage extends StatelessWidget { ); } - openPickupDetailsBottomSheet(BuildContext context){ + openPickupDetailsBottomSheet(BuildContext context) { showCommonBottomSheetWithoutHeight( - onCloseClicked: (){ - context - .read() - .flushPickupInformation(); + onCloseClicked: () { + context.read().flushPickupInformation(); }, - titleWidget: Transform.flip( + titleWidget: Transform.flip( flipX: emergencyServicesViewModel.isArabic ? true : false, child: Utils.buildSvgWithAssets( icon: AppAssets.arrow_back, @@ -377,45 +373,38 @@ class EmergencyServicesPage extends StatelessWidget { fit: BoxFit.contain, ), ).onPress(() { - context - .read() - .flushPickupInformation(); + context.read().flushPickupInformation(); Navigator.pop(context); openTranportationSelectionBottomSheet(context); }), context, - child: PickupLocation( - onTap: () { - Navigator.of(context).pop(); - context.read().flushSearchPredictions(); - context - .read() - .navigateTOAmbulancePage(); - }), + child: PickupLocation(onTap: () { + Navigator.of(context).pop(); + context.read().flushSearchPredictions(); + context.read().navigateTOAmbulancePage(); + }), isFullScreen: false, isCloseButtonVisible: true, hasBottomPadding: false, - backgroundColor: AppColors.bottomSheetBgColor, callBackFunc: () {}, ); } void openTranportationSelectionBottomSheet(BuildContext context) { - if(emergencyServicesViewModel.transportationOptions.isNotEmpty) { + if (emergencyServicesViewModel.transportationOptions.isNotEmpty) { showCommonBottomSheetWithoutHeight( title: "Transport Options".needTranslation, context, child: SizedBox( height: 400.h, - child: AmbulanceOptionSelectionBottomSheet( - onTap: () { - Navigator.of(context).pop(); - openPickupDetailsBottomSheet(context); - // context - // .read() - // .navigateTOAmbulancePage(); - }), + child: AmbulanceOptionSelectionBottomSheet(onTap: () { + Navigator.of(context).pop(); + openPickupDetailsBottomSheet(context); + // context + // .read() + // .navigateTOAmbulancePage(); + }), ), isFullScreen: false, isCloseButtonVisible: true, diff --git a/lib/presentation/hmg_services/services_page.dart b/lib/presentation/hmg_services/services_page.dart index dc0803b..2242441 100644 --- a/lib/presentation/hmg_services/services_page.dart +++ b/lib/presentation/hmg_services/services_page.dart @@ -1,25 +1,37 @@ import 'package:flutter/material.dart'; -import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; -import 'package:hmg_patient_app_new/features/hmg_services/models/hmg_services.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/ui_models/hmg_services_component_model.dart'; import 'package:hmg_patient_app_new/presentation/hmg_services/services_view.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; -class ServicesPage extends StatefulWidget { - const ServicesPage({super.key}); +class ServicesPage extends StatelessWidget { + ServicesPage({super.key}); - @override - State createState() => _ServicesPageState(); -} - -class _ServicesPageState extends State { - List hmgServices = []; - - @override - void initState() { - hmgServices.add(HmgServices(11,"E Referral Services".needTranslation, "".needTranslation, "assets/images/svg/e-referral.svg", true, bgColor: Colors.orangeAccent, textColor: Colors.black, route: "/ereferralPage")); - super.initState(); - } + final List hmgServices = [ + HmgServicesComponentModel( + 11, + "E Referral Services".needTranslation, + "".needTranslation, + AppAssets.eReferral, + true, + bgColor: Colors.orange, + textColor: AppColors.blackColor, + route: AppRoutes.eReferralPage, + ), + HmgServicesComponentModel( + 12, + "Comprehensive Checkup".needTranslation, + "".needTranslation, + AppAssets.comprehensiveCheckup, + true, + bgColor: AppColors.bgGreenColor, + textColor: AppColors.blackColor, + route: AppRoutes.comprehensiveCheckupPage, + ), + ]; @override Widget build(BuildContext context) { @@ -32,28 +44,25 @@ class _ServicesPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ "Medical & Care Services".needTranslation.toText18(isBold: true), - SizedBox(height: 20,), - Padding( - padding: const EdgeInsets.only( - left: 16, - right: 16, - top: 0, - ), - child: GridView.builder( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, // 4 icons per row - crossAxisSpacing: 16, - mainAxisSpacing: 24, - childAspectRatio: 0.75, + SizedBox(height: 20.h), + Padding( + padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 0), + child: GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, // 4 icons per row + crossAxisSpacing: 16.w, + mainAxisSpacing: 24.h, + childAspectRatio: 0.75, + ), + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: hmgServices.length, + padding: EdgeInsets.zero, + itemBuilder: (BuildContext context, int index) { + return ServiceGridViewItem(hmgServices[index], index, false); + }, ), - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: hmgServices.length, - padding: EdgeInsets.zero, - itemBuilder: (BuildContext context, int index) { - return ServiceGridView(hmgServices[index], index, false); - }, - )) + ) ], ), ), diff --git a/lib/presentation/hmg_services/services_view.dart b/lib/presentation/hmg_services/services_view.dart index 25fd365..225bd96 100644 --- a/lib/presentation/hmg_services/services_view.dart +++ b/lib/presentation/hmg_services/services_view.dart @@ -1,62 +1,50 @@ import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_export.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/extensions/string_extensions.dart'; -import 'package:hmg_patient_app_new/features/hmg_services/models/hmg_services.dart'; -import 'package:hmg_patient_app_new/routes/app_routes.dart'; +import 'package:hmg_patient_app_new/features/hmg_services/models/ui_models/hmg_services_component_model.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; +class ServiceGridViewItem extends StatelessWidget { + final HmgServicesComponentModel hmgServiceComponentModel; + final int index; + final bool isHomePage; + final bool isLocked; + + const ServiceGridViewItem(this.hmgServiceComponentModel, this.index, this.isHomePage, {super.key, this.isLocked = false}); -class ServiceGridView extends StatelessWidget { - HmgServices hmgServices; - int index; - bool isHomePage; - bool isLocked; - ServiceGridView(this.hmgServices, this.index, this.isHomePage, {super.key, this.isLocked = false}); - static final NavigationService _navigationService = getIt.get(); @override Widget build(BuildContext context) { return InkWell( - onTap: () { - _navigationService.pushAndReplace(hmgServices.route); - }, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - height: 48, - width: 48, - padding: EdgeInsets.all(0), - margin: EdgeInsets.all(0), - decoration: BoxDecoration( - color: hmgServices.bgColor, - borderRadius: BorderRadius.circular(12), + onTap: () => getIt.get().pushPageRoute(hmgServiceComponentModel.route), + child: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + height: 48.h, + width: 48.w, + padding: EdgeInsets.zero, + margin: EdgeInsets.zero, + decoration: BoxDecoration( + color: hmgServiceComponentModel.bgColor, + borderRadius: BorderRadius.circular(12.r), + ), + child: Utils.buildSvgWithAssets( + icon: hmgServiceComponentModel.icon, + height: 21.h, + width: 21.w, + fit: BoxFit.none, + ), ), - child:Utils.buildSvgWithAssets ( - icon: hmgServices.icon, - height: 21, - width: 21, - fit: BoxFit.none, + SizedBox(height: 5.h), + hmgServiceComponentModel.title.toText12( + fontWeight: FontWeight.w500, + color: hmgServiceComponentModel.textColor, + maxLine: 1, ), - ), - const SizedBox(height: 5), - hmgServices.title.toText12( - fontWeight: FontWeight.w500, - color:hmgServices.textColor, - - ), - // Text( - // hmgServices.subTitle, - // textAlign: TextAlign.left, - // style: TextStyle( - // fontSize: 14, - // fontWeight: FontWeight.w500, - // color: hmgServices.textColor, - // )), - // ) - ], - )); + ], + )); } - } diff --git a/lib/presentation/insurance/insurance_home_page.dart b/lib/presentation/insurance/insurance_home_page.dart index bd195c3..cdd9a2e 100644 --- a/lib/presentation/insurance/insurance_home_page.dart +++ b/lib/presentation/insurance/insurance_home_page.dart @@ -20,7 +20,7 @@ import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; -import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; +import 'package:hmg_patient_app_new/widgets/shimmer/common_shimmer_widget.dart'; import 'package:provider/provider.dart'; import 'widgets/insurance_history.dart'; diff --git a/lib/presentation/insurance/widgets/insurance_history.dart b/lib/presentation/insurance/widgets/insurance_history.dart index 1c7b1b9..a5114dd 100644 --- a/lib/presentation/insurance/widgets/insurance_history.dart +++ b/lib/presentation/insurance/widgets/insurance_history.dart @@ -12,7 +12,7 @@ import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.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/chip/app_custom_chip_widget.dart'; -import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; +import 'package:hmg_patient_app_new/widgets/shimmer/common_shimmer_widget.dart'; import 'package:provider/provider.dart'; class InsuranceHistory extends StatelessWidget { diff --git a/lib/presentation/insurance/widgets/insurance_update_details_card.dart b/lib/presentation/insurance/widgets/insurance_update_details_card.dart index acdf1c7..753a36c 100644 --- a/lib/presentation/insurance/widgets/insurance_update_details_card.dart +++ b/lib/presentation/insurance/widgets/insurance_update_details_card.dart @@ -12,7 +12,7 @@ import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.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/chip/app_custom_chip_widget.dart'; -import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; +import 'package:hmg_patient_app_new/widgets/shimmer/common_shimmer_widget.dart'; import 'package:provider/provider.dart'; class PatientInsuranceCardUpdateCard extends StatelessWidget { diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 84efb9c..193b639 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -56,7 +56,7 @@ import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; -import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; +import 'package:hmg_patient_app_new/widgets/shimmer/common_shimmer_widget.dart'; import 'package:provider/provider.dart'; import '../prescriptions/prescription_detail_page.dart'; @@ -460,7 +460,7 @@ class _MedicalFilePageState extends State { SizedBox(height: 16.h), Consumer(builder: (context, prescriptionVM, child) { return prescriptionVM.isPrescriptionsOrdersLoading - ? const MoviesShimmerWidget().paddingSymmetrical(24.w, 0.h) + ? const CommonShimmerWidget().paddingSymmetrical(24.w, 0.h) : prescriptionVM.patientPrescriptionOrders.isNotEmpty ? Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( diff --git a/lib/presentation/prescriptions/prescriptions_list_page.dart b/lib/presentation/prescriptions/prescriptions_list_page.dart index 1293c9c..87af39b 100644 --- a/lib/presentation/prescriptions/prescriptions_list_page.dart +++ b/lib/presentation/prescriptions/prescriptions_list_page.dart @@ -19,7 +19,7 @@ import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_deta 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/routes/custom_page_route.dart'; -import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; +import 'package:hmg_patient_app_new/widgets/shimmer/common_shimmer_widget.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; diff --git a/lib/presentation/radiology/radiology_orders_page.dart b/lib/presentation/radiology/radiology_orders_page.dart index 1d7dfe2..cb925ef 100644 --- a/lib/presentation/radiology/radiology_orders_page.dart +++ b/lib/presentation/radiology/radiology_orders_page.dart @@ -4,22 +4,20 @@ import 'package:easy_localization/easy_localization.dart'; 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/enums.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.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/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; -import 'package:hmg_patient_app_new/presentation/radiology/search_radiology.dart'; -import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/presentation/radiology/radiology_result_page.dart'; +import 'package:hmg_patient_app_new/presentation/radiology/search_radiology.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; -import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:provider/provider.dart'; @@ -34,7 +32,7 @@ class RadiologyOrdersPage extends StatefulWidget { class _RadiologyOrdersPageState extends State { late RadiologyViewModel radiologyViewModel; - String selectedFilterText =''; + String selectedFilterText = ''; int? expandedIndex; @override @@ -80,22 +78,22 @@ class _RadiologyOrdersPageState extends State { children: [ selectedFilterText!.isNotEmpty ? AppCustomChipWidget( - padding: EdgeInsets.symmetric(horizontal: 5.h), - labelText: selectedFilterText!, - deleteIcon:'assets/images/svg/cross_circle.svg', - backgroundColor:AppColors.alertColor, - textColor: AppColors.whiteColor, - deleteIconColor: AppColors.whiteColor, - deleteIconHasColor: true, - onDeleteTap: (){ - setState(() { - selectedFilterText =''; - model.filterRadiologyReports(''); - }); - }, - // chipType: ChipTypeEnum.alert, - // isSelected: true, - ) + padding: EdgeInsets.symmetric(horizontal: 5.h), + labelText: selectedFilterText!, + deleteIcon: 'assets/images/svg/cross_circle.svg', + backgroundColor: AppColors.alertColor, + textColor: AppColors.whiteColor, + deleteIconColor: AppColors.whiteColor, + deleteIconHasColor: true, + onDeleteTap: () { + setState(() { + selectedFilterText = ''; + model.filterRadiologyReports(''); + }); + }, + // chipType: ChipTypeEnum.alert, + // isSelected: true, + ) : SizedBox(), ListView.builder( shrinkWrap: true, diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index 47a19a9..842710d 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/presentation/authentication/login.dart'; import 'package:hmg_patient_app_new/presentation/authentication/register.dart'; import 'package:hmg_patient_app_new/presentation/authentication/register_step2.dart'; +import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/comprehensive_checkup_page.dart'; import 'package:hmg_patient_app_new/presentation/e_referral/e_referral_page_home.dart'; -import 'package:hmg_patient_app_new/presentation/home/landing_page.dart'; import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; import 'package:hmg_patient_app_new/splashPage.dart'; @@ -15,14 +15,17 @@ class AppRoutes { static const String registerStepTwo = '/registerStepTwo'; static const String landingScreen = '/landingScreen'; static const String medicalFilePage = '/medicalFilePage'; - static const String ereferralPage = '/ereferralPage'; + static const String eReferralPage = '/erReferralPage'; + static const String comprehensiveCheckupPage = '/comprehensiveCheckupPage'; + static Map get routes => { initialRoute: (context) => SplashPage(), loginScreen: (context) => LoginScreen(), landingScreen: (context) => LandingNavigation(), register: (context) => RegisterNew(), registerStepTwo: (context) => RegisterNewStep2(), - medicalFilePage: (context) => MedicalFilePage(), - ereferralPage: (context) => EReferralPage() + medicalFilePage: (context) => MedicalFilePage(), + eReferralPage: (context) => EReferralPage(), + comprehensiveCheckupPage: (context) => ComprehensiveCheckupPage() }; } diff --git a/lib/services/navigation_service.dart b/lib/services/navigation_service.dart index cb4405c..fe95140 100644 --- a/lib/services/navigation_service.dart +++ b/lib/services/navigation_service.dart @@ -13,8 +13,8 @@ class NavigationService { return navigatorKey.currentState!.push(route); } - Future pushAndRemoveUntil(Route route,RoutePredicate predicate) { - return navigatorKey.currentState!.pushAndRemoveUntil(route,predicate); + Future pushAndRemoveUntil(Route route, RoutePredicate predicate) { + return navigatorKey.currentState!.pushAndRemoveUntil(route, predicate); } void pop([T? result]) { @@ -38,11 +38,22 @@ class NavigationService { navigatorKey.currentState?.pushReplacementNamed(routeName); } + void pushPageRoute(String routeName) { + navigatorKey.currentState?.pushNamed(routeName); + } - - Future pushToOtpScreen({required String phoneNumber, required Function(int code) checkActivationCode, required Function(String phoneNumber) onResendOTPPressed, bool isFormFamilyFile = false}) { + Future pushToOtpScreen( + {required String phoneNumber, + required Function(int code) checkActivationCode, + required Function(String phoneNumber) onResendOTPPressed, + bool isFormFamilyFile = false}) { return navigatorKey.currentState!.push( - MaterialPageRoute(builder: (_) => OTPVerificationScreen(phoneNumber: phoneNumber, checkActivationCode: checkActivationCode, onResendOTPPressed: onResendOTPPressed, isFormFamilyFile : isFormFamilyFile)), + MaterialPageRoute( + builder: (_) => OTPVerificationScreen( + phoneNumber: phoneNumber, + checkActivationCode: checkActivationCode, + onResendOTPPressed: onResendOTPPressed, + isFormFamilyFile: isFormFamilyFile)), ); } diff --git a/lib/widgets/media_viewer/full_screen_image_viewer.dart b/lib/widgets/media_viewer/full_screen_image_viewer.dart new file mode 100644 index 0000000..0fb92f0 --- /dev/null +++ b/lib/widgets/media_viewer/full_screen_image_viewer.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; + +class FullScreenImageViewer extends StatelessWidget { + final bool isSvg; + final String path; + + const FullScreenImageViewer({super.key, required this.isSvg, required this.path}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.black, + leading: IconButton( + icon: Icon(Icons.close, color: AppColors.whiteColor), + onPressed: () => Navigator.of(context).pop(), + ), + ), + backgroundColor: Colors.black, + body: Center( + child: InteractiveViewer( + child: isSvg + ? SvgPicture.asset(path, width: double.infinity, fit: BoxFit.contain) + : Image.asset(width: double.infinity, path, fit: BoxFit.contain), + ), + ), + ); + } +} diff --git a/lib/widgets/radio_list_tile_widget.dart b/lib/widgets/radio_list_tile_widget.dart new file mode 100644 index 0000000..209866b --- /dev/null +++ b/lib/widgets/radio_list_tile_widget.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.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/theme/colors.dart'; + +class RadioListTileWidget extends StatelessWidget { + final T value; + final T? groupValue; + final String title; + final Widget? subtitleWidget; + final String? subtitle; + final ValueChanged onChanged; + final bool enabled; + + const RadioListTileWidget({ + super.key, + required this.value, + required this.groupValue, + required this.title, + this.subtitleWidget, + this.subtitle, + required this.onChanged, + this.enabled = true, + }); + + @override + Widget build(BuildContext context) { + final bool isSelected = value == groupValue; + + return InkWell( + onTap: enabled ? () => onChanged(value) : null, + child: Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.h, + hasShadow: false, + ), + margin: EdgeInsets.symmetric(horizontal: 16.w, vertical: 6.h), + padding: EdgeInsets.all(16.h), + child: Row( + children: [ + Container( + width: 20.h, + height: 20.h, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: isSelected ? AppColors.blackColor : const Color(0xff9E9E9E), + width: 2, + ), + ), + child: isSelected + ? Center( + child: Container( + width: 10.h, + height: 10.h, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: AppColors.blackColor, + ), + ), + ) + : null, + ), + SizedBox(width: 16.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + title.toText15(weight: FontWeight.w500, letterSpacing: -0.64), + if (subtitleWidget != null) ...[subtitleWidget!], + if (subtitle != null) ...[ + SizedBox(height: 4.h), + title.toText13( + weight: FontWeight.w400, + color: AppColors.greyTextColor, + letterSpacing: -0.56, + ), + ], + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/widgets/shimmer/movies_shimmer_widget.dart b/lib/widgets/shimmer/common_shimmer_widget.dart similarity index 93% rename from lib/widgets/shimmer/movies_shimmer_widget.dart rename to lib/widgets/shimmer/common_shimmer_widget.dart index fb1af25..d6a2906 100644 --- a/lib/widgets/shimmer/movies_shimmer_widget.dart +++ b/lib/widgets/shimmer/common_shimmer_widget.dart @@ -1,10 +1,10 @@ +import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/extensions/int_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; -import 'package:flutter/material.dart'; -class MoviesShimmerWidget extends StatelessWidget { - const MoviesShimmerWidget({super.key}); +class CommonShimmerWidget extends StatelessWidget { + const CommonShimmerWidget({super.key}); @override Widget build(BuildContext context) {