diff --git a/assets/images/svg/ambulance.svg b/assets/images/svg/ambulance.svg new file mode 100644 index 0000000..a73cfdb --- /dev/null +++ b/assets/images/svg/ambulance.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 99f28f2..2eab03a 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -455,6 +455,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; @@ -467,6 +469,7 @@ MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -638,6 +641,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; @@ -650,6 +655,7 @@ MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -664,6 +670,8 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; @@ -676,6 +684,7 @@ MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -693,7 +702,7 @@ 331C808A294A63A400263BE5 /* Profile */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; @@ -703,7 +712,7 @@ 249021D3217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { isa = XCConfigurationList; @@ -713,7 +722,7 @@ 249021D4217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; /* End XCConfigurationList section */ }; diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 69204f3..b276dd7 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -2,13 +2,14 @@ import Flutter import UIKit import FirebaseCore import FirebaseMessaging - +import GoogleMaps @main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { + GMSServices.provideAPIKey("AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng") FirebaseApp.configure() GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 73c3fe6..56a6b4a 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -173,7 +173,7 @@ class ApiClientImp implements ApiClient { body[_appState.isAuthenticated ? 'TokenID' : 'LogInTokenID'] = _appState.appAuthToken; } - // body['TokenID'] = "@dm!n"; + body['TokenID'] = "@dm!n"; // body['PatientID'] = 3966014; // body['PatientTypeID'] = 1; // diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 41ef922..29ec562 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -48,9 +48,9 @@ var PHARMACY_REDIRECT_URL = 'https://bit.ly/AlhabibPharmacy'; // var PHARMACY_BASE_URL = 'https://mdlaboratories.com/exacartapitest/api/'; // RC API URL -var RC_BASE_URL = 'https://rc.hmg.com/'; +// var RC_BASE_URL = 'https://rc.hmg.com/'; -// var RC_BASE_URL = 'https://rc.hmg.com/test/'; +var RC_BASE_URL = 'https://rc.hmg.com/uat/'; // var RC_BASE_URL = 'https://ms.hmg.com/rc/'; diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index a64110d..e8215ba 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -157,6 +157,7 @@ class AppAssets { static const String activeCheck = '$svgBasePath/active-check.svg'; static const String deleteIcon = '$svgBasePath/delete_icon.svg'; static const String call_ambulance_icon = '$svgBasePath/call_ambulance_icon.svg'; + static const String ambulance = '$svgBasePath/ambulance.svg'; static const String nearest_er_icon = '$svgBasePath/nearest_er_icon.svg'; static const String rrt_icon = '$svgBasePath/rrt_icon.svg'; static const String waiting_time_clock = '$svgBasePath/waiting_time_clock.svg'; diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index cbeb4d4..c8659a7 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -56,12 +56,12 @@ class AppState { } FutureOr checkIfGMSAvailableOrNot() async { + isGMSAvailable = (await GmsCheck().checkGmsAvailability()) ?? true; if(Platform.isIOS) { - isGMSAvailable = false; + isGMSAvailable = true; isAndroid = false; return; } - isGMSAvailable = (await GmsCheck().checkGmsAvailability()) ?? true; } AuthenticatedUser? getAuthenticatedUser({bool isFamily = false}) { diff --git a/lib/core/utils/date_util.dart b/lib/core/utils/date_util.dart index 2fbbd09..d58aef6 100644 --- a/lib/core/utils/date_util.dart +++ b/lib/core/utils/date_util.dart @@ -6,7 +6,11 @@ class DateUtil { /// convert String To Date function /// [date] String we want to convert static DateTime convertStringToDate(String? date) { - if (date != null) { + 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); @@ -14,9 +18,7 @@ class DateUtil { return DateTime.fromMillisecondsSinceEpoch(int.parse( date.substring(startIndex + start.length, endIndex), )); - } else { - return DateTime.now(); - } + } static DateTime convertStringToDateSaudiTimezone(String date, int projectId) { diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index d890d36..87faa20 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -102,6 +102,12 @@ class Utils { ? getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString() : getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString(); } + static String getDayMonthYearDateFormatted(DateTime? dateTime) { + if(dateTime == null ) return ""; + return appState.isArabic() + ? "${dateTime.day.toString()} ${getMonthArabic(dateTime.month)}, ${dateTime.year.toString()}" + : "${dateTime.day.toString()} ${getMonth(dateTime.month)}, ${dateTime.year.toString()}"; + } /// get month by /// [month] convert month number in to month name diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index 8be2b8e..bcdacac 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -245,6 +245,7 @@ class AuthenticationViewModel extends ChangeNotifier { } Future _handleNewImeiRegistration() async { + await selectDeviceImei(onSuccess: (dynamic respData) async { try { if (respData != null) { diff --git a/lib/features/emergency_services/emergency_services_repo.dart b/lib/features/emergency_services/emergency_services_repo.dart index a9bebd5..65594b8 100644 --- a/lib/features/emergency_services/emergency_services_repo.dart +++ b/lib/features/emergency_services/emergency_services_repo.dart @@ -3,6 +3,8 @@ 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/emergency_services/models/request_model/PatientER_RC.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/ProjectAvgERWaitingTime.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'; @@ -19,6 +21,12 @@ abstract class EmergencyServicesRepo { Future>>> getProjectList(); + Future>> submitAmbulanceRequest(PatientER_RC request); + + Future>>> getTransportationOrders({int? id}); + + Future>> cancelOrder(int? iD, int patientId); + } class EmergencyServicesRepoImp implements EmergencyServicesRepo { @@ -174,4 +182,112 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>> submitAmbulanceRequest(PatientER_RC request) async { + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + body: request.toJson(), + INSERT_TRANSPORTATION_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>>> getTransportationOrders({int? id}) async { + try { + GenericApiModel>? apiResponse; + Failure? failure; + await apiClient.post( + body: {}, + "$GET_ALL_TRANSPORTATIONS_ORDERS?patientID=$id", + isRCService: true, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + final list = response['response']; + final proceduresList = list.map((item) => AmbulanceRequestOrdersModel.fromJson(item as Map)).toList().cast(); + + apiResponse = GenericApiModel>( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: proceduresList, + ); + } 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>> cancelOrder(int? iD, int patientID) async { + try { + GenericApiModel? apiResponse; + + Map request = {}; + request['Id'] = iD; + request['StatusId'] = 6; + request['ClickButton'] = 14; + request['PatientID'] = patientID; + Failure? failure; + await apiClient.post( + body: request, + CANCEL_AMBULANCE_REQUEST, + 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())); + } + } } diff --git a/lib/features/emergency_services/emergency_services_view_model.dart b/lib/features/emergency_services/emergency_services_view_model.dart index 742678a..0b28c2a 100644 --- a/lib/features/emergency_services/emergency_services_view_model.dart +++ b/lib/features/emergency_services/emergency_services_view_model.dart @@ -5,14 +5,20 @@ import 'package:google_maps_flutter/google_maps_flutter.dart' as GMSMapServices; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/location_util.dart'; +import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/doctor_response_mapper.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.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/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'; import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/PatientERTransportationMethod.dart' show PatientERTransportationMethod; 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/rrt_procedures_response_model.dart'; +import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart' show PlaceDetails; +import 'package:hmg_patient_app_new/features/location/PlacePrediction.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/doctor_list_api_response.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; @@ -20,6 +26,8 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ 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/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'; import 'package:hmg_patient_app_new/presentation/emergency_services/nearest_er_page.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart' show AppRoutes; import 'package:hmg_patient_app_new/services/dialog_service.dart'; @@ -27,6 +35,7 @@ import 'package:hmg_patient_app_new/services/error_handler_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/widgets/expandable_bottom_sheet/model/BottomSheetType.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; +import 'package:hmg_patient_app_new/widgets/order_tracking/order_tracking_state.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:huawei_map/huawei_map.dart' as HMSCameraServices; import 'package:url_launcher/url_launcher.dart'; @@ -46,6 +55,7 @@ class EmergencyServicesViewModel extends ChangeNotifier { final NavigationService navServices; final LocationUtils? locationUtils; final AppState appState; + TextEditingController searchController = TextEditingController(); //loading variables bool isERListLoading = false; @@ -65,6 +75,8 @@ class EmergencyServicesViewModel extends ChangeNotifier { int hmgCount = 0; int hmcCount = 0; bool pickupFromInsideTheLocation = true; + List? appointments; + List? orders = []; //ambulance selection data section List transportationOptions = []; @@ -248,7 +260,14 @@ class EmergencyServicesViewModel extends ChangeNotifier { } void updateBottomSheetState(BottomSheetType sheetType) { + if (sheetType == BottomSheetType.EXPANDED && selectedHospital == null) { + dialogService.showErrorBottomSheet(message: "Kindly Select Hospital".needTranslation); + return; + } bottomSheetType = sheetType; + if (sheetType == BottomSheetType.EXPANDED) { + clearAppointmentData(); + } notifyListeners(); } @@ -300,8 +319,7 @@ class EmergencyServicesViewModel extends ChangeNotifier { loadingText: "Getting Ambulance Transport Option".needTranslation); notifyListeners(); - var response = - await emergencyServicesRepo.getTransportationMethods(id: 4767477); + var response = await emergencyServicesRepo.getTransportationMethods(id: id); response.fold( (failure) async { @@ -381,6 +399,7 @@ class EmergencyServicesViewModel extends ChangeNotifier { hmcHospitalList = data.where((e) => e.isHMC == true).toList(); hmgCount = hmgHospitalList?.length ?? 0; hmcCount = hmcHospitalList?.length ?? 0; + getDisplayList(); notifyListeners(); }, ); @@ -451,6 +470,14 @@ class EmergencyServicesViewModel extends ChangeNotifier { displayList = hospitalList; selectedFacility = FacilitySelection.ALL; pickupFromInsideTheLocation = false; + haveAnAppointment = false; + appointment = null; + notifyListeners(); + } + + void clearAppointmentData() { + haveAnAppointment = false; + appointment = null; notifyListeners(); } @@ -471,11 +498,179 @@ class EmergencyServicesViewModel extends ChangeNotifier { } Future updateAppointment(bool value) async { - haveAnAppointment = value; + if (value) { - await appointmentRepo.getPatientAppointments( - isActiveAppointment: true, isArrivedAppointments: false); + await getAppointments(); + } else { + clearAppointmentData(); + } + if(appointments?.isNotEmpty == true) { + haveAnAppointment = value; } notifyListeners(); } + + Future getAppointments() async { + LoaderBottomSheet.showLoader(loadingText: "Fetching Appointment".needTranslation); + var result = await appointmentRepo.getPatientAppointments(isActiveAppointment: true, isArrivedAppointments: false); + LoaderBottomSheet.hideLoader(); + + result.fold((failure) { + haveAnAppointment = false; + notifyListeners(); + errorHandlerService.handleError(failure: failure); + }, (response) { + appointments = response.data; + if (appointments?.isEmpty == true) { + haveAnAppointment = false; + dialogService.showErrorBottomSheet(message: "Unable to Fetch Appointment"); + } + notifyListeners(); + }); + } + + void setSelectedAppointment(PatientAppointmentHistoryResponseModel selectedAppointment) { + appointment = selectedAppointment; + notifyListeners(); + } + + void checkHasAppointment() { + if (appointment == null) { + haveAnAppointment = false; + } + notifyListeners(); + } + + FutureOr submitAmbulanceRequest(GeocodeResult? result, PlaceDetails? place, PlacePrediction? placePrediction) async { + PatientER_RC request = createRequest(result, place, placePrediction); + navServices.push(CustomPageRoute(page: RequestingServicesPage())); + + var response = await emergencyServicesRepo.submitAmbulanceRequest(request); + response.fold((failure) { + navServices.pushAndRemoveUntil( + CustomPageRoute( + page: TrackingScreen( + state: OrderTrackingState.failed, + )), + ModalRoute.withName("/EmergencyServicesPage")); + }, (success) { + getTransportationOrders(shouldNavigateToTrackingScreen: true); + }); + } + + Future getTransportationOrders({bool shouldNavigateToTrackingScreen = false, bool showLoader = false}) async { + if(shouldNavigateToTrackingScreen == false && showLoader ) { + LoaderBottomSheet.showLoader(loadingText: "Fetching Orders"); + } + int? id = appState.getAuthenticatedUser()?.patientId; + + var response = await emergencyServicesRepo.getTransportationOrders(id: id); + if(shouldNavigateToTrackingScreen == false && showLoader ) { + LoaderBottomSheet.hideLoader();} + response.fold( + (failure) async { + if (shouldNavigateToTrackingScreen) { + navServices.pushAndRemoveUntil(CustomPageRoute(page: TrackingScreen(state: OrderTrackingState.waitingForCall)), ModalRoute.withName("/EmergencyServicesPage")); + } + }, + (apiResponse) { + if (shouldNavigateToTrackingScreen) { + navServices.pushAndRemoveUntil( + CustomPageRoute( + page: TrackingScreen( + state: OrderTrackingState.waitingForCall, + order: apiResponse.data?.firstWhere((element) => element.statusId == 1), + )), + ModalRoute.withName("/EmergencyServicesPage")); + } + + orders = apiResponse.data; + notifyListeners(); + }, + ); + } + + PatientER_RC createRequest(GeocodeResult? result, PlaceDetails? place, PlacePrediction? placePrediction) { + PatientER_RC request = PatientER_RC(); + TransportationDetails transportationDetails = TransportationDetails(); + transportationDetails.requesterIsOutSA = false; + transportationDetails.pickupSpot = pickupFromInsideTheLocation ? 1 : 0; + + transportationDetails.tripType = ambulanceDirection == AmbulanceDirection.ONE_WAY ? 0 : 1; + transportationDetails.ambulate = (transportationOptions.indexOf(selectedTransportOption!) + 1); + transportationDetails.transportationType = selectedTransportOption?.iD.toString() ?? ""; + request.patientERTransportationMethod = selectedTransportOption; + transportationDetails.pickupUrgency = 1; + switch (callingPlace) { + case AmbulanceCallingPlace.FROM_HOSPITAL: + transportationDetails.dropoffLatitude = selectedHospital!.latitude; + transportationDetails.dropoffLongitude = selectedHospital!.longitude; + transportationDetails.dropoffLocationName = selectedHospital!.name; + transportationDetails.pickupLatitude = ((result?.geometry.location.lat) ?? place?.lat)?.toStringAsFixed(6); + transportationDetails.pickupLongitude = ((result?.geometry.location.lng) ?? place?.lng)?.toStringAsFixed(6); + transportationDetails.pickupLocationName = result?.formattedAddress ?? placePrediction?.description; + transportationDetails.direction = 1; + break; + case AmbulanceCallingPlace.TO_HOSPITAL: + transportationDetails.pickupLatitude = selectedHospital!.latitude; + transportationDetails.pickupLongitude = selectedHospital!.longitude; + transportationDetails.pickupLocationName = selectedHospital!.name; + transportationDetails.dropoffLatitude = ((result?.geometry.location.lat) ?? place?.lat)?.toStringAsFixed(6); + transportationDetails.dropoffLongitude = ((result?.geometry.location.lng) ?? place?.lng)?.toStringAsFixed(6); + transportationDetails.dropoffLocationName = result?.formattedAddress ?? placePrediction?.description; + transportationDetails.direction = 0; + break; + } + AuthenticatedUser? user = appState.getAuthenticatedUser(); + if (user == null) throw Exception("Authentication Required to Continue"); + + request.patientIdentificationID = user.patientIdentificationNo; + request.projectID = user.projectId; + request.patientID = user.patientId; + transportationDetails.requesterIsOutSA = false; + transportationDetails.requesterMobileNo = user.mobileNumber; + transportationDetails.requesterFileNo = user.patientId; + transportationDetails.pickupDateTime = DateUtil.convertDateToStringLocation(DateTime.now()); + if (haveAnAppointment) { + transportationDetails.appointmentNo = appointment!.appointmentNo.toString(); + transportationDetails.appointmentClinicName = appointment!.clinicName; + transportationDetails.appointmentDoctorName = appointment!.doctorNameObj; + transportationDetails.appointmentBranch = appointment!.projectName; + transportationDetails.appointmentTime = appointment!.appointmentDate; + transportationDetails.haveAppointment = 1; + transportationDetails.dropoffLatitude = appointment!.latitude; + transportationDetails.dropoffLongitude = appointment!.longitude; + transportationDetails.dropoffLocationName = appointment!.projectName; + } + + transportationDetails.pickupSpot = pickupFromInsideTheLocation ? 1 : 0; + transportationDetails.ambulate = 3; + transportationDetails.ambulateTitle = "none"; + transportationDetails.notes = ""; + request.transportationDetails = transportationDetails; + + return request; + } + + void clearSearchText() { + searchController.clear(); + } + + Future cancelOrder(AmbulanceRequestOrdersModel? order, {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.cancelOrder(order?.iD, appState.getAuthenticatedUser()?.patientId ?? 0); + LoaderBottomSheet.hideLoader(); + response.fold((failure) => errorHandlerService.handleError(failure: failure), (success) { + getTransportationOrders(); + if (shouldPop) navServices.pop(); + }); + }, + onCancelPressed: () { + navServices.pop(); + }); + } } diff --git a/lib/features/emergency_services/models/request_model/PatientER_RC.dart b/lib/features/emergency_services/models/request_model/PatientER_RC.dart index 8cb3876..9c3bbdc 100644 --- a/lib/features/emergency_services/models/request_model/PatientER_RC.dart +++ b/lib/features/emergency_services/models/request_model/PatientER_RC.dart @@ -42,7 +42,7 @@ class PatientER_RC { this.patientOutSa, this.projectID, this.lineItemNo, - this.transportationDetails}); + this.transportationDetails }); PatientER_RC.fromJson(Map json) { versionID = json['VersionID']; @@ -123,7 +123,7 @@ class TransportationDetails { TransportationDetails( {this.direction, - this.haveAppointment, + this.haveAppointment = 0, this.tripType, this.pickupUrgency, this.pickupSpot, @@ -141,11 +141,11 @@ class TransportationDetails { this.pickupLongitude, this.dropoffLatitude, this.dropoffLongitude, - this.appointmentNo, - this.appointmentClinicName, - this.appointmentDoctorName, - this.appointmentBranch, - this.appointmentTime}); + this.appointmentNo = "0", + this.appointmentClinicName = "", + this.appointmentDoctorName = "", + this.appointmentBranch = "", + this.appointmentTime = ""}); TransportationDetails.fromJson(Map json) { direction = json['direction']; diff --git a/lib/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart b/lib/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart new file mode 100644 index 0000000..6993183 --- /dev/null +++ b/lib/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart @@ -0,0 +1,346 @@ +class AmbulanceRequestOrdersModel { + String? statusText; + num? paymentStatus; + dynamic clientRequestid; + dynamic paymentStatusText; + dynamic projectName; + String? nearestProjectName; + num? paymentAmount; + WFOrder? wFOrder; + String? serviceText; + bool? isSentForApproval; + num? exaCartOrderId; + String? exaCartGUID; + bool? isTimer; + num? timeSeconds; + num? totalPendingSeconds; + num? timeMinute; + num? timeHour; + num? timeTotalSeconds; + num? timeTotalMinute; + num? timeTotalHour; + dynamic approvalStatus; + bool? isActive; + num? clickButton; + dynamic orderHistory; + String? pickupLocation; + String? dropOffLocation; + String? clinicName; + String? doctorName; + String? branch; + String? time; + String? notes; + int? iD; + num? patientId; + num? patientOutSa; + bool? isOutPatient; + num? projectId; + num? nearestProjectId; + dynamic longitude; + dynamic latitude; + dynamic appointmentNo; + dynamic dischargeId; + int? statusId; + num? serviceId; + num? channel; + Orderpayment? orderpayment; + dynamic wforder; + dynamic orderapprovalobj; + String? created; + dynamic createdBy; + dynamic modified; + dynamic modifiedBy; + bool? isDeleted; + + AmbulanceRequestOrdersModel( + {this.statusText, + this.paymentStatus, + this.clientRequestid, + this.paymentStatusText, + this.projectName, + this.nearestProjectName, + this.paymentAmount, + this.wFOrder, + this.serviceText, + this.isSentForApproval, + this.exaCartOrderId, + this.exaCartGUID, + this.isTimer, + this.timeSeconds, + this.totalPendingSeconds, + this.timeMinute, + this.timeHour, + this.timeTotalSeconds, + this.timeTotalMinute, + this.timeTotalHour, + this.approvalStatus, + this.isActive, + this.clickButton, + this.orderHistory, + this.pickupLocation, + this.dropOffLocation, + this.clinicName, + this.doctorName, + this.branch, + this.time, + this.notes, + 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.wforder, + this.orderapprovalobj, + this.created, + this.createdBy, + this.modified, + this.modifiedBy, + this.isDeleted}); + + AmbulanceRequestOrdersModel.fromJson(Map json) { + 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']; + exaCartGUID = json['ExaCart_GUID']; + 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']; + orderHistory = json['OrderHistory']; + pickupLocation = json['PickupLocation']; + dropOffLocation = json['DropOffLocation']; + clinicName = json['clinicName']; + doctorName = json['DoctorName']; + branch = json['Branch']; + time = json['Time']; + notes = json['Notes']; + 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; + wforder = json['wforder']; + orderapprovalobj = json['orderapprovalobj']; + created = json['Created']; + createdBy = json['CreatedBy']; + modified = json['Modified']; + modifiedBy = json['ModifiedBy']; + isDeleted = json['IsDeleted']; + } + + Map toJson() { + final Map data = new Map(); + 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['ExaCart_GUID'] = this.exaCartGUID; + 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['OrderHistory'] = this.orderHistory; + 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; + 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['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; + return data; + } +} + +class WFOrder { + dynamic wfButtonsDTO; + num? iD; + num? orderId; + num? previousStep; + num? nextStep; + num? 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 Orderpayment { + num? iD; + num? orderId; + dynamic clientRequestId; + num? totalAmount; + num? 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; + } +} diff --git a/lib/features/location/location_view_model.dart b/lib/features/location/location_view_model.dart index e7cd685..e2e0cc5 100644 --- a/lib/features/location/location_view_model.dart +++ b/lib/features/location/location_view_model.dart @@ -28,10 +28,6 @@ class LocationViewModel extends ChangeNotifier { Location? mapCapturedLocation; - - - - FutureOr getPlacesPrediction(String input) async { predictions = []; isPredictionLoading= true; diff --git a/lib/presentation/appointments/widgets/appointment_doctor_card.dart b/lib/presentation/appointments/widgets/appointment_doctor_card.dart index 2ea75d1..0b75977 100644 --- a/lib/presentation/appointments/widgets/appointment_doctor_card.dart +++ b/lib/presentation/appointments/widgets/appointment_doctor_card.dart @@ -13,17 +13,18 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; class AppointmentDoctorCard extends StatelessWidget { - AppointmentDoctorCard( + const AppointmentDoctorCard( {super.key, required this.patientAppointmentHistoryResponseModel, required this.onRescheduleTap, required this.onCancelTap, - required this.onAskDoctorTap}); + required this.onAskDoctorTap, this.renderWidgetForERDisplay = false}); final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; final VoidCallback onRescheduleTap; final VoidCallback onCancelTap; final VoidCallback onAskDoctorTap; + final bool renderWidgetForERDisplay; @override Widget build(BuildContext context) { @@ -98,8 +99,12 @@ class AppointmentDoctorCard extends StatelessWidget { ], ), SizedBox(height: 16.h), - getAppointmentActionButtons( - AppointmentType.isArrived(patientAppointmentHistoryResponseModel), + + Visibility( + visible: renderWidgetForERDisplay == false, + child: getAppointmentActionButtons( + AppointmentType.isArrived(patientAppointmentHistoryResponseModel), + ), ), ], ), diff --git a/lib/presentation/emergency_services/call_ambulance/call_ambulance_page.dart b/lib/presentation/emergency_services/call_ambulance/call_ambulance_page.dart index f39aaf2..d0d7c82 100644 --- a/lib/presentation/emergency_services/call_ambulance/call_ambulance_page.dart +++ b/lib/presentation/emergency_services/call_ambulance/call_ambulance_page.dart @@ -9,12 +9,17 @@ 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_checkin_bottom_sheet.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/requesting_services_page.dart' show RequestingServicesPage; import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/tracking_screen.dart' show TrackingScreen; 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'; @@ -68,8 +73,7 @@ class CallAmbulancePage extends StatelessWidget { ), body: Stack( children: [ - if (context.read().isGMSAvailable || - Platform.isIOS) + if (context.read().isGMSAvailable ) GMSMap( currentLocation: context.read().getGMSLocation(), @@ -117,10 +121,10 @@ class CallAmbulancePage extends StatelessWidget { return GestureDetector( onVerticalDragUpdate: (details){ - if(details.delta.dy<0){ - - context.read().updateBottomSheetState(BottomSheetType.EXPANDED); - } + // if(details.delta.dy<0){ + // + // context.read().updateBottomSheetState(BottomSheetType.EXPANDED); + // } }, child: Column( mainAxisSize: MainAxisSize.min, @@ -163,7 +167,7 @@ class CallAmbulancePage extends StatelessWidget { mainAxisSize: MainAxisSize.min, spacing: 24.h, children: [ - inputFields(context), + // inputFields(context), SizedBox( height: 200.h, child: DecoratedBox( @@ -231,21 +235,25 @@ class CallAmbulancePage extends StatelessWidget { ), child: Column( children: [ - SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 16.h, - children: [ - // "Select Pickup Location".needTranslation.toText21( - // weight: FontWeight.w600, - // color: AppColors.textColor, - // ), - // locationsSections(context), - hospitalAndPickUpSection(context), - - ], - ).paddingOnly(top: 24.h, bottom: 32.h,left: 24.h, right: 24.h), - ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 16.h, + children: [ + + hospitalAndPickUpSection(context), + if(context.read().appointment != null) + AppointmentDoctorCard( + renderWidgetForERDisplay: true, + patientAppointmentHistoryResponseModel: context.read().appointment!, + onAskDoctorTap: () {}, + onCancelTap: () async {}, + onRescheduleTap: () async {}, + ).onPress((){ + openAppointmentList(context); + }) + + ], + ).paddingOnly(top: 24.h, bottom: 32.h,left: 24.h, right: 24.h), bottomPriceContent(context) ], @@ -369,13 +377,15 @@ class CallAmbulancePage extends StatelessWidget { value: context .watch() .haveAnAppointment, - onChanged: (value) { - if (value) { + onChanged: (value) async { + // if (value) { + // openAppointmentList(context); + // } + await context.read() + .updateAppointment(value); + if (context.read().appointments?.isNotEmpty == true) { openAppointmentList(context); } - context - .read() - .updateAppointment(value); }, ) ], @@ -502,8 +512,12 @@ class CallAmbulancePage extends StatelessWidget { CustomButton( text: "Submit Request".needTranslation, onPressed: () { - Navigator.push(context, CustomPageRoute(page: RequestingServicesPage())); - }) + 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), ), @@ -518,6 +532,7 @@ class CallAmbulancePage extends StatelessWidget { context, child: Consumer( builder:(_,vm,__)=> HospitalBottomSheetBody( + searchText: vm.searchController, displayList: vm.displayList, onFacilityClicked: (value) { vm.setSelectedFacility(value); @@ -540,7 +555,9 @@ class CallAmbulancePage extends StatelessWidget { isCloseButtonVisible: true, hasBottomPadding: false, backgroundColor: AppColors.bottomSheetBgColor, - callBackFunc: () {}, + callBackFunc: () { + context.read().clearSearchText(); + }, ); } @@ -631,7 +648,7 @@ class CallAmbulancePage extends StatelessWidget { subTitle: context .read() .getSelectedHospitalName() ?? - "hospital".needTranslation, + "Select Hospital".needTranslation, leadingIcon: AppAssets.hospital, ), Utils.buildSvgWithAssets( @@ -649,18 +666,26 @@ class CallAmbulancePage extends StatelessWidget { } void openAppointmentList(BuildContext context) { - // showCommonBottomSheetWithoutHeight( - // title: "".needTranslation, - // context, - // child: SizedBox( - // height: MediaQuery.sizeOf(context).height * .6, - // child: AppointmentBottomSheet(), - // ), - // isFullScreen: false, - // isCloseButtonVisible: true, - // hasBottomPadding: false, - // backgroundColor: AppColors.bottomSheetBgColor, - // callBackFunc: () {}, + 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/call_ambulance/requesting_services_page.dart b/lib/presentation/emergency_services/call_ambulance/requesting_services_page.dart index 7f79be0..83c16b6 100644 --- a/lib/presentation/emergency_services/call_ambulance/requesting_services_page.dart +++ b/lib/presentation/emergency_services/call_ambulance/requesting_services_page.dart @@ -5,27 +5,17 @@ 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/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/emergency_services/models/request_model/PatientER_RC.dart'; import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/tracking_screen.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart' show CustomPageRoute; import 'package:lottie/lottie.dart'; -class RequestingServicesPage extends StatefulWidget { - @override - State createState() => _RequestingServicesPageState(); -} +class RequestingServicesPage extends StatelessWidget { -class _RequestingServicesPageState extends State { - @override - void initState() { - Timer(Duration(seconds: 3), () { - Navigator.pushReplacement( - context, CustomPageRoute(page: TrackingScreen())); - }); - super.initState(); - } + const RequestingServicesPage({super.key,}); @override Widget build(BuildContext context) { return Material( diff --git a/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart b/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart index c0f31e1..de153a3 100644 --- a/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart +++ b/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart @@ -7,6 +7,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/resp_model/AmbulanceRequestOrdersModel.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'; @@ -17,11 +18,33 @@ import 'package:hmg_patient_app_new/widgets/order_tracking/order_tracking_state. import 'package:hmg_patient_app_new/widgets/order_tracking/request_tracking.dart'; import 'package:lottie/lottie.dart'; import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher.dart' show launchUrl; class TrackingScreen extends StatelessWidget { - final OrderTrackingState state = OrderTrackingState.ended; + OrderTrackingState? state ; + final AmbulanceRequestOrdersModel? order; - const TrackingScreen({super.key}); + TrackingScreen({super.key, OrderTrackingState? state, this.order}){ + if(state == null){ + switch (order?.statusId) { + case 1: //pending + case 2: //processing + this.state = OrderTrackingState.waitingForCall; + break; + case 3: //completed + this.state = OrderTrackingState.dispactched; + break; + case 4: //cancel + case 6: + case 7: + this.state = OrderTrackingState.cancel; + break; + } + + }else { + this.state = state; + } + } @override Widget build(BuildContext context) { @@ -62,6 +85,10 @@ class TrackingScreen extends StatelessWidget { return Lottie.asset(AppAnimations.ambulance, repeat: true, reverse: false, width: 260.h, height: 200.h); case OrderTrackingState.ended: return Lottie.asset(AppAnimations.checkmark, repeat: true, width: 260.h, height: 200.h); + case OrderTrackingState.failed: + case OrderTrackingState.cancel: + case null: + return Lottie.asset(AppAnimations.errorAnimation, repeat: true, width: 260.h, height: 200.h); } } @@ -92,7 +119,11 @@ class TrackingScreen extends StatelessWidget { } Widget trackingBottomSection(BuildContext context) { - switch (state) { + if(state == null ) + { + return SizedBox.shrink(); + } + switch (state!) { case OrderTrackingState.waitingForCall: return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -102,7 +133,9 @@ class TrackingScreen extends StatelessWidget { ), CustomButton( text: "Cancel Request".needTranslation, - onPressed: () async {}, + onPressed: () async { + openCancelOrderBottomSheet(context); + }, backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, textColor: Colors.white, @@ -146,6 +179,10 @@ class TrackingScreen extends StatelessWidget { doctorSection(), ], ); + case OrderTrackingState.failed: + case OrderTrackingState.cancel: + return SizedBox.shrink(); + } } @@ -231,7 +268,10 @@ class TrackingScreen extends StatelessWidget { } currentStatus() { - switch (state) { + if(state == null){ + return SizedBox.shrink(); + } + switch (state!) { case OrderTrackingState.waitingForCall: case OrderTrackingState.dispactched: return RichText( @@ -285,10 +325,16 @@ class TrackingScreen extends StatelessWidget { ); case OrderTrackingState.ended: return "Arrived".needTranslation.toText21(color: AppColors.textColor, weight: FontWeight.w600); + case OrderTrackingState.failed: + case OrderTrackingState.cancel: + return SizedBox.shrink(); } } orderTrackingId() { + if(state == OrderTrackingState.failed){ + return SizedBox.shrink(); + } return Container( padding: EdgeInsets.all(16.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( @@ -300,15 +346,21 @@ class TrackingScreen extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, spacing: 8.h, children: [ - "Req ID:1234567890".toText16(color: AppColors.textColor, weight: FontWeight.w600), + + Visibility(visible:order != null ,child: "Req ID: ${order?.iD}".toText16(color: AppColors.textColor, weight: FontWeight.w600)), Row( spacing: 8.h, children: [ - chip("location name".needTranslation, AppAssets.location_pickup, AppColors.blackBgColor), - chip("hotel name ".needTranslation, AppAssets.hospital, AppColors.blackBgColor), + Flexible(child: + chip(order?.pickupLocation??"", AppAssets.location_pickup, AppColors.blackBgColor), + + ), + Flexible(child: + chip(order?.dropOffLocation??"", AppAssets.hospital, AppColors.blackBgColor), + + ) ], ), - chip("hotel name ".needTranslation, AppAssets.hospital, AppColors.blackBgColor), ], ), ); @@ -339,7 +391,7 @@ class TrackingScreen extends StatelessWidget { spacing: 4.h, children: [ "Contact Rapid Response Team (RRT)".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w600), - "1223456789".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + "0115259555".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), SizedBox(height: 8.h), ], ), @@ -357,7 +409,11 @@ class TrackingScreen extends StatelessWidget { borderColor: Colors.transparent, height: 36.h, ), - ) + ).onPress((){ + launchUrl( + Uri.parse("tel://0115259555"), + ); + }) ], ), ); @@ -372,7 +428,10 @@ class TrackingScreen extends StatelessWidget { // ] // } - getTitle(OrderTrackingState state) { + getTitle(OrderTrackingState? state) { + if(state == null) + return "Failed".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600); + switch (state) { case OrderTrackingState.waitingForCall: return "Confirmation Call".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600); @@ -382,6 +441,11 @@ class TrackingScreen extends StatelessWidget { return " On The Way To Hospital".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600); case OrderTrackingState.ended: return "Arrived at Hospital".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600); + case OrderTrackingState.failed: + return "Failed".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600); + + case OrderTrackingState.cancel: + return "Order Cancel".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600); } } @@ -392,4 +456,9 @@ class TrackingScreen extends StatelessWidget { child: ClipRRect(borderRadius: BorderRadius.circular(20.h), child: mapForRequestedCoordinate(context)), ); } + + + openCancelOrderBottomSheet(BuildContext context){ + context.read().cancelOrder(order, shouldPop: true); + } } diff --git a/lib/presentation/emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart b/lib/presentation/emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart index 14ea705..b1e740b 100644 --- a/lib/presentation/emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart +++ b/lib/presentation/emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart @@ -24,10 +24,9 @@ import 'package:provider/provider.dart'; class HospitalBottomSheetBody extends StatelessWidget { - final TextEditingController searchText = TextEditingController(); + final TextEditingController searchText ; final Debouncer debouncer = Debouncer(milliseconds: 500); - final int hmcCount; final int hmgCount; final List? displayList; @@ -36,9 +35,7 @@ class HospitalBottomSheetBody extends StatelessWidget { final Function(HospitalsModel) onHospitalClicked; final Function(String) onHospitalSearch; - - - HospitalBottomSheetBody({super.key, required this.hmcCount, required this.hmgCount, this.displayList, required this.selectedFacility, required this.onFacilityClicked, required this.onHospitalClicked, required this.onHospitalSearch}); + HospitalBottomSheetBody({super.key, required this.hmcCount, required this.hmgCount, this.displayList, required this.selectedFacility, required this.onFacilityClicked, required this.onHospitalClicked, required this.onHospitalSearch, required this.searchText}); @override Widget build(BuildContext context) { @@ -57,6 +54,7 @@ class HospitalBottomSheetBody extends StatelessWidget { }, isEnable: true, prefix: null, + autoFocus: false, isBorderAllowed: false, keyboardType: TextInputType.text, diff --git a/lib/presentation/emergency_services/call_ambulance/widgets/appointment_bottom_sheet.dart b/lib/presentation/emergency_services/call_ambulance/widgets/appointment_bottom_sheet.dart index 8616fc3..6f5db92 100644 --- a/lib/presentation/emergency_services/call_ambulance/widgets/appointment_bottom_sheet.dart +++ b/lib/presentation/emergency_services/call_ambulance/widgets/appointment_bottom_sheet.dart @@ -1,92 +1,54 @@ -// import 'package:flutter/cupertino.dart'; -// import 'package:hmg_patient_app_new/core/utils/size_utils.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/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; -// import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart'; -// import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/doctor_card.dart'; -// import 'package:hmg_patient_app_new/theme/colors.dart'; -// import 'package:provider/provider.dart'; -// -// class AppointmentBottomSheet extends StatelessWidget{ -// @override -// Widget build(BuildContext context) { -// // TODO: implement build -// throw UnimplementedError(); -// } -// -// Widget getAppointList(EmergencyServicesViewModel viewmodel, List filteredAppointmentList) { -// return Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// ListView.separated( -// padding: EdgeInsets.only(top: 24.h), -// shrinkWrap: true, -// physics: NeverScrollableScrollPhysics(), -// itemCount: viewmodel.isMyAppointmentsLoading -// ? 5 -// : filteredAppointmentList.isNotEmpty -// ? filteredAppointmentList.length -// : 1, -// itemBuilder: (context, index) { -// return viewmodel.isMyAppointmentsLoading -// ? Container( -// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), -// child: DoctorCard(doctorsListResponseModel: doctorsListResponseModel, isLoading: viewmodel.isMyAppointmentsLoading, bookAppointmentsViewModel: bookAppointmentsViewModel), -// ).paddingSymmetrical(24.h, 0.h) -// : filteredAppointmentList.isNotEmpty -// ? AnimationConfiguration.staggeredList( -// position: index, -// duration: const Duration(milliseconds: 500), -// child: SlideAnimation( -// verticalOffset: 100.0, -// child: FadeInAnimation( -// child: AnimatedContainer( -// duration: Duration(milliseconds: 300), -// curve: Curves.easeInOut, -// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), -// child: AppointmentCard( -// patientAppointmentHistoryResponseModel: filteredAppointmentList[index], -// myAppointmentsViewModel: myAppointmentsViewModel, -// bookAppointmentsViewModel: bookAppointmentsViewModel, -// isLoading: false, -// isFromHomePage: false, -// ), -// ).paddingSymmetrical(24.h, 0.h), -// ), -// ), -// ) -// : Utils.getNoDataWidget( -// context, -// noDataText: "You don't have any appointments yet.".needTranslation, -// callToActionButton: CustomButton( -// text: LocaleKeys.bookAppo.tr(context: context), -// onPressed: () { -// Navigator.of(context).push( -// CustomPageRoute( -// page: BookAppointmentPage(), -// ), -// ); -// }, -// backgroundColor: Color(0xffFEE9EA), -// borderColor: Color(0xffFEE9EA), -// textColor: Color(0xffED1C2B), -// fontSize: 14.f, -// fontWeight: FontWeight.w500, -// borderRadius: 12.r, -// padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), -// height: 40.h, -// icon: AppAssets.add_icon, -// iconColor: AppColors.primaryRedColor, -// ).paddingSymmetrical(48.h, 0.h), -// ); -// }, -// separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h), -// ), -// SizedBox(height: 24.h), -// ], -// ); -// } -// -// -// } \ No newline at end of file +import 'package:flutter/cupertino.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.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/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart'; +import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/doctor_card.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:provider/provider.dart'; + +class AppointmentBottomSheet extends StatelessWidget{ + + + final Function(PatientAppointmentHistoryResponseModel) onAppointmentSelection; + final List list; + + const AppointmentBottomSheet({super.key, required this.onAppointmentSelection, required this.list}); + + @override + Widget build(BuildContext context) => getAppointList(list); + + Widget getAppointList( List list) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: ListView.separated( + padding: EdgeInsets.only(top: 24.h), + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemCount: list.length, + itemBuilder: (context, index) { + PatientAppointmentHistoryResponseModel item = list[index]; + return AppointmentDoctorCard( + renderWidgetForERDisplay: true, + patientAppointmentHistoryResponseModel: item, + onAskDoctorTap: () {}, + onCancelTap: () async {}, + onRescheduleTap: () async {}, + ).onPress((){ + onAppointmentSelection(item); + }); + }, + separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h), + ), + ), + SizedBox(height: 24.h), + ], + ); + } + + +} \ No newline at end of file diff --git a/lib/presentation/emergency_services/emergency_services_page.dart b/lib/presentation/emergency_services/emergency_services_page.dart index 5bd0afe..5d7c11b 100644 --- a/lib/presentation/emergency_services/emergency_services_page.dart +++ b/lib/presentation/emergency_services/emergency_services_page.dart @@ -14,6 +14,7 @@ import 'package:hmg_patient_app_new/presentation/emergency_services/RRT/rrt_requ 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'; @@ -36,7 +37,9 @@ class EmergencyServicesPage extends StatelessWidget { locationUtils!.isShowConfirmDialog = true; return CollapsingListView( title: "Emergency Services".needTranslation, - requests: () {}, + requests: () { + Navigator.of(context).push(CustomPageRoute(page: ErHistoryListing(), direction: AxisDirection.up)); + }, child: Padding( padding: EdgeInsets.all(24.h), child: Column( @@ -66,76 +69,86 @@ 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( - color: AppColors.primaryRedColor, - borderRadius: 24.h, - ), - child: Padding( - padding: EdgeInsets.all(24.h), - 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), - SizedBox(height: 8.h), - "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), - SizedBox(height: 24.h), - CustomButton( - text: LocaleKeys.confirm.tr(context: context), - onPressed: () async { - // - Navigator.of(context).pop(); - await emergencyServicesViewModel.getTransportationOption(); - openTranportationSelectionBottomSheet(context); - }, - backgroundColor: AppColors.whiteColor, - borderColor: AppColors.whiteColor, - textColor: AppColors.primaryRedColor, - icon: AppAssets.checkmark_icon, - iconColor: AppColors.primaryRedColor, - ), - SizedBox(height: 8.h), - ], - ), - ), - ), - isFullScreen: false, - isCloseButtonVisible: false, - hasBottomPadding: false, - backgroundColor: AppColors.primaryRedColor, - callBackFunc: () {}, - ); + + locationUtils!.getLocation( + isShowConfirmDialog: true, + onSuccess: (position) { + // updateBottomSheetState(BottomSheetType.FIXED); + Navigator.of(context).push( + CustomPageRoute( + page: CallAmbulancePage(), direction: AxisDirection.down), + ); + }); + // showCommonBottomSheetWithoutHeight( + // context, + // child: Container( + // decoration: + // RoundedRectangleBorder().toSmoothCornerDecoration( + // color: AppColors.primaryRedColor, + // borderRadius: 24.h, + // ), + // child: Padding( + // padding: EdgeInsets.all(24.h), + // 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), + // SizedBox(height: 8.h), + // "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), + // SizedBox(height: 24.h), + // CustomButton( + // text: LocaleKeys.confirm.tr(context: context), + // onPressed: () async { + // // + // Navigator.of(context).pop(); + // await emergencyServicesViewModel.getTransportationOption(); + // openTranportationSelectionBottomSheet(context); + // }, + // backgroundColor: AppColors.whiteColor, + // borderColor: AppColors.whiteColor, + // textColor: AppColors.primaryRedColor, + // icon: AppAssets.checkmark_icon, + // iconColor: AppColors.primaryRedColor, + // ), + // SizedBox(height: 8.h), + // ], + // ), + // ), + // ), + // isFullScreen: false, + // isCloseButtonVisible: false, + // hasBottomPadding: false, + // backgroundColor: AppColors.primaryRedColor, + // callBackFunc: () {}, + // ); }), ), SizedBox(height: 16.h), diff --git a/lib/presentation/emergency_services/history/er_history_listing.dart b/lib/presentation/emergency_services/history/er_history_listing.dart new file mode 100644 index 0000000..e5dd1e4 --- /dev/null +++ b/lib/presentation/emergency_services/history/er_history_listing.dart @@ -0,0 +1,62 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.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/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/widgets/appbar/collapsing_list_view.dart'; +import 'package:provider/provider.dart'; + +class ErHistoryListing extends StatelessWidget { + @override + Widget build(BuildContext context) { + 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]), + ) + ), + ),] + ).paddingAll(16.h) + + )) + + ), + + + Visibility( + visible: context + .read() + .orders + ?.isEmpty == true, + child: Utils.getNoDataWidget(context, + noDataText: "You don't have any history" + .needTranslation)), + ], + ), + ); + } +} diff --git a/lib/presentation/emergency_services/history/widget/RequestStatus.dart b/lib/presentation/emergency_services/history/widget/RequestStatus.dart new file mode 100644 index 0000000..de95bdc --- /dev/null +++ b/lib/presentation/emergency_services/history/widget/RequestStatus.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; + +class RequestStatus extends StatelessWidget { + final int status; + + const RequestStatus({super.key, required this.status}); + + @override + Widget build(BuildContext context) { + return AppCustomChipWidget( + labelText: getTitle(status), + backgroundColor: getBackgroundColor(status), + textColor: getTextColor(status), + ); + } + + String? getTitle(int status) { + switch (status) { + case 1: //pending + case 2: //processing + return "Under Processing".needTranslation; + case 3: //completed + return "Completed".needTranslation; + break; + case 4: //cancel + case 6: + case 7: + return "Canceled by patient".needTranslation; + break; + } + return null; + } + + Color? getBackgroundColor(int status) { + switch (status) { + case 1: //pending + case 2: //processing + case 3: //completed + return AppColors.switchBackgroundColor; + break; + case 4: //cancel + case 6: + case 7: + return AppColors.lightRedButtonColor; + break; + } + return null; + } + + Color? getTextColor(int status) { + switch (status) { + case 1: //pending + case 2: + return AppColors.successColor;//processing + case 3: //completed + case 4: //cancel + case 6: + case 7: + return AppColors.errorColor; + break; + } + return null; + } +} diff --git a/lib/presentation/emergency_services/history/widget/ambulance_history_item.dart b/lib/presentation/emergency_services/history/widget/ambulance_history_item.dart new file mode 100644 index 0000000..5f4c8b2 --- /dev/null +++ b/lib/presentation/emergency_services/history/widget/ambulance_history_item.dart @@ -0,0 +1,81 @@ +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/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 AmbulanceHistoryItem extends StatelessWidget { + final AmbulanceRequestOrdersModel order; + + const AmbulanceHistoryItem({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("Ambulance".needTranslation, AppAssets.ambulance, AppColors.blackBgColor), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Flexible(child: chip(order?.dropOffLocation ?? "", (order.dropOffLocation?.toLowerCase().contains("hospital") == true)?AppAssets.hospital:AppAssets.location_pickup, 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: 14.h, + ); + } + + openCancelOrderBottomSheet(BuildContext context) { + context.read().cancelOrder(order); + } +} diff --git a/lib/presentation/home/widgets/small_service_card.dart b/lib/presentation/home/widgets/small_service_card.dart index ee5fcca..234fad1 100644 --- a/lib/presentation/home/widgets/small_service_card.dart +++ b/lib/presentation/home/widgets/small_service_card.dart @@ -2,6 +2,7 @@ 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/features/emergency_services/emergency_services_view_model.dart'; import 'package:hmg_patient_app_new/presentation/appointments/my_doctors_page.dart'; import 'package:hmg_patient_app_new/presentation/emergency_services/emergency_services_page.dart'; import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart'; @@ -10,6 +11,7 @@ import 'package:hmg_patient_app_new/presentation/medical_file/patient_sickleaves import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; +import 'package:provider/provider.dart'; import '../../../core/utils/utils.dart'; import '../../../theme/colors.dart'; @@ -106,9 +108,12 @@ class SmallServiceCard extends StatelessWidget { ); break; case "emergency": + context.read().flushData(); + context.read().getTransportationOrders(showLoader: false,); Navigator.of(context).push( CustomPageRoute( page: EmergencyServicesPage(), + settings: const RouteSettings(name: '/EmergencyServicesPage'), ), ); break; diff --git a/lib/services/dialog_service.dart b/lib/services/dialog_service.dart index cf8918c..b91e093 100644 --- a/lib/services/dialog_service.dart +++ b/lib/services/dialog_service.dart @@ -215,12 +215,12 @@ Widget exceptionBottomSheetWidget({required BuildContext context, required Strin Padding( padding: EdgeInsets.only(bottom: 10.h), child: CustomButton( - text: LocaleKeys.ok.tr(), + text: LocaleKeys.cancel.tr(), onPressed: (onCancelPressed == null) ? () { context.pop(); } - : onOkPressed, + : onCancelPressed, backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedBorderColor, textColor: Colors.white, diff --git a/lib/services/navigation_service.dart b/lib/services/navigation_service.dart index b5c5e03..cb4405c 100644 --- a/lib/services/navigation_service.dart +++ b/lib/services/navigation_service.dart @@ -13,6 +13,10 @@ class NavigationService { return navigatorKey.currentState!.push(route); } + Future pushAndRemoveUntil(Route route,RoutePredicate predicate) { + return navigatorKey.currentState!.pushAndRemoveUntil(route,predicate); + } + void pop([T? result]) { navigatorKey.currentState!.pop(result); } @@ -34,6 +38,8 @@ class NavigationService { navigatorKey.currentState?.pushReplacementNamed(routeName); } + + 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)), diff --git a/lib/widgets/order_tracking/order_tracking_state.dart b/lib/widgets/order_tracking/order_tracking_state.dart index d33e762..5389488 100644 --- a/lib/widgets/order_tracking/order_tracking_state.dart +++ b/lib/widgets/order_tracking/order_tracking_state.dart @@ -3,4 +3,6 @@ enum OrderTrackingState { dispactched, returning, ended, + failed, + cancel } \ No newline at end of file diff --git a/lib/widgets/order_tracking/request_tracking.dart b/lib/widgets/order_tracking/request_tracking.dart index d25d8bc..c0847f9 100644 --- a/lib/widgets/order_tracking/request_tracking.dart +++ b/lib/widgets/order_tracking/request_tracking.dart @@ -5,7 +5,7 @@ import 'package:hmg_patient_app_new/widgets/order_tracking/order_tracking_state. class OrderTrackingWidget extends StatelessWidget { final double? height; - final OrderTrackingState state; + final OrderTrackingState? state; final double parentPaddingValue; const OrderTrackingWidget({super.key, this.height, required this.state, required this.parentPaddingValue}); @@ -23,7 +23,7 @@ class OrderTrackingWidget extends StatelessWidget { ); } - Widget? getBarAndDot(OrderTrackingState state, BuildContext context, + Widget? getBarAndDot(OrderTrackingState? state, BuildContext context, double width) { print("the parent padding value is $parentPaddingValue"); print("the parent padding value is ${(parentPaddingValue+24)}"); @@ -31,6 +31,16 @@ class OrderTrackingWidget extends StatelessWidget { double widthOfOneState = (width/4) - (parentPaddingValue+8.h); print("te width of one state is $widthOfOneState"); print("the value of${width/4}"); + if(state == null) { + return Row( + children: List.generate(4, (index) { + if (index == 0) { + return oneProgressBar(widthOfOneState, AppColors.primaryRedColor, true); + } else { + return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false); + } + })); + } switch (state) { case OrderTrackingState.waitingForCall: return Row( @@ -73,6 +83,26 @@ class OrderTrackingWidget extends StatelessWidget { // } }) ); + case OrderTrackingState.failed: + return Row( + children: List.generate(4, (index){ + // if(index == 3) { + return oneProgressBar(widthOfOneState, AppColors.errorColor, index == 3); + // } else { + // return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false); + // } + }) + ); + case OrderTrackingState.cancel: + return Row( + children: List.generate(4, (index){ + // if(index == 3) { + return oneProgressBar(widthOfOneState, AppColors.errorColor, index == 3); + // } else { + // return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false); + // } + }) + ); } } diff --git a/lib/widgets/routes/custom_page_route.dart b/lib/widgets/routes/custom_page_route.dart index 475b2ee..b89d710 100644 --- a/lib/widgets/routes/custom_page_route.dart +++ b/lib/widgets/routes/custom_page_route.dart @@ -7,8 +7,10 @@ class CustomPageRoute extends PageRouteBuilder { final AxisDirection direction; final bool fullScreenDialog; - CustomPageRoute({required this.page, this.direction = AxisDirection.right, this.fullScreenDialog = false}) + + CustomPageRoute({required this.page, this.direction = AxisDirection.right, this.fullScreenDialog = false, super.settings}) : super( + transitionDuration: const Duration(milliseconds: 1500), reverseTransitionDuration: const Duration(milliseconds: 500), fullscreenDialog: fullScreenDialog,