diff --git a/assets/images/svg/all_payment_method.svg b/assets/images/svg/all_payment_method.svg new file mode 100644 index 0000000..ef72e6a --- /dev/null +++ b/assets/images/svg/all_payment_method.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/svg/ic_rrt_vehicle.svg b/assets/images/svg/ic_rrt_vehicle.svg new file mode 100644 index 0000000..d858fb4 --- /dev/null +++ b/assets/images/svg/ic_rrt_vehicle.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/svg/mada.svg b/assets/images/svg/mada.svg new file mode 100644 index 0000000..99fd132 --- /dev/null +++ b/assets/images/svg/mada.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index b276dd7..6a5d34f 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ import Flutter import UIKit -import FirebaseCore -import FirebaseMessaging +//import FirebaseCore +//import FirebaseMessaging import GoogleMaps @main @objc class AppDelegate: FlutterAppDelegate { @@ -10,13 +10,13 @@ import GoogleMaps didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GMSServices.provideAPIKey("AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng") - FirebaseApp.configure() +// FirebaseApp.configure() GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken:Data){ - Messaging.messaging().apnsToken = deviceToken +// Messaging.messaging().apnsToken = deviceToken super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken) } } diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 28475ea..3fb1470 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -201,6 +201,7 @@ class ApiClientImp implements ApiClient { log("uri: ${Uri.parse(url.trim())}"); log("body: ${json.encode(body)}"); log("response.body: ${response.body}"); + // log("response.body: ${response.body}"); if (statusCode < 200 || statusCode >= 400) { onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data")); logApiEndpointError(endPoint, 'Error While Fetching data', statusCode); @@ -364,7 +365,7 @@ class ApiClientImp implements ApiClient { debugPrint("URL : $url"); // print("Body : ${json.encode(body)}"); - if (await Utils.checkConnection()) { + if (await Utils.checkConnection(bypassConnectionCheck: true)) { final response = await http.get( Uri.parse(url.trim()), headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}, diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index 3f524be..5fccc6e 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -173,6 +173,9 @@ class AppAssets { 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'; + static const String all_payment_method = '$svgBasePath/all_payment_method.svg'; + static const String ic_rrt_vehicle = '$svgBasePath/ic_rrt_vehicle.svg'; + //bottom navigation// static const String homeBottom = '$svgBasePath/home_bottom.svg'; diff --git a/lib/core/utils/date_util.dart b/lib/core/utils/date_util.dart index 82b9909..a918706 100644 --- a/lib/core/utils/date_util.dart +++ b/lib/core/utils/date_util.dart @@ -6,6 +6,8 @@ class DateUtil { /// convert String To Date function /// [date] String we want to convert static DateTime convertStringToDate(String? date) { + + if (date == null) return DateTime.now(); if (date.isEmpty) return DateTime.now(); diff --git a/lib/features/emergency_services/emergency_services_repo.dart b/lib/features/emergency_services/emergency_services_repo.dart index ccfc210..f44724d 100644 --- a/lib/features/emergency_services/emergency_services_repo.dart +++ b/lib/features/emergency_services/emergency_services_repo.dart @@ -8,9 +8,11 @@ import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart'; import 'package:hmg_patient_app_new/features/emergency_services/models/request_model/PatientER_RC.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/request_model/RRTRequestModel.dart'; import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart'; import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/EROnlineCheckInPaymentDetailsResponse.dart'; import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/ProjectAvgERWaitingTime.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/RRTServiceData.dart'; import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/rrt_procedures_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; @@ -18,7 +20,7 @@ import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'models/resp_model/PatientERTransportationMethod.dart'; abstract class EmergencyServicesRepo { - Future>>> getRRTProcedures(); + Future>>> getRRTProcedures(int languageId); Future>>> getNearestEr({int? id, int? projectID}); @@ -48,7 +50,13 @@ abstract class EmergencyServicesRepo { Future>>> getTransportationOrders({int? id}); - Future>> cancelOrder(int? iD, int patientId); + Future>> cancelOrder(int? iD, int patientId); + + Future>> submitRRTRequest(RRTRequestModel request); + + Future>> getRRTOrders({int? id}); + + Future>> cancelRRTOrder(int? iD); } class EmergencyServicesRepoImp implements EmergencyServicesRepo { @@ -95,8 +103,8 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo { } @override - Future>>> getRRTProcedures() async { - Map mapDevice = {"ProjectID": 15}; + Future>>> getRRTProcedures(int languageId) async { + Map mapDevice = {"ProjectID": 15, "languageID":1}; try { GenericApiModel>? apiResponse; @@ -558,4 +566,120 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>> submitRRTRequest(RRTRequestModel request) async { + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + body: request.toJson(), + ADD_RRT_ORDER_RC, + isRCService: true, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: true, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } + + @override + Future>> cancelRRTOrder(int? iD) async{ + try { + GenericApiModel? apiResponse; + + Map request = {"Id": iD, "ClickButton": 14}; + + Failure? failure; + await apiClient.post( + body: request, + UPDATE_RRT_ORDER_RC, + isRCService: true, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: true, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + + } + + @override + Future>> getRRTOrders({int? id}) async { + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + body: {}, + GET_ALL_RRT_ORDERS_RC, + isRCService: true, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + final list = response['response']; + + RRTServiceData serviceData = RRTServiceData(); + list.forEach((item) { + if (item["StatusId"] == 1 || item["StatusId"] == 2) { + // Pending + serviceData.pendingOrders.add(GetCMCAllOrdersResponseModel.fromJson(item)); + } + serviceData.completedOrders.add(GetCMCAllOrdersResponseModel.fromJson(item)); + }); + + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: serviceData, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } + + } diff --git a/lib/features/emergency_services/emergency_services_view_model.dart b/lib/features/emergency_services/emergency_services_view_model.dart index cba6399..a6d80f3 100644 --- a/lib/features/emergency_services/emergency_services_view_model.dart +++ b/lib/features/emergency_services/emergency_services_view_model.dart @@ -10,6 +10,12 @@ import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart'; import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_repo.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/OrderDisplay.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/request_model/RRTRequestModel.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/EROnlineCheckInPaymentDetailsResponse.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/RRTServiceData.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; import 'package:hmg_patient_app_new/features/emergency_services/models/AmbulanceCallingPlace.dart'; import 'package:hmg_patient_app_new/features/emergency_services/models/request_model/PatientER_RC.dart'; import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart'; @@ -24,6 +30,8 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/facility_sel import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; +import 'package:hmg_patient_app_new/presentation/authentication/login.dart'; +import 'package:hmg_patient_app_new/presentation/emergency_services/RRT/rrt_map_screen.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/requesting_services_page.dart'; import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/tracking_screen.dart'; @@ -65,7 +73,6 @@ class EmergencyServicesViewModel extends ChangeNotifier { List nearestERList = []; List nearestERFilteredList = []; - List RRTProceduresList = []; List? hospitalList; List? hmgHospitalList; @@ -77,7 +84,7 @@ class EmergencyServicesViewModel extends ChangeNotifier { int hmcCount = 0; bool pickupFromInsideTheLocation = true; List? appointments; - List? orders = []; + List? ambulanceOrders = []; //ambulance selection data section List transportationOptions = []; @@ -85,7 +92,6 @@ class EmergencyServicesViewModel extends ChangeNotifier { AmbulanceCallingPlace callingPlace = AmbulanceCallingPlace.FROM_HOSPITAL; AmbulanceDirection ambulanceDirection = AmbulanceDirection.ONE_WAY; - late RRTProceduresResponseModel selectedRRTProcedure; bool patientHasAdvanceERBalance = false; bool isERBookAppointment = false; @@ -93,6 +99,21 @@ class EmergencyServicesViewModel extends ChangeNotifier { BottomSheetType bottomSheetType = BottomSheetType.FIXED; + ///RRT request data + List RRTProceduresList = []; + RRTProceduresResponseModel? selectedRRTProcedure; + bool agreedToTermsAndCondition = false; + RRTServiceData? ordersRRT; + TextEditingController rrtNotes = TextEditingController(); + + + List allOrders = []; + List orderDisplayList = []; + bool historyLoading= false; + OrderDislpay currentlyDisplayedOrder = OrderDislpay.ALL; + + + setSelectedRRTProcedure(RRTProceduresResponseModel procedure) { selectedRRTProcedure = procedure; notifyListeners(); @@ -126,10 +147,21 @@ class EmergencyServicesViewModel extends ChangeNotifier { bool isMyAppointmentsLoading = false; Future getRRTProcedures({Function(dynamic)? onSuccess, Function(String)? onError}) async { + + print("the app state is ${appState.isAuthenticated}"); + if (!appState.isAuthenticated) { + dialogService.showErrorBottomSheet( + message: "You Need To Login First To Continue".needTranslation, + onOkPressed: () { + getIt().onLoginPressed(); + }); + return; + } + RRTProceduresList.clear(); notifyListeners(); - final result = await emergencyServicesRepo.getRRTProcedures(); + final result = await emergencyServicesRepo.getRRTProcedures(appState.getLanguageID()); result.fold( (failure) async => await errorHandlerService.handleError(failure: failure), @@ -723,6 +755,8 @@ class EmergencyServicesViewModel extends ChangeNotifier { LoaderBottomSheet.showLoader(loadingText: "Fetching Orders"); } int? id = appState.getAuthenticatedUser()?.patientId; + historyLoading = true; + notifyListeners(); var response = await emergencyServicesRepo.getTransportationOrders(id: id); if (shouldNavigateToTrackingScreen == false && showLoader) { @@ -730,6 +764,8 @@ class EmergencyServicesViewModel extends ChangeNotifier { } response.fold( (failure) async { + historyLoading = false; + notifyListeners(); if (shouldNavigateToTrackingScreen) { navServices.pushAndRemoveUntil( CustomPageRoute(page: TrackingScreen(state: OrderTrackingState.waitingForCall)), ModalRoute.withName("/EmergencyServicesPage")); @@ -745,8 +781,12 @@ class EmergencyServicesViewModel extends ChangeNotifier { )), ModalRoute.withName("/EmergencyServicesPage")); } - - orders = apiResponse.data; + historyLoading = false; + ambulanceOrders = apiResponse.data; + allOrders.clear(); + allOrders.addAll(ambulanceOrders??[]); + allOrders.addAll(ordersRRT?.completedOrders??[]); + changeOrderDisplayItems(OrderDislpay.ALL); notifyListeners(); }, ); @@ -835,4 +875,157 @@ class EmergencyServicesViewModel extends ChangeNotifier { navServices.pop(); }); } + + + RRTRequestModel createRRTRequest(GeocodeResult? result, PlaceDetails? place, PlacePrediction? placePrediction){ + AuthenticatedUser? user = appState.getAuthenticatedUser(); + if (user == null) throw Exception("Authentication Required to Continue"); + + RRTRequestModel rrtRequestModel = new RRTRequestModel(); + Procedures procedures = new Procedures(); + rrtRequestModel.procedures = []; + + + procedures.serviceID = selectedRRTProcedure?.procedureID; + + rrtRequestModel.latitude = ((result?.geometry.location.lat) ?? place?.lat); + rrtRequestModel.longitude = ((result?.geometry.location.lat) ?? place?.lat); + rrtRequestModel.additionalDetails = ""; + rrtRequestModel.nationality = user.nationalityId; + rrtRequestModel.paymentAmount = selectedRRTProcedure?.patientShareWithTax; + rrtRequestModel.nearestProjectId = 0; + rrtRequestModel.patientId = user.patientId; + rrtRequestModel.patientOutSa = user.outSa; + rrtRequestModel.procedures!.add(procedures); + + return rrtRequestModel; + } + + ///method to toggle the value for the aggremnent to the terms and conditon for the rrt + void setTermsAndConditions(bool value) { + agreedToTermsAndCondition = value; + notifyListeners(); + } + + FutureOr submitRRTRequest(GeocodeResult? result, PlaceDetails? place, PlacePrediction? placePrediction) async { + RRTRequestModel request = createRRTRequest(result, place, placePrediction); + navServices.push(CustomPageRoute(page: RequestingServicesPage())); + + var response = await emergencyServicesRepo.submitRRTRequest(request); + response.fold((failure) { + navServices.pushAndRemoveUntil( + CustomPageRoute( + page: TrackingScreen( + isRRTOrder: true, + state: OrderTrackingState.failed, + )), + ModalRoute.withName("/EmergencyServicesPage")); + }, (success) { + getRRTOrders(shouldNavigateToTrackingScreen: true); + }); + } + + Future getRRTOrders({bool shouldNavigateToTrackingScreen = false, bool showLoader = false}) async { + if(shouldNavigateToTrackingScreen == false && showLoader ) { + LoaderBottomSheet.showLoader(loadingText: "Fetching Orders"); + } + historyLoading = true; + notifyListeners(); + int? id = appState.getAuthenticatedUser()?.patientId; + + var response = await emergencyServicesRepo.getRRTOrders(id: id); + if(shouldNavigateToTrackingScreen == false && showLoader ) { + LoaderBottomSheet.hideLoader();} + response.fold( + (failure) async { + historyLoading = false; + notifyListeners(); + if (shouldNavigateToTrackingScreen) { + navServices.pushAndRemoveUntil(CustomPageRoute(page: TrackingScreen(isRRTOrder: true,state: OrderTrackingState.waitingForCall)), ModalRoute.withName("/EmergencyServicesPage")); + } + }, + (apiResponse) { + if (shouldNavigateToTrackingScreen) { + navServices.pushAndRemoveUntil( + CustomPageRoute( + page: TrackingScreen( + state: OrderTrackingState.waitingForCall, + isRRTOrder: true, + rrtOrder: apiResponse.data?.pendingOrders.first, + )), + ModalRoute.withName("/EmergencyServicesPage")); + } + historyLoading = false; + ordersRRT = apiResponse.data; + allOrders.clear(); + allOrders.addAll(ambulanceOrders??[]); + allOrders.addAll(ordersRRT?.completedOrders??[]); + changeOrderDisplayItems(OrderDislpay.ALL); + notifyListeners(); + }, + ); + } + + + FutureOr cancelRRTOrder(int? orderID, {bool shouldPop = false}) async { + dialogService.showCommonBottomSheetWithoutH( + message: "Do you want to cancel the order".needTranslation, + onOkPressed: () async { + navServices.pop(); + LoaderBottomSheet.showLoader(loadingText: "Cancelling Order".needTranslation); + var response = await emergencyServicesRepo.cancelRRTOrder(orderID); + LoaderBottomSheet.hideLoader(); + response.fold((failure) => errorHandlerService.handleError(failure: failure), (success) { + getRRTOrders(); + if (shouldPop) navServices.pop(); + }); + }, + onCancelPressed: () { + navServices.pop(); + }); + } + + void changeOrderDisplayItems(OrderDislpay currentlyDisplayedOrder){ + this.currentlyDisplayedOrder = currentlyDisplayedOrder; + switch(currentlyDisplayedOrder){ + case OrderDislpay.ALL: + orderDisplayList = allOrders; + break; + case OrderDislpay.RRT: + orderDisplayList = ordersRRT?.completedOrders ?? []; + break; + case OrderDislpay.AMBULANCE: + orderDisplayList = ambulanceOrders??[]; + break; + } + notifyListeners(); + } + + void openRRT(){ + print("the app state is ${appState.isAuthenticated}"); + if (appState.isAuthenticated) { + if(agreedToTermsAndCondition == false){ + dialogService.showErrorBottomSheet(message: "You Need To Agree To Terms And Conditions".needTranslation); + return; + } + locationUtils!.getLocation( + isShowConfirmDialog: true, + onSuccess: (position) { + updateBottomSheetState(BottomSheetType.FIXED); + navServices.push( + CustomPageRoute( + page: RrtMapScreen(), direction: AxisDirection.down), + ); + }); + } else{ + dialogService.showErrorBottomSheet( + message: "You Need To Login First To Continue".needTranslation, + onOkPressed: () { + getIt().onLoginPressed(); + }); + } + } + clearRRTData(){ + selectedRRTProcedure = null; + } } diff --git a/lib/features/emergency_services/models/OrderDisplay.dart b/lib/features/emergency_services/models/OrderDisplay.dart new file mode 100644 index 0000000..9f1e929 --- /dev/null +++ b/lib/features/emergency_services/models/OrderDisplay.dart @@ -0,0 +1,3 @@ +enum OrderDislpay{ + ALL,RRT,AMBULANCE +} \ No newline at end of file diff --git a/lib/features/emergency_services/models/request_model/RRTRequestModel.dart b/lib/features/emergency_services/models/request_model/RRTRequestModel.dart new file mode 100644 index 0000000..dfb5b1b --- /dev/null +++ b/lib/features/emergency_services/models/request_model/RRTRequestModel.dart @@ -0,0 +1,75 @@ +class RRTRequestModel { + num? patientId; + int? patientOutSa; + bool? isOutPatient; + int? nearestProjectId; + num? longitude; + num? latitude; + String? additionalDetails; + String? nationality; + num? paymentAmount; + List? procedures; + + RRTRequestModel( + {this.patientId, + this.patientOutSa, + this.isOutPatient, + this.nearestProjectId, + this.longitude, + this.latitude, + this.additionalDetails, + this.nationality, + this.paymentAmount, + this.procedures}); + + RRTRequestModel.fromJson(Map json) { + patientId = json['patientId']; + patientOutSa = json['patientOutSa']; + isOutPatient = json['isOutPatient']; + nearestProjectId = json['nearestProjectId']; + longitude = json['longitude']; + latitude = json['latitude']; + additionalDetails = json['additionalDetails']; + nationality = json['nationality']; + paymentAmount = json['paymentAmount']; + if (json['procedures'] != null) { + procedures = []; + json['procedures'].forEach((v) { + procedures!.add(new Procedures.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['patientId'] = this.patientId; + data['patientOutSa'] = this.patientOutSa; + data['isOutPatient'] = this.isOutPatient; + data['nearestProjectId'] = this.nearestProjectId; + data['longitude'] = this.longitude; + data['latitude'] = this.latitude; + data['additionalDetails'] = this.additionalDetails; + data['nationality'] = this.nationality; + data['paymentAmount'] = this.paymentAmount; + if (this.procedures != null) { + data['procedures'] = this.procedures!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class Procedures { + String? serviceID; + + Procedures({this.serviceID}); + + Procedures.fromJson(Map json) { + serviceID = json['ServiceID']; + } + + Map toJson() { + final Map data = new Map(); + data['ServiceID'] = this.serviceID; + return data; + } +} diff --git a/lib/features/emergency_services/models/request_model/service_price.dart b/lib/features/emergency_services/models/request_model/service_price.dart new file mode 100644 index 0000000..abb57be --- /dev/null +++ b/lib/features/emergency_services/models/request_model/service_price.dart @@ -0,0 +1,53 @@ +class ServicePrice { + String? currency; + dynamic maxPrice; + dynamic maxTotalPrice; + dynamic maxVAT; + dynamic minPrice; + dynamic minTotalPrice; + dynamic minVAT; + dynamic price; + dynamic totalPrice; + dynamic vat; + + ServicePrice({ + this.currency, + this.maxPrice, + this.maxTotalPrice, + this.maxVAT, + this.minPrice, + this.minTotalPrice, + this.minVAT, + this.price, + this.totalPrice, + this.vat}); + + ServicePrice.fromJson(dynamic json) { + currency = json["Currency"]; + maxPrice = json["MaxPrice"]; + maxTotalPrice = json["MaxTotalPrice"]; + maxVAT = json["MaxVAT"]; + minPrice = json["MinPrice"]; + minTotalPrice = json["MinTotalPrice"]; + minVAT = json["MinVAT"]; + price = json["Price"]; + totalPrice = json["TotalPrice"]; + vat = json["VAT"]; + } + + Map toJson() { + var map = {}; + map["Currency"] = currency; + map["MaxPrice"] = maxPrice; + map["MaxTotalPrice"] = maxTotalPrice; + map["MaxVAT"] = maxVAT; + map["MinPrice"] = minPrice; + map["MinTotalPrice"] = minTotalPrice; + map["MinVAT"] = minVAT; + map["Price"] = price; + map["TotalPrice"] = totalPrice; + map["VAT"] = vat; + return map; + } + +} \ No newline at end of file diff --git a/lib/features/emergency_services/models/resp_model/RRTServiceData.dart b/lib/features/emergency_services/models/resp_model/RRTServiceData.dart new file mode 100644 index 0000000..e4e7ce7 --- /dev/null +++ b/lib/features/emergency_services/models/resp_model/RRTServiceData.dart @@ -0,0 +1,406 @@ +class RRTServiceData { + List pendingOrders = []; + List completedOrders = []; + ServicePrice servicePrice = ServicePrice(); +} + +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) { + 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 + ? new 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 + ? new 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 = new Map(); + data['ID'] = this.iD; + data['PatientId'] = this.patientId; + data['PatientOutSa'] = this.patientOutSa; + data['IsOutPatient'] = this.isOutPatient; + data['ProjectId'] = this.projectId; + data['NearestProjectId'] = this.nearestProjectId; + data['Longitude'] = this.longitude; + data['Latitude'] = this.latitude; + data['AppointmentNo'] = this.appointmentNo; + data['DischargeId'] = this.dischargeId; + data['StatusId'] = this.statusId; + data['ServiceId'] = this.serviceId; + data['Channel'] = this.channel; + if (this.orderpayment != null) { + data['orderpayment'] = this.orderpayment!.toJson(); + } + data['orderselectedservice'] = this.orderselectedservice; + + data['wforder'] = this.wforder; + data['orderapprovalobj'] = this.orderapprovalobj; + data['Created'] = this.created; + data['CreatedBy'] = this.createdBy; + data['Modified'] = this.modified; + data['ModifiedBy'] = this.modifiedBy; + data['IsDeleted'] = this.isDeleted; + data['StatusText'] = this.statusText; + data['PaymentStatus'] = this.paymentStatus; + data['ClientRequestid'] = this.clientRequestid; + data['PaymentStatusText'] = this.paymentStatusText; + data['ProjectName'] = this.projectName; + data['NearestProjectName'] = this.nearestProjectName; + data['PaymentAmount'] = this.paymentAmount; + if (this.wFOrder != null) { + data['WF_order'] = this.wFOrder!.toJson(); + } + data['ServiceText'] = this.serviceText; + data['isSentForApproval'] = this.isSentForApproval; + data['ExaCart_OrderId'] = this.exaCartOrderId; + data['isTimer'] = this.isTimer; + data['TimeSeconds'] = this.timeSeconds; + data['TotalPendingSeconds'] = this.totalPendingSeconds; + data['TimeMinute'] = this.timeMinute; + data['TimeHour'] = this.timeHour; + data['TimeTotalSeconds'] = this.timeTotalSeconds; + data['TimeTotalMinute'] = this.timeTotalMinute; + data['TimeTotalHour'] = this.timeTotalHour; + data['ApprovalStatus'] = this.approvalStatus; + data['isActive'] = this.isActive; + data['ClickButton'] = this.clickButton; + data['PickupLocation'] = this.pickupLocation; + data['DropOffLocation'] = this.dropOffLocation; + data['clinicName'] = this.clinicName; + data['DoctorName'] = this.doctorName; + data['Branch'] = this.branch; + data['Time'] = this.time; + data['Notes'] = this.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 = new Map(); + data['ID'] = this.iD; + data['OrderId'] = this.orderId; + data['ClientRequestId'] = this.clientRequestId; + data['TotalAmount'] = this.totalAmount; + data['PaymentStatus'] = this.paymentStatus; + data['Order'] = this.order; + data['Created'] = this.created; + data['CreatedBy'] = this.createdBy; + data['Modified'] = this.modified; + data['ModifiedBy'] = this.modifiedBy; + data['IsDeleted'] = this.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 = new Map(); + data['wf_ButtonsDTO'] = this.wfButtonsDTO; + data['ID'] = this.iD; + data['OrderId'] = this.orderId; + data['PreviousStep'] = this.previousStep; + data['NextStep'] = this.nextStep; + data['ServiceId'] = this.serviceId; + data['Order'] = this.order; + data['Created'] = this.created; + data['CreatedBy'] = this.createdBy; + data['Modified'] = this.modified; + data['ModifiedBy'] = this.modifiedBy; + data['IsDeleted'] = this.isDeleted; + return data; + } +} + + +class ServicePrice { + String? currency; + dynamic maxPrice; + dynamic maxTotalPrice; + dynamic maxVAT; + dynamic minPrice; + dynamic minTotalPrice; + dynamic minVAT; + dynamic price; + dynamic totalPrice; + dynamic vat; + + ServicePrice({ + this.currency, + this.maxPrice, + this.maxTotalPrice, + this.maxVAT, + this.minPrice, + this.minTotalPrice, + this.minVAT, + this.price, + this.totalPrice, + this.vat}); + + ServicePrice.fromJson(dynamic json) { + currency = json["Currency"]; + maxPrice = json["MaxPrice"]; + maxTotalPrice = json["MaxTotalPrice"]; + maxVAT = json["MaxVAT"]; + minPrice = json["MinPrice"]; + minTotalPrice = json["MinTotalPrice"]; + minVAT = json["MinVAT"]; + price = json["Price"]; + totalPrice = json["TotalPrice"]; + vat = json["VAT"]; + } + + Map toJson() { + var map = {}; + map["Currency"] = currency; + map["MaxPrice"] = maxPrice; + map["MaxTotalPrice"] = maxTotalPrice; + map["MaxVAT"] = maxVAT; + map["MinPrice"] = minPrice; + map["MinTotalPrice"] = minTotalPrice; + map["MinVAT"] = minVAT; + map["Price"] = price; + map["TotalPrice"] = totalPrice; + map["VAT"] = vat; + return map; + } + +} \ No newline at end of file diff --git a/lib/presentation/emergency_services/RRT/rrt_map_screen.dart b/lib/presentation/emergency_services/RRT/rrt_map_screen.dart new file mode 100644 index 0000000..ca260d9 --- /dev/null +++ b/lib/presentation/emergency_services/RRT/rrt_map_screen.dart @@ -0,0 +1,636 @@ +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/app_export.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/emergency_services/emergency_services_view_model.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/AmbulanceCallingPlace.dart'; +import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart'; +import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart'; +import 'package:hmg_patient_app_new/features/location/PlacePrediction.dart'; +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/appointments/widgets/appointment_doctor_card.dart'; +import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/AddressItem.dart'; +import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart'; +import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/appointment_bottom_sheet.dart' show AppointmentBottomSheet; +import 'package:hmg_patient_app_new/presentation/emergency_services/widgets/location_input_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/CustomSwitch.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/expandable_bottom_sheet/ExpandableBottomSheet.dart'; +import 'package:hmg_patient_app_new/widgets/expandable_bottom_sheet/model/BottomSheetType.dart'; +import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:hmg_patient_app_new/widgets/map/HMSMap.dart'; +import 'package:hmg_patient_app_new/widgets/map/map.dart'; +import 'package:provider/provider.dart'; + +import '../../../widgets/common_bottom_sheet.dart'; + +class RrtMapScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + floatingActionButton: Visibility( + visible: context.watch().bottomSheetType == + BottomSheetType.FIXED, + child: Padding( + padding: EdgeInsetsDirectional.only(end: 8.h, bottom: 68.h), + child: DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, borderRadius: 12.h), + child: Utils.buildSvgWithAssets( + icon: AppAssets.locate_me, width: 24.h, height: 24.h) + .paddingAll(12.h) + .onPress(() { + context + .read() + .moveToCurrentLocation(); + }), + ), + ), + ), + bottomSheet: ExpandableBottomSheet( + bottomSheetType: + context.watch().bottomSheetType, + children: { + BottomSheetType.EXPANDED: ExpanedBottomSheet(context), + BottomSheetType.FIXED: FixedBottomSheet(context), + }, + ), + body: Stack( + children: [ + if (context.read().isGMSAvailable ) + GMSMap( + currentLocation: + context.read().getGMSLocation(), + onCameraMoved: (value) => context + .read() + .handleGMSMapCameraMoved(value), + onCameraIdle: + context.read().handleOnCameraIdle, + myLocationEnabled: true, + inputController: + context.read().gmsController, + showCenterMarker: true, + ) + else + HMSMap( + currentLocation: + context.read().getHMSLocation(), + onCameraMoved: (value) => context + .read() + .handleHMSMapCameraMoved(value), + onCameraIdle: + context.read().handleOnCameraIdle, + myLocationEnabled: false, + inputController: + context.read().hmsController, + showCenterMarker: true, + ), + Align( + alignment: AlignmentDirectional.topStart, + child: Utils.buildSvgWithAssets( + icon: AppAssets.closeBottomNav, width: 32.h, height: 32.h) + .onPress(() { + context + .read() + .flushPickupInformation(); + Navigator.pop(context); + }), + ).paddingOnly(top: 51.h, left: 24.h), + ], + ), + ); + } + + Widget FixedBottomSheet(BuildContext context) { + return GestureDetector( + onVerticalDragUpdate: (details){ + }, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + spacing: 24.h, + children: [ + inputFields(context), + SizedBox( + height: 200.h, + child: DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.scaffoldBgColor, + customBorder: BorderRadius.only( + topLeft: Radius.circular(24.h), + topRight: Radius.circular(24.h), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 24.h, + children: [ + Column( + spacing: 4.h, + children: [ + "Select Pickup Details".needTranslation.toText21( + weight: FontWeight.w600, + color: AppColors.textColor, + ), + " Please select the details of pickup" + .needTranslation + .toText12( + fontWeight: FontWeight.w500, + color: AppColors.greyTextColor, + ) + ], + ), + CustomButton( + text: "Select Details".needTranslation, + onPressed: () { + LocationViewModel locationViewModel = context.read(); + GeocodeResponse? response = locationViewModel.geocodeResponse; + PlaceDetails? placeDetails = locationViewModel.placeDetails; + PlacePrediction? placePrediction = locationViewModel.selectedPrediction; + context.read().submitRRTRequest(response?.results.first, placeDetails, placePrediction); + }) + ], + ).paddingOnly(top: 24.h, bottom: 32.h, left: 24.h, right: 24.h), + ), + ), + ], + ), + ], + ), + ); + } + + Widget ExpanedBottomSheet(BuildContext context) { + return GestureDetector( + onVerticalDragUpdate: (details){ + if(details.delta.dy>0){ + context.read().updateBottomSheetState(BottomSheetType.FIXED); + } + }, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.scaffoldBgColor, + customBorder: BorderRadius.only( + topLeft: Radius.circular(24.h), + topRight: Radius.circular(24.h), + ), + ), + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 16.h, + children: [ + + hospitalAndPickUpSection(context), + + + ], + ).paddingOnly(top: 24.h, bottom: 32.h,left: 24.h, right: 24.h), + + bottomPriceContent(context) + ], + ), + ), + ], + ), + ); + } + + locationsSections(BuildContext context) { + return DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.h, + ), + child: Column(mainAxisSize: MainAxisSize.min, children: [ + ListView.separated( + separatorBuilder: (_, __) => Column( + children: [ + SizedBox(height: 16.h), + Divider( + color: AppColors.bottomNAVBorder, + height: 1, + thickness: 1, + ), + SizedBox(height: 16.h), + ], + ), + shrinkWrap: true, + itemCount: 3, + itemBuilder: (__, index) { + if (index == + 2) // todo means the end of the list so handle as per the viewmodel + { + return CustomButton( + height: 40.h, + backgroundColor: AppColors.lightRedButtonColor, + borderColor: Colors.transparent, + text: "Add new address".needTranslation, + textColor: AppColors.primaryRedColor, + iconColor: AppColors.primaryRedColor, + onPressed: () {}, + icon: AppAssets.add_icon); + } else { + return AddressItem( + isSelected: index == 0, + address: + "Flat No 301, Building No 12, Palm Spring Apartment, Sector 45, Gurugram, Haryana 122003", + title: index == 0 + ? "Home".needTranslation + : "Work".needTranslation, + onTap: () {}, + ); + } + }) + ]).paddingAll(16.h), + ); + } + + hospitalAndPickUpSection(BuildContext context) { + return DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 16.h, + children: [ + // Row( + // children: [ + // hospitalAndPickUpItemContent( + // title: "Select Hospital".needTranslation, + // subTitle: "hospital".needTranslation, + // leadingIcon: AppAssets.hospital, + // ), + // Utils.buildSvgWithAssets(icon: AppAssets.down_cheveron, + // width: 24.h, height: 24.h) + // .paddingAll(16.h) + // ], + // ).onPress((){ + // showHospitalBottomSheet(context); + // }), + // SizedBox(height: 16.h), + // Divider( + // color: AppColors.bottomNAVBorder, + // height: 1, + // thickness: 1, + // ), + // SizedBox(height: 16.h), + + Row( + children: [ + hospitalAndPickUpItemContent( + title: "Pick".needTranslation, + subTitle: "Inside the home".needTranslation, + leadingIcon: AppAssets.pickup_bed, + ), + CustomSwitch( + value: context + .watch() + .pickupFromInsideTheLocation, + onChanged: (value){ + context + .read() + .updateThePickupPlaceFromLocation(value); + }, + ) + ], + ), + + Row( + children: [ + hospitalAndPickUpItemContent( + title: '', + subTitle: "Have any appointment".needTranslation, + leadingIcon: AppAssets.appointment_checkin_icon, + ), + CustomSwitch( + value: context + .watch() + .haveAnAppointment, + onChanged: (value) async { + // if (value) { + // openAppointmentList(context); + // } + await context.read() + .updateAppointment(value); + if (context.read().appointments?.isNotEmpty == true) { + openAppointmentList(context); + } + }, + ) + ], + ), + ], + ).paddingAll(16.h), + ); + } + + leadingIcon(String leadingIcon) { + return Container( + height: 40.h, + width: 40.h, + margin: EdgeInsets.only(right: 10.h), + padding: EdgeInsets.all(8.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + borderRadius: 12.h, + color: AppColors.greyColor, + ), + child: Utils.buildSvgWithAssets(icon: leadingIcon), + ); + } + + hospitalAndPickUpItemContent({ + required String title, + required String subTitle, + required String leadingIcon, + }) { + return Expanded( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + this.leadingIcon(leadingIcon), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Visibility( + visible: title.isNotEmpty, + child: Column( + children: [ + title.toText12( + color: AppColors.greyTextColor, + fontWeight: FontWeight.w500, + ), + SizedBox(height: 2.h), + ], + ), + ), + subTitle.toText14( + color: AppColors.textColor, + weight: FontWeight.w500, + ), + ], + ), + ), + ], + ), + ); + } + + bottomPriceContent(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.scaffoldBgColor, + customBorder: BorderRadius.only( + topLeft: Radius.circular(24.h), + topRight: Radius.circular(24.h), + ), + hasShadow: true + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 12.h, + children: [ + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 4.h, + children: [ + "Total amount to pay".needTranslation.toText18( + weight: FontWeight.w600, + color: AppColors.textColor, + ), + Row( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.warning, + height: 18.h, width: 18.h), + SizedBox(width: 4.h,), + "Amount will be paid at the hospital" + .needTranslation + .toText12( + fontWeight: FontWeight.w500, + color: AppColors.greyTextColor, + ), + ], + ) + ], + ), + ), + Utils.getPaymentAmountWithSymbol( + (Utils.formatNumberToInternationalFormat(context + .read() + .getTotalPrice() ?? + 0)) + .toText24( + fontWeight: FontWeight.w600, + color: AppColors.textColor, + letterSpacing: -2), + AppColors.blackColor, + 17.h) + + // Utils.getPaymentAmountWithSymbol2(context.read().selectedTransportOption?.priceTotal??"0", letterSpacing: -2) + ], + ), + CustomButton( + text: "Submit Request".needTranslation, + onPressed: () { + LocationViewModel locationViewModel = context.read(); + GeocodeResponse? response = locationViewModel.geocodeResponse; + PlaceDetails? placeDetails = locationViewModel.placeDetails; + PlacePrediction? placePrediction = locationViewModel.selectedPrediction; + context.read().submitAmbulanceRequest(response?.results.first, placeDetails, placePrediction); + }) + ], + ).paddingOnly(top: 24.h, bottom: 12.h, left: 24.h, right: 24.h), + ), + ], + ); + } + + showHospitalBottomSheet(BuildContext context){ + showCommonBottomSheetWithoutHeight( + title: + LocaleKeys.selectHospital.tr(), + context, + child: Consumer( + builder:(_,vm,__)=> HospitalBottomSheetBody( + searchText: vm.searchController, + displayList: vm.displayList, + onFacilityClicked: (value) { + vm.setSelectedFacility(value); + vm.getDisplayList(); + }, + onHospitalClicked: (hospital) { + Navigator.pop(context); + vm.setSelectedHospital(hospital); + }, + onHospitalSearch: (value) { + vm.searchHospitals(value ?? ""); + }, + selectedFacility: + vm.selectedFacility, + hmcCount: vm.hmcCount, + hmgCount: vm.hmgCount, + ), + ), + isFullScreen: false, + isCloseButtonVisible: true, + hasBottomPadding: false, + backgroundColor: AppColors.bottomSheetBgColor, + callBackFunc: () { + context.read().clearSearchText(); + }, + ); + } + + ///it will show the places field first and then hospital field + PlaceFirstThanHospitalField(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 16.h, + children: [ + textPlaceInput(context), + hospitalField(context), + ], + ).paddingOnly(right: 24.h, left: 24.h); + } + + HospitalFieldFirstThanPlaces(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 16.h, + children: [hospitalField(context), textPlaceInput(context)], + ).paddingOnly(right: 24.h, left: 24.h); + } + + textPlaceInput(context) { + return Consumer(builder: (_, vm, __) { + print( + "the data is ${vm.geocodeResponse?.results.first.formattedAddress ?? vm.selectedPrediction?.description}"); + return SizedBox( + width: MediaQuery.sizeOf(context).width, + child: TextInputWidget( + labelText: "Enter Pickup Location Manually".needTranslation, + hintText: "Enter Pickup Location".needTranslation, + controller: TextEditingController( + text: vm.geocodeResponse?.results.first.formattedAddress ?? + vm.selectedPrediction?.description, + ), + leadingIcon: AppAssets.location_pickup, + isAllowLeadingIcon: true, + isEnable: false, + prefix: null, + autoFocus: false, + isBorderAllowed: false, + keyboardType: TextInputType.text, + padding: EdgeInsets.symmetric( + vertical: ResponsiveExtension(10).h, + horizontal: ResponsiveExtension(15).h, + ), + ).onPress(() { + openLocationInputBottomSheet(context); + }), + ); + }); + } + + ///decide which field to show first based on the selected calling place + inputFields(BuildContext context) { + return textPlaceInput(context); + } + + openLocationInputBottomSheet(BuildContext context) { + context.read().flushSearchPredictions(); + showCommonBottomSheetWithoutHeight( + title: "".needTranslation, + context, + child: SizedBox( + height: MediaQuery.sizeOf(context).height * .8, + child: LocationInputBottomSheet(), + ), + isFullScreen: false, + isCloseButtonVisible: true, + hasBottomPadding: false, + backgroundColor: AppColors.bottomSheetBgColor, + callBackFunc: () {}, + ); + } + + hospitalField(BuildContext context) { + return DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, borderRadius: 12.h), + child: Row( + children: [ + hospitalAndPickUpItemContent( + title: "Select Hospital".needTranslation, + subTitle: context + .read() + .getSelectedHospitalName() ?? + "Select Hospital".needTranslation, + leadingIcon: AppAssets.hospital, + ), + Utils.buildSvgWithAssets( + icon: AppAssets.down_cheveron, width: 24.h, height: 24.h) + .paddingAll(16.h) + ], + ).onPress(() { + print("the item is clicked"); + showHospitalBottomSheet(context); + }).paddingSymmetrical( + 10.w, + 12.h, + ), + ); + } + + void openAppointmentList(BuildContext context) { + showCommonBottomSheetWithoutHeight( + title: "Select Appointment".needTranslation, + context, + child: SizedBox( + height: MediaQuery.sizeOf(context).height * .5, + child: AppointmentBottomSheet( + list: context.read().appointments!, + onAppointmentSelection: (appointment) { + Navigator.pop(context); + context.read().setSelectedAppointment(appointment); + }), + ), + isFullScreen: false, + isCloseButtonVisible: true, + hasBottomPadding: false, + backgroundColor: AppColors.bottomSheetBgColor, + callBackFunc: () { + context.read().checkHasAppointment(); + }, + ); + // ); + } +} diff --git a/lib/presentation/emergency_services/RRT/rrt_request_type_select.dart b/lib/presentation/emergency_services/RRT/rrt_request_type_select.dart index 4d22610..8c3db26 100644 --- a/lib/presentation/emergency_services/RRT/rrt_request_type_select.dart +++ b/lib/presentation/emergency_services/RRT/rrt_request_type_select.dart @@ -1,9 +1,16 @@ +import 'package:easy_localization/easy_localization.dart' show tr, StringTranslateExtension; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.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/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/emergency_services/emergency_services_view_model.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/rrt_procedures_response_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/radio/custom_radio_button.dart'; import 'package:provider/provider.dart'; @@ -13,34 +20,250 @@ class RrtRequestTypeSelect extends StatelessWidget { @override Widget build(BuildContext context) { return Consumer(builder: (context, emergencyServicesVM, child) { + print("the checkbox is ${emergencyServicesVM.agreedToTermsAndCondition}"); return Column( children: [ - Container( - padding: EdgeInsets.all(16.h), - height: 200.h, + Column( + children: [ + "Rapid Response Team (RRT) options".needTranslation.toText20(color: AppColors.textColor, isBold: true), + SizedBox( + height: 16.h, + ), + DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: Colors.white, + borderRadius: 20.r, + ), + child: OptionSelection(context)), + SizedBox( + height: 24.h, + ), + termsAndCondition(context, emergencyServicesVM), + ], + ).paddingSymmetrical(24.w, 0.h), + bottomPriceContent(context, emergencyServicesVM) + ], + ); + }); + } + + bottomPriceContent(BuildContext context, EmergencyServicesViewModel emergencyServicesVM) { + if (emergencyServicesVM.selectedRRTProcedure == null) return SizedBox.shrink(); + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + DecoratedBox( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24.h, - ), + color: AppColors.scaffoldBgColor, + customBorder: BorderRadius.only( + topLeft: Radius.circular(24.h), + topRight: Radius.circular(24.h), + ), + hasShadow: true), child: Column( crossAxisAlignment: CrossAxisAlignment.start, + spacing: 12.h, children: [ Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 12.h, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Total amount to pay".needTranslation.toText18( + weight: FontWeight.w600, + color: AppColors.textColor, + ), + Utils.getPaymentAmountWithSymbol( + (Utils.formatNumberToInternationalFormat(context.read().selectedRRTProcedure?.patientShare ?? 0)) + .toText24(fontWeight: FontWeight.w600, color: AppColors.textColor, letterSpacing: -2), + AppColors.blackColor, + 17.h) + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.warning, height: 18.h, width: 18.h), + SizedBox( + width: 4.h, + ), + "Amount will be paid at the hospital".needTranslation.toText11( + color: AppColors.greyTextColor, + ), + ], + ), + Row( + children: [ + "+ VAT 15%(".needTranslation.toText12( + fontWeight: FontWeight.w500, + color: AppColors.greyTextColor, + ), + "${emergencyServicesVM.selectedRRTProcedure?.patientTaxAmount})".needTranslation.toText14( + weight: FontWeight.w600, + color: AppColors.greyTextColor, + ), + ], + ), + ], + ) + ], + ), + ), + + // Utils.getPaymentAmountWithSymbol2(context.read().selectedTransportOption?.priceTotal??"0", letterSpacing: -2) + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - CustomRadioOption( - value: "", - groupValue: "", - onChanged: (value) {}, - text: "Home Visit Emergency", + Row( + spacing: 6.w, + children: [ + Image.asset(AppAssets.mada, width: 24.h, height: 24.h), + Image.asset(AppAssets.visa, width: 24.h, height: 24.h), + Image.asset(AppAssets.Mastercard, width: 24.h, height: 24.h), + Image.asset(AppAssets.apple_pay, width: 24.h, height: 24.h), + ], + ), + Column( + children: [ + Divider( + color: AppColors.dividerColor, + thickness: 1.h, + ), + Utils.getPaymentAmountWithSymbol( + (Utils.formatNumberToInternationalFormat(context.read().selectedRRTProcedure?.patientShareWithTax ?? 0)) + .toText24(fontWeight: FontWeight.w600, color: AppColors.textColor, letterSpacing: -2), + AppColors.blackColor, + 17.h), + ], ) ], ), + CustomButton(text: LocaleKeys.next.tr(), onPressed: () { + Navigator.pop(context); + emergencyServicesVM.openRRT(); + }) ], - ), + ).paddingAll(24.h), ), - SizedBox(height: 32.h), ], ); - }); + } + + Widget OptionSelection(BuildContext context) { + return Selector?, RRTProceduresResponseModel?)>( + // Select both the list and the currently selected procedure + selector: (context, viewModel) => (viewModel.RRTProceduresList, viewModel.selectedRRTProcedure), + builder: (context, data, child) { + final procedureList = data.$1; + final selectedProcedure = data.$2; + + // Handle loading or empty state + if (procedureList == null || procedureList.isEmpty) { + return const SizedBox.shrink(); + } + + return ListView.separated( + shrinkWrap: true, + padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 16.w), + // Important for ListView inside a Column + physics: const NeverScrollableScrollPhysics(), + // If the parent is scrollable + itemCount: procedureList.length, + separatorBuilder: (_, __) => Divider(thickness: 1.h, color: AppColors.dividerColor), + itemBuilder: (_, index) { + final procedure = procedureList[index]; + + final indexOfSelectedItem = selectedProcedure != null ? procedureList.indexOf(selectedProcedure) : -1; + return RadioListTile( + title: (procedure.procedureName ?? "").toText12(color: AppColors.textColor), + value: index, + fillColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return AppColors.primaryRedColor; + } + return Color(0xffEEEEEE); + }), + contentPadding: EdgeInsets.zero, + groupValue: indexOfSelectedItem, + onChanged: (int? newValue) { + context.read().setSelectedRRTProcedure(procedure); + }, + ); + // return Row( + // children: [ + // Radio( + // // Specify the type for the Radio button + // value: procedure.procedureID ?? "", + // groupValue: selectedProcedure?.procedureID, + // // Compare with the selected procedure's ID + // activeColor: AppColors.primaryRedColor, + // fillColor: MaterialStateProperty.all(AppColors.primaryRedColor), + // onChanged: (value) { + // // The onChanged of the Radio button should handle the state update + // context.read().setSelectedRRTProcedure(procedure); + // }, + // ), + // Expanded( + // // Use Expanded to allow text to wrap if it's too long + // child: (procedure.procedureName ?? "").toText12(color: AppColors.textColor), + // ) + // ], + }, + ); + }, + ); + } + + termsAndCondition( + BuildContext context, + EmergencyServicesViewModel emergencyServicesVM, + ) { + return Row( + children: [ + Checkbox( + value: emergencyServicesVM.agreedToTermsAndCondition, + checkColor: AppColors.whiteColor, + fillColor: MaterialStateProperty.resolveWith((Set states) { + print("the state is ${states}"); + if (states.contains(WidgetState.selected)) { + return AppColors.errorColor; + } + return AppColors.whiteColor; + }), + onChanged: (value) { + emergencyServicesVM.setTermsAndConditions(value ?? false); + }), + Row( + children: [ + LocaleKeys.agreeTo.tr().toText12(color: AppColors.textColor), + LocaleKeys.termsConditoins.tr().toText12(color: AppColors.errorColor, isUnderLine: true), + ], + ), + ], + ); + + // CheckboxListTile( + // title: Row( + // children: [ + // LocaleKeys.agreeTo.tr().toText12(color: AppColors.textColor), + // LocaleKeys.termsConditoins.tr().toText12(color: AppColors.errorColor, isUnderLine: true), + // ], + // ), + // value: emergencyServicesVM.agreedToTermsAndCondition, + // onChanged: (value) { + // emergencyServicesVM.setTermsAndConditions(value ?? false); + // }, + // ); } } diff --git a/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart b/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart index eddca11..87bbead 100644 --- a/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart +++ b/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart @@ -8,6 +8,7 @@ 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/emergency_services/emergency_services_view_model.dart'; import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/RRTServiceData.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'; @@ -22,11 +23,13 @@ import 'package:url_launcher/url_launcher.dart' show launchUrl; class TrackingScreen extends StatelessWidget { OrderTrackingState? state ; + final bool isRRTOrder; final AmbulanceRequestOrdersModel? order; + final GetCMCAllOrdersResponseModel? rrtOrder; - TrackingScreen({super.key, OrderTrackingState? state, this.order}){ + TrackingScreen({super.key, OrderTrackingState? state, this.order, this.isRRTOrder = false, this.rrtOrder}){ if(state == null){ - switch (order?.statusId) { + switch (order?.statusId ?? rrtOrder?.statusId) { case 1: //pending case 2: //processing this.state = OrderTrackingState.waitingForCall; @@ -70,7 +73,7 @@ class TrackingScreen extends StatelessWidget { animationSection(), Column( spacing: 16.h, - children: [orderStatus(context), orderTrackingId(), contactSection()], + children: [orderStatus(context), orderTrackingId(context), contactSection()], ).paddingAll(16.h), ], ))), @@ -328,11 +331,12 @@ class TrackingScreen extends StatelessWidget { } } - orderTrackingId() { + orderTrackingId(BuildContext context) { if(state == OrderTrackingState.failed){ return SizedBox.shrink(); } return Container( + width: MediaQuery.sizeOf(context).width-32.h, padding: EdgeInsets.all(16.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, @@ -344,20 +348,10 @@ class TrackingScreen extends StatelessWidget { spacing: 8.h, children: [ - Visibility(visible:order != null ,child: "Req ID: ${order?.iD}".toText16(color: AppColors.textColor, weight: FontWeight.w600)), - Row( - spacing: 8.h, - children: [ - Flexible(child: - chip(order?.pickupLocation??"", AppAssets.location_pickup, AppColors.blackBgColor), - - ), - Flexible(child: - chip(order?.dropOffLocation??"", AppAssets.hospital, AppColors.blackBgColor), + Visibility(visible:(order != null || rrtOrder != null) ,child: "Req ID: ${order?.iD?? rrtOrder?.iD}".toText16(color: AppColors.textColor, weight: FontWeight.w600)), + if(order != null) ambulanceOrderData() + // else rrtOrderData() - ) - ], - ), ], ), ); @@ -456,6 +450,44 @@ class TrackingScreen extends StatelessWidget { openCancelOrderBottomSheet(BuildContext context){ - context.read().cancelOrder(order, shouldPop: true); + if(isRRTOrder){ + context.read().cancelRRTOrder(rrtOrder?.iD??-1, shouldPop: true); + return; + }else { + context.read().cancelOrder(order, shouldPop: true); + return; + } + } + + Widget ambulanceOrderData() { + return Row( + spacing: 8.h, + children: [ + Flexible(child: + chip(order?.pickupLocation??"", AppAssets.location_pickup, AppColors.blackBgColor), + + ), + Flexible(child: + chip(order?.dropOffLocation??"", AppAssets.hospital, AppColors.blackBgColor), + + ) + ], + ); } + + // Widget rrtOrderData() { + // return Row( + // spacing: 8.h, + // children: [ + // Flexible(child: + // chip(rrtOrder?.pickupLocation??"", AppAssets.location_pickup, AppColors.blackBgColor), + // + // ), + // // Flexible(child: + // // chip(rrtOrder?.??"", AppAssets.hospital, AppColors.blackBgColor), + // // + // // ) + // ], + // ); + // } } diff --git a/lib/presentation/emergency_services/emergency_services_page.dart b/lib/presentation/emergency_services/emergency_services_page.dart index d41f2eb..8f6fd23 100644 --- a/lib/presentation/emergency_services/emergency_services_page.dart +++ b/lib/presentation/emergency_services/emergency_services_page.dart @@ -6,6 +6,7 @@ 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/emergency_services/emergency_services_view_model.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/OrderDisplay.dart'; 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'; @@ -35,7 +36,8 @@ class EmergencyServicesPage extends StatelessWidget { return CollapsingListView( title: LocaleKeys.emergencyServices.tr(), requests: () { - Navigator.of(context).push(CustomPageRoute(page: ErHistoryListing(), direction: AxisDirection.up)); + emergencyServicesViewModel.changeOrderDisplayItems(OrderDislpay.ALL); + Navigator.of(context).push(CustomPageRoute(page: ErHistoryListing(), direction: AxisDirection.up)); }, child: Padding( padding: EdgeInsets.all(24.h), @@ -198,23 +200,7 @@ class EmergencyServicesPage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "".toText14(), - Utils.buildSvgWithAssets( - icon: AppAssets.cancel_circle_icon, - iconColor: AppColors.whiteColor, - width: 24.h, - height: 24.h, - fit: BoxFit.contain, - ).onPress(() { - Navigator.of(context).pop(); - }), - ], - ), - 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), @@ -228,10 +214,23 @@ class EmergencyServicesPage extends StatelessWidget { Navigator.of(context).pop(); LoaderBottomSheet.showLoader(); + emergencyServicesViewModel.clearRRTData(); await emergencyServicesViewModel.getRRTProcedures(onSuccess: (val) { LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight( - title: "Rapid Response Team (RRT)".needTranslation, + padding: EdgeInsets.only(top: 24.h), + titleWidget: Transform.flip( + flipX: emergencyServicesViewModel.isArabic, + child: Utils.buildSvgWithAssets( + icon: AppAssets.arrow_back, + iconColor: Color(0xff2B353E), + fit: BoxFit.contain, + ), + ).onPress(() { + + Navigator.pop(context); + }), + // title: "Rapid Response Team (RRT)".needTranslation, context, child: RrtRequestTypeSelect(), isFullScreen: false, @@ -359,8 +358,8 @@ class EmergencyServicesPage extends StatelessWidget { onCloseClicked: () { context.read().flushPickupInformation(); }, - titleWidget: Transform.flip( - flipX: emergencyServicesViewModel.isArabic ? true : false, + titleWidget: Transform.flip( + flipX: emergencyServicesViewModel.isArabic, child: Utils.buildSvgWithAssets( icon: AppAssets.arrow_back, iconColor: Color(0xff2B353E), diff --git a/lib/presentation/emergency_services/history/er_history_listing.dart b/lib/presentation/emergency_services/history/er_history_listing.dart index e5dd1e4..903e084 100644 --- a/lib/presentation/emergency_services/history/er_history_listing.dart +++ b/lib/presentation/emergency_services/history/er_history_listing.dart @@ -1,13 +1,20 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart' show AppAssets; import 'package:hmg_patient_app_new/core/app_export.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/emergency_services/emergency_services_view_model.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/OrderDisplay.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/RRTServiceData.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; -import 'package:hmg_patient_app_new/presentation/emergency_services/history/widget/ambulance_history_item.dart'; +import 'package:hmg_patient_app_new/presentation/emergency_services/history/widget/ambulance_history_item.dart' show AmbulanceHistoryItem; +import 'package:hmg_patient_app_new/presentation/emergency_services/history/widget/rrt_item.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/chip/app_custom_chip_widget.dart'; import 'package:provider/provider.dart'; class ErHistoryListing extends StatelessWidget { @@ -16,30 +23,52 @@ class ErHistoryListing extends StatelessWidget { return Scaffold( body: Column( children: [ + Expanded( child: CollapsingListView( title: "History Log".needTranslation, child: SingleChildScrollView( physics: NeverScrollableScrollPhysics(), child: Column( - children: [Visibility( - visible: context - .read() - .orders - ?.isNotEmpty == true, - child: ListView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: context - .read() - .orders - ?.length ?? 0, - itemBuilder: (_, index) => - Consumer( builder: (_, vm, __)=> - AmbulanceHistoryItem(order: vm.orders![index]), - ) + children: [ + + Selector( + selector: (context, vm) => (vm.orderDisplayList, vm.historyLoading), + builder: (context, data, _) { + + return Column( + children: [ + orderChips(context, data.$2), + + Visibility( + visible:data.$1.isNotEmpty == true, + child: ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount:data?.$1.length ?? 0, + itemBuilder: (_, index) { + var order = data.$1[index]; + if (order is AmbulanceRequestOrdersModel) { + return AmbulanceHistoryItem(order: order).toShimmer2(isShow: data.$2); + } else { + return RRTItem(order: (order as GetCMCAllOrdersResponseModel)).toShimmer2(isShow: data.$2); + } + }), + ), + Visibility( + visible: data.$1 + ?.isEmpty == true, child: Center( + child: Utils.getNoDataWidget(context, + noDataText: "You don't have any history" + .needTranslation), + )), + ], + ); + } ), - ),] + + + ] ).paddingAll(16.h) )) @@ -47,16 +76,84 @@ class ErHistoryListing extends StatelessWidget { ), - Visibility( - visible: context - .read() - .orders - ?.isEmpty == true, - child: Utils.getNoDataWidget(context, - noDataText: "You don't have any history" - .needTranslation)), + ], ), ); } + + orderChips(BuildContext context, bool isLoading) { + + if (context + .read() + .displayList + ?.isEmpty == true) { + return SizedBox.shrink(); + } + return + Selector( + selector: (context, vm) => vm.currentlyDisplayedOrder, + builder: (context, value, __) { + return Row( + spacing: 8.h, + children: [ + if(context + .read() + .orderDisplayList + ?.isNotEmpty == true) + AppCustomChipWidget( + labelText: "All Facilities".needTranslation, + shape: RoundedRectangleBorder( + side: BorderSide( + color: value == OrderDislpay.ALL ? AppColors.errorColor : AppColors.chipBorderColorOpacity20, + width: 1, + ), + borderRadius: BorderRadius.circular(10)), + backgroundColor: value == OrderDislpay.ALL ? AppColors.secondaryLightRedColor : AppColors.whiteColor, + textColor: value == OrderDislpay.ALL ? AppColors.errorColor : AppColors.blackColor, + ).onPress(() { + context.read().changeOrderDisplayItems(OrderDislpay.ALL); + }).toShimmer2(isShow: isLoading), + if(context + .read() + .ambulanceOrders + ?.isNotEmpty == true) + AppCustomChipWidget( + labelText: "Ambulance".needTranslation, + icon: AppAssets.ambulance, + shape: RoundedRectangleBorder( + side: BorderSide( + color: value == OrderDislpay.AMBULANCE ? AppColors.errorColor : AppColors.chipBorderColorOpacity20, + width: 1, + ), + borderRadius: BorderRadius.circular(10)), + backgroundColor: value == OrderDislpay.AMBULANCE ? AppColors.secondaryLightRedColor : AppColors.whiteColor, + textColor: value == OrderDislpay.AMBULANCE ? AppColors.errorColor : AppColors.blackColor, + ).toShimmer2(isShow: isLoading).onPress(() { + context.read().changeOrderDisplayItems(OrderDislpay.AMBULANCE); + }), + if(context + .read() + .ordersRRT + ?.completedOrders + .isNotEmpty == true) + AppCustomChipWidget( + labelText: "Rapid Response Team".needTranslation, + icon: AppAssets.ic_rrt_vehicle, + shape: RoundedRectangleBorder( + side: BorderSide( + color: value == OrderDislpay.RRT ? AppColors.errorColor : AppColors.chipBorderColorOpacity20, + width: 1, + ), + borderRadius: BorderRadius.circular(10)), + backgroundColor: value == OrderDislpay.RRT ? AppColors.secondaryLightRedColor : AppColors.whiteColor, + textColor: value == OrderDislpay.RRT ? AppColors.errorColor : AppColors.blackColor, + ).toShimmer2(isShow: isLoading).onPress(() { + context.read().changeOrderDisplayItems(OrderDislpay.RRT); + }), + ], + ); + }); + + } } diff --git a/lib/presentation/emergency_services/history/widget/ambulance_history_item.dart b/lib/presentation/emergency_services/history/widget/ambulance_history_item.dart index 5f4c8b2..42bf257 100644 --- a/lib/presentation/emergency_services/history/widget/ambulance_history_item.dart +++ b/lib/presentation/emergency_services/history/widget/ambulance_history_item.dart @@ -71,7 +71,7 @@ class AmbulanceHistoryItem extends StatelessWidget { labelText: title, icon: iconString, iconColor: iconColor, - iconSize: 14.h, + iconSize: 12.h, ); } diff --git a/lib/presentation/emergency_services/history/widget/rrt_item.dart b/lib/presentation/emergency_services/history/widget/rrt_item.dart new file mode 100644 index 0000000..84108fb --- /dev/null +++ b/lib/presentation/emergency_services/history/widget/rrt_item.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.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/core/utils/date_util.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/emergency_services/emergency_services_view_model.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/RRTServiceData.dart'; +import 'package:hmg_patient_app_new/presentation/emergency_services/history/widget/RequestStatus.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:provider/provider.dart'; + +import '../../../../core/utils/utils.dart'; + + +class RRTItem extends StatelessWidget { + final GetCMCAllOrdersResponseModel order; + + const RRTItem({super.key, required this.order}); + + @override + Widget build(BuildContext context) { + return DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: Colors.white, + hasShadow: true, + customBorder: BorderRadius.all( + Radius.circular(20.h), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 8.h, + children: [ + RequestStatus(status: order.statusId ?? 0), + "Req ID: ${order.iD}".toText16(color: AppColors.textColor, weight: FontWeight.w600), + Row( + spacing: 4.w, + children: [ + chip( Utils.getDayMonthYearDateFormatted(DateUtil.convertStringToDate(order.time)), AppAssets.calendar, AppColors.blackBgColor), + chip("Rapid Response Team(RRT)".needTranslation, AppAssets.ic_rrt_vehicle, AppColors.blackBgColor), + ], + ), + + if (order.statusId == 1 || order.statusId == 2) + CustomButton( + text: "Cancel Request".needTranslation, + onPressed: () async { + openCancelOrderBottomSheet(context); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: Colors.white, + icon: AppAssets.cancel, + ), + ], + ).paddingAll(16.h), + ).paddingOnly(bottom: 16.h); + } + + chip(String title, String iconString, Color iconColor) { + return AppCustomChipWidget( + labelText: title, + icon: iconString, + iconColor: iconColor, + iconSize: 12.h, + ); + } + + openCancelOrderBottomSheet(BuildContext context) { + context.read().cancelRRTOrder(order.iD); + } +} diff --git a/lib/presentation/home/widgets/small_service_card.dart b/lib/presentation/home/widgets/small_service_card.dart index 234fad1..f54f442 100644 --- a/lib/presentation/home/widgets/small_service_card.dart +++ b/lib/presentation/home/widgets/small_service_card.dart @@ -110,6 +110,7 @@ class SmallServiceCard extends StatelessWidget { case "emergency": context.read().flushData(); context.read().getTransportationOrders(showLoader: false,); + context.read().getRRTOrders(showLoader: false,); Navigator.of(context).push( CustomPageRoute( page: EmergencyServicesPage(), diff --git a/lib/widgets/common_bottom_sheet.dart b/lib/widgets/common_bottom_sheet.dart index 8021641..ee8c0e2 100644 --- a/lib/widgets/common_bottom_sheet.dart +++ b/lib/widgets/common_bottom_sheet.dart @@ -115,6 +115,7 @@ void showCommonBottomSheetWithoutHeight( Widget? titleWidget, bool useSafeArea = false, bool hasBottomPadding = true, + EdgeInsets? padding, Color backgroundColor = AppColors.bottomSheetBgColor, VoidCallback? onCloseClicked, }) { @@ -146,44 +147,46 @@ void showCommonBottomSheetWithoutHeight( physics: ClampingScrollPhysics(), child: isCloseButtonVisible ? Container( - padding: EdgeInsets.only( - left: 24, - top: 24, - right: 24, - bottom: 12, - ), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.bottomSheetBgColor, - borderRadius: 24.h, - ), - child: Column( - mainAxisSize: MainAxisSize.min, + padding: padding ?? const EdgeInsets.only( + left: 24, + top: 24, + right: 24, + bottom: 12, + ), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.bottomSheetBgColor, + borderRadius: 24.h, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: padding != null? EdgeInsets.symmetric(horizontal: 24.w): EdgeInsets.zero, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - titleWidget ?? - Expanded( - child: title.toText20(weight: FontWeight.w600), - ), - if (isCloseButtonVisible) ...[ - Utils.buildSvgWithAssets( - icon: AppAssets.close_bottom_sheet_icon, - iconColor: Color(0xff2B353E), - ).onPress(() { - onCloseClicked?.call(); - Navigator.of(context).pop(); - }), - ], - ], - ), - SizedBox(height: 16.h), - child, + titleWidget ?? + Expanded( + child: title.toText20(weight: FontWeight.w600), + ), + if (isCloseButtonVisible) ...[ + Utils.buildSvgWithAssets( + icon: AppAssets.close_bottom_sheet_icon, + iconColor: Color(0xff2B353E), + ).onPress(() { + onCloseClicked?.call(); + Navigator.of(context).pop(); + }),], ], ), - ) + ), + SizedBox(height: 16.h), + child, + ], + ), + ) : child, ), ),