From 0742d64428bc3a54619250796f6a08670be5cf59 Mon Sep 17 00:00:00 2001 From: Mohammad Aljammal Date: Tue, 23 Mar 2021 10:03:38 +0200 Subject: [PATCH] add lab result services --- lib/client/base_app_client.dart | 155 ++++++++++++ lib/config/config.dart | 18 ++ lib/config/localized_values.dart | 16 ++ lib/core/enum/filter_type.dart | 2 + lib/core/model/labs/LabOrderResult.dart | 88 +++++++ lib/core/model/labs/lab_result.dart | 98 ++++++++ lib/core/model/labs/patient_lab_orders.dart | 158 ++++++++++++ .../labs/patient_lab_special_result.dart | 32 +++ .../labs/request_patient_lab_orders.dart | 64 +++++ .../request_patient_lab_special_result.dart | 84 +++++++ .../labs/request_send_lab_report_email.dart | 112 +++++++++ lib/core/service/labs_service.dart | 136 ++++++++++ lib/core/viewModel/labs_view_model.dart | 175 +++++++++++++ lib/lookups/patient_lookup.dart | 2 +- .../patients/patient_search_screen.dart | 4 +- .../profile/lab_result/FlowChartPage.dart | 44 ++++ .../profile/lab_result/LabResultWidget.dart | 175 +++++++++++++ .../Lab_Result_details_wideget.dart | 119 +++++++++ .../profile/lab_result/LineChartCurved.dart | 229 +++++++++++++++++ .../lab_result_chart_and_detials.dart | 41 +++ .../lab_result/laboratory_result_page.dart | 55 ++++ .../lab_result/laboratory_result_widget.dart | 235 ++++++++++++++++++ .../profile/lab_result/labs_home_page.dart | 117 +++++++++ lib/util/date-utils.dart | 41 +++ lib/util/dr_app_shared_pref.dart | 7 + lib/util/translations_delegate_base.dart | 11 + lib/widgets/shared/StarRating.dart | 48 ++++ .../shared/app_expandable_notifier_new.dart | 126 ++++++++++ lib/widgets/shared/doctor_card.dart | 198 +++++++++++++++ pubspec.lock | 98 ++++++++ pubspec.yaml | 3 + 31 files changed, 2688 insertions(+), 3 deletions(-) create mode 100644 lib/core/enum/filter_type.dart create mode 100644 lib/core/model/labs/LabOrderResult.dart create mode 100644 lib/core/model/labs/lab_result.dart create mode 100644 lib/core/model/labs/patient_lab_orders.dart create mode 100644 lib/core/model/labs/patient_lab_special_result.dart create mode 100644 lib/core/model/labs/request_patient_lab_orders.dart create mode 100644 lib/core/model/labs/request_patient_lab_special_result.dart create mode 100644 lib/core/model/labs/request_send_lab_report_email.dart create mode 100644 lib/core/service/labs_service.dart create mode 100644 lib/core/viewModel/labs_view_model.dart create mode 100644 lib/screens/patients/profile/lab_result/FlowChartPage.dart create mode 100644 lib/screens/patients/profile/lab_result/LabResultWidget.dart create mode 100644 lib/screens/patients/profile/lab_result/Lab_Result_details_wideget.dart create mode 100644 lib/screens/patients/profile/lab_result/LineChartCurved.dart create mode 100644 lib/screens/patients/profile/lab_result/lab_result_chart_and_detials.dart create mode 100644 lib/screens/patients/profile/lab_result/laboratory_result_page.dart create mode 100644 lib/screens/patients/profile/lab_result/laboratory_result_widget.dart create mode 100644 lib/screens/patients/profile/lab_result/labs_home_page.dart create mode 100644 lib/widgets/shared/StarRating.dart create mode 100644 lib/widgets/shared/app_expandable_notifier_new.dart create mode 100644 lib/widgets/shared/doctor_card.dart diff --git a/lib/client/base_app_client.dart b/lib/client/base_app_client.dart index 559f7132..aefd3bb2 100644 --- a/lib/client/base_app_client.dart +++ b/lib/client/base_app_client.dart @@ -3,9 +3,12 @@ import 'dart:convert'; import 'package:doctor_app_flutter/config/config.dart'; import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; import 'package:doctor_app_flutter/models/doctor/doctor_profile_model.dart'; +import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart'; import 'package:doctor_app_flutter/util/dr_app_shared_pref.dart'; import 'package:doctor_app_flutter/util/helpers.dart'; import 'package:http/http.dart' as http; +import 'dart:io' show Platform; + DrAppSharedPreferances sharedPref = new DrAppSharedPreferances(); Helpers helpers = new Helpers(); @@ -120,6 +123,158 @@ class BaseAppClient { } } + postPatient(String endPoint, + {Map body, + Function(dynamic response, int statusCode) onSuccess, + Function(String error, int statusCode) onFailure, + PatiantInformtion patient, + bool isExternal = false}) async { + String url = BASE_URL + endPoint; + + try { + Map headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }; + + String token = await sharedPref.getString(TOKEN); + var languageID = + await sharedPref.getStringWithDefaultValue(APP_Language, 'ar'); + if (body.containsKey('SetupID')) { + body['SetupID'] = body.containsKey('SetupID') + ? body['SetupID'] != null + ? body['SetupID'] + : SETUP_ID + : SETUP_ID; + } + + body['VersionID'] = VERSION_ID; + body['Channel'] = CHANNEL; + body['LanguageID'] = languageID == 'ar' ? 1 : 2; + + body['IPAdress'] = IP_ADDRESS; + body['generalid'] = GENERAL_ID; + body['PatientOutSA'] = body.containsKey('PatientOutSA') + ? body['PatientOutSA'] != null + ? body['PatientOutSA'] + : PATIENT_OUT_SA_PATIENT_REQ + : PATIENT_OUT_SA_PATIENT_REQ; + + if (body.containsKey('isDentalAllowedBackend')) { + body['isDentalAllowedBackend'] = + body.containsKey('isDentalAllowedBackend') + ? body['isDentalAllowedBackend'] != null + ? body['isDentalAllowedBackend'] + : IS_DENTAL_ALLOWED_BACKEND + : IS_DENTAL_ALLOWED_BACKEND; + } + + body['DeviceTypeID'] = Platform.isAndroid ? 1: 2; + + + body['PatientType'] = body.containsKey('PatientType') + ? body['PatientType'] != null + ? body['PatientType'] + : patient.patientType!= null + ? patient.patientType + : PATIENT_TYPE + : PATIENT_TYPE; + + body['PatientTypeID'] = body.containsKey('PatientTypeID') + ? body['PatientTypeID'] != null + ? body['PatientTypeID'] + : patient.patientType!= null + ? patient.patientType + : PATIENT_TYPE_ID + : PATIENT_TYPE_ID; + + body['TokenID'] = token; + body['PatientID'] = body['PatientID'] != null + ? body['PatientID'] + : patient.patientId?? patient.patientMRN; + + body['PatientOutSA'] = 0;//user['OutSA']; //TODO change it + body['SessionID'] = SESSION_ID; //getSe + + + print("URL : $url"); + print("Body : ${json.encode(body)}"); + + if (await Helpers.checkConnection()) { + final response = await http.post(url.trim(), + body: json.encode(body), headers: headers); + final int statusCode = response.statusCode; + print("statusCode :$statusCode"); + if (statusCode < 200 || statusCode >= 400 || json == null) { + onFailure('Error While Fetching data', statusCode); + } else { + // var parsed = json.decode(response.body.toString()); + var parsed = json.decode(utf8.decode(response.bodyBytes)); + if (parsed['Response_Message'] != null) { + onSuccess(parsed, statusCode); + } else { + if (parsed['IsAuthenticated'] == null) { + if (parsed['isSMSSent'] == true) { + onSuccess(parsed, statusCode); + } else if (parsed['MessageStatus'] == 1) { + onSuccess(parsed, statusCode); + } else if (parsed['Result'] == 'OK') { + onSuccess(parsed, statusCode); + } else { + if (parsed != null) { + onSuccess(parsed, statusCode); + } else { + onFailure(getError(parsed), statusCode); + } + } + } else if (parsed['MessageStatus'] == 1 || + parsed['SMSLoginRequired'] == true) { + onSuccess(parsed, statusCode); + } else if (parsed['MessageStatus'] == 2 && + parsed['IsAuthenticated']) { + if (parsed['SameClinicApptList'] != null) { + onSuccess(parsed, statusCode); + } else { + if (parsed['message'] == null && + parsed['ErrorEndUserMessage'] == null) { + if (parsed['ErrorSearchMsg'] == null) { + onFailure("Server Error found with no available message", + statusCode); + } else { + onFailure(parsed['ErrorSearchMsg'], statusCode); + } + } else { + onFailure( + parsed['message'] ?? + parsed['ErrorEndUserMessage'] ?? + parsed['ErrorMessage'], + statusCode); + } + } + } else { + if (parsed['SameClinicApptList'] != null) { + onSuccess(parsed, statusCode); + } else { + if (parsed['message'] != null) { + onFailure(parsed['message'] ?? parsed['message'], statusCode); + } else { + onFailure( + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode); + } + } + } + } + } + } else { + onFailure('Please Check The Internet Connection', -1); + } + } catch (e) { + print(e); + onFailure(e.toString(), -1); + } + } + String getError(parsed) { //TODO change this fun String error = parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']; diff --git a/lib/config/config.dart b/lib/config/config.dart index 4ba98b6b..a512d136 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -143,6 +143,17 @@ const POST_PROCEDURE_LIST = 'Services/DoctorApplication.svc/REST/PostProcedure'; const GET_PATIENT_ARRIVAL_LIST = 'Services/DoctorApplication.svc/REST/PatientArrivalList'; +///Lab Order +const GET_Patient_LAB_ORDERS = 'Services/Patients.svc/REST/GetPatientLabOrders'; +const GET_Patient_LAB_SPECIAL_RESULT = + 'Services/Patients.svc/REST/GetPatientLabSpecialResults'; +const SEND_LAB_RESULT_EMAIL = + 'Services/Notifications.svc/REST/SendLabReportEmail'; +const GET_Patient_LAB_RESULT = + 'Services/Patients.svc/REST/GetPatientLabResults'; +const GET_Patient_LAB_ORDERS_RESULT = 'Services/Patients.svc/REST/GetPatientLabOrdersResults'; + + // SOAP const GET_ALLERGIES = 'Services/DoctorApplication.svc/REST/GetAllergies'; @@ -274,6 +285,13 @@ const CHANNEL = 9; const SESSION_ID = 'BlUSkYymTt'; const IS_LOGIN_FOR_DOCTOR_APP = true; const PATIENT_OUT_SA = false; +const IS_DENTAL_ALLOWED_BACKEND = false; +const PATIENT_OUT_SA_PATIENT_REQ = 0; +const SETUP_ID = '91877'; +const GENERAL_ID = 'Cs2020@2016\$2958'; +const PATIENT_TYPE = 1; +const PATIENT_TYPE_ID = 1; + /// Timer Info const TIMER_MIN = 10; diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 356c321d..b2ab19b9 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -748,4 +748,20 @@ const Map> localizedValues = { }, 'appointmentDate': {'en': "Appointment Date", 'ar': "تاريخ الموعد"}, 'arrived_p': {'en': "Arrived", 'ar': "وصل"}, + 'details': {'en': 'Details', 'ar': 'التفاصيل'}, + "liveCare": {"en": "Live Care", "ar": "لايف كير"}, + "out-patient": {"en": "Out Patient", "ar": "عيادات خارجية"}, + "BillNo": {"en": "Bill No :", "ar": "رقم الفاتورة"}, + "labResults": {"en": "Lab Result", "ar": "نتيجة المختبر"}, + "sendSuc": { + "en": "A copy has been sent to the email", + "ar": "تم إرسال نسخة إلى البريد الإلكتروني" + }, + "SpecialResult": {"en": " Special Result", "ar": "نتيجة خاصة"}, + "noDataAvailable": { + "en": "No data available", + "ar": " لا يوجد بيانات متاحة " + }, + "show-more-btn": {"en": "Flow Chart", "ar": "النتائج التراكمية"}, + }; diff --git a/lib/core/enum/filter_type.dart b/lib/core/enum/filter_type.dart new file mode 100644 index 00000000..4591e023 --- /dev/null +++ b/lib/core/enum/filter_type.dart @@ -0,0 +1,2 @@ +enum FilterType { Clinic, Hospital } + diff --git a/lib/core/model/labs/LabOrderResult.dart b/lib/core/model/labs/LabOrderResult.dart new file mode 100644 index 00000000..ecb4ae65 --- /dev/null +++ b/lib/core/model/labs/LabOrderResult.dart @@ -0,0 +1,88 @@ +class LabOrderResult { + String description; + dynamic femaleInterpretativeData; + int gender; + int lineItemNo; + dynamic maleInterpretativeData; + dynamic notes; + String packageID; + int patientID; + String projectID; + String referanceRange; + String resultValue; + String sampleCollectedOn; + String sampleReceivedOn; + String setupID; + dynamic superVerifiedOn; + String testCode; + String uOM; + String verifiedOn; + String verifiedOnDateTime; + + LabOrderResult( + {this.description, + this.femaleInterpretativeData, + this.gender, + this.lineItemNo, + this.maleInterpretativeData, + this.notes, + this.packageID, + this.patientID, + this.projectID, + this.referanceRange, + this.resultValue, + this.sampleCollectedOn, + this.sampleReceivedOn, + this.setupID, + this.superVerifiedOn, + this.testCode, + this.uOM, + this.verifiedOn, + this.verifiedOnDateTime}); + + LabOrderResult.fromJson(Map json) { + description = json['Description']; + femaleInterpretativeData = json['FemaleInterpretativeData']; + gender = json['Gender']; + lineItemNo = json['LineItemNo']; + maleInterpretativeData = json['MaleInterpretativeData']; + notes = json['Notes']; + packageID = json['PackageID']; + patientID = json['PatientID']; + projectID = json['ProjectID']; + referanceRange = json['ReferanceRange']; + resultValue = json['ResultValue']; + sampleCollectedOn = json['SampleCollectedOn']; + sampleReceivedOn = json['SampleReceivedOn']; + setupID = json['SetupID']; + superVerifiedOn = json['SuperVerifiedOn']; + testCode = json['TestCode']; + uOM = json['UOM']; + verifiedOn = json['VerifiedOn']; + verifiedOnDateTime = json['VerifiedOnDateTime']; + } + + Map toJson() { + final Map data = new Map(); + data['Description'] = this.description; + data['FemaleInterpretativeData'] = this.femaleInterpretativeData; + data['Gender'] = this.gender; + data['LineItemNo'] = this.lineItemNo; + data['MaleInterpretativeData'] = this.maleInterpretativeData; + data['Notes'] = this.notes; + data['PackageID'] = this.packageID; + data['PatientID'] = this.patientID; + data['ProjectID'] = this.projectID; + data['ReferanceRange'] = this.referanceRange; + data['ResultValue'] = this.resultValue; + data['SampleCollectedOn'] = this.sampleCollectedOn; + data['SampleReceivedOn'] = this.sampleReceivedOn; + data['SetupID'] = this.setupID; + data['SuperVerifiedOn'] = this.superVerifiedOn; + data['TestCode'] = this.testCode; + data['UOM'] = this.uOM; + data['VerifiedOn'] = this.verifiedOn; + data['VerifiedOnDateTime'] = this.verifiedOnDateTime; + return data; + } +} diff --git a/lib/core/model/labs/lab_result.dart b/lib/core/model/labs/lab_result.dart new file mode 100644 index 00000000..2deb13f3 --- /dev/null +++ b/lib/core/model/labs/lab_result.dart @@ -0,0 +1,98 @@ +class LabResult { + String description; + dynamic femaleInterpretativeData; + int gender; + int lineItemNo; + dynamic maleInterpretativeData; + String notes; + String packageID; + int patientID; + String projectID; + String referanceRange; + String resultValue; + String sampleCollectedOn; + String sampleReceivedOn; + String setupID; + dynamic superVerifiedOn; + String testCode; + String uOM; + String verifiedOn; + dynamic verifiedOnDateTime; + + LabResult( + {this.description, + this.femaleInterpretativeData, + this.gender, + this.lineItemNo, + this.maleInterpretativeData, + this.notes, + this.packageID, + this.patientID, + this.projectID, + this.referanceRange, + this.resultValue, + this.sampleCollectedOn, + this.sampleReceivedOn, + this.setupID, + this.superVerifiedOn, + this.testCode, + this.uOM, + this.verifiedOn, + this.verifiedOnDateTime}); + + LabResult.fromJson(Map json) { + description = json['Description']; + femaleInterpretativeData = json['FemaleInterpretativeData']; + gender = json['Gender']; + lineItemNo = json['LineItemNo']; + maleInterpretativeData = json['MaleInterpretativeData']; + notes = json['Notes']; + packageID = json['PackageID']; + patientID = json['PatientID']; + projectID = json['ProjectID']; + referanceRange = json['ReferanceRange']; + resultValue = json['ResultValue']; + sampleCollectedOn = json['SampleCollectedOn']; + sampleReceivedOn = json['SampleReceivedOn']; + setupID = json['SetupID']; + superVerifiedOn = json['SuperVerifiedOn']; + testCode = json['TestCode']; + uOM = json['UOM']; + verifiedOn = json['VerifiedOn']; + verifiedOnDateTime = json['VerifiedOnDateTime']; + } + + Map toJson() { + final Map data = new Map(); + data['Description'] = this.description; + data['FemaleInterpretativeData'] = this.femaleInterpretativeData; + data['Gender'] = this.gender; + data['LineItemNo'] = this.lineItemNo; + data['MaleInterpretativeData'] = this.maleInterpretativeData; + data['Notes'] = this.notes; + data['PackageID'] = this.packageID; + data['PatientID'] = this.patientID; + data['ProjectID'] = this.projectID; + data['ReferanceRange'] = this.referanceRange; + data['ResultValue'] = this.resultValue; + data['SampleCollectedOn'] = this.sampleCollectedOn; + data['SampleReceivedOn'] = this.sampleReceivedOn; + data['SetupID'] = this.setupID; + data['SuperVerifiedOn'] = this.superVerifiedOn; + data['TestCode'] = this.testCode; + data['UOM'] = this.uOM; + data['VerifiedOn'] = this.verifiedOn; + data['VerifiedOnDateTime'] = this.verifiedOnDateTime; + return data; + } +} + + +class LabResultList { + String filterName = ""; + List patientLabResultList = List(); + + LabResultList({this.filterName, LabResult lab}) { + patientLabResultList.add(lab); + } +} diff --git a/lib/core/model/labs/patient_lab_orders.dart b/lib/core/model/labs/patient_lab_orders.dart new file mode 100644 index 00000000..07044b0e --- /dev/null +++ b/lib/core/model/labs/patient_lab_orders.dart @@ -0,0 +1,158 @@ +import 'package:doctor_app_flutter/util/date-utils.dart'; + +class PatientLabOrders { + int actualDoctorRate; + String clinicDescription; + String clinicDescriptionEnglish; + Null clinicDescriptionN; + int clinicID; + int doctorID; + String doctorImageURL; + String doctorName; + String doctorNameEnglish; + Null doctorNameN; + int doctorRate; + String doctorTitle; + int gender; + String genderDescription; + String invoiceNo; + bool isActiveDoctorProfile; + bool isDoctorAllowVedioCall; + bool isExecludeDoctor; + bool isInOutPatient; + String isInOutPatientDescription; + String isInOutPatientDescriptionN; + bool isRead; + String nationalityFlagURL; + int noOfPatientsRate; + DateTime orderDate; + String orderNo; + String patientID; + String projectID; + String projectName; + Null projectNameN; + String qR; + String setupID; + List speciality; + bool isLiveCareAppointment; + PatientLabOrders( + {this.actualDoctorRate, + this.clinicDescription, + this.clinicDescriptionEnglish, + this.clinicDescriptionN, + this.clinicID, + this.doctorID, + this.doctorImageURL, + this.doctorName, + this.doctorNameEnglish, + this.doctorNameN, + this.doctorRate, + this.doctorTitle, + this.gender, + this.genderDescription, + this.invoiceNo, + this.isActiveDoctorProfile, + this.isDoctorAllowVedioCall, + this.isExecludeDoctor, + this.isInOutPatient, + this.isInOutPatientDescription, + this.isInOutPatientDescriptionN, + this.isRead, + this.nationalityFlagURL, + this.noOfPatientsRate, + this.orderDate, + this.orderNo, + this.patientID, + this.projectID, + this.projectName, + this.projectNameN, + this.qR, + this.setupID, + this.speciality,this.isLiveCareAppointment}); + + PatientLabOrders.fromJson(Map json) { + actualDoctorRate = json['ActualDoctorRate']; + clinicDescription = json['ClinicDescription']; + clinicDescriptionEnglish = json['ClinicDescriptionEnglish']; + clinicDescriptionN = json['ClinicDescriptionN']; + clinicID = json['ClinicID']; + doctorID = json['DoctorID']; + doctorImageURL = json['DoctorImageURL']; + doctorName = json['DoctorName']; + doctorNameEnglish = json['DoctorNameEnglish']; + doctorNameN = json['DoctorNameN']; + doctorRate = json['DoctorRate']; + doctorTitle = json['DoctorTitle']; + gender = json['Gender']; + genderDescription = json['GenderDescription']; + invoiceNo = json['InvoiceNo']; + isActiveDoctorProfile = json['IsActiveDoctorProfile']; + isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall']; + isExecludeDoctor = json['IsExecludeDoctor']; + isInOutPatient = json['IsInOutPatient']; + isInOutPatientDescription = json['IsInOutPatientDescription']; + isInOutPatientDescriptionN = json['IsInOutPatientDescriptionN']; + isRead = json['IsRead']; + nationalityFlagURL = json['NationalityFlagURL']; + noOfPatientsRate = json['NoOfPatientsRate']; + orderDate = DateUtils.convertStringToDate(json['OrderDate']); + orderNo = json['OrderNo']; + patientID = json['PatientID']; + projectID = json['ProjectID']; + projectName = json['ProjectName']; + projectNameN = json['ProjectNameN']; + qR = json['QR']; + setupID = json['SetupID']; + isLiveCareAppointment = json['IsLiveCareAppointment']; + // speciality = json['Speciality'].cast(); + } + + Map toJson() { + final Map data = new Map(); + data['ActualDoctorRate'] = this.actualDoctorRate; + data['ClinicDescription'] = this.clinicDescription; + data['ClinicDescriptionEnglish'] = this.clinicDescriptionEnglish; + data['ClinicDescriptionN'] = this.clinicDescriptionN; + data['ClinicID'] = this.clinicID; + data['DoctorID'] = this.doctorID; + data['DoctorImageURL'] = this.doctorImageURL; + data['DoctorName'] = this.doctorName; + data['DoctorNameEnglish'] = this.doctorNameEnglish; + data['DoctorNameN'] = this.doctorNameN; + data['DoctorRate'] = this.doctorRate; + data['DoctorTitle'] = this.doctorTitle; + data['Gender'] = this.gender; + data['GenderDescription'] = this.genderDescription; + data['InvoiceNo'] = this.invoiceNo; + data['IsActiveDoctorProfile'] = this.isActiveDoctorProfile; + data['IsDoctorAllowVedioCall'] = this.isDoctorAllowVedioCall; + data['IsExecludeDoctor'] = this.isExecludeDoctor; + data['IsInOutPatient'] = this.isInOutPatient; + data['IsInOutPatientDescription'] = this.isInOutPatientDescription; + data['IsInOutPatientDescriptionN'] = this.isInOutPatientDescriptionN; + data['IsRead'] = this.isRead; + data['NationalityFlagURL'] = this.nationalityFlagURL; + data['NoOfPatientsRate'] = this.noOfPatientsRate; + data['OrderDate'] = this.orderDate; + data['OrderNo'] = this.orderNo; + data['PatientID'] = this.patientID; + data['ProjectID'] = this.projectID; + data['ProjectName'] = this.projectName; + data['ProjectNameN'] = this.projectNameN; + data['QR'] = this.qR; + data['SetupID'] = this.setupID; + data['Speciality'] = this.speciality; + data['IsLiveCareAppointment'] = this.isLiveCareAppointment; + return data; + } +} + +class PatientLabOrdersList { + String filterName = ""; + List patientLabOrdersList = List(); + + PatientLabOrdersList( + {this.filterName, PatientLabOrders patientDoctorAppointment}) { + patientLabOrdersList.add(patientDoctorAppointment); + } +} diff --git a/lib/core/model/labs/patient_lab_special_result.dart b/lib/core/model/labs/patient_lab_special_result.dart new file mode 100644 index 00000000..2fbcb832 --- /dev/null +++ b/lib/core/model/labs/patient_lab_special_result.dart @@ -0,0 +1,32 @@ +class PatientLabSpecialResult { + String invoiceNo; + String moduleID; + String resultData; + String resultDataHTML; + Null resultDataTxt; + + PatientLabSpecialResult( + {this.invoiceNo, + this.moduleID, + this.resultData, + this.resultDataHTML, + this.resultDataTxt}); + + PatientLabSpecialResult.fromJson(Map json) { + invoiceNo = json['InvoiceNo']; + moduleID = json['ModuleID']; + resultData = json['ResultData']; + resultDataHTML = json['ResultDataHTML']; + resultDataTxt = json['ResultDataTxt']; + } + + Map toJson() { + final Map data = new Map(); + data['InvoiceNo'] = this.invoiceNo; + data['ModuleID'] = this.moduleID; + data['ResultData'] = this.resultData; + data['ResultDataHTML'] = this.resultDataHTML; + data['ResultDataTxt'] = this.resultDataTxt; + return data; + } +} diff --git a/lib/core/model/labs/request_patient_lab_orders.dart b/lib/core/model/labs/request_patient_lab_orders.dart new file mode 100644 index 00000000..ce9263ef --- /dev/null +++ b/lib/core/model/labs/request_patient_lab_orders.dart @@ -0,0 +1,64 @@ +class RequestPatientLabOrders { + double versionID; + int channel; + int languageID; + String iPAdress; + String generalid; + int patientOutSA; + String sessionID; + bool isDentalAllowedBackend; + int deviceTypeID; + int patientID; + String tokenID; + int patientTypeID; + int patientType; + + RequestPatientLabOrders( + {this.versionID, + this.channel, + this.languageID, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID, + this.patientID, + this.tokenID, + this.patientTypeID, + this.patientType}); + + RequestPatientLabOrders.fromJson(Map json) { + versionID = json['VersionID']; + channel = json['Channel']; + languageID = json['LanguageID']; + iPAdress = json['IPAdress']; + generalid = json['generalid']; + patientOutSA = json['PatientOutSA']; + sessionID = json['SessionID']; + isDentalAllowedBackend = json['isDentalAllowedBackend']; + deviceTypeID = json['DeviceTypeID']; + patientID = json['PatientID']; + tokenID = json['TokenID']; + patientTypeID = json['PatientTypeID']; + patientType = json['PatientType']; + } + + Map toJson() { + final Map data = new Map(); + data['VersionID'] = this.versionID; + data['Channel'] = this.channel; + data['LanguageID'] = this.languageID; + data['IPAdress'] = this.iPAdress; + data['generalid'] = this.generalid; + data['PatientOutSA'] = this.patientOutSA; + data['SessionID'] = this.sessionID; + data['isDentalAllowedBackend'] = this.isDentalAllowedBackend; + data['DeviceTypeID'] = this.deviceTypeID; + data['PatientID'] = this.patientID; + data['TokenID'] = this.tokenID; + data['PatientTypeID'] = this.patientTypeID; + data['PatientType'] = this.patientType; + return data; + } +} diff --git a/lib/core/model/labs/request_patient_lab_special_result.dart b/lib/core/model/labs/request_patient_lab_special_result.dart new file mode 100644 index 00000000..bdeb3930 --- /dev/null +++ b/lib/core/model/labs/request_patient_lab_special_result.dart @@ -0,0 +1,84 @@ +class RequestPatientLabSpecialResult { + String invoiceNo; + String orderNo; + String setupID; + String projectID; + int clinicID; + double versionID; + int channel; + int languageID; + String iPAdress; + String generalid; + int patientOutSA; + String sessionID; + bool isDentalAllowedBackend; + int deviceTypeID; + int patientID; + String tokenID; + int patientTypeID; + int patientType; + + RequestPatientLabSpecialResult( + {this.invoiceNo, + this.orderNo, + this.setupID, + this.projectID, + this.clinicID, + this.versionID, + this.channel, + this.languageID, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID, + this.patientID, + this.tokenID, + this.patientTypeID, + this.patientType}); + + RequestPatientLabSpecialResult.fromJson(Map json) { + invoiceNo = json['InvoiceNo']; + orderNo = json['OrderNo']; + setupID = json['SetupID']; + projectID = json['ProjectID']; + clinicID = json['ClinicID']; + versionID = json['VersionID']; + channel = json['Channel']; + languageID = json['LanguageID']; + iPAdress = json['IPAdress']; + generalid = json['generalid']; + patientOutSA = json['PatientOutSA']; + sessionID = json['SessionID']; + isDentalAllowedBackend = json['isDentalAllowedBackend']; + deviceTypeID = json['DeviceTypeID']; + patientID = json['PatientID']; + tokenID = json['TokenID']; + patientTypeID = json['PatientTypeID']; + patientType = json['PatientType']; + } + + Map toJson() { + final Map data = new Map(); + data['InvoiceNo'] = this.invoiceNo; + data['OrderNo'] = this.orderNo; + data['SetupID'] = this.setupID; + data['ProjectID'] = this.projectID; + data['ClinicID'] = this.clinicID; + data['VersionID'] = this.versionID; + data['Channel'] = this.channel; + data['LanguageID'] = this.languageID; + data['IPAdress'] = this.iPAdress; + data['generalid'] = this.generalid; + data['PatientOutSA'] = this.patientOutSA; + data['SessionID'] = this.sessionID; + data['isDentalAllowedBackend'] = this.isDentalAllowedBackend; + data['DeviceTypeID'] = this.deviceTypeID; + data['PatientID'] = this.patientID; + data['TokenID'] = this.tokenID; + data['PatientTypeID'] = this.patientTypeID; + data['PatientType'] = this.patientType; + return data; + } +} diff --git a/lib/core/model/labs/request_send_lab_report_email.dart b/lib/core/model/labs/request_send_lab_report_email.dart new file mode 100644 index 00000000..118da906 --- /dev/null +++ b/lib/core/model/labs/request_send_lab_report_email.dart @@ -0,0 +1,112 @@ +class RequestSendLabReportEmail { + double versionID; + int channel; + int languageID; + String iPAdress; + String generalid; + int patientOutSA; + String sessionID; + bool isDentalAllowedBackend; + int deviceTypeID; + int patientID; + String tokenID; + int patientTypeID; + int patientType; + String to; + String dateofBirth; + String patientIditificationNum; + String patientMobileNumber; + String patientName; + String setupID; + String projectName; + String clinicName; + String doctorName; + String projectID; + String invoiceNo; + String orderDate; + + RequestSendLabReportEmail( + {this.versionID, + this.channel, + this.languageID, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID, + this.patientID, + this.tokenID, + this.patientTypeID, + this.patientType, + this.to, + this.dateofBirth, + this.patientIditificationNum, + this.patientMobileNumber, + this.patientName, + this.setupID, + this.projectName, + this.clinicName, + this.doctorName, + this.projectID, + this.invoiceNo, + this.orderDate}); + + RequestSendLabReportEmail.fromJson(Map json) { + versionID = json['VersionID']; + channel = json['Channel']; + languageID = json['LanguageID']; + iPAdress = json['IPAdress']; + generalid = json['generalid']; + patientOutSA = json['PatientOutSA']; + sessionID = json['SessionID']; + isDentalAllowedBackend = json['isDentalAllowedBackend']; + deviceTypeID = json['DeviceTypeID']; + patientID = json['PatientID']; + tokenID = json['TokenID']; + patientTypeID = json['PatientTypeID']; + patientType = json['PatientType']; + to = json['To']; + dateofBirth = json['DateofBirth']; + patientIditificationNum = json['PatientIditificationNum']; + patientMobileNumber = json['PatientMobileNumber']; + patientName = json['PatientName']; + setupID = json['SetupID']; + projectName = json['ProjectName']; + clinicName = json['ClinicName']; + doctorName = json['DoctorName']; + projectID = json['ProjectID']; + invoiceNo = json['InvoiceNo']; + orderDate = json['OrderDate']; + } + + Map toJson() { + final Map data = new Map(); + data['VersionID'] = this.versionID; + data['Channel'] = this.channel; + data['LanguageID'] = this.languageID; + data['IPAdress'] = this.iPAdress; + data['generalid'] = this.generalid; + data['PatientOutSA'] = this.patientOutSA; + data['SessionID'] = this.sessionID; + data['isDentalAllowedBackend'] = this.isDentalAllowedBackend; + data['DeviceTypeID'] = this.deviceTypeID; + data['PatientID'] = this.patientID; + data['TokenID'] = this.tokenID; + data['PatientTypeID'] = this.patientTypeID; + data['PatientType'] = this.patientType; + data['To'] = this.to; + data['DateofBirth'] = this.dateofBirth; + data['PatientIditificationNum'] = this.patientIditificationNum; + data['PatientMobileNumber'] = this.patientMobileNumber; + data['PatientName'] = this.patientName; + data['SetupID'] = this.setupID; + data['ProjectName'] = this.projectName; + data['ClinicName'] = this.clinicName; + data['DoctorName'] = this.doctorName; + data['ProjectID'] = this.projectID; + data['InvoiceNo'] = this.invoiceNo; + data['OrderDate'] = this.orderDate; + return data; + } +} diff --git a/lib/core/service/labs_service.dart b/lib/core/service/labs_service.dart new file mode 100644 index 00000000..1a641d1f --- /dev/null +++ b/lib/core/service/labs_service.dart @@ -0,0 +1,136 @@ +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/core/model/labs/LabOrderResult.dart'; +import 'package:doctor_app_flutter/core/model/labs/lab_result.dart'; +import 'package:doctor_app_flutter/core/model/labs/patient_lab_orders.dart'; +import 'package:doctor_app_flutter/core/model/labs/patient_lab_special_result.dart'; +import 'package:doctor_app_flutter/core/model/labs/request_patient_lab_special_result.dart'; +import 'package:doctor_app_flutter/core/model/labs/request_send_lab_report_email.dart'; +import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart'; + +import 'base/base_service.dart'; + +class LabsService extends BaseService { + List patientLabOrdersList = List(); + + Future getPatientLabOrdersList(PatiantInformtion patient) async { + hasError = false; + Map body = Map(); + body['isDentalAllowedBackend'] = false; + await baseAppClient.postPatient(GET_Patient_LAB_ORDERS, patient: patient, + onSuccess: (dynamic response, int statusCode) { + patientLabOrdersList.clear(); + response['ListPLO'].forEach((hospital) { + patientLabOrdersList.add(PatientLabOrders.fromJson(hospital)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: body); + } + + RequestPatientLabSpecialResult _requestPatientLabSpecialResult = + RequestPatientLabSpecialResult(); + + List patientLabSpecialResult = List(); + List labResultList = List(); + List labOrdersResultsList = List(); + + Future getLaboratoryResult( + {String projectID, + int clinicID, + String invoiceNo, + String orderNo, + PatiantInformtion patient}) async { + hasError = false; + _requestPatientLabSpecialResult.projectID = projectID; + _requestPatientLabSpecialResult.clinicID = clinicID; + _requestPatientLabSpecialResult.invoiceNo = invoiceNo; + _requestPatientLabSpecialResult.orderNo = orderNo; + + await baseAppClient.postPatient(GET_Patient_LAB_SPECIAL_RESULT, + patient: patient, + onSuccess: (dynamic response, int statusCode) { + patientLabSpecialResult.clear(); + response['ListPLSR'].forEach((hospital) { + patientLabSpecialResult.add(PatientLabSpecialResult.fromJson(hospital)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: _requestPatientLabSpecialResult.toJson()); + } + + Future getPatientLabResult({PatientLabOrders patientLabOrder,PatiantInformtion patient}) async { + hasError = false; + Map body = Map(); + body['InvoiceNo'] = patientLabOrder.invoiceNo; + body['OrderNo'] = patientLabOrder.orderNo; + body['isDentalAllowedBackend'] = false; + body['SetupID'] = patientLabOrder.setupID; + body['ProjectID'] = patientLabOrder.projectID; + body['ClinicID'] = patientLabOrder.clinicID; + await baseAppClient.postPatient(GET_Patient_LAB_RESULT, + patient: patient, + onSuccess: (dynamic response, int statusCode) { + patientLabSpecialResult.clear(); + labResultList.clear(); + response['ListPLR'].forEach((lab) { + labResultList.add(LabResult.fromJson(lab)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: body); + } + + Future getPatientLabOrdersResults( + {PatientLabOrders patientLabOrder, String procedure,PatiantInformtion patient}) async { + hasError = false; + Map body = Map(); + body['InvoiceNo'] = patientLabOrder.invoiceNo; + body['OrderNo'] = patientLabOrder.orderNo; + body['isDentalAllowedBackend'] = false; + body['SetupID'] = patientLabOrder.setupID; + body['ProjectID'] = patientLabOrder.projectID; + body['ClinicID'] = patientLabOrder.clinicID; + body['Procedure'] = procedure; + await baseAppClient.postPatient(GET_Patient_LAB_ORDERS_RESULT, + patient: patient, + onSuccess: (dynamic response, int statusCode) { + labOrdersResultsList.clear(); + response['ListPLR'].forEach((lab) { + labOrdersResultsList.add(LabOrderResult.fromJson(lab)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: body); + } + + RequestSendLabReportEmail _requestSendLabReportEmail = + RequestSendLabReportEmail(); + + Future sendLabReportEmail({PatientLabOrders patientLabOrder}) async { + // _requestSendLabReportEmail.projectID = patientLabOrder.projectID; + // _requestSendLabReportEmail.invoiceNo = patientLabOrder.invoiceNo; + // _requestSendLabReportEmail.doctorName = patientLabOrder.doctorName; + // _requestSendLabReportEmail.clinicName = patientLabOrder.clinicDescription; + // _requestSendLabReportEmail.patientName = user.firstName +" "+ user.lastName; + // _requestSendLabReportEmail.patientIditificationNum = + // user.patientIdentificationNo; + // _requestSendLabReportEmail.dateofBirth = user.dateofBirth; + // _requestSendLabReportEmail.to = user.emailAddress; + // _requestSendLabReportEmail.orderDate = '${patientLabOrder.orderDate.year}-${patientLabOrder.orderDate.month}-${patientLabOrder.orderDate.day}'; + // _requestSendLabReportEmail.patientMobileNumber = user.mobileNumber; + // _requestSendLabReportEmail.projectName = patientLabOrder.projectName; + // _requestSendLabReportEmail.setupID = user.setupID; + // + // await baseAppClient.post(SEND_LAB_RESULT_EMAIL, + // onSuccess: (dynamic response, int statusCode) { + // + // }, onFailure: (String error, int statusCode) { + // hasError = true; + // super.error = error; + // }, body: _requestSendLabReportEmail.toJson()); + } +} diff --git a/lib/core/viewModel/labs_view_model.dart b/lib/core/viewModel/labs_view_model.dart new file mode 100644 index 00000000..3f457956 --- /dev/null +++ b/lib/core/viewModel/labs_view_model.dart @@ -0,0 +1,175 @@ +import 'package:doctor_app_flutter/core/enum/filter_type.dart'; +import 'package:doctor_app_flutter/core/enum/viewstate.dart'; +import 'package:doctor_app_flutter/core/model/labs/LabOrderResult.dart'; +import 'package:doctor_app_flutter/core/model/labs/lab_result.dart'; +import 'package:doctor_app_flutter/core/model/labs/patient_lab_orders.dart'; +import 'package:doctor_app_flutter/core/model/labs/patient_lab_special_result.dart'; +import 'package:doctor_app_flutter/core/service/labs_service.dart'; +import 'package:doctor_app_flutter/locator.dart'; +import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/util/dr_app_toast_msg.dart'; + +import 'base_view_model.dart'; + +class LabsViewModel extends BaseViewModel { + FilterType filterType = FilterType.Clinic; + LabsService _labsService = locator(); + + List get labOrdersResultsList => + _labsService.labOrdersResultsList; + + List _patientLabOrdersListClinic = List(); + List _patientLabOrdersListHospital = List(); + + List get patientLabOrdersList => + filterType == FilterType.Clinic + ? _patientLabOrdersListClinic + : _patientLabOrdersListHospital; + + void getLabs(PatiantInformtion patient) async { + setState(ViewState.Busy); + await _labsService.getPatientLabOrdersList(patient); + if (_labsService.hasError) { + error = _labsService.error; + setState(ViewState.Error); + } else { + _labsService.patientLabOrdersList.forEach((element) { + List patientLabOrdersClinic = + _patientLabOrdersListClinic + .where((elementClinic) => + elementClinic.filterName == element.clinicDescription) + .toList(); + + if (patientLabOrdersClinic.length != 0) { + _patientLabOrdersListClinic[_patientLabOrdersListClinic + .indexOf(patientLabOrdersClinic[0])] + .patientLabOrdersList + .add(element); + } else { + _patientLabOrdersListClinic.add(PatientLabOrdersList( + filterName: element.clinicDescription, + patientDoctorAppointment: element)); + } + + // doctor list sort via project + List patientLabOrdersHospital = + _patientLabOrdersListHospital + .where( + (elementClinic) => + elementClinic.filterName == element.projectName, + ) + .toList(); + + if (patientLabOrdersHospital.length != 0) { + _patientLabOrdersListHospital[_patientLabOrdersListHospital + .indexOf(patientLabOrdersHospital[0])] + .patientLabOrdersList + .add(element); + } else { + _patientLabOrdersListHospital.add(PatientLabOrdersList( + filterName: element.projectName, + patientDoctorAppointment: element)); + } + }); + + setState(ViewState.Idle); + } + } + + setFilterType(FilterType filterType) { + this.filterType = filterType; + notifyListeners(); + } + + List get patientLabSpecialResult => + _labsService.patientLabSpecialResult; + + List get labResultList => _labsService.labResultList; + + List labResultLists = List(); + + getLaboratoryResult( + {String projectID, + int clinicID, + String invoiceNo, + String orderNo, + PatiantInformtion patient}) async { + setState(ViewState.Busy); + await _labsService.getLaboratoryResult( + invoiceNo: invoiceNo, + orderNo: orderNo, + projectID: projectID, + clinicID: clinicID, + patient: patient); + if (_labsService.hasError) { + error = _labsService.error; + setState(ViewState.Error); + } else { + setState(ViewState.Idle); + } + } + + getPatientLabResult({PatientLabOrders patientLabOrder,PatiantInformtion patient}) async { + setState(ViewState.Busy); + await _labsService.getPatientLabResult(patientLabOrder: patientLabOrder,patient: patient); + if (_labsService.hasError) { + error = _labsService.error; + setState(ViewState.Error); + } else { + _labsService.labResultList.forEach((element) { + List patientLabOrdersClinic = labResultLists + .where( + (elementClinic) => elementClinic.filterName == element.testCode) + .toList(); + + if (patientLabOrdersClinic.length != 0) { + var value = + labResultLists[labResultLists.indexOf(patientLabOrdersClinic[0])] + .patientLabResultList + .where((e) => + e.sampleCollectedOn == element.sampleCollectedOn && + e.resultValue == element.resultValue) + .toList(); + if (value.isEmpty) + labResultLists[labResultLists.indexOf(patientLabOrdersClinic[0])] + .patientLabResultList + .add(element); + } else { + labResultLists + .add(LabResultList(filterName: element.testCode, lab: element)); + } + }); + setState(ViewState.Idle); + } + } + + getPatientLabOrdersResults( + {PatientLabOrders patientLabOrder, String procedure,PatiantInformtion patient}) async { + setState(ViewState.Busy); + await _labsService.getPatientLabOrdersResults( + patientLabOrder: patientLabOrder, procedure: procedure,patient: patient); + if (_labsService.hasError) { + error = _labsService.error; + setState(ViewState.Error); + } else { + bool isShouldClear = false; + if (_labsService.labOrdersResultsList.length == 1) { + labOrdersResultsList.forEach((element) { + if (element.resultValue.contains('/') || + element.resultValue.contains('*') || + element.resultValue.isEmpty) isShouldClear = true; + }); + } + if (isShouldClear) _labsService.labOrdersResultsList.clear(); + setState(ViewState.Idle); + } + } + + sendLabReportEmail({PatientLabOrders patientLabOrder, String mes}) async { + await _labsService.sendLabReportEmail(patientLabOrder: patientLabOrder); + if (_labsService.hasError) { + error = _labsService.error; + } else + DrAppToastMsg.showSuccesToast(mes); + } +} diff --git a/lib/lookups/patient_lookup.dart b/lib/lookups/patient_lookup.dart index 08b6471f..5418c357 100644 --- a/lib/lookups/patient_lookup.dart +++ b/lib/lookups/patient_lookup.dart @@ -1,4 +1,4 @@ -const PATIENT_TYPE = const [ +const PATIENT_TYPE_Des = const [ {"text": "Outpatient", "text_ar": "المريض الخارجي", "val": "0"}, {"text": "Inpatient", "text_ar": "المريض المنوم", "val": "1"}, {"text": "Discharge", "text_ar": "المريض المعافى", "val": "2"}, diff --git a/lib/screens/patients/patient_search_screen.dart b/lib/screens/patients/patient_search_screen.dart index 492e7d5e..7e8302c9 100644 --- a/lib/screens/patients/patient_search_screen.dart +++ b/lib/screens/patients/patient_search_screen.dart @@ -263,7 +263,7 @@ class _PatientSearchScreenState extends State { elevation: 16, selectedItemBuilder: (BuildContext context) { - return PATIENT_TYPE.map((item) { + return PATIENT_TYPE_Des.map((item) { return Row( mainAxisSize: MainAxisSize.max, @@ -292,7 +292,7 @@ class _PatientSearchScreenState extends State { int.parse(_selectedType); }) }, - items: PATIENT_TYPE.map((item) { + items: PATIENT_TYPE_Des.map((item) { !projectsProvider.isArabic ? itemText = item['text'] : itemText = diff --git a/lib/screens/patients/profile/lab_result/FlowChartPage.dart b/lib/screens/patients/profile/lab_result/FlowChartPage.dart new file mode 100644 index 00000000..772391b0 --- /dev/null +++ b/lib/screens/patients/profile/lab_result/FlowChartPage.dart @@ -0,0 +1,44 @@ +import 'package:doctor_app_flutter/core/model/labs/patient_lab_orders.dart'; +import 'package:doctor_app_flutter/core/viewModel/labs_view_model.dart'; +import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/widgets/shared/Text.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; + +import 'package:flutter/cupertino.dart'; + +import 'lab_result_chart_and_detials.dart'; + +class FlowChartPage extends StatelessWidget { + final PatientLabOrders patientLabOrder; + final String filterName; + final PatiantInformtion patient; + FlowChartPage({this.patientLabOrder, this.filterName, this.patient}); + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) => model.getPatientLabOrdersResults( + patientLabOrder: patientLabOrder, procedure: filterName,patient: patient), + builder: (context, model, w) => AppScaffold( + isShowAppBar: true, + appBarTitle: filterName, + baseViewModel: model, + body: SingleChildScrollView( + child: model.labOrdersResultsList.isNotEmpty + ? Container( + child: LabResultChartAndDetails( + name: filterName, + labResult: model.labOrdersResultsList, + ), + ) + : Container( + child: Center( + child: Texts('no Data'), + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/patients/profile/lab_result/LabResultWidget.dart b/lib/screens/patients/profile/lab_result/LabResultWidget.dart new file mode 100644 index 00000000..57b4614d --- /dev/null +++ b/lib/screens/patients/profile/lab_result/LabResultWidget.dart @@ -0,0 +1,175 @@ +import 'package:doctor_app_flutter/core/model/labs/lab_result.dart'; +import 'package:doctor_app_flutter/core/model/labs/patient_lab_orders.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/lab_result/FlowChartPage.dart'; +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/shared/Text.dart'; +import 'package:doctor_app_flutter/widgets/transitions/fade_page.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + + +class LabResultWidget extends StatelessWidget { + + final String filterName ; + final List patientLabResultList; + final PatientLabOrders patientLabOrder; + final PatiantInformtion patient; + LabResultWidget({Key key, this.filterName, this.patientLabResultList, this.patientLabOrder, this.patient}) : super(key: key); + ProjectViewModel projectViewModel; + @override + Widget build(BuildContext context) { + projectViewModel = Provider.of(context); + + return Container( + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Texts(filterName), + InkWell( + onTap: () { + Navigator.push( + context, + FadePage( + page: FlowChartPage( + filterName: filterName, + patientLabOrder: patientLabOrder, + patient: patient, + ), + ), + ); + }, + child: Texts( + TranslationBase.of(context).showMoreBtn, + textDecoration: TextDecoration.underline, + color: Colors.blue, + ), + ), + ], + ), + Table( + border: TableBorder.symmetric( + inside: BorderSide( + width: 2.0, color: Colors.grey[300]), + ), + children: fullData(patientLabResultList,context), + ), + ], + ), + ); + } + List fullData(List labResultList,context) { + List tableRow = []; + tableRow.add( + TableRow( + children: [ + Container( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.only( + topLeft: projectViewModel.isArabic + ? Radius.circular(0.0) + : Radius.circular(10.0), + topRight: projectViewModel.isArabic + ? Radius.circular(10.0) + : Radius.circular(0.0), + ), + ), + child: Center( + child: Texts( + TranslationBase.of(context).description, + color: Colors.white, + ), + ), + height: 60, + ), + ), + Container( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + ), + child: Center( + child: Texts(TranslationBase.of(context).value, color: Colors.white), + ), + height: 60), + ), + Container( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.only( + topLeft: projectViewModel.isArabic + ? Radius.circular(10.0) + : Radius.circular(0.0), + topRight: projectViewModel.isArabic + ? Radius.circular(0.0) + : Radius.circular(10.0), + ), + ), + child: Center( + child: Texts(TranslationBase.of(context).range, color: Colors.white), + ), + height: 60), + ), + ], + ), + ); + labResultList.forEach((lab) { + tableRow.add( + TableRow( + children: [ + Container( + child: Container( + padding: EdgeInsets.all(10), + color: Colors.white, + child: Center( + child: Texts( + lab.description, + textAlign: TextAlign.center, + ), + ), + ), + ), + Container( + child: Container( + padding: EdgeInsets.all(10), + color: Colors.white, + child: Center( + child: Texts( + lab.resultValue+" "+lab.uOM, + textAlign: TextAlign.center, + ), + ), + ), + ), + Container( + child: Container( + padding: EdgeInsets.all(10), + color: Colors.white, + child: Center( + child: Texts( + lab.referanceRange, + textAlign: TextAlign.center, + ), + ), + ), + ), + ], + ), + ); + }); + return tableRow; + } + +} + + diff --git a/lib/screens/patients/profile/lab_result/Lab_Result_details_wideget.dart b/lib/screens/patients/profile/lab_result/Lab_Result_details_wideget.dart new file mode 100644 index 00000000..9da22707 --- /dev/null +++ b/lib/screens/patients/profile/lab_result/Lab_Result_details_wideget.dart @@ -0,0 +1,119 @@ +import 'package:doctor_app_flutter/core/model/labs/LabOrderResult.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/util/date-utils.dart'; +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/shared/Text.dart'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:provider/provider.dart'; + +class LabResultDetailsWidget extends StatefulWidget { + final List labResult; + + LabResultDetailsWidget({ + this.labResult, + }); + + @override + _VitalSignDetailsWidgetState createState() => _VitalSignDetailsWidgetState(); +} + +class _VitalSignDetailsWidgetState extends State { + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + return Container( + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10.0), topRight: Radius.circular(10.0)), + border: Border.all(color: Colors.grey, width: 1), + ), + margin: EdgeInsets.all(20), + child: Container( + color: Colors.transparent, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Table( + border: TableBorder.symmetric( + inside: BorderSide(width: 2.0, color: Colors.grey[300]), + ), + children: fullData(projectViewModel), + ), + ], + ), + ), + ); + } + + List fullData(ProjectViewModel projectViewModel) { + List tableRow = []; + tableRow.add(TableRow(children: [ + Container( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.only( + topLeft: projectViewModel.isArabic? Radius.circular(0.0):Radius.circular(10.0), + topRight: projectViewModel.isArabic? Radius.circular(10.0):Radius.circular(0.0), + ), + ), + child: Center( + child: Texts( + TranslationBase.of(context).date, + color: Colors.white, + ), + ), + height: 60, + ), + ), + Container( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.only( + topRight: projectViewModel.isArabic? Radius.circular(0.0):Radius.circular(10.0), + topLeft: projectViewModel.isArabic? Radius.circular(10.0):Radius.circular(0.0), + ), + ), + child: Center( + child: Texts(TranslationBase.of(context).labResult, color: Colors.white), + ), + height: 60), + ) + ])); + widget.labResult.forEach((vital) { + var date = DateUtils.convertStringToDate(vital.verifiedOnDateTime); + tableRow.add(TableRow(children: [ + Container( + child: Container( + padding: EdgeInsets.all(10), + color: Colors.white, + child: Center( + child: Texts( + '${projectViewModel.isArabic? DateUtils.getWeekDayArabic(date.weekday): DateUtils.getWeekDay(date.weekday)} ,${date.day} ${projectViewModel.isArabic? DateUtils.getMonthArabic(date.month) : DateUtils.getMonth(date.month)} ${date.year}', + textAlign: TextAlign.center, + ), + ), + ), + ), + Container( + child: Container( + padding: EdgeInsets.all(10), + color: Colors.white, + child: Center( + child: Texts( + '${vital.resultValue}', + textAlign: TextAlign.center, + ), + ), + ), + ), + ])); + }); + return tableRow; + } +} diff --git a/lib/screens/patients/profile/lab_result/LineChartCurved.dart b/lib/screens/patients/profile/lab_result/LineChartCurved.dart new file mode 100644 index 00000000..f5558a61 --- /dev/null +++ b/lib/screens/patients/profile/lab_result/LineChartCurved.dart @@ -0,0 +1,229 @@ +import 'package:doctor_app_flutter/util/date-utils.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; + +import '../../../../core/model/labs/LabOrderResult.dart'; + +class LineChartCurved extends StatefulWidget { + final String title; + final List labResult; + + LineChartCurved({this.title, this.labResult}); + + @override + State createState() => LineChartCurvedState(); +} + +class LineChartCurvedState extends State { + bool isShowingMainData; + List xAxixs = List(); + int indexes = 0; + + @override + void initState() { + super.initState(); + getXaxix(); + isShowingMainData = true; + } + + getXaxix() { + indexes = widget.labResult.length ~/ 3.5; + for (int index = 0; index < widget.labResult.length; index++) { + int mIndex = indexes * index; + if (mIndex < widget.labResult.length) { + xAxixs.add(mIndex); + } + } + } + + @override + Widget build(BuildContext context) { + return AspectRatio( + aspectRatio: 1.23, + child: Container( + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(18)), + // color: Colors.white, + ), + child: Stack( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const SizedBox( + height: 4, + ), + Text( + widget.title, + style: TextStyle( + color: Colors.black, + fontSize: 32, + fontWeight: FontWeight.bold, + letterSpacing: 2), + textAlign: TextAlign.center, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(right: 16.0, left: 6.0), + child: LineChart( + sampleData1(), + swapAnimationDuration: const Duration(milliseconds: 250), + ), + ), + ), + const SizedBox( + height: 10, + ), + ], + ), + ], + ), + ), + ); + } + + LineChartData sampleData1() { + return LineChartData( + lineTouchData: LineTouchData( + touchTooltipData: LineTouchTooltipData( + tooltipBgColor: Colors.white, + ), + touchCallback: (LineTouchResponse touchResponse) {}, + handleBuiltInTouches: true, + ), + gridData: FlGridData( + show: true, drawVerticalLine: true, drawHorizontalLine: true), + titlesData: FlTitlesData( + bottomTitles: SideTitles( + showTitles: true, + getTextStyles: (value) => const TextStyle( + color: Colors.black, + fontSize: 12, + ), + margin: 22, + rotateAngle:-65, + getTitles: (value) { + print(value); + DateTime date = DateUtils.convertStringToDate(widget.labResult[value.toInt()].verifiedOnDateTime); + if (widget.labResult.length < 8) { + if (widget.labResult.length > value.toInt()) { + return '${date.day}/ ${date.year}'; + } else + return ''; + } else { + if (value.toInt() == 0) + return '${date.day}/ ${date.year}'; + if (value.toInt() == widget.labResult.length - 1) + return '${date.day}/ ${date.year}'; + if (xAxixs.contains(value.toInt())) { + return '${date.day}/ ${date.year}'; + } + } + + + + return ''; + }, + ), + leftTitles: SideTitles( + showTitles: true, + getTextStyles: (value) => const TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + fontSize: 10, + ), + getTitles: (value) { + return '${value.toInt()}'; + }, + margin: 8, + //reservedSize: 30, + ), + ), + borderData: FlBorderData( + show: true, + border: const Border( + bottom: BorderSide( + color: Colors.black, + width: 0.5, + ), + left: BorderSide( + color: Colors.black, + ), + right: BorderSide( + color: Colors.black, + ), + top: BorderSide( + color: Colors.transparent, + ), + ), + ), + minX: 0, + maxX: (widget.labResult.length - 1).toDouble(), + maxY: getMaxY(), + minY: getMinY(), + lineBarsData: getData(), + ); + } + + double getMaxY() { + double max = 0; + widget.labResult.forEach((element) { + try{ + double resultValueDouble = double.parse(element.resultValue); + if (resultValueDouble > max) max = resultValueDouble;} + catch(e){ + print(e); + } + }); + + return max.roundToDouble(); + } + + double getMinY() { + double min = 0; + try{ + min = double.parse(widget.labResult[0].resultValue); + + widget.labResult.forEach((element) { + double resultValueDouble = double.parse(element.resultValue); + if (resultValueDouble < min) min = resultValueDouble; + });}catch(e){ + print(e); + } + int value = min.toInt(); + + return value.toDouble(); + } + + List getData() { + List spots = List(); + for (int index = 0; index < widget.labResult.length; index++) { + try{ + var resultValueDouble = double.parse(widget.labResult[index].resultValue); + spots.add(FlSpot(index.toDouble(), resultValueDouble)); + }catch(e){ + print(e); + spots.add(FlSpot(index.toDouble(), 0.0)); + + } + } + + final LineChartBarData lineChartBarData1 = LineChartBarData( + spots: spots, + isCurved: true, + colors: [Theme.of(context).primaryColor], + barWidth: 5, + isStrokeCapRound: true, + dotData: FlDotData( + show: false, + ), + belowBarData: BarAreaData( + show: false, + ), + ); + + return [ + lineChartBarData1, + ]; + } +} diff --git a/lib/screens/patients/profile/lab_result/lab_result_chart_and_detials.dart b/lib/screens/patients/profile/lab_result/lab_result_chart_and_detials.dart new file mode 100644 index 00000000..6c4ebf36 --- /dev/null +++ b/lib/screens/patients/profile/lab_result/lab_result_chart_and_detials.dart @@ -0,0 +1,41 @@ + +import 'package:doctor_app_flutter/core/model/labs/LabOrderResult.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_expandable_notifier_new.dart'; +import 'package:flutter/material.dart'; + +import 'package:charts_flutter/flutter.dart' as charts; + +import 'Lab_Result_details_wideget.dart'; +import 'LineChartCurved.dart'; + + +class LabResultChartAndDetails extends StatelessWidget { + LabResultChartAndDetails({ + Key key, + @required this.labResult, + @required this.name, + }) : super(key: key); + + final List labResult; + final String name; + + + @override + Widget build(BuildContext context) { + return Column( + children: [ + AppExpandableNotifier( + headerWidget: Padding( + padding: const EdgeInsets.all(8.0), + child: LineChartCurved(title: name,labResult:labResult,), + ), + bodyWidget: LabResultDetailsWidget( + labResult: labResult.reversed.toList(), + ), + isExpand: true, + ), + ], + ); + } + +} diff --git a/lib/screens/patients/profile/lab_result/laboratory_result_page.dart b/lib/screens/patients/profile/lab_result/laboratory_result_page.dart new file mode 100644 index 00000000..398479c4 --- /dev/null +++ b/lib/screens/patients/profile/lab_result/laboratory_result_page.dart @@ -0,0 +1,55 @@ +import 'package:doctor_app_flutter/core/model/labs/patient_lab_orders.dart'; +import 'package:doctor_app_flutter/core/viewModel/labs_view_model.dart'; +import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/loader/gif_loader_dialog_utils.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'laboratory_result_widget.dart'; + +class LaboratoryResultPage extends StatefulWidget { + final PatientLabOrders patientLabOrders; + final PatiantInformtion patient; + + LaboratoryResultPage({Key key, this.patientLabOrders, this.patient}); + + @override + _LaboratoryResultPageState createState() => _LaboratoryResultPageState(); +} + +class _LaboratoryResultPageState extends State { + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) => model.getLaboratoryResult( + invoiceNo: widget.patientLabOrders.invoiceNo, + clinicID: widget.patientLabOrders.clinicID, + projectID: widget.patientLabOrders.projectID, + orderNo: widget.patientLabOrders.orderNo, + patient: widget.patient), + builder: (_, model, w) => AppScaffold( + isShowAppBar: true, + appBarTitle: TranslationBase.of(context).labResults, + baseViewModel: model, + body: Scaffold( + body: ListView.builder( + itemBuilder: (context, index) => LaboratoryResultWidget( + onTap: () async { + + }, + billNo: widget.patientLabOrders.invoiceNo, + details: model.patientLabSpecialResult[index].resultDataHTML, + orderNo: widget.patientLabOrders.orderNo, + patientLabOrder: widget.patientLabOrders, + patient: widget.patient, + ), + itemCount: model.patientLabSpecialResult.length, + ), + ), + ), + ); + } +} diff --git a/lib/screens/patients/profile/lab_result/laboratory_result_widget.dart b/lib/screens/patients/profile/lab_result/laboratory_result_widget.dart new file mode 100644 index 00000000..25663fa6 --- /dev/null +++ b/lib/screens/patients/profile/lab_result/laboratory_result_widget.dart @@ -0,0 +1,235 @@ +import 'package:doctor_app_flutter/core/model/labs/patient_lab_orders.dart'; +import 'package:doctor_app_flutter/core/viewModel/labs_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/lab_result/LabResultWidget.dart'; +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/shared/Text.dart'; +import 'package:doctor_app_flutter/widgets/shared/network_base_view.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_html/flutter_html.dart'; + +import 'package:provider/provider.dart'; + +class LaboratoryResultWidget extends StatefulWidget { + final GestureTapCallback onTap; + final String billNo; + final String details; + final String orderNo; + final PatientLabOrders patientLabOrder; + final PatiantInformtion patient; + const LaboratoryResultWidget( + {Key key, + this.onTap, + this.billNo, + this.details, + this.orderNo, + this.patientLabOrder, this.patient}) + : super(key: key); + + @override + _LaboratoryResultWidgetState createState() => _LaboratoryResultWidgetState(); +} + +class _LaboratoryResultWidgetState extends State { + bool _isShowMore = true; + bool _isShowMoreGeneral = true; + ProjectViewModel projectViewModel; + + @override + Widget build(BuildContext context) { + projectViewModel = Provider.of(context); + return BaseView( + onModelReady: (model) => + model.getPatientLabResult(patientLabOrder: widget.patientLabOrder,patient: widget.patient), + builder: (_, model, w) => NetworkBaseView( + baseViewModel: model, + child: Container( + margin: EdgeInsets.all(15), + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.all(8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(5.0), + )), + padding: EdgeInsets.all(10.0), + margin: EdgeInsets.only(left: 5, right: 5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Texts(TranslationBase.of(context).invoiceNo), + Texts(widget.billNo), + ], + ), + ), + ), + ], + ), + ), + SizedBox( + height: 12, + ), + if (model.labResultLists.isNotEmpty) + Container( + child: Column( + children: [ + InkWell( + onTap: () { + setState( + () { + _isShowMoreGeneral = !_isShowMoreGeneral; + }, + ); + }, + child: Container( + padding: EdgeInsets.all(10.0), + margin: EdgeInsets.only(left: 5, right: 5), + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(5.0), + )), + child: Row( + children: [ + Expanded( + child: Texts(TranslationBase.of(context) + .generalResult)), + Container( + width: 25, + height: 25, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context).primaryColor), + child: Icon( + _isShowMoreGeneral + ? Icons.keyboard_arrow_up + : Icons.keyboard_arrow_down, + color: Colors.white, + size: 22, + ), + ) + ], + ), + ), + ), + if (_isShowMoreGeneral) + AnimatedContainer( + padding: EdgeInsets.all(10.0), + margin: EdgeInsets.only(left: 5, right: 5), + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.white, + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(5.0), + bottomRight: Radius.circular(5.0), + ), + ), + duration: Duration(milliseconds: 7000), + child: Container( + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ...List.generate( + model.labResultLists.length, + (index) => LabResultWidget( + patientLabOrder: widget.patientLabOrder, + filterName: model + .labResultLists[index].filterName, + patientLabResultList: model + .labResultLists[index] + .patientLabResultList, + patient:widget.patient, + ), + ) + ], + ), + ), + ), + ], + ), + ), + SizedBox( + height: 10, + ), + InkWell( + onTap: () { + setState(() { + _isShowMore = !_isShowMore; + }); + }, + child: Container( + padding: EdgeInsets.all(10.0), + margin: EdgeInsets.only(left: 5, right: 5), + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(5.0), + )), + child: Row( + children: [ + Expanded( + child: Texts( + TranslationBase.of(context).specialResult)), + Container( + width: 25, + height: 25, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context).primaryColor), + child: Icon( + _isShowMore + ? Icons.keyboard_arrow_up + : Icons.keyboard_arrow_down, + color: Colors.white, + size: 22, + ), + ) + ], + ), + ), + ), + if (_isShowMore) + AnimatedContainer( + padding: EdgeInsets.all(10.0), + margin: EdgeInsets.only(left: 5, right: 5), + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.white, + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(5.0), + bottomRight: Radius.circular(5.0), + )), + duration: Duration(milliseconds: 7000), + child: Container( + width: double.infinity, + child: Html( + data: widget.details ?? + TranslationBase.of(context).noDataAvailable, + )), + ), + ], + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/patients/profile/lab_result/labs_home_page.dart b/lib/screens/patients/profile/lab_result/labs_home_page.dart new file mode 100644 index 00000000..c0118e5f --- /dev/null +++ b/lib/screens/patients/profile/lab_result/labs_home_page.dart @@ -0,0 +1,117 @@ +import 'package:doctor_app_flutter/core/enum/filter_type.dart'; +import 'package:doctor_app_flutter/core/viewModel/labs_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/lab_result/laboratory_result_page.dart'; +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_expandable_notifier_new.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/doctor_card.dart'; +import 'package:doctor_app_flutter/widgets/transitions/fade_page.dart'; +import 'package:doctor_app_flutter/util/date-utils.dart'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class LabsHomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final routeArgs = ModalRoute.of(context).settings.arguments as Map; + PatiantInformtion patient = routeArgs['patient']; + ProjectViewModel projectViewModel = Provider.of(context); + return BaseView( + onModelReady: (model) => model.getLabs(patient), + builder: (context, LabsViewModel model, widget) => AppScaffold( + baseViewModel: model, + isShowAppBar: true, + appBarTitle: TranslationBase.of(context).labOrders, + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: FractionallySizedBox( + widthFactor: 1.0, + child: Center( + child: Column( + children: [ + Row( + children: [ + Expanded( + flex: 1, + child: InkWell( + onTap: () => model.setFilterType(FilterType.Clinic), + child: ListTile( + title: Text(TranslationBase.of(context).clinic), + leading: Radio( + value: FilterType.Clinic, + groupValue: model.filterType, + onChanged: (FilterType value) { + model.setFilterType(value); + }, + ), + ), + ), + ), + Expanded( + flex: 1, + child: InkWell( + onTap: () => model.setFilterType(FilterType.Hospital), + child: ListTile( + title: Text(TranslationBase.of(context).hospital), + leading: Radio( + value: FilterType.Hospital, + groupValue: model.filterType, + onChanged: (FilterType value) => + model.setFilterType(value), + ), + ), + ), + ) + ], + ), + ...List.generate( + model.patientLabOrdersList.length, + (index) => AppExpandableNotifier( + title: model.patientLabOrdersList[index].filterName, + bodyWidget: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: model + .patientLabOrdersList[index].patientLabOrdersList + .map((labOrder) { + return DoctorCard( + onTap: () => Navigator.push( + context, + FadePage( + page: LaboratoryResultPage( + patientLabOrders: labOrder, + patient: patient, + ), + ), + ), + isInOutPatient: labOrder.isInOutPatient, + name: labOrder.doctorName, + billNo: ' ${labOrder.invoiceNo}', + profileUrl: labOrder.doctorImageURL, + subName: labOrder.projectName, + isLiveCareAppointment: + labOrder.isLiveCareAppointment, + date: projectViewModel.isArabic + ? DateUtils.getMonthDayYearDateFormattedAr( + labOrder.orderDate) + : DateUtils.getMonthDayYearDateFormatted( + labOrder.orderDate), + ); + }).toList(), + ), + ), + ) + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/util/date-utils.dart b/lib/util/date-utils.dart index af90acf6..8e6cd17c 100644 --- a/lib/util/date-utils.dart +++ b/lib/util/date-utils.dart @@ -217,6 +217,47 @@ class DateUtils { } } + static DateTime convertStringToDate(String date) { // /Date(1585774800000+0300)/ + if (date != null) { + const start = "/Date("; + const end = "+0300)"; + final startIndex = date.indexOf(start); + final endIndex = date.indexOf(end, startIndex + start.length); + return DateTime.fromMillisecondsSinceEpoch( + int.parse( + date.substring(startIndex + start.length, endIndex), + ), + ); + } else + return DateTime.now(); + } + + /// get data formatted like Apr 26,2020 + /// [dateTime] convert DateTime to data formatted Arabic + static String getMonthDayYearDateFormattedAr(DateTime dateTime) { + if (dateTime != null) + return getMonthArabic(dateTime.month) + + " " + + dateTime.day.toString() + + ", " + + dateTime.year.toString(); + else + return ""; + } + + /// get data formatted like Apr 26,2020 + /// [dateTime] convert DateTime to data formatted + static String getMonthDayYearDateFormatted(DateTime dateTime) { + if (dateTime != null) + return getMonth(dateTime.month) + + " " + + dateTime.day.toString() + + ", " + + dateTime.year.toString(); + else + return ""; + } + static String getAgeByBirthday(dynamic birthday, BuildContext context){ // https://leechy.dev/calculate-dates-diff-in-dart DateTime birthDate = DateUtils.getDateTimeFromServerFormat(birthday); diff --git a/lib/util/dr_app_shared_pref.dart b/lib/util/dr_app_shared_pref.dart index 54c8cc45..2f6f3232 100644 --- a/lib/util/dr_app_shared_pref.dart +++ b/lib/util/dr_app_shared_pref.dart @@ -37,6 +37,13 @@ class DrAppSharedPreferances { return prefs.getString(key); } + /// Get String [key] the key was saved + getStringWithDefaultValue(String key, String defaultVal) async { + final SharedPreferences prefs = await _prefs; + String value = prefs.getString(key); + return value == null ? defaultVal : value; + } + setObj(String key, value) async { final SharedPreferences prefs = await _prefs; diff --git a/lib/util/translations_delegate_base.dart b/lib/util/translations_delegate_base.dart index 8c8afde2..dcba4c84 100644 --- a/lib/util/translations_delegate_base.dart +++ b/lib/util/translations_delegate_base.dart @@ -1136,6 +1136,17 @@ class TranslationBase { String get appointmentDate => localizedValues['appointmentDate'][locale.languageCode]; String get arrivedP => localizedValues['arrived_p'][locale.languageCode]; + + String get details => localizedValues['details'][locale.languageCode]; + String get liveCare => localizedValues['liveCare'][locale.languageCode]; + String get outpatient => localizedValues['out-patient'][locale.languageCode]; + String get billNo => localizedValues['BillNo'][locale.languageCode]; + String get labResults => localizedValues['labResults'][locale.languageCode]; + String get sendSuc => localizedValues['sendSuc'][locale.languageCode]; + String get specialResult => localizedValues['SpecialResult'][locale.languageCode]; + String get noDataAvailable => localizedValues['noDataAvailable'][locale.languageCode]; + String get showMoreBtn => localizedValues['show-more-btn'][locale.languageCode]; + } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/shared/StarRating.dart b/lib/widgets/shared/StarRating.dart new file mode 100644 index 00000000..10c12fa5 --- /dev/null +++ b/lib/widgets/shared/StarRating.dart @@ -0,0 +1,48 @@ +import 'package:eva_icons_flutter/eva_icons_flutter.dart'; +import 'package:flutter/material.dart'; + +import 'Text.dart'; + +class StarRating extends StatelessWidget { + final double totalAverage; + final double size; + final int totalCount; + final bool forceStars; + + StarRating( + {Key key, + this.totalAverage: 0.0, + this.size: 16.0, + this.totalCount = 5, + this.forceStars = false}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Row(mainAxisAlignment: MainAxisAlignment.start, children: [ + if (!forceStars && (totalAverage == null || totalAverage == 0)) + Texts("New", style: "caption"), + if (forceStars || (totalAverage != null && totalAverage > 0)) + ...List.generate( + 5, + (index) => Padding( + padding: EdgeInsets.only(right: 1.0), + child: Icon( + (index + 1) <= (totalAverage ?? 0) + ? EvaIcons.star + : EvaIcons.starOutline, + size: size, + color: (index + 1) <= (totalAverage ?? 0) + ? Color.fromRGBO(255, 186, 0, 1.0) + : Theme.of(context).hintColor), + )), + if (totalCount != null) SizedBox(width: 9.0), + if (totalCount != null) + Texts( + "(" + totalCount.toString() + ")", + style: "overline", + color: Colors.grey[400], + ) + ]); + } +} diff --git a/lib/widgets/shared/app_expandable_notifier_new.dart b/lib/widgets/shared/app_expandable_notifier_new.dart new file mode 100644 index 00000000..ea5777a5 --- /dev/null +++ b/lib/widgets/shared/app_expandable_notifier_new.dart @@ -0,0 +1,126 @@ +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:expandable/expandable.dart'; +import 'package:flutter/material.dart'; + + +/// App Expandable Notifier with animation +/// [headerWidget] widget want to show in the header +/// [bodyWidget] widget want to show in the body +/// [title] the widget title +/// [collapsed] The widget shown in the collapsed state +class AppExpandableNotifier extends StatefulWidget { + final Widget headerWidget; + final Widget bodyWidget; + final String title; + final Widget collapsed; + final bool isExpand; + bool expandFlag = false; + var controller = new ExpandableController(); + AppExpandableNotifier( + {this.headerWidget, + this.bodyWidget, + this.title, + this.collapsed, + this.isExpand = false}); + + _AppExpandableNotifier createState() => _AppExpandableNotifier(); +} + +class _AppExpandableNotifier extends State { + + @override + void initState() { + setState(() { + if (widget.isExpand) { + widget.expandFlag = widget.isExpand; + widget.controller.expanded = true; + } + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + + return ExpandableNotifier( + child: Padding( + padding: const EdgeInsets.only(left: 10, right: 10, top: 4), + child: Card( + clipBehavior: Clip.antiAlias, + child: Column( + children: [ + SizedBox( + child: widget.headerWidget, + ), + ScrollOnExpand( + scrollOnExpand: true, + scrollOnCollapse: false, + child: ExpandablePanel( + hasIcon: false, + theme: const ExpandableThemeData( + headerAlignment: ExpandablePanelHeaderAlignment.center, + tapBodyToCollapse: true, + ), + header: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.all(10), + child: Text( + widget.title ?? TranslationBase.of(context).details, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: SizeConfig.textMultiplier * 2, + ), + ), + ), + ), + IconButton( + icon: new Container( + height: 28.0, + width: 30.0, + decoration: new BoxDecoration( + color: Theme.of(context).primaryColor, + shape: BoxShape.circle, + ), + child: new Center( + child: new Icon( + widget.expandFlag + ? Icons.keyboard_arrow_up + : Icons.keyboard_arrow_down, + color: Colors.white, + size: 30.0, + ), + ), + ), + onPressed: () { + setState(() { + widget.expandFlag = !widget.expandFlag; + widget.controller.expanded = widget.expandFlag; + }); + }), + ]), + collapsed: widget.collapsed ?? Container(), + expanded: widget.bodyWidget, + builder: (_, collapsed, expanded) { + return Padding( + padding: EdgeInsets.only(left: 5, right: 5, bottom: 5), + child: Expandable( + controller: widget.controller, + collapsed: collapsed, + expanded: expanded, + theme: const ExpandableThemeData(crossFadePoint: 0), + ), + ); + }, + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/widgets/shared/doctor_card.dart b/lib/widgets/shared/doctor_card.dart new file mode 100644 index 00000000..080a4fab --- /dev/null +++ b/lib/widgets/shared/doctor_card.dart @@ -0,0 +1,198 @@ + +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/patients/profile/large_avatar.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:provider/provider.dart'; + +import 'StarRating.dart'; +import 'Text.dart'; + +class DoctorCard extends StatelessWidget { + final String name; + final String subName; + final double rat; + final String date; + final String profileUrl; + final String billNo; + final Function onTap; + final Function onEmailTap; + final bool isInOutPatient; + final bool isLiveCareAppointment; + + DoctorCard( + {this.name, + this.subName, + this.rat, + this.date, + this.profileUrl, + this.billNo, + this.onTap, + this.onEmailTap, + this.isInOutPatient, + this.isLiveCareAppointment = false}); + + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + return Container( + margin: EdgeInsets.all(10), + decoration: BoxDecoration( + border: Border.all( + width: 0.5, + color: Theme.of(context).primaryColor, + ), + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + color: Colors.white), + child: InkWell( + onTap: onTap, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + width: projectViewModel.isArabic ? 27 : 20, + height: date == null + ? projectViewModel.isArabic + ? 185 + : 100 + : 180, + decoration: BoxDecoration( + //Colors.red[900] Color(0xff404545) + color: isLiveCareAppointment + ? Color(0xff404545) + : !isInOutPatient + ? Colors.red[900] + : Theme.of(context).primaryColor, + borderRadius: BorderRadius.only( + topLeft: projectViewModel.isArabic + ? Radius.circular(0) + : Radius.circular(8), + bottomLeft: projectViewModel.isArabic + ? Radius.circular(0) + : Radius.circular(8), + topRight: projectViewModel.isArabic + ? Radius.circular(8) + : Radius.circular(0), + bottomRight: projectViewModel.isArabic + ? Radius.circular(8) + : Radius.circular(0), + ), + ), + child: RotatedBox( + quarterTurns: 3, + child: Center( + child: Text( + isLiveCareAppointment + ? TranslationBase.of(context) + .liveCare + .toUpperCase() + : !isInOutPatient + ? TranslationBase.of(context) + .inPatient + .toUpperCase() + : TranslationBase.of(context) + .outpatient + .toUpperCase(), + style: TextStyle(color: Colors.white), + ), + )), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Row( + children: [ + Expanded( + flex: 1, + child: LargeAvatar( + name: name, + url: profileUrl, + ), + ), + Expanded( + flex: 4, + child: Container( + margin: EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Texts( + TranslationBase.of(context).dr + + " " + + name, + bold: true, + ), + Texts( + subName, + ), + if (billNo != null) + Row( + children: [ + Texts( + '${TranslationBase.of(context).billNo}: ', + ), + Texts( + billNo, + ) + ], + ), + if (rat != null) + StarRating( + totalAverage: rat, forceStars: true), + ], + ), + ), + ), + if (onEmailTap != null) + InkWell( + onTap: onEmailTap, + child: Icon( + Icons.email, + color: Theme.of(context).primaryColor, + ), + ), + ], + ), + ), + if (date != null) + Divider( + height: 8, + color: Colors.grey[400], + ), + if (date != null) + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/Icon-awesome-calendar.png', + width: 30, + height: 30, + ), + Expanded( + child: Texts( + date, + variant: 'bodyText', + ), + ) + ], + ) + ], + ), + ) + ], + ), + ], + ), + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index d044f1fb..4a3f9c9e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -169,6 +169,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.4" + chewie: + dependency: transitive + description: + name: chewie + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.10" + chewie_audio: + dependency: transitive + description: + name: chewie_audio + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0+1" cli_util: dependency: transitive description: @@ -239,6 +253,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.5" + css_colors: + dependency: transitive + description: + name: css_colors + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" csslib: dependency: transitive description: @@ -398,6 +419,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + flutter_html: + dependency: "direct main" + description: + name: flutter_html + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" flutter_localizations: dependency: "direct main" description: flutter @@ -417,6 +445,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.11" + flutter_svg: + dependency: transitive + description: + name: flutter_svg + url: "https://pub.dartlang.org" + source: hosted + version: "0.18.1" flutter_swiper: dependency: "direct main" description: @@ -602,6 +637,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + open_iconic_flutter: + dependency: transitive + description: + name: open_iconic_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" package_config: dependency: transitive description: @@ -679,6 +721,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" platform: dependency: transitive description: @@ -756,6 +805,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.0.4+3" + screen: + dependency: transitive + description: + name: screen + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.5" shared_preferences: dependency: "direct main" description: @@ -950,6 +1006,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0-nullsafety.3" + video_player: + dependency: transitive + description: + name: video_player + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.12+5" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + video_player_web: + dependency: transitive + description: + name: video_player_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4+1" + wakelock: + dependency: transitive + description: + name: wakelock + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4+2" watcher: dependency: transitive description: @@ -964,6 +1048,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + webview_flutter: + dependency: transitive + description: + name: webview_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.24" win32: dependency: transitive description: @@ -978,6 +1069,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.2" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "4.5.1" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6dd072f5..8c3825e1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -76,6 +76,9 @@ dependencies: # Html html: ^0.14.0+4 + # Flutter Html View + flutter_html: 1.0.2 + #speech to text