From fd2a86dca403ef62f7432da3104027f44ef825bf Mon Sep 17 00:00:00 2001 From: mosazaid Date: Thu, 7 Jan 2021 11:21:43 +0200 Subject: [PATCH 01/12] some changes in patientArrivalList And make action when click on vitalSign widget inside pendingReferral --- lib/config/localized_values.dart | 4 ++++ lib/core/service/base/base_service.dart | 5 +++-- lib/core/viewModel/patient-referral-viewmodel.dart | 2 +- .../viewModel/patient-vital-sign-viewmodel.dart | 3 --- .../referral/my-referral-detail-screen.dart | 14 ++++++++++++-- lib/util/translations_delegate_base.dart | 1 + 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 3048a39d..672796a6 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -536,4 +536,8 @@ const Map> localizedValues = { 'en': "There is no Chief Complaint", 'ar': "ليس هناك شكوى رئيس" }, + 'patientNoDetailErrMsg': { + 'en': "There is no detail for this patient", + 'ar': "لا توجد تفاصيل لهذا المريض" + }, }; diff --git a/lib/core/service/base/base_service.dart b/lib/core/service/base/base_service.dart index 32edf34f..6f4c5d1e 100644 --- a/lib/core/service/base/base_service.dart +++ b/lib/core/service/base/base_service.dart @@ -1,4 +1,5 @@ import 'package:doctor_app_flutter/client/base_app_client.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/config/config.dart'; import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; @@ -12,7 +13,7 @@ class BaseService { DrAppSharedPreferances sharedPref = new DrAppSharedPreferances(); DoctorProfileModel doctorProfile; - List patientArrivalList = []; + List patientArrivalList = []; //TODO add the user login model when we need it Future getDoctorProfile() async { @@ -50,7 +51,7 @@ class BaseService { patientArrivalList.clear(); response['patientArrivalList']['entityList'].forEach((v) { - PatientArrivalEntity item = PatientArrivalEntity.fromJson(v); + PatiantInformtion item = PatiantInformtion.fromJson(v); patientArrivalList.add(item); }); }, diff --git a/lib/core/viewModel/patient-referral-viewmodel.dart b/lib/core/viewModel/patient-referral-viewmodel.dart index 35747c37..028eac0d 100644 --- a/lib/core/viewModel/patient-referral-viewmodel.dart +++ b/lib/core/viewModel/patient-referral-viewmodel.dart @@ -27,7 +27,7 @@ class PatientReferralViewModel extends BaseViewModel { List get pendingReferral => _referralPatientService.pendingReferralList; - List get patientArrivalList => + List get patientArrivalList => _referralPatientService.patientArrivalList; Future getMasterLookup(MasterKeysService masterKeys) async { diff --git a/lib/core/viewModel/patient-vital-sign-viewmodel.dart b/lib/core/viewModel/patient-vital-sign-viewmodel.dart index 4f2e7e28..5674030c 100644 --- a/lib/core/viewModel/patient-vital-sign-viewmodel.dart +++ b/lib/core/viewModel/patient-vital-sign-viewmodel.dart @@ -11,9 +11,6 @@ import '../../locator.dart'; class VitalSignsViewModel extends BaseViewModel { VitalSignsService _vitalSignService = locator(); - List get patientArrivalList => - _vitalSignService.patientArrivalList; - VitalSignData get patientVitalSigns => _vitalSignService.patientVitalSigns; Future getPatientVitalSign(PatiantInformtion patient) async { diff --git a/lib/screens/patients/profile/referral/my-referral-detail-screen.dart b/lib/screens/patients/profile/referral/my-referral-detail-screen.dart index 1019ede4..77b17e3d 100644 --- a/lib/screens/patients/profile/referral/my-referral-detail-screen.dart +++ b/lib/screens/patients/profile/referral/my-referral-detail-screen.dart @@ -12,6 +12,7 @@ import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; import 'package:doctor_app_flutter/widgets/shared/borderedButton.dart'; import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; import 'package:provider/provider.dart'; import '../../../../routes.dart'; @@ -39,7 +40,7 @@ class MyReferralDetailScreen extends StatelessWidget { builder: (_, model, w) => AppScaffold( baseViewModel: model, appBarTitle: TranslationBase.of(context).referPatient, - body: Column( + body: model.patientArrivalList != null ? Column( children: [ Expanded( child: SingleChildScrollView( @@ -110,7 +111,7 @@ class MyReferralDetailScreen extends StatelessWidget { icon: 'lab.png'), PatientProfileButton( key: key, - // patient: patient, + patient: model.patientArrivalList[0], route: PATIENT_VITAL_SIGN, nameLine1: TranslationBase.of(context).vital, nameLine2: TranslationBase.of(context).signs, @@ -160,6 +161,15 @@ class MyReferralDetailScreen extends StatelessWidget { ), ), ], + ) : Container( + child: Center( + child: AppText( + TranslationBase.of(context).patientNoDetailErrMsg, + color: HexColor("#B8382B"), + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), ), ), ); diff --git a/lib/util/translations_delegate_base.dart b/lib/util/translations_delegate_base.dart index b167b48e..8ee0dc7d 100644 --- a/lib/util/translations_delegate_base.dart +++ b/lib/util/translations_delegate_base.dart @@ -553,6 +553,7 @@ class TranslationBase { String get approvalRequired => localizedValues['approvalRequired'][locale.languageCode]; String get uncoveredByDoctor => localizedValues['uncoveredByDoctor'][locale.languageCode]; String get chiefComplaintEmptyMsg => localizedValues['chiefComplaintEmptyMsg'][locale.languageCode]; + String get patientNoDetailErrMsg => localizedValues['patientNoDetailErrMsg'][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { From 4f1a892be4cfb7c6918481bea998ffc3df0bb143 Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Thu, 7 Jan 2021 14:37:26 +0200 Subject: [PATCH 02/12] first step form create episode --- lib/config/config.dart | 3 + lib/config/localized_values.dart | 2 +- lib/core/service/SOAP_service.dart | 13 ++ lib/core/viewModel/SOAP_view_model.dart | 13 ++ lib/models/SOAP/PostEpisodeReqModel.dart | 28 +++ lib/screens/dashboard_screen.dart | 47 +++++ lib/screens/patients/patients_screen.dart | 9 +- .../profile/patient-page-header-widget.dart | 166 ++++++++++-------- .../profile/profile_medical_info_widget.dart | 71 +++++--- 9 files changed, 254 insertions(+), 98 deletions(-) create mode 100644 lib/models/SOAP/PostEpisodeReqModel.dart diff --git a/lib/config/config.dart b/lib/config/config.dart index e3163bb2..e8e0f6ce 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -132,6 +132,9 @@ const GET_PATIENT_ARRIVAL_LIST = const GET_ALLERGIES = 'Services/DoctorApplication.svc/REST/GetAllergies'; const GET_MASTER_LOOKUP_LIST = 'Services/DoctorApplication.svc/REST/GetMasterLookUpList'; + +const POST_EPISODE = 'Services/DoctorApplication.svc/REST/PostEpisode'; + const POST_ALLERGY = 'Services/DoctorApplication.svc/REST/PostAllergies'; const POST_HISTORY = 'Services/DoctorApplication.svc/REST/PostHistory'; const POST_CHIEF_COMPLAINT = diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 4ad53ebe..e96daef0 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -295,7 +295,7 @@ const Map> localizedValues = { }, 'clinicSelect': {'en': "Select Clinic", 'ar': 'اختار عيادة'}, 'doctorSelect': {'en': "Select Doctor", 'ar': 'اختار طبيب'}, - "empty-message": {"en": "Please enter message", "ar": "يرجى ادخال الموضوع"}, + "empty-message": {"en": "Please enter this field", "ar": "يرجى ادخال هذا الحقل"}, 'no-sickleve-applied': { 'en': "No sick leave applied", 'ar': 'لم تطبق إجازة مرضية' diff --git a/lib/core/service/SOAP_service.dart b/lib/core/service/SOAP_service.dart index d1fff03b..9707dc53 100644 --- a/lib/core/service/SOAP_service.dart +++ b/lib/core/service/SOAP_service.dart @@ -11,6 +11,7 @@ import 'package:doctor_app_flutter/models/SOAP/GetHistoryReqModel.dart'; import 'package:doctor_app_flutter/models/SOAP/GetHistoryResModel.dart'; import 'package:doctor_app_flutter/models/SOAP/GetPhysicalExamListResModel.dart'; import 'package:doctor_app_flutter/models/SOAP/GetPhysicalExamReqModel.dart'; +import 'package:doctor_app_flutter/models/SOAP/PostEpisodeReqModel.dart'; import 'package:doctor_app_flutter/models/SOAP/get_Allergies_request_model.dart'; import 'package:doctor_app_flutter/models/SOAP/master_key_model.dart'; import 'package:doctor_app_flutter/models/SOAP/post_allergy_request_model.dart'; @@ -48,6 +49,18 @@ class SOAPService extends LookupService { ); } + Future postEpisode(PostEpisodeReqModel postEpisodeReqModel) async { + hasError = false; + + await baseAppClient.post(POST_EPISODE, + onSuccess: (dynamic response, int statusCode) { + print("Success"); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: postEpisodeReqModel.toJson()); + } + Future postAllergy(PostAllergyRequestModel postAllergyRequestModel) async { hasError = false; diff --git a/lib/core/viewModel/SOAP_view_model.dart b/lib/core/viewModel/SOAP_view_model.dart index fff7a239..31764c45 100644 --- a/lib/core/viewModel/SOAP_view_model.dart +++ b/lib/core/viewModel/SOAP_view_model.dart @@ -13,6 +13,7 @@ import 'package:doctor_app_flutter/models/SOAP/GetHistoryReqModel.dart'; import 'package:doctor_app_flutter/models/SOAP/GetHistoryResModel.dart'; import 'package:doctor_app_flutter/models/SOAP/GetPhysicalExamListResModel.dart'; import 'package:doctor_app_flutter/models/SOAP/GetPhysicalExamReqModel.dart'; +import 'package:doctor_app_flutter/models/SOAP/PostEpisodeReqModel.dart'; import 'package:doctor_app_flutter/models/SOAP/get_Allergies_request_model.dart'; import 'package:doctor_app_flutter/models/SOAP/master_key_model.dart'; import 'package:doctor_app_flutter/models/SOAP/post_allergy_request_model.dart'; @@ -99,6 +100,17 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } + + Future postEpisode(PostEpisodeReqModel postEpisodeReqModel) async { + setState(ViewState.BusyLocal); + await _SOAPService.postEpisode(postEpisodeReqModel); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + Future postAllergy(PostAllergyRequestModel postAllergyRequestModel) async { setState(ViewState.BusyLocal); await _SOAPService.postAllergy(postAllergyRequestModel); @@ -222,6 +234,7 @@ class SOAPViewModel extends BaseViewModel { Future getPatientAllergy(GeneralGetReqForSOAP generalGetReqForSOAP) async { + setState(ViewState.Busy); await _SOAPService.getPatientAllergy(generalGetReqForSOAP); if (_SOAPService.hasError) { diff --git a/lib/models/SOAP/PostEpisodeReqModel.dart b/lib/models/SOAP/PostEpisodeReqModel.dart new file mode 100644 index 00000000..6d3ee45a --- /dev/null +++ b/lib/models/SOAP/PostEpisodeReqModel.dart @@ -0,0 +1,28 @@ +class PostEpisodeReqModel { + int appointmentNo; + int patientMRN; + int doctorID; + String vidaAuthTokenID; + + PostEpisodeReqModel( + {this.appointmentNo, + this.patientMRN, + this.doctorID, + this.vidaAuthTokenID}); + + PostEpisodeReqModel.fromJson(Map json) { + appointmentNo = json['AppointmentNo']; + patientMRN = json['PatientMRN']; + doctorID = json['DoctorID']; + vidaAuthTokenID = json['VidaAuthTokenID']; + } + + Map toJson() { + final Map data = new Map(); + data['AppointmentNo'] = this.appointmentNo; + data['PatientMRN'] = this.patientMRN; + data['DoctorID'] = this.doctorID; + data['VidaAuthTokenID'] = this.vidaAuthTokenID; + return data; + } +} diff --git a/lib/screens/dashboard_screen.dart b/lib/screens/dashboard_screen.dart index 20f22382..dd07f6d7 100644 --- a/lib/screens/dashboard_screen.dart +++ b/lib/screens/dashboard_screen.dart @@ -9,9 +9,11 @@ import 'package:doctor_app_flutter/models/doctor/profile_req_Model.dart'; import 'package:doctor_app_flutter/core/viewModel/auth_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/hospital_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/models/patient/patient_model.dart'; import 'package:doctor_app_flutter/screens/base/base_view.dart'; import 'package:doctor_app_flutter/screens/patients/profile/referral/my-referral-patient-screen.dart'; import 'package:doctor_app_flutter/screens/reschedule-leaves/add-rescheduleleave.dart'; +import 'package:doctor_app_flutter/util/date-utils.dart'; import 'package:doctor_app_flutter/util/dr_app_shared_pref.dart'; import 'package:doctor_app_flutter/util/helpers.dart'; import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; @@ -77,6 +79,25 @@ class _DashboardScreenState extends State { if (!currentFocus.hasPrimaryFocus) { currentFocus.unfocus(); } + + var _patientSearchFormValues = PatientModel( + FirstName: "0", + MiddleName: "0", + LastName: "0", + PatientMobileNumber: "0", + PatientIdentificationID: "0", + PatientID: 0, + From: DateUtils.convertDateToFormat(DateTime. now(), 'yyyy-MM-dd').toString(), + To: DateUtils.convertDateToFormat(DateTime. now(), 'yyyy-MM-dd').toString(), + LanguageID: 2, + stamp: "2020-03-02T13:56:39.170Z", + IPAdress: "11.11.11.11", + VersionID: 1.2, + Channel: 9, + TokenID: "2Fi7HoIHB0eDyekVa6tCJg==", + SessionID: "5G0yXn0Jnq", + IsLoginForDoctorApp: true, + PatientOutSA: false); return BaseView( onModelReady: (model) => model.getDashboard(), builder: (_, model, w) => AppScaffold( @@ -957,6 +978,8 @@ class _DashboardScreenState extends State { height: 20, ), Row( + // mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.start, children: [ DashboardItem( child: Column( @@ -984,6 +1007,30 @@ class _DashboardScreenState extends State { ), ); }, + ), + SizedBox(width: 8,), + DashboardItem( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Icon( + DoctorApp.patient, + size: 50, + ), + AppText( + TranslationBase.of(context).arrived, + color: Colors.black, + textAlign: TextAlign.center, + ) + ], + ), + hasBorder: true, + onTap: () { + Navigator.of(context).pushNamed(PATIENTS, arguments: { + "patientSearchForm": _patientSearchFormValues, + "selectedType": "7" + }); + }, ) ], ), diff --git a/lib/screens/patients/patients_screen.dart b/lib/screens/patients/patients_screen.dart index 602bd180..0c2a53d4 100644 --- a/lib/screens/patients/patients_screen.dart +++ b/lib/screens/patients/patients_screen.dart @@ -274,7 +274,8 @@ class _PatientsScreenState extends State { .then((res) { setState(() { _isLoading = false; - if (res['MessageStatus'] == 1) { + + if (res != null && res['MessageStatus'] == 1) { if (val2 == 7) { if (res[SERVICES_PATIANT2[val2]] == null) { _isError = true; @@ -282,6 +283,9 @@ class _PatientsScreenState extends State { this.error = error.toString(); } else { var localList = []; + if(res["patientArrivalList"]["entityList"] == null){ + res["patientArrivalList"]["entityList"] = []; + } res["patientArrivalList"]["entityList"].forEach((v) { Map mergedPatient = { ...v, @@ -289,7 +293,6 @@ class _PatientsScreenState extends State { }; localList.add(mergedPatient); }); - print(localList.toString()); lItems = localList; } } else { @@ -301,7 +304,7 @@ class _PatientsScreenState extends State { _isError = false; } else { _isError = true; - error = res['ErrorEndUserMessage'] ?? res['ErrorMessage']; + error = model.error; //res['ErrorEndUserMessage'] ?? res['ErrorMessage']; } }); }).catchError((error) { diff --git a/lib/widgets/patients/profile/patient-page-header-widget.dart b/lib/widgets/patients/profile/patient-page-header-widget.dart index 3e870be5..f4de0615 100644 --- a/lib/widgets/patients/profile/patient-page-header-widget.dart +++ b/lib/widgets/patients/profile/patient-page-header-widget.dart @@ -1,92 +1,112 @@ +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; import 'package:doctor_app_flutter/icons_app/doctor_app_icons.dart'; +import 'package:doctor_app_flutter/models/SOAP/GeneralGetReqForSOAP.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/patients/profile/patient_profile_widget.dart'; import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/network_base_view.dart'; import 'package:flutter/material.dart'; class PatientPageHeaderWidget extends StatelessWidget { final PatiantInformtion patient; - + String allergiesString=''; PatientPageHeaderWidget(this.patient); @override Widget build(BuildContext context) { - return Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - AvatarWidget( - Icon( - patient.genderDescription == "Male" - ? DoctorApp.male - : DoctorApp.female_icon, - size: 70, - color: Colors.white, - ), - ), - SizedBox( - width: 20, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - SizedBox( - height: 5, - ), - AppText( - patient.firstName + ' ' + patient.lastName, - color: Colors.black, - fontWeight: FontWeight.bold, - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AppText( - TranslationBase.of(context).age, - color: Colors.black, - fontWeight: FontWeight.bold, - ), - SizedBox( - width: 20, + return BaseView( + onModelReady: (model) async { + GeneralGetReqForSOAP generalGetReqForSOAP = GeneralGetReqForSOAP( + patientMRN: patient.patientMRN, + episodeId: patient.episodeNo, + appointmentNo: patient.appointmentNo, + doctorID: '', + editedBy: ''); + await model.getPatientAllergy(generalGetReqForSOAP); + model.patientAllergiesList.forEach((element) { + allergiesString += element.allergyDiseaseName+' , '; + }); + }, + builder: (_, model, w) => Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + AvatarWidget( + Icon( + patient.genderDescription == "Male" + ? DoctorApp.male + : DoctorApp.female_icon, + size: 70, + color: Colors.white, ), - AppText( - patient.age.toString(), - color: Colors.black, - fontWeight: FontWeight.normal, + ), + SizedBox( + width: 20, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + height: 5, + ), + AppText( + patient.firstName + ' ' + patient.lastName, + color: Colors.black, + fontWeight: FontWeight.bold, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).age, + color: Colors.black, + fontWeight: FontWeight.bold, + ), + SizedBox( + width: 20, + ), + AppText( + patient.age.toString(), + color: Colors.black, + fontWeight: FontWeight.normal, + ), + ], + ), + NetworkBaseView( + baseViewModel: model, + child: AppText( + "ALLERGIC TO: $allergiesString", + color: Color(0xFFB9382C), + fontWeight: FontWeight.bold, + ), + ), + ], ), - ], - ), - AppText( - "ALLERGIC TO: FOOD, ASPIRIN, EGG WHITE", - color: Color(0xFFB9382C), - fontWeight: FontWeight.bold, - ), - ], + ) + ], + ), + ), + Container( + width: double.infinity, + height: 1, + color: Color(0xffCCCCCC), + ), + SizedBox( + width: 20, ), - ) - ], - ), - ), - Container( - width: double.infinity, - height: 1, - color: Color(0xffCCCCCC), - ), - SizedBox( - width: 20, - ), - ], - ), - ); + ], + ), + )); } } diff --git a/lib/widgets/patients/profile/profile_medical_info_widget.dart b/lib/widgets/patients/profile/profile_medical_info_widget.dart index 8860a7dc..34433fa7 100644 --- a/lib/widgets/patients/profile/profile_medical_info_widget.dart +++ b/lib/widgets/patients/profile/profile_medical_info_widget.dart @@ -1,7 +1,13 @@ import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/core/enum/viewstate.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/models/SOAP/PostEpisodeReqModel.dart'; import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart'; import 'package:doctor_app_flutter/routes.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/dr_app_circular_progress_Indeicator.dart'; +import 'package:doctor_app_flutter/widgets/shared/network_base_view.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:hexcolor/hexcolor.dart'; @@ -22,26 +28,42 @@ class ProfileMedicalInfoWidget extends StatelessWidget { String patientType; @override Widget build(BuildContext context) { - return SliverGrid.count( + return BaseView( + onModelReady: (model) async {}, + builder: (_, model, w) => SliverGrid.count( crossAxisSpacing: 10, mainAxisSpacing: 20, crossAxisCount: 2, childAspectRatio: 1.5, children: [ + if (int.parse(patientType) == 7) + PatientProfileButton( + key: key, + patient: patient, + isDisable: patient.episodeNo != 0 ? true : false, + nameLine1: TranslationBase.of(context).createNew, + nameLine2: TranslationBase.of(context).episode, + route: CREATE_EPISODE, + onTap: () async { + PostEpisodeReqModel postEpisodeReqModel = PostEpisodeReqModel( + appointmentNo: patient.appointmentNo, + patientMRN: patient.patientMRN); + await model.postEpisode(postEpisodeReqModel); + }, + isLoading: model.state == ViewState.BusyLocal, + icon: 'create-episod.png' + ), if(int.parse(patientType) ==7) PatientProfileButton( key: key, patient: patient, - nameLine1: TranslationBase.of(context).createNew, - nameLine2: TranslationBase.of(context).episode, - route: CREATE_EPISODE, - icon: 'create-episod.png'), - if(int.parse(patientType) ==7) - PatientProfileButton( - key: key, - patient: patient, - nameLine1: TranslationBase.of(context).update, - nameLine2: TranslationBase.of(context).episode, + isDisable: patient.episodeNo == 0 ? true : false, + nameLine1: TranslationBase + .of(context) + .update, + nameLine2: TranslationBase + .of(context) + .episode, route: UPDATE_EPISODE, icon: 'modilfy-episode.png'), if(selectedPatientType == 6 || selectedPatientType == 7) @@ -146,7 +168,7 @@ class ProfileMedicalInfoWidget extends StatelessWidget { .of(context) .ucaf, icon: 'lab.png'), - ]); + ],),); } } @@ -206,20 +228,25 @@ class PatientProfileButton extends StatelessWidget { final dynamic route; final PatiantInformtion patient; final String url = "assets/images/"; - PatientProfileButton( - {Key key, - this.patient, - this.nameLine1, - this.nameLine2, - this.icon, - this.route}) + final bool isDisable; + final bool isLoading; + final Function onTap; + + + PatientProfileButton({Key key, + this.patient, + this.nameLine1, + this.nameLine2, + this.icon, + this.route, this.isDisable = false, this.onTap, this.isLoading = false}) : super(key: key); + @override Widget build(BuildContext context) { return new Container( margin: new EdgeInsets.symmetric(horizontal: 4.0), child: InkWell( - onTap: () { + onTap: isDisable?null:onTap != null ? onTap : () { navigator(context, this.route); }, child: Column(children: [ @@ -243,6 +270,8 @@ class PatientProfileButton extends StatelessWidget { textAlign: TextAlign.left, fontSize: SizeConfig.textMultiplier * 2, ), + if(isLoading) + DrAppCircularProgressIndeicator() ], ), ), @@ -261,7 +290,7 @@ class PatientProfileButton extends StatelessWidget { ), decoration: BoxDecoration( // border: Border.all(), - color: Colors.white, + color: isDisable ? Colors.grey.withOpacity(0.4) : Colors.white, borderRadius: BorderRadius.all(Radius.circular(10)), border: Border.fromBorderSide(BorderSide( color: Color(0xffBBBBBB), From 175ba545e7cdd622af9590bbb7ef38255625073d Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Sun, 10 Jan 2021 12:14:25 +0200 Subject: [PATCH 03/12] finish create episode --- lib/core/service/SOAP_service.dart | 3 +++ lib/core/viewModel/SOAP_view_model.dart | 2 ++ lib/widgets/patients/profile/profile_medical_info_widget.dart | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/lib/core/service/SOAP_service.dart b/lib/core/service/SOAP_service.dart index 9707dc53..e3ab61b2 100644 --- a/lib/core/service/SOAP_service.dart +++ b/lib/core/service/SOAP_service.dart @@ -32,6 +32,7 @@ class SOAPService extends LookupService { List patientProgressNoteList = []; List patientAssessmentList = []; + int episodeID; Future getAllergies(GetAllergiesRequestModel getAllergiesRequestModel) async { await baseAppClient.post( GET_ALLERGIES, @@ -54,7 +55,9 @@ class SOAPService extends LookupService { await baseAppClient.post(POST_EPISODE, onSuccess: (dynamic response, int statusCode) { + print("Success"); + episodeID = response['EpisodeID']; }, onFailure: (String error, int statusCode) { hasError = true; super.error = error; diff --git a/lib/core/viewModel/SOAP_view_model.dart b/lib/core/viewModel/SOAP_view_model.dart index 31764c45..ebb282ef 100644 --- a/lib/core/viewModel/SOAP_view_model.dart +++ b/lib/core/viewModel/SOAP_view_model.dart @@ -79,6 +79,8 @@ class SOAPViewModel extends BaseViewModel { List get patientAssessmentList => _SOAPService.patientAssessmentList; + int get episodeID => + _SOAPService.episodeID; Future getAllergies(GetAllergiesRequestModel getAllergiesRequestModel) async { setState(ViewState.Busy); diff --git a/lib/widgets/patients/profile/profile_medical_info_widget.dart b/lib/widgets/patients/profile/profile_medical_info_widget.dart index 34433fa7..a614ddb4 100644 --- a/lib/widgets/patients/profile/profile_medical_info_widget.dart +++ b/lib/widgets/patients/profile/profile_medical_info_widget.dart @@ -49,6 +49,10 @@ class ProfileMedicalInfoWidget extends StatelessWidget { appointmentNo: patient.appointmentNo, patientMRN: patient.patientMRN); await model.postEpisode(postEpisodeReqModel); + patient.episodeNo = model.episodeID; + Navigator.of(context).pushNamed(CREATE_EPISODE, arguments: {'patient': patient}); + + }, isLoading: model.state == ViewState.BusyLocal, icon: 'create-episod.png' From 0147e7e49b5016fd6f51b05a71238864e741783f Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Sun, 10 Jan 2021 15:15:42 +0200 Subject: [PATCH 04/12] do translation, fix some bugs --- lib/config/localized_values.dart | 1 + lib/core/viewModel/SOAP_view_model.dart | 8 ++++++++ lib/util/translations_delegate_base.dart | 1 + .../patients/profile/patient-page-header-widget.dart | 11 ++++------- .../profile/profile_medical_info_widget.dart | 2 +- .../profile/soap_update/update_assessment_page.dart | 11 ++++------- .../profile/soap_update/update_objective_page.dart | 6 +++--- .../profile/soap_update/update_plan_page.dart | 12 +++++------- 8 files changed, 27 insertions(+), 25 deletions(-) diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index e96daef0..d1c52f7a 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -541,4 +541,5 @@ const Map> localizedValues = { 'physicalSystemExamination': {'en': "Physical/System Examination", 'ar':" الفحص البدني / النظام" }, 'searchExamination': {'en': "Search Examination", 'ar':"فحص البحث" }, 'addExamination': {'en': "Add Examination", 'ar':"اضافه" }, + 'doc': {'en': "Doc :", 'ar':" د: " }, }; diff --git a/lib/core/viewModel/SOAP_view_model.dart b/lib/core/viewModel/SOAP_view_model.dart index ebb282ef..e3daf6e9 100644 --- a/lib/core/viewModel/SOAP_view_model.dart +++ b/lib/core/viewModel/SOAP_view_model.dart @@ -246,6 +246,14 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } + String getAllergicNames(){ + String allergiesString=''; + patientAllergiesList.forEach((element) { + allergiesString += element.allergyDiseaseName+' , '; + }); + return allergiesString; + } + Future getPatientHistories(GetHistoryReqModel getHistoryReqModel, {bool isFirst = false}) async { setState(ViewState.Busy); await _SOAPService.getPatientHistories(getHistoryReqModel, isFirst: isFirst); diff --git a/lib/util/translations_delegate_base.dart b/lib/util/translations_delegate_base.dart index e6b5dbd5..0cfd0b6f 100644 --- a/lib/util/translations_delegate_base.dart +++ b/lib/util/translations_delegate_base.dart @@ -558,6 +558,7 @@ class TranslationBase { String get physicalSystemExamination => localizedValues['physicalSystemExamination'][locale.languageCode]; String get searchExamination => localizedValues['searchExamination'][locale.languageCode]; String get addExamination => localizedValues['addExamination'][locale.languageCode]; + String get doc => localizedValues['doc'][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/patients/profile/patient-page-header-widget.dart b/lib/widgets/patients/profile/patient-page-header-widget.dart index f4de0615..a6c47a7f 100644 --- a/lib/widgets/patients/profile/patient-page-header-widget.dart +++ b/lib/widgets/patients/profile/patient-page-header-widget.dart @@ -12,7 +12,6 @@ import 'package:flutter/material.dart'; class PatientPageHeaderWidget extends StatelessWidget { final PatiantInformtion patient; - String allergiesString=''; PatientPageHeaderWidget(this.patient); @override @@ -26,9 +25,7 @@ class PatientPageHeaderWidget extends StatelessWidget { doctorID: '', editedBy: ''); await model.getPatientAllergy(generalGetReqForSOAP); - model.patientAllergiesList.forEach((element) { - allergiesString += element.allergyDiseaseName+' , '; - }); + }, builder: (_, model, w) => Container( child: Column( @@ -85,11 +82,11 @@ class PatientPageHeaderWidget extends StatelessWidget { ), NetworkBaseView( baseViewModel: model, - child: AppText( - "ALLERGIC TO: $allergiesString", + child: model.patientAllergiesList.isNotEmpty ?AppText( + "ALLERGIC TO: "+model.getAllergicNames(), color: Color(0xFFB9382C), fontWeight: FontWeight.bold, - ), + ) : AppText(''), ), ], ), diff --git a/lib/widgets/patients/profile/profile_medical_info_widget.dart b/lib/widgets/patients/profile/profile_medical_info_widget.dart index a614ddb4..d3ea6048 100644 --- a/lib/widgets/patients/profile/profile_medical_info_widget.dart +++ b/lib/widgets/patients/profile/profile_medical_info_widget.dart @@ -94,7 +94,7 @@ class ProfileMedicalInfoWidget extends StatelessWidget { nameLine1: TranslationBase.of(context).previewHealth, nameLine2: TranslationBase.of(context).summaryReport, icon: 'radiology-1.png'), - if (selectedPatientType != 0 && selectedPatientType != 5) + if (selectedPatientType != 0 && selectedPatientType != 5 && selectedPatientType != 7) PatientProfileButton( key: key, patient: patient, diff --git a/lib/widgets/patients/profile/soap_update/update_assessment_page.dart b/lib/widgets/patients/profile/soap_update/update_assessment_page.dart index 10bfc120..0cec0609 100644 --- a/lib/widgets/patients/profile/soap_update/update_assessment_page.dart +++ b/lib/widgets/patients/profile/soap_update/update_assessment_page.dart @@ -41,7 +41,6 @@ class _UpdateAssessmentPageState extends State { bool isAssessmentExpand = false; @override Widget build(BuildContext context) { - final screenSize = MediaQuery.of(context).size; return BaseView( onModelReady: (model) async{ @@ -152,12 +151,10 @@ class _UpdateAssessmentPageState extends State { model: model); }, readOnly: true, - // hintColor: Colors.black, suffixIcon: EvaIcons.plusCircleOutline, suffixIconColor: AppGlobal .appPrimaryColor, fontWeight: FontWeight.w600, - // controller: messageController, validator: (value) { if (value == null) return TranslationBase @@ -217,7 +214,7 @@ class _UpdateAssessmentPageState extends State { MainAxisAlignment.start, children: [ AppText( - "Appointment #: ", + TranslationBase.of(context).appointmentNo, fontWeight: FontWeight .bold, fontSize: 16, @@ -250,7 +247,7 @@ class _UpdateAssessmentPageState extends State { MainAxisAlignment.start, children: [ AppText( - "Type : ", + TranslationBase.of(context).type +':', fontWeight: FontWeight .bold, fontSize: 16, @@ -270,7 +267,7 @@ class _UpdateAssessmentPageState extends State { MainAxisAlignment.start, children: [ AppText( - "Doc : ", + TranslationBase.of(context).doc, fontWeight: FontWeight .bold, fontSize: 16, @@ -671,7 +668,7 @@ class _AddAssessmentDetailsState extends State { height: 10, ), AppButton( - title: "Add".toUpperCase(), + title: (widget.isUpdate?TranslationBase.of(context).update:TranslationBase.of(context).add).toUpperCase(), loading: model.state == ViewState.BusyLocal, onPressed: () async { widget.mySelectedAssessment.remark = diff --git a/lib/widgets/patients/profile/soap_update/update_objective_page.dart b/lib/widgets/patients/profile/soap_update/update_objective_page.dart index 0c8bece6..550a36ca 100644 --- a/lib/widgets/patients/profile/soap_update/update_objective_page.dart +++ b/lib/widgets/patients/profile/soap_update/update_objective_page.dart @@ -397,10 +397,10 @@ class _UpdateObjectivePageState extends State { widget.changePageViewIndex(2); } } else { - helpers.showErrorToast(TranslationBase.of(context).requiredMsg); - } + widget.changePageViewIndex(2); - widget.changePageViewIndex(2); + // helpers.showErrorToast(TranslationBase.of(context).requiredMsg); + } } removeExamination(MasterKeyModel masterKey) { diff --git a/lib/widgets/patients/profile/soap_update/update_plan_page.dart b/lib/widgets/patients/profile/soap_update/update_plan_page.dart index a91447d6..b8ceea79 100644 --- a/lib/widgets/patients/profile/soap_update/update_plan_page.dart +++ b/lib/widgets/patients/profile/soap_update/update_plan_page.dart @@ -51,8 +51,6 @@ class _UpdatePlanPageState extends State { @override Widget build(BuildContext context) { - final screenSize = MediaQuery.of(context).size; - return BaseView( onModelReady: (model) async { GetGetProgressNoteReqModel getGetProgressNoteReqModel = @@ -287,13 +285,13 @@ class _UpdatePlanPageState extends State { appointmentNo: widget.patientInfo.appointmentNo, planNote: progressNoteController.text, doctorID: '', editedBy: ''); - // if(model.patientProgressNoteList.isEmpty){ + if(model.patientProgressNoteList.isEmpty){ await model.postProgressNote(postProgressNoteRequestModel); - // }else { - // await model.patchProgressNote(postProgressNoteRequestModel); - // - // } + }else { + await model.patchProgressNote(postProgressNoteRequestModel); + + } if (model.state == ViewState.ErrorLocal) { helpers.showErrorToast(model.error); From fb035cd4c9e385325357b11def3eb2279bc19ba8 Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Sun, 10 Jan 2021 17:35:40 +0200 Subject: [PATCH 05/12] fix patient_search_screen.dart --- .../patients/patient_search_screen.dart | 12 ------ lib/widgets/patients/dynamic_elements.dart | 39 ++++++++++++++++--- lib/widgets/shared/app_text_form_field.dart | 5 +-- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/lib/screens/patients/patient_search_screen.dart b/lib/screens/patients/patient_search_screen.dart index 61eb5fcf..94102b1b 100644 --- a/lib/screens/patients/patient_search_screen.dart +++ b/lib/screens/patients/patient_search_screen.dart @@ -68,21 +68,9 @@ class _PatientSearchScreenState extends State { try { - - /* Map profile = await sharedPref.getObj(DOCTOR_PROFILE); - DoctorProfileModel doctorProfile = - new DoctorProfileModel.fromJson(profile)*/; if (_formKey.currentState.validate()) { _formKey.currentState.save(); - /* sharedPref.setString(SLECTED_PATIENT_TYPE, _selectedType); - String token = await sharedPref.getString(TOKEN); - - _patientSearchFormValues.TokenID = token; - _patientSearchFormValues.ProjectID = doctorProfile.projectID; //15 - _patientSearchFormValues.DoctorID = doctorProfile.doctorID; - _patientSearchFormValues.ClinicID = doctorProfile.clinicID;*/ - if ((_patientSearchFormValues.From == "0" || _patientSearchFormValues.To == "0") && _selectedType == "7") { diff --git a/lib/widgets/patients/dynamic_elements.dart b/lib/widgets/patients/dynamic_elements.dart index 25d196d0..e6688397 100644 --- a/lib/widgets/patients/dynamic_elements.dart +++ b/lib/widgets/patients/dynamic_elements.dart @@ -59,22 +59,49 @@ class _DynamicElementsState extends State { @override Widget build(BuildContext context) { + final screenSize = MediaQuery + .of(context) + .size; + InputDecoration textFieldSelectorDecoration({String hintText, + String selectedText, bool isDropDown,IconData icon}) { + return InputDecoration( + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Color(0xFFCCCCCC), width: 2.0), + borderRadius: BorderRadius.circular(8), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Color(0xFFCCCCCC), width: 2.0), + borderRadius: BorderRadius.circular(8), + ), + disabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Color(0xFFCCCCCC), width: 2.0), + borderRadius: BorderRadius.circular(8), + ), + hintText: selectedText != null ? selectedText : hintText, + suffixIcon: isDropDown ? Icon(icon ?? Icons.arrow_drop_down) : null, + hintStyle: TextStyle( + fontSize: 14, + color: Colors.grey.shade600, + ), + ) + ; + } return LayoutBuilder( builder: (ctx, constraints) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + SizedBox( + height: 10, + ), SizedBox( height: 10, ), AppTextFormField( - textInputType: TextInputType.number, + onTap: ()=> _presentDatePicker('_selectedFromDate'), hintText: TranslationBase.of(context).fromDate, controller: _fromDateController, inputFormatter: ONLY_DATE, - onTap: () { - _presentDatePicker('_selectedFromDate'); - }, onSaved: (value) { if (_fromDateController.text.toString().trim().isEmpty) { widget._patientSearchFormValues.From = "0"; @@ -82,12 +109,14 @@ class _DynamicElementsState extends State { widget._patientSearchFormValues.From = _fromDateController.text.replaceAll("/", "-"); } }, + readOnly: true, + ), SizedBox( height: 10, ), AppTextFormField( - textInputType: TextInputType.number, + readOnly: true, hintText: TranslationBase .of(context) .toDate, diff --git a/lib/widgets/shared/app_text_form_field.dart b/lib/widgets/shared/app_text_form_field.dart index 4c2573cd..82a273bb 100644 --- a/lib/widgets/shared/app_text_form_field.dart +++ b/lib/widgets/shared/app_text_form_field.dart @@ -4,10 +4,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hexcolor/hexcolor.dart'; -// OWNER : Ibrahim albitar -// DATE : 19-04-2020 -// DESCRIPTION : Custom Text Form Field for app. - class AppTextFormField extends FormField { AppTextFormField( {FormFieldSetter onSaved, @@ -41,6 +37,7 @@ class AppTextFormField extends FormField { obscureText: obscureText, focusNode: focusNode, keyboardType: textInputType, + readOnly: readOnly, inputFormatters: [ FilteringTextInputFormatter.allow( RegExp(inputFormatter)), From 90a16676db8fe07d6bc14f51a8de3ca1f47e3342 Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Mon, 11 Jan 2021 13:54:57 +0200 Subject: [PATCH 06/12] fix issue related to SOAP --- .../soap_update/custom_validation_error.dart | 33 +++++ .../subjective/update_allergies_widget.dart | 42 ++++-- .../subjective/update_history_widget.dart | 121 +++++++++-------- .../soap_update/update_assessment_page.dart | 24 +++- .../soap_update/update_objective_page.dart | 2 +- .../profile/soap_update/update_plan_page.dart | 7 +- .../master_key_checkbox_search_widget.dart | 125 +++++++++--------- 7 files changed, 215 insertions(+), 139 deletions(-) create mode 100644 lib/widgets/patients/profile/soap_update/custom_validation_error.dart diff --git a/lib/widgets/patients/profile/soap_update/custom_validation_error.dart b/lib/widgets/patients/profile/soap_update/custom_validation_error.dart new file mode 100644 index 00000000..a05d52a2 --- /dev/null +++ b/lib/widgets/patients/profile/soap_update/custom_validation_error.dart @@ -0,0 +1,33 @@ + +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; + +// ignore: must_be_immutable +class CustomValidationError extends StatelessWidget { + String error; + CustomValidationError({ + Key key, this.error, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + if(error == null ) + error = TranslationBase + .of(context) + .emptyMessage; + return Column( + children: [ + SizedBox( + height: 2, + ), + Container( + margin: EdgeInsets.symmetric(horizontal: 3), + child: AppText(error, color: Theme + .of(context) + .errorColor, fontSize: 14,), + ), + ], + ); + } +} \ No newline at end of file diff --git a/lib/widgets/patients/profile/soap_update/subjective/update_allergies_widget.dart b/lib/widgets/patients/profile/soap_update/subjective/update_allergies_widget.dart index 6de9e031..38a0896b 100644 --- a/lib/widgets/patients/profile/soap_update/subjective/update_allergies_widget.dart +++ b/lib/widgets/patients/profile/soap_update/subjective/update_allergies_widget.dart @@ -19,6 +19,8 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:provider/provider.dart'; +import '../custom_validation_error.dart'; + class UpdateAllergiesWidget extends StatefulWidget { final List myAllergiesList; @@ -226,10 +228,11 @@ class _AddAllergiesState extends State { MasterKeyModel _selectedAllergy; TextEditingController remarkController = TextEditingController(); GlobalKey key = new GlobalKey>(); + bool isFormSubmitted = false; - - InputDecoration textFieldSelectorDecoration(String hintText, - String selectedText, bool isDropDown,{IconData icon}) { + InputDecoration textFieldSelectorDecoration( + String hintText, String selectedText, bool isDropDown, + {IconData icon}) { return InputDecoration( focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Color(0xFFCCCCCC), width: 2.0), @@ -328,18 +331,24 @@ class _AddAllergiesState extends State { input.toLowerCase()) || suggestion.nameEn.toLowerCase() .startsWith(input.toLowerCase()), - ):TextField( + ) : TextField( decoration: textFieldSelectorDecoration( TranslationBase .of(context) .selectAllergy, _selectedAllergy != null - ? projectViewModel.isArabic?_selectedAllergy.nameAr: _selectedAllergy.nameEn - : null, true, icon: EvaIcons.search), + ? projectViewModel.isArabic + ? _selectedAllergy.nameAr + : _selectedAllergy.nameEn + : null, + true, + icon: EvaIcons.search), enabled: false, ), ), ), + if(isFormSubmitted && _selectedAllergy == null) + CustomValidationError(), SizedBox( height: 10, ), @@ -382,6 +391,8 @@ class _AddAllergiesState extends State { ), ), ), + if(isFormSubmitted && _selectedAllergySeverity == null) + CustomValidationError(), SizedBox( height: 10, ), @@ -410,12 +421,18 @@ class _AddAllergiesState extends State { AppButton( title: TranslationBase.of(context).add.toUpperCase(), onPressed: () { - MySelectedAllergy mySelectedAllergy = new MySelectedAllergy( - remark: remarkController.text, - selectedAllergy: _selectedAllergy, - isChecked: true, - selectedAllergySeverity: _selectedAllergySeverity,); - widget.addAllergiesFun(mySelectedAllergy); + setState(() { + isFormSubmitted = true; + }); + if(_selectedAllergy !=null && _selectedAllergySeverity !=null) { + MySelectedAllergy mySelectedAllergy = new MySelectedAllergy( + remark: remarkController.text, + selectedAllergy: _selectedAllergy, + isChecked: true, + selectedAllergySeverity: _selectedAllergySeverity,); + widget.addAllergiesFun(mySelectedAllergy); + } + }, ), ] @@ -433,3 +450,4 @@ class _AddAllergiesState extends State { + diff --git a/lib/widgets/patients/profile/soap_update/subjective/update_history_widget.dart b/lib/widgets/patients/profile/soap_update/subjective/update_history_widget.dart index 9a7cba01..28f9f466 100644 --- a/lib/widgets/patients/profile/soap_update/subjective/update_history_widget.dart +++ b/lib/widgets/patients/profile/soap_update/subjective/update_history_widget.dart @@ -10,6 +10,7 @@ import 'package:doctor_app_flutter/widgets/shared/Text.dart'; import 'package:doctor_app_flutter/widgets/shared/TextFields.dart'; import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; import 'package:doctor_app_flutter/widgets/shared/master_key_checkbox_search_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/network_base_view.dart'; import 'package:eva_icons_flutter/eva_icons_flutter.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; @@ -271,6 +272,9 @@ class _AddHistoryDialogState extends State { onModelReady: (model) async { if (model.historyFamilyList.length == 0) { await model.getMasterLookup(MasterKeysService.HistoryFamily); + setState(() { + + }); } }, builder: (_, model, w) => AppScaffold( @@ -313,62 +317,71 @@ class _AddHistoryDialogState extends State { }, scrollDirection: Axis.horizontal, children: [ - MasterKeyCheckboxSearchWidget( - model: model, - masterList: model.historyFamilyList, - removeHistory: (history){ - setState(() { - widget.removeHistory(history); - }); - }, - addHistory: (history){ - setState(() { - createAndAddHistory( - history); - }); - }, - addSelectedHistories: (){ - widget.addSelectedHistories(); - }, - isServiceSelected: (master) =>isServiceSelected(master), + NetworkBaseView( + baseViewModel: model, + child: MasterKeyCheckboxSearchWidget( + model: model, + masterList: model.historyFamilyList, + removeHistory: (history){ + setState(() { + widget.removeHistory(history); + }); + }, + addHistory: (history){ + setState(() { + createAndAddHistory( + history); + }); + }, + addSelectedHistories: (){ + widget.addSelectedHistories(); + }, + isServiceSelected: (master) =>isServiceSelected(master), + ), ), - MasterKeyCheckboxSearchWidget( - model: model, - masterList: model.mergeHistorySurgicalWithHistorySportList, - removeHistory: (history){ - setState(() { - widget.removeHistory(history); - }); - }, - addHistory: (history){ - setState(() { - createAndAddHistory( - history); - }); - }, - addSelectedHistories: (){ - widget.addSelectedHistories(); - }, - isServiceSelected: (master) =>isServiceSelected(master), + NetworkBaseView( + baseViewModel: model, + child: MasterKeyCheckboxSearchWidget( + model: model, + masterList: model.mergeHistorySurgicalWithHistorySportList, + removeHistory: (history){ + setState(() { + widget.removeHistory(history); + }); + }, + addHistory: (history){ + setState(() { + createAndAddHistory( + history); + }); + }, + addSelectedHistories: (){ + widget.addSelectedHistories(); + }, + isServiceSelected: (master) =>isServiceSelected(master), + ), ), - MasterKeyCheckboxSearchWidget( - model: model, - masterList: model.historyMedicalList, - removeHistory: (history){ - setState(() { - widget.removeHistory(history); - }); - }, - addHistory: (history){ - setState(() { - createAndAddHistory( - history); - }); - }, - addSelectedHistories: (){ - widget.addSelectedHistories(); - }, - isServiceSelected: (master) =>isServiceSelected(master), + NetworkBaseView( + baseViewModel: model, + child: MasterKeyCheckboxSearchWidget( + model: model, + masterList: model.historyMedicalList, + removeHistory: (history){ + setState(() { + widget.removeHistory(history); + }); + }, + addHistory: (history){ + setState(() { + createAndAddHistory( + history); + }); + }, + addSelectedHistories: (){ + widget.addSelectedHistories(); + }, + isServiceSelected: (master) =>isServiceSelected(master), + ), ), ], ), diff --git a/lib/widgets/patients/profile/soap_update/update_assessment_page.dart b/lib/widgets/patients/profile/soap_update/update_assessment_page.dart index 0cec0609..93d56af2 100644 --- a/lib/widgets/patients/profile/soap_update/update_assessment_page.dart +++ b/lib/widgets/patients/profile/soap_update/update_assessment_page.dart @@ -23,6 +23,8 @@ import 'package:eva_icons_flutter/eva_icons_flutter.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'custom_validation_error.dart'; + class UpdateAssessmentPage extends StatefulWidget { final Function changePageViewIndex; List mySelectedAssessmentList; @@ -399,6 +401,7 @@ class _UpdateAssessmentPageState extends State { addSelectedAssessment: (MySelectedAssessment mySelectedAssessment, bool isUpdate) async { setState(() { + widget.mySelectedAssessmentList.add(mySelectedAssessment); }); }); @@ -413,7 +416,6 @@ class AddAssessmentDetails extends StatefulWidget { final Function(MySelectedAssessment mySelectedAssessment, bool isUpdate) addSelectedAssessment; final PatiantInformtion patientInfo; final bool isUpdate; - AddAssessmentDetails( {Key key, this.mySelectedAssessment, this.addSelectedAssessment, this.patientInfo, this.isUpdate = false, this.mySelectedAssessmentList}); @@ -426,6 +428,7 @@ class _AddAssessmentDetailsState extends State { TextEditingController remarkController = TextEditingController(); TextEditingController appointmentIdController = TextEditingController(); GlobalKey key = new GlobalKey>(); + bool isFormSubmitted = false; @override Widget build(BuildContext context) { @@ -549,6 +552,9 @@ class _AddAssessmentDetailsState extends State { ), ), ), + if(isFormSubmitted && widget.mySelectedAssessment + .selectedICD == null) + CustomValidationError(), SizedBox( height: 10, ), @@ -595,6 +601,9 @@ class _AddAssessmentDetailsState extends State { ), ), ), + if(isFormSubmitted && widget.mySelectedAssessment + .selectedDiagnosisCondition == null) + CustomValidationError(), SizedBox( height: 10, ), @@ -641,6 +650,9 @@ class _AddAssessmentDetailsState extends State { ), ), ), + if(isFormSubmitted && widget.mySelectedAssessment + .selectedDiagnosisType == null) + CustomValidationError(), SizedBox( height: 10, ), @@ -671,6 +683,9 @@ class _AddAssessmentDetailsState extends State { title: (widget.isUpdate?TranslationBase.of(context).update:TranslationBase.of(context).add).toUpperCase(), loading: model.state == ViewState.BusyLocal, onPressed: () async { + setState(() { + isFormSubmitted = true; + }); widget.mySelectedAssessment.remark = remarkController.text; widget.mySelectedAssessment @@ -692,10 +707,6 @@ class _AddAssessmentDetailsState extends State { model: model, mySelectedAssessment: widget .mySelectedAssessment); - } else { - helpers.showErrorToast(TranslationBase - .of(context) - .requiredMsg); } }, ), @@ -752,7 +763,8 @@ class _AddAssessmentDetailsState extends State { mySelectedAssessment.icdCode10ID = mySelectedAssessment.selectedICD.code; if (!isUpdate) { - widget.mySelectedAssessmentList.add(mySelectedAssessment); + // widget.mySelectedAssessmentList.add(mySelectedAssessment); + widget.addSelectedAssessment(mySelectedAssessment,isUpdate); } Navigator.of(context).pop(); } diff --git a/lib/widgets/patients/profile/soap_update/update_objective_page.dart b/lib/widgets/patients/profile/soap_update/update_objective_page.dart index 550a36ca..9bd38666 100644 --- a/lib/widgets/patients/profile/soap_update/update_objective_page.dart +++ b/lib/widgets/patients/profile/soap_update/update_objective_page.dart @@ -315,7 +315,7 @@ class _UpdateObjectivePageState extends State { fontWeight: FontWeight.w600, maxLines: 25, minLines: 4, - controller: remarksController, + // controller: remarksController, validator: (value) { if (value == null) return TranslationBase.of(context) diff --git a/lib/widgets/patients/profile/soap_update/update_plan_page.dart b/lib/widgets/patients/profile/soap_update/update_plan_page.dart index b8ceea79..a3c2cdd2 100644 --- a/lib/widgets/patients/profile/soap_update/update_plan_page.dart +++ b/lib/widgets/patients/profile/soap_update/update_plan_page.dart @@ -113,7 +113,7 @@ class _UpdatePlanPageState extends State { ), Column( children: [ - if(model.patientProgressNoteList.isEmpty) + if(model.patientProgressNoteList.isEmpty || progressNoteController.text !='') Container( margin: EdgeInsets.only(left: 10, right: 10, top: 15), @@ -140,7 +140,7 @@ class _UpdatePlanPageState extends State { SizedBox( height: 20, ), - if (progressNoteController.text.isNotEmpty) + if (progressNoteController.text !='') Container( margin: EdgeInsets.only(left: 5, right: 5, top: 15), @@ -350,6 +350,9 @@ class _UpdatePlanPageState extends State { AppButton( title: "Add".toUpperCase(), onPressed: () { + setState(() { + print(progressNoteController.text); + }); Navigator.of(context).pop(); }, ), diff --git a/lib/widgets/shared/master_key_checkbox_search_widget.dart b/lib/widgets/shared/master_key_checkbox_search_widget.dart index aafb8adc..dd9e2f3d 100644 --- a/lib/widgets/shared/master_key_checkbox_search_widget.dart +++ b/lib/widgets/shared/master_key_checkbox_search_widget.dart @@ -53,71 +53,68 @@ class _MasterKeyCheckboxSearchWidgetState extends State Date: Mon, 11 Jan 2021 14:45:09 +0200 Subject: [PATCH 07/12] fix issue related to landing page --- lib/landing_page.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/landing_page.dart b/lib/landing_page.dart index edfc496c..c5494acf 100644 --- a/lib/landing_page.dart +++ b/lib/landing_page.dart @@ -64,10 +64,9 @@ class _LandingPageState extends State { ShowCaseWidget( builder: Builder(builder: (context) => DashboardScreen()), ), - MessagesScreen(), - //MyScheduleScreen(), - NewPrescriptionScreen(), - ServicesScreen() + // MessagesScreen(), + MyScheduleScreen(), + // ServicesScreen() ], ), bottomNavigationBar: BottomNavBar(changeIndex: _changeCurrentTab), From 2f17167e2f1025ab271ebe87b4389e9399d85a3c Mon Sep 17 00:00:00 2001 From: mosazaid Date: Mon, 11 Jan 2021 18:33:12 +0200 Subject: [PATCH 08/12] some design enhancments --- .../patients/profile/UCAF/UCAF-detail-screen.dart | 8 ++++---- .../profile/referral/refer-patient-screen.dart | 12 +++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/screens/patients/profile/UCAF/UCAF-detail-screen.dart b/lib/screens/patients/profile/UCAF/UCAF-detail-screen.dart index 0a655231..83f2d68b 100644 --- a/lib/screens/patients/profile/UCAF/UCAF-detail-screen.dart +++ b/lib/screens/patients/profile/UCAF/UCAF-detail-screen.dart @@ -72,11 +72,11 @@ class _UcafDetailScreenState extends State { ), Container( margin: - EdgeInsets.symmetric(vertical: 16, horizontal: 16), + EdgeInsets.symmetric(vertical: 8, horizontal: 16), child: BorderedButton( TranslationBase.of(context).save, hasBorder: true, - vPadding: 16, + vPadding: 8, hPadding: 8, borderColor: HexColor("#B8382B"), backgroundColor: HexColor("#B8382B"), @@ -87,11 +87,11 @@ class _UcafDetailScreenState extends State { ), Container( margin: - EdgeInsets.only(left: 16, right: 16, top: 0, bottom: 16), + EdgeInsets.only(left: 16, right: 16, top: 0.0, bottom: 8), child: BorderedButton( TranslationBase.of(context).cancel, hasBorder: true, - vPadding: 16, + vPadding: 8, hPadding: 8, borderColor: Colors.white, backgroundColor: Colors.white, diff --git a/lib/screens/patients/profile/referral/refer-patient-screen.dart b/lib/screens/patients/profile/referral/refer-patient-screen.dart index e46ab6d5..62952108 100644 --- a/lib/screens/patients/profile/referral/refer-patient-screen.dart +++ b/lib/screens/patients/profile/referral/refer-patient-screen.dart @@ -40,11 +40,7 @@ class _PatientMakeReferralScreenState extends State { @override void initState() { super.initState(); - referToList = List(); - dynamic sameBranch = {"id": 1, "name": "Same Branch"}; - dynamic otherBranch = {"id": 2, "name": "Other Branch"}; - referToList.add(sameBranch); - referToList.add(otherBranch); + appointmentDate = DateTime.now(); } @@ -53,6 +49,12 @@ class _PatientMakeReferralScreenState extends State { final routeArgs = ModalRoute.of(context).settings.arguments as Map; patient = routeArgs['patient']; + referToList = List(); + dynamic sameBranch = {"id": 1, "name": TranslationBase.of(context).sameBranch}; + dynamic otherBranch = {"id": 2, "name": TranslationBase.of(context).otherBranch}; + referToList.add(sameBranch); + referToList.add(otherBranch); + final screenSize = MediaQuery.of(context).size; return BaseView( From 40e9ab864a2dc371dd588c7ae78a0bd731d155b3 Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Tue, 12 Jan 2021 11:36:42 +0300 Subject: [PATCH 09/12] login changes --- android/app/build.gradle | 4 +- android/app/google-services.json | 39 + android/build.gradle | 1 + android/google-services.json | 39 + android/gradle.properties | 3 +- assets/images/login/101.png | Bin 0 -> 3484 bytes assets/images/login/102.png | Bin 0 -> 3991 bytes assets/images/login/103.png | Bin 0 -> 2377 bytes assets/images/login/104.png | Bin 0 -> 4981 bytes assets/images/login/fileNum.png | Bin 0 -> 1515 bytes assets/images/login/forget.png | Bin 0 -> 1980 bytes assets/images/login/id.png | Bin 0 -> 1308 bytes assets/images/login/more_icon.png | Bin 0 -> 488 bytes assets/images/login/nationalID.png | Bin 0 -> 2834 bytes lib/client/base_app_client.dart | 24 +- lib/config/config.dart | 10 +- lib/config/localized_values.dart | 35 + lib/config/shared_pref_kay.dart | 2 + lib/core/model/imei_details.dart | 88 ++ lib/core/model/insert_imei_model.dart | 92 ++ lib/core/service/auth_service.dart | 29 + lib/core/service/medicine_service.dart | 1 - lib/core/viewModel/auth_view_model.dart | 76 +- lib/core/viewModel/imei_view_model.dart | 21 + lib/core/viewModel/project_view_model.dart | 7 +- lib/locator.dart | 5 + lib/main.dart | 51 +- .../auth/activation_Code_req_model.dart | 21 +- .../check_activation_code_request_model.dart | 29 +- lib/screens/auth/login_screen.dart | 149 +-- .../auth/verification_methods_screen.dart | 2 +- lib/screens/dashboard_screen.dart | 9 + .../reschedule-leaves/reschedule_leave.dart | 4 +- lib/util/helpers.dart | 17 +- lib/util/translations_delegate_base.dart | 53 +- lib/widgets/auth/known_user_login.dart | 4 +- lib/widgets/auth/login_form.dart | 35 +- lib/widgets/auth/verification_methods.dart | 861 ++++++++++++++---- lib/widgets/otp/sms-popup.dart | 346 +++++++ pubspec.lock | 28 + pubspec.yaml | 4 +- 41 files changed, 1702 insertions(+), 387 deletions(-) create mode 100644 android/app/google-services.json create mode 100644 android/google-services.json create mode 100644 assets/images/login/101.png create mode 100644 assets/images/login/102.png create mode 100644 assets/images/login/103.png create mode 100644 assets/images/login/104.png create mode 100644 assets/images/login/fileNum.png create mode 100644 assets/images/login/forget.png create mode 100644 assets/images/login/id.png create mode 100644 assets/images/login/more_icon.png create mode 100644 assets/images/login/nationalID.png create mode 100644 lib/core/model/imei_details.dart create mode 100644 lib/core/model/insert_imei_model.dart create mode 100644 lib/core/service/auth_service.dart create mode 100644 lib/core/viewModel/imei_view_model.dart create mode 100644 lib/widgets/otp/sms-popup.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index ae87782e..da345fc2 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -44,6 +44,7 @@ android { versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + multiDexEnabled true } buildTypes { @@ -72,9 +73,10 @@ dependencies { implementation 'com.opentok.android:opentok-android-sdk:2.16.5' //permissions implementation 'pub.devrel:easypermissions:0.4.0' - +implementation 'com.google.firebase:firebase-core:9.6.1' //retrofit implementation 'com.squareup.retrofit2:retrofit:2.6.2' implementation 'com.squareup.retrofit2:converter-gson:2.6.2' implementation 'com.squareup.okhttp3:logging-interceptor:3.14.1' + apply plugin: 'com.google.gms.google-services' } diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 00000000..3c00f05c --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,39 @@ +{ + "project_info": { + "project_number": "1008895414777", + "project_id": "doctorapp-9f172", + "storage_bucket": "doctorapp-9f172.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:1008895414777:android:d00fe21d6955c21b1f6d28", + "android_client_info": { + "package_name": "com.example.doctor_app_flutter" + } + }, + "oauth_client": [ + { + "client_id": "1008895414777-3mg88j5ocs5r1au7rf4sh3f4pgsri2f2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCNncEIj8ehVUSxV89rx0x1NaWp8t1YVkw" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "1008895414777-3mg88j5ocs5r1au7rf4sh3f4pgsri2f2.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 357c6a1a..ea0f0026 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,6 +8,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.5.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.google.gms:google-services:4.3.2' } } diff --git a/android/google-services.json b/android/google-services.json new file mode 100644 index 00000000..3c00f05c --- /dev/null +++ b/android/google-services.json @@ -0,0 +1,39 @@ +{ + "project_info": { + "project_number": "1008895414777", + "project_id": "doctorapp-9f172", + "storage_bucket": "doctorapp-9f172.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:1008895414777:android:d00fe21d6955c21b1f6d28", + "android_client_info": { + "package_name": "com.example.doctor_app_flutter" + } + }, + "oauth_client": [ + { + "client_id": "1008895414777-3mg88j5ocs5r1au7rf4sh3f4pgsri2f2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCNncEIj8ehVUSxV89rx0x1NaWp8t1YVkw" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "1008895414777-3mg88j5ocs5r1au7rf4sh3f4pgsri2f2.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/gradle.properties b/android/gradle.properties index 38c8d454..9c0729c9 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,5 @@ -org.gradle.jvmargs=-Xmx1536M + android.enableR8=true android.useAndroidX=true android.enableJetifier=true +org.gradle.jvmargs=-Xmx4608m diff --git a/assets/images/login/101.png b/assets/images/login/101.png new file mode 100644 index 0000000000000000000000000000000000000000..90c1c575a19e47ad913fbe1e2be3f9182be3f826 GIT binary patch literal 3484 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 ZIgsNVRcpaEn4PP#nej=?ebiaz{{cCP0nY#c literal 0 HcmV?d00001 diff --git a/assets/images/login/103.png b/assets/images/login/103.png new file mode 100644 index 0000000000000000000000000000000000000000..3326814bc80e6682a73f4a36f62f4cbd5b15f36d GIT binary patch literal 2377 zcmaJ@cT`hZ9)1bvMh9FeHrhNAR9qlU2qYMRkkBNE5Rj2(Ade72ib;?FYQV7(P{9$g zuF4=55QgT`22>Df!wf3oAO{uO*Fr4%_8{fU!T52S?aRlY}z1+)gOP zEHcm`X|#kVmhnVFP|L`U5+%r}XjtjzEeOP4Xob>+GQkDI$=PBY0gKmeX)%z={Qsc> z!Ix;MECBkC-v3D~WhIFrTmU2$B}k&-gNwmvQ;8|=5{NAmNmwFL{9+aTV?{ENG*%=A z-QBfSa{{e*@`M~wqIAuLZBuw( z*Fyg)-vXBNRV@U@SFt!)3{HEv|8>}lOR$5q!!Oo_Ctu7D31P=eU~8LCIi3N4CDq<^ zH=N^s8Ds4cK8b(m$_7)nbmh>oA#W>;fzd&iOpEumRzFtDe;bj%JDq;W%+NRF zqy??ahrXRQbH#!s)`eE-nk%pt#ybtH@{Z`|{eGisT|*v!_t@={k2SYy9g`yEzeC9d zwR0&o^~JY}Cxn?E7(};cAPSM{3LwFisQ^kBeAQ48UjHQ4-q&>!oU{^QB7H12&HD&B z<{D3RgxWKG_5)gN88jnRDbN=GbjcoA-{ALg*DT}CpBvXa>lneRe>DQ4Qn*pzw}{A zf~LsA<424Y7c(mP+dr5jtmt~J-xN`}UcIKHtX;X{QdoTJg{;W<0wr=?)E3*(kU`YF zrdXUV2p|!tg=#IKsr;rr47mH{mW+fS?Ceiru!?a!VK>PA(e;9M&= zVzu#(u)Z$Zt#bw2dOP*1w+XW^jFvn}Y`dKOsylKV0fo%!$C+PT-A$^@aoLfS5p?P9 zyn9%;(ZqDbypi+ezud3pKHK|P{hT$de$bt0l`gb8;^OtXZn4eSK*I8-nV5P8e>#+>C+m+g63uCHYj=eYN z-5b(Vv^4AXkr~@z7!jnC&($#7_k^1tt+-amsCT8c*Tw}rtx{h0cYeO7<7Z7mg#%(z zb^f--)ayB7lTAfkrS2nx1Brbzdd`J9j~rAf;WcFln5dVOvcLE3iyuqJQTaDDc0Kz9 zWUZoJq=9d8Y4tEb?uFY^RT+f4QHGfRtR>3bD->I%>zv;7hKWBB)~Vk4xd z1j7NX`;NDTYJT&6e2VMb(JE^#Jz{^Zuh=;`JkF~~{gedhpB8L%3H>%zCvRJ*4zotG z#IO*SMZEBhZ_kS+mp4EZ#o*WEPuUT?(DRuuO0TYexZ>P0ul6YpA8A-ySE)mMf&b~% zv@vM3@?K`39mUM*W?N`&@R>UHM^ZNR*jUBGNlwPg{?zeboDT%&s)Li$;`Y50_yvxy z>E==!gQ&SCk0c|eRWt5UryZRp&Z_*g@vZC}lxwFB$Y;#F^>4v-N?vj?q^$4JDR-Z( zOOVvAF1<5~P&=vy7^K5Dj0$rSTp#;rd=62m6SS_Ff=LOt>%^eZLB-mh6|f8Wz8w+R zUc%{{Je~4*ouN);%EiKV%^@KNTHkG_;IXY&Z`DWfd;CczyXsPGc zyVD%+N}8Xgptkwvkq?%pLFGI9d-f00J*_Kd>w`Z~eGgbp8Q5INFHw$dD&%4+%bL^X z0y)!3Co{&FH~t(=)pbm<)Wag-JM!~Q2_P9y6i7Xw3VFkY99pw DG{ouR literal 0 HcmV?d00001 diff --git a/assets/images/login/104.png b/assets/images/login/104.png new file mode 100644 index 0000000000000000000000000000000000000000..ad55ff74ccab0ca8b0e74beefb641f0d55274f09 GIT binary patch literal 4981 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 literal 0 HcmV?d00001 diff --git a/assets/images/login/fileNum.png b/assets/images/login/fileNum.png new file mode 100644 index 0000000000000000000000000000000000000000..386299b71c8891a99fa03ee33616a4045bb7e1a7 GIT binary patch literal 1515 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAnN?apKg7ec#$`gxH85~pclTsBt za}(23gHjVyDhp4h+AuIMt7V2nltlRYSS9D@>Lr5I=vCwv0Ch7k*w|MTBqnF4mMA2p zrf25aD!t#mUr8Y|#a1cY)Yrhbz&SM|)1#^=HMq(zB)KX(*)m1R-cG@$!U||WZfZ%Q zLPc&)Ua?h$trFN=Dz9|8 z>y;bpKhp88yV>WRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<-In3$Ab zT4JjNbScCOxdm`z^NOLt1Pn0!io^naLp=kKmtYEgeeo;J&4sHjE(uCSxEHIz#UYgi zsro^w#rdU0$-sz9QwCX8VC7ttnpl!w6q28x0}I7~jQo=P;*9(P1!reas97jzglFcZ z|Z5PA)9>IEf-+ybD@E~!PCWvMA{Mftf3U~gMx;&h9l zD^ByEdQ)(^#n26>UVWfr^g)q}6xlE#UXa%Gads*vRAZsrY^%^n9k zcf{5=9M^iR@z7VtELDWFc}ms!)#sf3Q^LMiCHPP6KK@VbbEor_C!9MB{)V01{(6p0 zlXbxAESu#5@xdOt{OJp|&kAerJgnsyeR=NGkK3eLQ?`zJe92QOY`BS%J!ACvQ>vKLOUft&R{Q3GL*V6<# zOQuc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuk#7M#1QqR!L zz|zP>N5ROz&|KfZT;I@G*TB%qz|6|nQUMB-fVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr7I$DAX(zG{Q6U zQu51-HNkp(eXTt6ic1pnl2bihY?Xkf=w)W6SeY0Z8=JbAy1E)!8XFqAT3Q-g8aNv} zS~xj6IXPNdy213iEv!_1oxXPkT zDaO(tEs6~a3{4IK42}vM4GID*9%_$1)!wgt7akkI`KiVyDk5-(+Q}Vj>v(qCN_INU zcx&GFFMb-c(Bec%j}L6Sdsbx@+*rR{WlQv?4kKpGIFCp+HMNgUDi%6jgJ$rOxZilDsn=b#%Wm_aNYgar+ zlMc6o00)x-2MePBOA`afrKc9VT4(#HY0mWv))C|0a(QV`XVK0%|0K+0LSJ3Yn)>Va z)f>yhR)%C06l|!D6+6!tdL*G@+Nvw_9nw73hAqx8S>nY15*%(~o`_+S%#lHoW?}Yf4peUS8j`=g%`UGFB}8Jb(WD%<@4Zj& zRyLa1BgSHGZa&LHt>*UEjhi<=-j#p-`t@5!juhR!2W(`sxLGo1LCrWwdYF)gf(SYWlV6OyrcwDXu#-tSl`r8gF2m zJ$v>%mY?hH?91$B&s&%GS|?HbM&ABin+%?;{{8OVyRSO}G%g%G*!XyVadmaK*IjNs zef`q!TefXmc3t@S^XDtBgeD{=HeS1aJu@NUz}4S(_wgGZVSl{q@ynMlV|gA)-N z+xd4)*s9bsx4R$`m^&sE9N1n}>8@;liX}T-_f6W9WY65>4=2->UhlhlHT3@Nw$qyw zCwko2XJ=;CCb3AUzrSBVh2sqC!kLQ~E3b)*t;^jX&3dhO0Os)=Qv18 z1m!&tt4451Ut&O;y^e?6;{`nJHO*c2NmK0aKGi;^eB-8~j+`N%RJ{INlX=XQAGRmR gbDjS5c|Q{mgUjL{4U(<*w}a|aPgg&ebxsLQ02Xi>SO5S3 literal 0 HcmV?d00001 diff --git a/assets/images/login/id.png b/assets/images/login/id.png new file mode 100644 index 0000000000000000000000000000000000000000..9260cf11180d8e60b98b933e0fc6841698ddac67 GIT binary patch literal 1308 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAnN?apKg7ec#$`gxH85~pclTsBt za}(23gHjVyDhp4h+AuIMt7V2nltlRYSS9D@>Lr5I=vCwv0Ch7k*w|MTBqnF4mMA2p zrf25aD!t#mUr8Y|#a1cY)Yrhbz&SM|)1#^=HMq(zB)KX(*)m1R-cG@$!U||WZfZ%Q zLPc&)Ua?h$trFN=Dz9|8 z>y;bpKhp88yV>WRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<-In3$Ab zT4JjNbScCOxdm`z^NOLt1Pn0!io^naLp=kKmtYEgeeo;J&4sHjE(uCSxEHIz#UYgi zsro^w#rdU0$-sz9QwCX8VC7ttnpl!w6q28x0}I7~jQo=P;*9(P1!reas97jzglFcZ z12bv3duGcJdP9C8bQHoK%2WtOF;xE1B+DuBIhm5JLe z&N$73>P^Az78jg)^?{Dj2SqMYWW$7jDG0=bCtV;1p7>MqfGNHRn6zK^f9z&pVC?a9 zaSW-rmGtNTe|zS&jKa*a46!O=R0koXr7Mcj2q1a^w}S&Whkv=Oj0#rwr5&dwIEf#U`A^ar%?vmqXdoJf*s$P zK2~c;OIz?A(JuHYHeGd6MvdeOM+I+@3r`%Tydo{-?$a-u^su}u!CQO zH{uF6b91k>M2ddL*`6kcJN-wdGdxmK5MzDh?ocDoUdOjZqc_6as4;@ocMVrZWy6e_ z0ngOTc3j!ev60bmh04@pf-wpoxFurFdvprtG)T^Bxms|do}DdR`NAUUDG^Lwp-Wk= zG(1`}N5cCX!$!HNn!U|xi2*AW+LtHH@zU5)vEYl4#xb^E9hzYi&NM|A$wnP(=$h#1 z@TYysCT$KJp00i_>zopr04ad7(EtDd literal 0 HcmV?d00001 diff --git a/assets/images/login/more_icon.png b/assets/images/login/more_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b696d345a329b1fc4d647bf3802be648ecea8b66 GIT binary patch literal 488 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 localizedValues = { 'en': "There is no Chief Complaint", 'ar': "ليس هناك شكوى رئيس" }, + "more-verify": { + "en": "More Verification Options", + "ar": "المزيد من خيارات التحقق" + }, + "welcome-back": {"en": "Welcome back!", "ar": "مرحبا بعودتك!"}, + "account-info": { + "en": "Would you like to login with current username?", + "ar": "هل ترغب في تسجيل الدخول باسم المستخدم الحالي؟" + }, + "another-acc": {"en": "Use Another Account", "ar": "استخدم حسابا آخر"}, + "verify-login-with": { + "en": "Please choose one of the following options to verify", + "ar": "الرجاء اختيار احدى الخيارات التالية للتحقق من البيانات" + }, + "register-user": {"en": "Register", "ar": "تسجيل"}, + "verify-with-fingerprint": {"en": "Fingerprint", "ar": "بصمة"}, + "verify-with-faceid": {"en": "Face ID", "ar": "معرف الوجه"}, + "verify-with-sms": {"en": "SMS", "ar": "الرسائل القصيرة"}, + "verify-with-whatsapp": {"en": "Whatsapp", "ar": " الواتس اب"}, + "last-login": {"en": "LAST LOGIN AT:", "ar": "آخر تسجيل دخول"}, + "last-login-with": {"en": "VERIFICATION TYPE:", "ar": "نوع التحقق:"}, + "verify-fingerprint": { + "en": + "To activate the fingerprint login service, please verify data by using one of the following options.", + "ar": + "لتفعيل خدمة الدخول بالبصمة، يرجى اختيار احدى القنوات التالية للتحقق من البيانات" + }, + "verification_message": { + "en": "Please enter the Verification Code sent to", + "ar": "الرجاء ادخال رمز التحقق الذي تم إرساله إلى" + }, + "validation_message": { + "en": "The verification code expires in", + "ar": "تنتهي صلاحية رمز التحقق خلال" + }, }; diff --git a/lib/config/shared_pref_kay.dart b/lib/config/shared_pref_kay.dart index e483c7d1..1520207f 100644 --- a/lib/config/shared_pref_kay.dart +++ b/lib/config/shared_pref_kay.dart @@ -10,3 +10,5 @@ final DOCTOR_PROFILE = 'doctorProfile'; final LIVE_CARE_PATIENT = 'livecare-patient-profile'; final LOGGED_IN_USER = 'loggedUser'; final DASHBOARD_DATA = 'dashboard-data'; +final OTP_TYPE = 'otp-type'; +final LAST_LOGIN_USER = 'last-login-user'; diff --git a/lib/core/model/imei_details.dart b/lib/core/model/imei_details.dart new file mode 100644 index 00000000..2cb0cd97 --- /dev/null +++ b/lib/core/model/imei_details.dart @@ -0,0 +1,88 @@ +class GetIMEIDetailsModel { + String iMEI; + int logInTypeID; + bool outSA; + String mobile; + String identificationNo; + int doctorID; + String doctorName; + String doctorNameN; + int clinicID; + String clinicDescription; + String clnicDescriptionN; + String projectName; + String genderDescription; + String genderDescriptionN; + String titleDescription; + String titleDescriptionN; + bool biometricEnabled; + int preferredLanguage; + bool isActive; + + GetIMEIDetailsModel( + {this.iMEI, + this.logInTypeID, + this.outSA, + this.mobile, + this.identificationNo, + this.doctorID, + this.doctorName, + this.doctorNameN, + this.clinicID, + this.clinicDescription, + this.clnicDescriptionN, + this.projectName, + this.genderDescription, + this.genderDescriptionN, + this.titleDescription, + this.titleDescriptionN, + this.biometricEnabled, + this.preferredLanguage, + this.isActive}); + + GetIMEIDetailsModel.fromJson(Map json) { + iMEI = json['IMEI']; + logInTypeID = json['LogInTypeID']; + outSA = json['OutSA']; + mobile = json['Mobile']; + identificationNo = json['IdentificationNo']; + doctorID = json['DoctorID']; + doctorName = json['DoctorName']; + doctorNameN = json['DoctorNameN']; + clinicID = json['ClinicID']; + clinicDescription = json['ClinicDescription']; + clnicDescriptionN = json['ClnicDescriptionN']; + projectName = json['ProjectName']; + genderDescription = json['Gender_Description']; + genderDescriptionN = json['Gender_DescriptionN']; + titleDescription = json['Title_Description']; + titleDescriptionN = json['Title_DescriptionN']; + biometricEnabled = json['BiometricEnabled']; + preferredLanguage = json['PreferredLanguage']; + isActive = json['IsActive']; + } + + Map toJson() { + final Map data = new Map(); + data['IMEI'] = this.iMEI; + data['LogInTypeID'] = this.logInTypeID; + data['OutSA'] = this.outSA; + data['Mobile'] = this.mobile; + data['IdentificationNo'] = this.identificationNo; + data['DoctorID'] = this.doctorID; + data['DoctorName'] = this.doctorName; + data['DoctorNameN'] = this.doctorNameN; + data['ClinicID'] = this.clinicID; + data['ClinicDescription'] = this.clinicDescription; + data['ClnicDescriptionN'] = this.clnicDescriptionN; + data['ProjectName'] = this.projectName; + data['Gender_Description'] = this.genderDescription; + data['Gender_DescriptionN'] = this.genderDescriptionN; + data['Title_Description'] = this.titleDescription; + data['Title_DescriptionN'] = this.titleDescriptionN; + data['BiometricEnabled'] = this.biometricEnabled; + data['PreferredLanguage'] = this.preferredLanguage; + data['IsActive'] = this.isActive; + return data; + } +} diff --git a/lib/core/model/insert_imei_model.dart b/lib/core/model/insert_imei_model.dart new file mode 100644 index 00000000..c2285d92 --- /dev/null +++ b/lib/core/model/insert_imei_model.dart @@ -0,0 +1,92 @@ +class InsertIMEIDetailsModel { + String iMEI; + int logInTypeID; + bool outSA; + String mobileNo; + String identificationNo; + int doctorID; + String doctorName; + String doctorNameN; + int clinicID; + String clinicDescription; + String clinicDescriptionN; + String projectName; + int projectID; + String genderDescription; + String genderDescriptionN; + String titleDescription; + String titleDescriptionN; + bool bioMetricEnabled; + int preferredLanguage; + bool isActive; + + InsertIMEIDetailsModel( + {this.iMEI, + this.logInTypeID, + this.outSA, + this.mobileNo, + this.identificationNo, + this.doctorID, + this.doctorName, + this.doctorNameN, + this.clinicID, + this.clinicDescription, + this.clinicDescriptionN, + this.projectName, + this.projectID, + this.genderDescription, + this.genderDescriptionN, + this.titleDescription, + this.titleDescriptionN, + this.bioMetricEnabled, + this.preferredLanguage, + this.isActive}); + + InsertIMEIDetailsModel.fromJson(Map json) { + iMEI = json['IMEI']; + logInTypeID = json['LogInTypeID']; + outSA = json['OutSA']; + mobileNo = json['MobileNo']; + identificationNo = json['IdentificationNo']; + doctorID = json['DoctorID']; + doctorName = json['DoctorName']; + doctorNameN = json['DoctorNameN']; + clinicID = json['ClinicID']; + clinicDescription = json['ClinicDescription']; + clinicDescriptionN = json['ClinicDescriptionN']; + projectName = json['ProjectName']; + projectID = json['ProjectID']; + genderDescription = json['GenderDescription']; + genderDescriptionN = json['GenderDescriptionN']; + titleDescription = json['TitleDescription']; + titleDescriptionN = json['TitleDescriptionN']; + bioMetricEnabled = json['BioMetricEnabled']; + preferredLanguage = json['PreferredLanguage']; + isActive = json['IsActive']; + } + + Map toJson() { + final Map data = new Map(); + data['IMEI'] = this.iMEI; + data['LogInTypeID'] = this.logInTypeID; + data['OutSA'] = this.outSA; + data['MobileNo'] = this.mobileNo; + data['IdentificationNo'] = this.identificationNo; + data['DoctorID'] = this.doctorID; + data['DoctorName'] = this.doctorName; + data['DoctorNameN'] = this.doctorNameN; + data['ClinicID'] = this.clinicID; + data['ClinicDescription'] = this.clinicDescription; + data['ClinicDescriptionN'] = this.clinicDescriptionN; + data['ProjectName'] = this.projectName; + data['ProjectID'] = this.projectID; + data['GenderDescription'] = this.genderDescription; + data['GenderDescriptionN'] = this.genderDescriptionN; + data['TitleDescription'] = this.titleDescription; + data['TitleDescriptionN'] = this.titleDescriptionN; + data['BioMetricEnabled'] = this.bioMetricEnabled; + data['PreferredLanguage'] = this.preferredLanguage; + data['IsActive'] = this.isActive; + return data; + } +} diff --git a/lib/core/service/auth_service.dart b/lib/core/service/auth_service.dart new file mode 100644 index 00000000..e116ccdd --- /dev/null +++ b/lib/core/service/auth_service.dart @@ -0,0 +1,29 @@ +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/core/model/imei_details.dart'; +import 'package:doctor_app_flutter/core/service/base/base_service.dart'; +import 'package:doctor_app_flutter/models/dashboard/dashboard_model.dart'; + +class AuthService extends BaseService { + List _imeiDetails = []; + List get dashboardItemsList => _imeiDetails; + + Future selectDeviceImei(imei) async { + try { + // dynamic localRes; + await baseAppClient.post(SELECT_DEVICE_IMEI, + onSuccess: (dynamic response, int statusCode) { + _imeiDetails = []; + response['List_DoctorDeviceDetails'].forEach((v) { + _imeiDetails.add(GetIMEIDetailsModel.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: {"IMEI": imei, "TokenID": "@dm!n"}); + //return Future.value(localRes); + } catch (error) { + hasError = true; + super.error = error; + } + } +} diff --git a/lib/core/service/medicine_service.dart b/lib/core/service/medicine_service.dart index df23172f..f205dab1 100644 --- a/lib/core/service/medicine_service.dart +++ b/lib/core/service/medicine_service.dart @@ -14,7 +14,6 @@ class MedicineService extends BaseService { PharmaciesItemsRequestModel(); PharmaciesListRequestModel _listRequestModel = PharmaciesListRequestModel(); - Future getMedicineItem(String itemName) async { _itemsRequestModel.pHRItemName = itemName; await baseAppClient.post( diff --git a/lib/core/viewModel/auth_view_model.dart b/lib/core/viewModel/auth_view_model.dart index 47ffe730..00089ef9 100644 --- a/lib/core/viewModel/auth_view_model.dart +++ b/lib/core/viewModel/auth_view_model.dart @@ -1,4 +1,10 @@ import 'package:doctor_app_flutter/client/base_app_client.dart'; +import 'package:doctor_app_flutter/core/enum/viewstate.dart'; +import 'package:doctor_app_flutter/core/model/imei_details.dart'; +import 'package:doctor_app_flutter/core/model/insert_imei_model.dart'; +import 'package:doctor_app_flutter/core/service/auth_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart'; +import 'package:doctor_app_flutter/locator.dart'; import 'package:doctor_app_flutter/models/auth/activation_Code_req_model.dart'; import 'package:doctor_app_flutter/models/auth/check_activation_code_request_model.dart'; import 'package:doctor_app_flutter/models/doctor/clinic_model.dart'; @@ -12,8 +18,9 @@ import '../../models/doctor/user_model.dart'; DrAppSharedPreferances sharedPref = new DrAppSharedPreferances(); enum APP_STATUS { LOADING, UNAUTHENTICATED, AUTHENTICATED } -class AuthViewModel with ChangeNotifier { +class AuthViewModel extends BaseViewModel { List doctorsClinicList = []; + String selectedClinicName; bool isLogin = false; bool isLoading = true; @@ -71,35 +78,29 @@ class AuthViewModel with ChangeNotifier { } } - Future insertDeviceImei(imei) async { - try { - dynamic localRes; - - await baseAppClient.post(INSERT_DEVICE_IMEI, - onSuccess: (dynamic response, int statusCode) { - localRes = response; - }, onFailure: (String error, int statusCode) { - throw error; - }, body: imei); - return Future.value(localRes); - } catch (error) { - print(error); - throw error; - } - } + Future insertDeviceImei(request) async { + var loggedIn = await sharedPref.getObj(LOGGED_IN_USER); + + request['IMEI'] = DEVICE_TOKEN; + request['LogInTypeID'] = await sharedPref.getInt(OTP_TYPE); + request['BioMetricEnabled'] = true; + request['MobileNo'] = loggedIn['MobileNumber']; + InsertIMEIDetailsModel nRequest = InsertIMEIDetailsModel.fromJson(request); + nRequest.genderDescription = request['Gender_Description']; + nRequest.genderDescriptionN = request['Gender_DescriptionN']; + nRequest.genderDescriptionN = request['Gender_DescriptionN']; + nRequest.titleDescription = request['Title_Description']; + nRequest.titleDescriptionN = request['Title_DescriptionN']; + nRequest.projectID = await sharedPref.getInt(PROJECT_ID); - Future selectDeviceImei(imei) async { try { - dynamic localRes; - await baseAppClient.post(SELECT_DEVICE_IMEI, + var localRes; + await baseAppClient.post(INSERT_DEVICE_IMEI, onSuccess: (dynamic response, int statusCode) { localRes = response; - }, onFailure: (String error, int statusCode) { - throw error; - }, body: imei); + }, onFailure: (String error, int statusCode) {}, body: nRequest.toJson()); return Future.value(localRes); } catch (error) { - print(error); throw error; } } @@ -120,7 +121,8 @@ class AuthViewModel with ChangeNotifier { } } - Future sendActivationCodeForDoctorApp(ActivationCodeModel activationCodeModel) async { + Future sendActivationCodeForDoctorApp( + ActivationCodeModel activationCodeModel) async { try { var localRes; await baseAppClient.post(SEND_ACTIVATION_CODE_FOR_DOCTOR_APP, @@ -158,22 +160,22 @@ class AuthViewModel with ChangeNotifier { } } - - Future checkActivationCodeForDoctorApp(CheckActivationCodeRequestModel checkActivationCodeRequestModel) async { + Future checkActivationCodeForDoctorApp( + CheckActivationCodeRequestModel checkActivationCodeRequestModel) async { try { dynamic localRes; await baseAppClient.post(CHECK_ACTIVATION_CODE_FOR_DOCTOR_APP, onSuccess: (dynamic response, int statusCode) { - localRes = response; - selectedClinicName = - ClinicModel.fromJson(response['List_DoctorsClinic'][0]).clinicName; - - response['List_DoctorsClinic'].forEach((v) { - doctorsClinicList.add(new ClinicModel.fromJson(v)); - }); - }, onFailure: (String error, int statusCode) { - throw error; - }, body: checkActivationCodeRequestModel.toJson()); + localRes = response; + selectedClinicName = + ClinicModel.fromJson(response['List_DoctorsClinic'][0]).clinicName; + + response['List_DoctorsClinic'].forEach((v) { + doctorsClinicList.add(new ClinicModel.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + throw error; + }, body: checkActivationCodeRequestModel.toJson()); return Future.value(localRes); } catch (error) { print(error); diff --git a/lib/core/viewModel/imei_view_model.dart b/lib/core/viewModel/imei_view_model.dart new file mode 100644 index 00000000..29253b1d --- /dev/null +++ b/lib/core/viewModel/imei_view_model.dart @@ -0,0 +1,21 @@ +import 'package:doctor_app_flutter/client/base_app_client.dart'; +import 'package:doctor_app_flutter/core/enum/viewstate.dart'; +import 'package:doctor_app_flutter/core/model/imei_details.dart'; +import 'package:doctor_app_flutter/core/service/auth_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart'; +import 'package:doctor_app_flutter/locator.dart'; + +class IMEIViewModel extends BaseViewModel { + AuthService _authService = locator(); + List get imeiDetails => _authService.dashboardItemsList; + + Future selectDeviceImei(imei) async { + setState(ViewState.Busy); + await _authService.selectDeviceImei(imei); + if (_authService.hasError) { + error = _authService.error; + setState(ViewState.Error); + } else + setState(ViewState.Idle); + } +} diff --git a/lib/core/viewModel/project_view_model.dart b/lib/core/viewModel/project_view_model.dart index 1448fb47..aed67d83 100644 --- a/lib/core/viewModel/project_view_model.dart +++ b/lib/core/viewModel/project_view_model.dart @@ -24,6 +24,7 @@ class ProjectViewModel with ChangeNotifier { List doctorClinicsList = []; bool isLoading = false; bool isError = false; + bool isLogin = false; String error = ''; BaseAppClient baseAppClient = BaseAppClient(); @@ -56,7 +57,9 @@ class ProjectViewModel with ChangeNotifier { currentLanguage = await sharedPref.getString(APP_Language); _appLocale = Locale(currentLanguage ?? 'en'); _isArabic = currentLanguage != null - ? currentLanguage == 'ar' ? true : false + ? currentLanguage == 'ar' + ? true + : false : false; notifyListeners(); } @@ -69,7 +72,7 @@ class ProjectViewModel with ChangeNotifier { sharedPref.setString(APP_Language, 'ar'); } else if (lan != "ar" && currentLanguage != lan) { _appLocale = Locale("en"); - _isArabic = false; + _isArabic = false; currentLanguage = 'en'; sharedPref.setString(APP_Language, 'en'); } diff --git a/lib/locator.dart b/lib/locator.dart index a4ca7289..f939effc 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -1,10 +1,13 @@ +import 'package:doctor_app_flutter/core/service/auth_service.dart'; import 'package:doctor_app_flutter/core/service/dasboard_service.dart'; import 'package:doctor_app_flutter/core/service/medical_file_service.dart'; import 'package:doctor_app_flutter/core/service/patient_service.dart'; import 'package:doctor_app_flutter/core/service/prescription_service.dart'; import 'package:doctor_app_flutter/core/service/procedure_service.dart'; import 'package:doctor_app_flutter/core/service/sickleave_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/auth_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/dashboard_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/imei_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/medical_file_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/patient_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/prescription_view_model.dart'; @@ -54,9 +57,11 @@ void setupLocator() { locator.registerLazySingleton(() => MedicalFileService()); locator.registerLazySingleton(() => AdmissionRequestService()); locator.registerLazySingleton(() => UcafService()); + locator.registerLazySingleton(() => AuthService()); /// View Model locator.registerFactory(() => DoctorReplayViewModel()); + locator.registerFactory(() => IMEIViewModel()); locator.registerFactory(() => ScheduleViewModel()); locator.registerFactory(() => ReferralPatientViewModel()); locator.registerFactory(() => ReferredPatientViewModel()); diff --git a/lib/main.dart b/lib/main.dart index 3df44a70..1283da1e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -41,32 +41,31 @@ class MyApp extends StatelessWidget { ), ], child: Consumer( - builder: (context,projectProvider,child) => MaterialApp( - showSemanticsDebugger: false, - title: 'Flutter Demo', - locale: projectProvider.appLocal, - localizationsDelegates: [ - TranslationBaseDelegate(), - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - supportedLocales: [ - const Locale('ar', ''), // Arabic - const Locale('en', ''), // English - ], - theme: ThemeData( - primarySwatch: Colors.grey, - primaryColor: Colors.grey, - buttonColor: HexColor('#B8382C'), - fontFamily: 'WorkSans', - dividerColor: Colors.grey[350], - backgroundColor: Color.fromRGBO(255,255,255, 1), - ), - initialRoute: INIT_ROUTE, - routes: routes, - debugShowCheckedModeBanner: false, - ) - ), + builder: (context, projectProvider, child) => MaterialApp( + showSemanticsDebugger: false, + title: 'Flutter Demo', + locale: projectProvider.appLocal, + localizationsDelegates: [ + TranslationBaseDelegate(), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: [ + const Locale('ar', ''), // Arabic + const Locale('en', ''), // English + ], + theme: ThemeData( + primarySwatch: Colors.grey, + primaryColor: Colors.grey, + buttonColor: HexColor('#B8382C'), + fontFamily: 'WorkSans', + dividerColor: Colors.grey[350], + backgroundColor: Color.fromRGBO(255, 255, 255, 1), + ), + initialRoute: INIT_ROUTE, + routes: routes, + debugShowCheckedModeBanner: false, + )), ); }); }, diff --git a/lib/models/auth/activation_Code_req_model.dart b/lib/models/auth/activation_Code_req_model.dart index f8f48cd8..1a9510e8 100644 --- a/lib/models/auth/activation_Code_req_model.dart +++ b/lib/models/auth/activation_Code_req_model.dart @@ -8,17 +8,18 @@ class ActivationCodeModel { String password; int facilityId; String generalid; - + String otpSendType; ActivationCodeModel( {this.mobileNumber, - this.zipCode, - this.channel, - this.languageID, - this.versionID, - this.memberID, - this.password, - this.facilityId, - this.generalid}); + this.zipCode, + this.channel, + this.languageID, + this.versionID, + this.memberID, + this.password, + this.facilityId, + this.otpSendType, + this.generalid}); ActivationCodeModel.fromJson(Map json) { mobileNumber = json['MobileNumber']; @@ -29,6 +30,7 @@ class ActivationCodeModel { memberID = json['MemberID']; password = json['Password']; facilityId = json['facilityId']; + otpSendType = json['OTP_SendType']; generalid = json['generalid']; } @@ -42,6 +44,7 @@ class ActivationCodeModel { data['MemberID'] = this.memberID; data['Password'] = this.password; data['facilityId'] = this.facilityId; + data['OTP_SendType'] = otpSendType; data['generalid'] = this.generalid; return data; } diff --git a/lib/models/auth/check_activation_code_request_model.dart b/lib/models/auth/check_activation_code_request_model.dart index 856f1c43..9bb3d4f6 100644 --- a/lib/models/auth/check_activation_code_request_model.dart +++ b/lib/models/auth/check_activation_code_request_model.dart @@ -12,21 +12,22 @@ class CheckActivationCodeRequestModel { String activationCode; String vidaAuthTokenID; String vidaRefreshTokenID; - + int oTPSendType; CheckActivationCodeRequestModel( {this.mobileNumber, - this.zipCode, - this.doctorID, - this.iPAdress, - this.channel, - this.languageID, - this.projectID, - this.versionID, - this.generalid, - this.logInTokenID, - this.activationCode, - this.vidaAuthTokenID, - this.vidaRefreshTokenID}); + this.zipCode, + this.doctorID, + this.iPAdress, + this.channel, + this.languageID, + this.projectID, + this.versionID, + this.generalid, + this.logInTokenID, + this.activationCode, + this.vidaAuthTokenID, + this.vidaRefreshTokenID, + this.oTPSendType}); CheckActivationCodeRequestModel.fromJson(Map json) { mobileNumber = json['MobileNumber']; @@ -42,6 +43,7 @@ class CheckActivationCodeRequestModel { activationCode = json['activationCode']; vidaAuthTokenID = json['VidaAuthTokenID']; vidaRefreshTokenID = json['VidaRefreshTokenID']; + oTPSendType = json['OTP_SendType']; } Map toJson() { @@ -59,6 +61,7 @@ class CheckActivationCodeRequestModel { data['activationCode'] = this.activationCode; data['VidaAuthTokenID'] = this.vidaAuthTokenID; data['VidaRefreshTokenID'] = this.vidaRefreshTokenID; + data['OTP_SendType'] = this.oTPSendType; return data; } } diff --git a/lib/screens/auth/login_screen.dart b/lib/screens/auth/login_screen.dart index 5b495abb..1ed441e4 100644 --- a/lib/screens/auth/login_screen.dart +++ b/lib/screens/auth/login_screen.dart @@ -1,7 +1,17 @@ import 'dart:async'; +import 'dart:io'; import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; +import 'package:doctor_app_flutter/core/service/auth_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/auth_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/imei_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/screens/auth/verification_methods_screen.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../lookups/auth_lookup.dart'; @@ -23,21 +33,48 @@ class _LoginsreenState extends State { Future _prefs = SharedPreferences.getInstance(); String platformImei; - Future platformImeiFuture; - - bool _isLoading = false; - - Future getSharedPref() async { - sharedPref.getString('platformImei').then((imei) { - platformImei = imei; - }); - } - + // Future platformImeiFuture; + final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); + bool _isLoading = true; + ProjectViewModel projectViewModel; + AuthService authService = AuthService(); @override void initState() { super.initState(); - platformImeiFuture = _prefs.then((SharedPreferences prefs) { - return (prefs.getString('platformImei')); + + _firebaseMessaging.setAutoInitEnabled(true); + if (Platform.isIOS) { + _firebaseMessaging.requestNotificationPermissions(); + } + + _firebaseMessaging.getToken().then((String token) async { + if (DEVICE_TOKEN == "" && projectViewModel.isLogin == false) { + DEVICE_TOKEN = token; + changeLoadingStata(true); + authService.selectDeviceImei(DEVICE_TOKEN).then((value) { + print(authService.dashboardItemsList); + + if (authService.dashboardItemsList.length > 0) { + sharedPref.setObj( + LAST_LOGIN_USER, authService.dashboardItemsList[0]); + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (BuildContext context) => VerificationMethodsScreen( + password: null, + ))); + } else { + changeLoadingStata(false); + } + //changeLoadingStata(false); + }); + } else { + changeLoadingStata(false); + } + + // else if (projectViewModel.isLogin) { + // getNotificationCount(token); + // } + }).catchError((err) { + print(err); }); } @@ -56,54 +93,46 @@ class _LoginsreenState extends State { @override Widget build(BuildContext context) { - getSharedPref(); - return AppScaffold( - isLoading: _isLoading, - isShowAppBar: false, - body: SafeArea( - child: ListView(children: [ - FutureBuilder( - future: platformImeiFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return DrAppCircularProgressIndeicator(); - default: - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return Container( - margin: EdgeInsetsDirectional.fromSTEB(30, 0, 30, 30), - alignment: Alignment.topLeft, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - (platformImei == null) - ? Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - AuthHeader(loginType.knownUser), - LoginForm( - changeLoadingStata: - changeLoadingStata, - ), - ], - ) - : Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - AuthHeader(loginType.unknownUser), - KnownUserLogin(), - ], + projectViewModel = Provider.of(context); + + return BaseView( + onModelReady: (model) => {}, + builder: (_, model, w) => AppScaffold( + baseViewModel: model, + isShowAppBar: false, + body: SafeArea( + child: (_isLoading == false) + ? ListView(children: [ + Container( + margin: + EdgeInsetsDirectional.fromSTEB(30, 0, 30, 30), + alignment: Alignment.topLeft, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + AuthHeader(loginType.knownUser), + LoginForm( + changeLoadingStata: changeLoadingStata, ), - ])); - } - } - }), - ]), - ), - ); + ], + ) + + // : Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // AuthHeader(loginType.unknownUser), + // KnownUserLogin(), + // ], + // ), + ])) + ]) + : Center(child: CircularProgressIndicator()), + ), + )); } } diff --git a/lib/screens/auth/verification_methods_screen.dart b/lib/screens/auth/verification_methods_screen.dart index 2b411dc0..0045f032 100644 --- a/lib/screens/auth/verification_methods_screen.dart +++ b/lib/screens/auth/verification_methods_screen.dart @@ -42,7 +42,7 @@ class _VerificationMethodsScreenState extends State { Widget build(BuildContext context) { return AppScaffold( isLoading: _isLoading, - isShowAppBar: false, + isShowAppBar: false, body: ListView(children: [ Container( margin: EdgeInsetsDirectional.fromSTEB(30, 0, 30, 0), diff --git a/lib/screens/dashboard_screen.dart b/lib/screens/dashboard_screen.dart index 20f22382..adc912d6 100644 --- a/lib/screens/dashboard_screen.dart +++ b/lib/screens/dashboard_screen.dart @@ -1,3 +1,4 @@ +import 'package:doctor_app_flutter/config/config.dart'; import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; import 'package:doctor_app_flutter/config/size_config.dart'; import 'package:doctor_app_flutter/core/viewModel/dashboard_view_model.dart'; @@ -58,6 +59,14 @@ class _DashboardScreenState extends State { if (_isInit) { projectsProvider = Provider.of(context); projectsProvider.getDoctorClinicsList(); + + if (DEVICE_TOKEN != '') { + var request = await sharedPref.getObj(DOCTOR_PROFILE); + authProvider.insertDeviceImei(request).then((value) { + print(value['ReturnValue']); + changeIsLoading(false); + }); + } } _isInit = false; } diff --git a/lib/screens/reschedule-leaves/reschedule_leave.dart b/lib/screens/reschedule-leaves/reschedule_leave.dart index 6f3299d1..5d546c04 100644 --- a/lib/screens/reschedule-leaves/reschedule_leave.dart +++ b/lib/screens/reschedule-leaves/reschedule_leave.dart @@ -792,7 +792,7 @@ class _RescheduleLeaveScreen extends State { "doctorId": this.profile['DoctorID'], "dateTimeFrom": fromDate, "dateTimeTo": toDate, - "date": df.format(DateTime.now()), + "date": offTime == '1' ? fromDate : df.format(DateTime.now()), "reasonId": reason == null ? model.allOffTime[0]['code'] : reason, "coveringDoctorId": doctorID == null ? model.coveringDoctors[0]['doctorID'] : doctorID, @@ -846,7 +846,7 @@ class _RescheduleLeaveScreen extends State { "doctorId": this.profile['DoctorID'], "dateTimeFrom": fromDate, "dateTimeTo": toDate, - "date": df.format(DateTime.now()), + "date": offTime == '1' ? fromDate : df.format(DateTime.now()), "reasonId": reason == null ? model.allOffTime[0]['code'] : reason, "coveringDoctorId": doctorID == null ? model.coveringDoctors[0]['doctorID'] : doctorID, diff --git a/lib/util/helpers.dart b/lib/util/helpers.dart index 9a398949..a7229ca2 100644 --- a/lib/util/helpers.dart +++ b/lib/util/helpers.dart @@ -346,15 +346,17 @@ class Helpers { } logout() async { + DEVICE_TOKEN = ""; String lang = await sharedPref.getString(APP_Language); await clearSharedPref(); sharedPref.setString(APP_Language, lang); Navigator.of(AppGlobal.CONTEX).pushReplacementNamed(LOGIN); + // TODO Fix it // Navigator.of(AppGlobal.CONTEX).popUntil((ModalRoute.withName(LOGIN))); } - String parseHtmlString(String htmlString) { + String parseHtmlString(String htmlString) { final document = parse(htmlString); final String parsedString = parse(document.body.text).documentElement.text; @@ -380,11 +382,11 @@ class Helpers { hintText: selectedText != null ? selectedText : hintText, suffixIcon: isDropDown ? suffixIcon != null - ? suffixIcon - : Icon( - Icons.arrow_drop_down, - color: dropDownColor != null ? dropDownColor : Colors.black, - ) + ? suffixIcon + : Icon( + Icons.arrow_drop_down, + color: dropDownColor != null ? dropDownColor : Colors.black, + ) : null, hintStyle: TextStyle( fontSize: 14, @@ -394,7 +396,8 @@ class Helpers { } static BoxDecoration containerBorderDecoration( - Color containerColor, Color borderColor, {double borderWidth = -1}) { + Color containerColor, Color borderColor, + {double borderWidth = -1}) { return BoxDecoration( color: containerColor, shape: BoxShape.rectangle, diff --git a/lib/util/translations_delegate_base.dart b/lib/util/translations_delegate_base.dart index b167b48e..600b5f33 100644 --- a/lib/util/translations_delegate_base.dart +++ b/lib/util/translations_delegate_base.dart @@ -544,15 +544,60 @@ class TranslationBase { localizedValues['referralEmptyMsg'][locale.languageCode]; String get referralSuccessMsg => localizedValues['referralSuccessMsg'][locale.languageCode]; - String get diagnoseType => localizedValues['diagnoseType'][locale.languageCode]; + String get diagnoseType => + localizedValues['diagnoseType'][locale.languageCode]; String get condition => localizedValues['condition'][locale.languageCode]; String get id => localizedValues['id'][locale.languageCode]; String get quantity => localizedValues['quantity'][locale.languageCode]; String get codeNo => localizedValues['codeNo'][locale.languageCode]; String get covered => localizedValues['covered'][locale.languageCode]; - String get approvalRequired => localizedValues['approvalRequired'][locale.languageCode]; - String get uncoveredByDoctor => localizedValues['uncoveredByDoctor'][locale.languageCode]; - String get chiefComplaintEmptyMsg => localizedValues['chiefComplaintEmptyMsg'][locale.languageCode]; + String get approvalRequired => + localizedValues['approvalRequired'][locale.languageCode]; + String get uncoveredByDoctor => + localizedValues['uncoveredByDoctor'][locale.languageCode]; + String get chiefComplaintEmptyMsg => + localizedValues['chiefComplaintEmptyMsg'][locale.languageCode]; + + String get moreVerification => + localizedValues['more-verify'][locale.languageCode]; + + String get welcomeBack => + localizedValues['welcome-back'][locale.languageCode]; + + String get accountInfo => + localizedValues['account-info'][locale.languageCode]; + + String get useAnotherAccount => + localizedValues['another-acc'][locale.languageCode]; + + String get verifyLoginWith => + localizedValues['verify-login-with'][locale.languageCode]; + + String get register => localizedValues['register-user'][locale.languageCode]; + + String get verifyFingerprint => + localizedValues['verify-with-fingerprint'][locale.languageCode]; + + String get verifyFaceID => + localizedValues['verify-with-faceid'][locale.languageCode]; + + String get verifySMS => + localizedValues['verify-with-sms'][locale.languageCode]; + + String get verifyWhatsApp => + localizedValues['verify-with-whatsapp'][locale.languageCode]; + + String get lastLoginAt => localizedValues['last-login'][locale.languageCode]; + + String get lastLoginWith => + localizedValues['last-login-with'][locale.languageCode]; + + String get verifyFingerprint2 => + localizedValues['verify-fingerprint'][locale.languageCode]; + String get verificationMessage => + localizedValues['verification_message'][locale.languageCode]; + String get validationMessage => + localizedValues['validation_message'][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/auth/known_user_login.dart b/lib/widgets/auth/known_user_login.dart index 4df37d66..b181aed8 100644 --- a/lib/widgets/auth/known_user_login.dart +++ b/lib/widgets/auth/known_user_login.dart @@ -70,8 +70,8 @@ class _KnownUserLoginState extends State { @override Widget build(BuildContext context) { AuthViewModel authProv = Provider.of(context); - var imeiModel = {'IMEI': _platformImei}; - _loginTypeFuture = authProv.selectDeviceImei(imeiModel); + // var imeiModel = {'IMEI': _platformImei}; + // _loginTypeFuture = authProv.selectDeviceImei(imeiModel); return FutureBuilder( future: Future.wait([_loggedUserFuture, _loginTypeFuture]), builder: (BuildContext context, AsyncSnapshot snapshot) { diff --git a/lib/widgets/auth/login_form.dart b/lib/widgets/auth/login_form.dart index 808b1763..3aac5cdd 100644 --- a/lib/widgets/auth/login_form.dart +++ b/lib/widgets/auth/login_form.dart @@ -224,26 +224,29 @@ class _LoginFormState extends State { } login(context, AuthViewModel authProv, Function changeLoadingStata) { - FocusScopeNode currentFocus = FocusScope.of(context); - changeLoadingStata(true); + showLoading(); if (loginFormKey.currentState.validate()) { loginFormKey.currentState.save(); sharedPref.setInt(PROJECT_ID, userInfo.projectID); authProv.login(userInfo).then((res) { - changeLoadingStata(false); - + //changeLoadingStata(false); + hideLoading(); if (res['MessageStatus'] == 1) { // insertDeviceImei(res, authProv); saveObjToString(LOGGED_IN_USER, res); + sharedPref.remove(LAST_LOGIN_USER); sharedPref.setString(TOKEN, res['LogInTokenID']); print("token" + res['LogInTokenID']); - Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (BuildContext context) => VerificationMethodsScreen(password: userInfo.password,))); + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (BuildContext context) => VerificationMethodsScreen( + password: userInfo.password, + ))); } else { // handel error helpers.showErrorToast(res['ErrorEndUserMessage']); } }).catchError((err) { - print('$err'); + hideLoading(); changeLoadingStata(false); helpers.showErrorToast(err); }); @@ -273,7 +276,11 @@ class _LoginFormState extends State { if (res['MessageStatus'] == 1) { setSharedPref('platformImei', _platformImei); saveObjToString(LOGGED_IN_USER, preRes); - Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (BuildContext context) => VerificationMethodsScreen(password: userInfo.password,))); + + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (BuildContext context) => VerificationMethodsScreen( + password: userInfo.password, + ))); // save imei on shared preferance } else { @@ -350,4 +357,18 @@ class _LoginFormState extends State { primaryFocus.unfocus(); } + + showLoading() { + showDialog( + context: context, + builder: (BuildContext context) { + return Center( + child: CircularProgressIndicator(), + ); + }); + } + + hideLoading() { + Navigator.pop(context); + } } diff --git a/lib/widgets/auth/verification_methods.dart b/lib/widgets/auth/verification_methods.dart index 32c541a3..0de81fdf 100644 --- a/lib/widgets/auth/verification_methods.dart +++ b/lib/widgets/auth/verification_methods.dart @@ -1,11 +1,22 @@ import 'dart:io' show Platform; import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; +import 'package:doctor_app_flutter/core/model/imei_details.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; import 'package:doctor_app_flutter/models/auth/activation_Code_req_model.dart'; -import 'package:doctor_app_flutter/screens/auth/verification_methods_screen.dart'; +import 'package:doctor_app_flutter/models/auth/check_activation_code_request_model.dart'; +import 'package:doctor_app_flutter/models/doctor/clinic_model.dart'; +import 'package:doctor_app_flutter/models/doctor/doctor_profile_model.dart'; +import 'package:doctor_app_flutter/models/doctor/profile_req_Model.dart'; import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/otp/sms-popup.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_button.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/rounded_container_widget.dart'; import 'package:flutter/material.dart'; -import 'package:hexcolor/hexcolor.dart'; +import 'package:flutter/services.dart'; +import 'package:intl/intl.dart'; +import 'package:local_auth/local_auth.dart'; import 'package:provider/provider.dart'; import '../../config/size_config.dart'; @@ -40,6 +51,17 @@ class _VerificationMethodsState extends State { Future _loggedUserFuture; var _loggedUser; var verificationMethod; + GetIMEIDetailsModel user; + final LocalAuthentication auth = LocalAuthentication(); + var _availableBiometrics; + ProjectViewModel projectsProvider; + var isMoreOption = false; + var onlySMSBox = false; + static BuildContext _context; + var loginTokenID; + + bool authenticated; + @override void initState() { super.initState(); @@ -50,6 +72,13 @@ class _VerificationMethodsState extends State { sharedPref.getObj(LOGGED_IN_USER).then((userInfo) { _loggedUser = userInfo; }); + sharedPref.getObj(LAST_LOGIN_USER).then((lastLogin) { + if (lastLogin != null) { + user = GetIMEIDetailsModel.fromJson(lastLogin); + } + }); + + print(user); } @override @@ -63,6 +92,7 @@ class _VerificationMethodsState extends State { @override Widget build(BuildContext context) { AuthViewModel authProv = Provider.of(context); + projectsProvider = Provider.of(context); return FutureBuilder( future: Future.wait([_loggedUserFuture]), builder: (BuildContext context, AsyncSnapshot snapshot) { @@ -75,66 +105,205 @@ class _VerificationMethodsState extends State { return Text('Error: ${snapshot.error}'); } else { return Container( - width: SizeConfig.realScreenWidth * 0.80, + width: SizeConfig.realScreenWidth, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - hideSilentMethods() - ? TranslationBase.of(context).firstStep - : TranslationBase.of(context).pleaseChoose, - style: TextStyle( - fontSize: 3.5 * SizeConfig.textMultiplier, - ), - ), - SizedBox( - height: 20, - ), Container( - height: SizeConfig.realScreenHeight * 0.6, - child: CustomScrollView( - primary: false, - slivers: [ - SliverPadding( - padding: const EdgeInsets.all(0), - sliver: SliverGrid.count( - // childAspectRatio: 0.7, - crossAxisSpacing: 0, - mainAxisSpacing: 5, - crossAxisCount: 2, - children: [ - Visibility( - visible: hideSilentMethods() ? false : true, - child: buildFingerprintMethod( - context, authProv), - replacement: - buildWhatsAppMethod(context, authProv), - ), - Visibility( - visible: hideSilentMethods() ? false : true, - child: buildFaceIDMethod(context, authProv), - replacement: - buildSMSMethod(context, authProv), - ), - Visibility( - visible: - hideSilentMethods() ? false : true, - child: buildWhatsAppMethod( - context, authProv)), - Visibility( - visible: hideSilentMethods() ? false : true, - child: buildSMSMethod(context, authProv), - ), - ], - ), - ), - ], - ), - // height: 500, - ), - SizedBox( - // height: 20, - ) + height: SizeConfig.realScreenHeight * 0.6, + child: Column( + children: [ + user != null && isMoreOption == false + ? Column( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context) + .welcomeBack + + ' ' + + user.doctorName, + fontSize: + SizeConfig.textMultiplier * 3.5, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context) + .accountInfo, + fontSize: + SizeConfig.textMultiplier * 2.5, + ), + SizedBox( + height: 20, + ), + Card( + color: Colors.grey[300], + child: Row( + children: [ + Flexible( + child: ListTile( + title: Text( + TranslationBase.of(context) + .lastLoginAt, + textAlign: TextAlign.center, + overflow: + TextOverflow.ellipsis, + ), + subtitle: Text( + // user. != null + // ? formatDate(Helpers + // .convertStringToDate( + // user + // .)) + // : user != + // null + // ? formatDate(Helpers + // .convertStringToDate(user + // .createdOn)) + //: + '--', + overflow: + TextOverflow.ellipsis, + textAlign: + TextAlign.center), + )), + Flexible( + child: ListTile( + title: Text( + TranslationBase.of( + context) + .lastLoginWith, + overflow: + TextOverflow.ellipsis, + textAlign: + TextAlign.center), + subtitle: Text( + getType(user.logInTypeID, + context), + overflow: + TextOverflow.ellipsis, + textAlign: + TextAlign.center), + )) + ], + )), + ], + ) + : Column( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + this.onlySMSBox == false + ? AppText( + TranslationBase.of(context) + .verifyLoginWith, + fontSize: SizeConfig + .textMultiplier * + 3.5, + textAlign: TextAlign.left, + ) + : AppText( + TranslationBase.of(context) + .verifyFingerprint2, + fontSize: SizeConfig + .textMultiplier * + 2.5, + textAlign: TextAlign.start, + ), + ]), + user != null && isMoreOption == false + ? Column( + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Expanded( + child: InkWell( + onTap: () => { + authenticateUser( + 3, + BiometricType + .face + .index, + authProv) + }, + child: getButton( + user.logInTypeID, + authProv))), + Expanded( + child: + getButton(5, authProv)) + ]) + ]) + : Column( + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + onlySMSBox == false + ? Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Expanded( + child: getButton( + 3, authProv)), + Expanded( + child: getButton( + 2, authProv)) + ], + ) + : SizedBox(), + Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Expanded( + child: + getButton(1, authProv)), + Expanded( + child: getButton(4, authProv)) + ], + ), + ]), + Expanded( + flex: 1, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + user != null + ? Row( + children: [ + Expanded( + child: Button( + title: + TranslationBase.of(context) + .useAnotherAccount, + onTap: () { + Navigator.of(context) + .pushNamed(LOGIN); + }, + )), + ], + ) + : SizedBox(), + ], + ), + ) + ], + )) ], ), ); @@ -143,119 +312,6 @@ class _VerificationMethodsState extends State { }); } - /* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: buildSMSMethod Methods widget - */ - Center buildSMSMethod(BuildContext context, AuthViewModel authProv) { - return buildVerificationMethod( - context, - 'assets/images/verification_sms_icon.png', - TranslationBase.of(context).sms, () { - sendActivationCodeByOtpNotificationType(1, authProv); - }); - } - - /* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: build WhatsApp Methods widget - */ - Center buildWhatsAppMethod(BuildContext context, AuthViewModel authProv) { - return buildVerificationMethod( - context, - 'assets/images/verification_whatsapp_icon.png', - TranslationBase.of(context).whatsApp, () { - sendActivationCodeByOtpNotificationType(2, authProv); - }); - } - -/* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: build FaceID Methods widget - */ - Center buildFaceIDMethod(BuildContext context, AuthViewModel authProv) { - return buildVerificationMethod( - context, - 'assets/images/verification_faceid_icon.png', - TranslationBase.of(context).faceId, () { - sendActivationCodeByOtpNotificationType(3, authProv); - }); - } - -/* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: build Fingerprint Methods widget - */ - Center buildFingerprintMethod(BuildContext context, AuthViewModel authProv) { - return buildVerificationMethod( - context, - 'assets/images/verification_fingerprint_icon.png', - TranslationBase.of(context).fingerprint, () { - sendActivationCodeByOtpNotificationType(4, authProv); - }); - } - - /* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: build Verification Methods widget - */ - Center buildVerificationMethod(context, url, dec, Function fun) { - return Center( - child: InkWell( - onTap: fun, - child: Container( - // height: SizeConfig.heightMultiplier *2, - height: SizeConfig.heightMultiplier * 19, - width: SizeConfig.widthMultiplier * 37, - - padding: EdgeInsets.all(10), - decoration: BoxDecoration( - border: Border.all( - width: 1, - color: HexColor( - '#CCCCCC') // <--- border width here - ), - borderRadius: BorderRadius.all(Radius.circular(10))), - child: Column( - children: [ - Container( - margin: EdgeInsetsDirectional.only( - top: SizeConfig.heightMultiplier * 0.5), - child: Image.asset( - url, - height: SizeConfig.heightMultiplier * 10, - fit: BoxFit.cover, - ), - ), - SizedBox( - height: 10, - ), - Text( - dec, - style: TextStyle(fontSize: SizeConfig.textMultiplier * 2), - ) - ], - ), - ), - ), - ); - } - bool hideSilentMethods() { return verificationMethod == 4 || verificationMethod == 3 ? true : false; } @@ -267,64 +323,473 @@ class _VerificationMethodsState extends State { *@return: *@desc: send Activation Code By Otp Notification Type */ - sendActivationCodeByOtpNotificationType(oTPSendType, AuthViewModel authProv) async { + sendActivationCodeByOtpNotificationType( + oTPSendType, AuthViewModel authProv) async { // TODO : build enum for verfication method if (oTPSendType == 1 || oTPSendType == 2) { widget.changeLoadingStata(true); int projectID = await sharedPref.getInt(PROJECT_ID); ActivationCodeModel activationCodeModel = ActivationCodeModel( + // facilityId: projectID != null ? projectID : 15, //user.projectID, + // generalid: "Cs2020@2016\$2958", + // memberID: _loggedUser != null + // ? _loggedUser['List_MemberInformation'][0]['MemberID'] + // : user.doctorID, + // zipCode: _loggedUser != null + // ? _loggedUser['ZipCode'] + // : user.outSA == true + // ? '966' + // : '971', + // mobileNumber: + // _loggedUser != null ? _loggedUser['MobileNumber'] : user.mobile, facilityId: projectID, generalid: "Cs2020@2016\$2958", memberID: _loggedUser['List_MemberInformation'][0]['MemberID'], zipCode: _loggedUser['ZipCode'], mobileNumber: _loggedUser['MobileNumber'], - + otpSendType: oTPSendType.toString(), password: widget.password); - Map model = { - - "OTP_SendType": oTPSendType - }; - try { authProv .sendActivationCodeForDoctorApp(activationCodeModel) .then((res) { - widget.changeLoadingStata(false); - - if (res['MessageStatus'] == 1) { - print("VerificationCode : "+ res["VerificationCode"]); - sharedPref.setString(VIDA_AUTH_TOKEN_ID, res["VidaAuthTokenID"]); - sharedPref.setString(VIDA_REFRESH_TOKEN_ID, res["VidaRefreshTokenID"]); - sharedPref.setString(LOGIN_TOKEN_ID, res["LogInTokenID"]); - Navigator.of(context).pushReplacementNamed(VERIFY_ACCOUNT, - arguments: {'model': model}); - } else { - print(res['ErrorEndUserMessage']); - helpers.showErrorToast(res['ErrorEndUserMessage']); - } - }) - .catchError((err) { + widget.changeLoadingStata(false); + + if (res['MessageStatus'] == 1) { + print("VerificationCode : " + res["VerificationCode"]); + sharedPref.setString(VIDA_AUTH_TOKEN_ID, res["VidaAuthTokenID"]); + sharedPref.setString( + VIDA_REFRESH_TOKEN_ID, res["VidaRefreshTokenID"]); + sharedPref.setString(LOGIN_TOKEN_ID, res["LogInTokenID"]); + this.startSMSService(oTPSendType, authProv); + } else { + print(res['ErrorEndUserMessage']); + helpers.showErrorToast(res['ErrorEndUserMessage']); + } + }).catchError((err) { print('$err'); widget.changeLoadingStata(false); helpers.showErrorToast(); }); } catch (e) {} - - } else { // TODO route to this page with parameters to inicate we should present 2 option if (Platform.isAndroid && oTPSendType == 3) { helpers.showErrorToast('Your device not support this feature'); } else { - Navigator.of(context).push(MaterialPageRoute( - builder: (BuildContext context) => - VerificationMethodsScreen(password: widget.password,))); + // Navigator.of(context).push(MaterialPageRoute( + // builder: (BuildContext context) => + // VerificationMethodsScreen(password: widget.password,))); // Navigator.of(context).pushNamed(VERIFICATION_METHODS, // arguments: {'verificationMethod': oTPSendType}); } } } + + Widget getButton(flag, authProv) { + switch (flag) { + case 2: + return InkWell( + onTap: () => {authenticateUser(2, true, authProv)}, + child: RoundedContainer( + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(30, 15, 30, 15), + child: Column( + children: [ + Image.asset( + 'assets/images/login/104.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).verifyWhatsApp, + fontSize: SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + break; + case 1: + return InkWell( + onTap: () => {authenticateUser(1, true, authProv)}, + child: RoundedContainer( + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(5, 15, 5, 15), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/login/103.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + projectsProvider.isArabic + ? SizedBox( + height: 20, + ) + : SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).verifySMS, + fontSize: projectsProvider.isArabic + ? SizeConfig.textMultiplier * 1.8 + : SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + break; + case 3: + return InkWell( + onTap: () => { + authenticateUser(3, BiometricType.fingerprint.index, authProv) + }, + child: RoundedContainer( + backgroundColor: BiometricType.fingerprint.index == 1 + ? Colors.white + : Colors.white.withOpacity(.7), + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(5, 15, 5, 15), + child: Column( + children: [ + Image.asset( + 'assets/images/login/102.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).verifyFingerprint, + fontSize: SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + break; + case 4: + return InkWell( + onTap: () => + {authenticateUser(4, BiometricType.face.index, authProv)}, + child: RoundedContainer( + backgroundColor: checkIfBiometricAvailable(BiometricType.face) + ? Colors.white + : Colors.white.withOpacity(.7), + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(5, 15, 5, 15), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/login/101.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).verifyFaceID, + fontSize: SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + break; + + default: + return InkWell( + onTap: () => { + setState(() { + isMoreOption = true; + }) + }, + child: RoundedContainer( + backgroundColor: BiometricType.fingerprint.index == 1 + ? Colors.white + : Colors.white.withOpacity(.7), + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(5, 0, 5, 5), + child: Column( + children: [ + Image.asset( + 'assets/images/login/more_icon.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + projectsProvider.isArabic + ? SizedBox( + height: 15, + ) + : SizedBox( + height: 10, + ), + AppText( + TranslationBase.of(context).moreVerification, + fontSize: SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + } + } + + getType(type, context) { + switch (type) { + case 1: + return TranslationBase.of(context).verifySMS; + break; + case 3: + return TranslationBase.of(context).verifyFingerprint; + break; + case 4: + return TranslationBase.of(context).verifyFaceID; + break; + case 2: + return TranslationBase.of(context).verifyWhatsApp; + break; + default: + return TranslationBase.of(context).verifySMS; + break; + } + } + + bool checkIfBiometricAvailable(BiometricType biometricType) { + bool isAvailable = false; + if (_availableBiometrics != null) { + for (var i = 0; i < _availableBiometrics.length; i++) { + if (biometricType == _availableBiometrics[i]) isAvailable = true; + } + } + return isAvailable; + } + + formatDate(date) { + return DateFormat('MMM dd, yyy, kk:mm').format(date); + } + + authenticateUser(type, isActive, authProv) { + //GifLoaderDialogUtils.showMyDialog(context); + // if (type == 2 || type == 3) { + // fingrePrintBefore = type; + // } + //this.selectedOption = fingrePrintBefore != null ? fingrePrintBefore : type; + + switch (type) { + case 1: + this.loginWithSMS(1, isActive, authProv); + break; + case 2: + this.loginWithSMS(2, isActive, authProv); + + break; + case 3: + this.loginWithFingurePrintFace(3, isActive, authProv); + break; + case 4: + this.loginWithFingurePrintFace(4, isActive, authProv); + break; + default: + break; + } + // sharedPref.setInt(LAST_LOGIN, + // this.selectedOption); //this.cs.sharedService.setStorage(this.selectedOption, AuthenticationService.LAST_LOGIN); + } + + loginWithSMS(type, isActive, authProv) { + this.sendActivationCode(type, authProv); + // //if (!el.disabled) { + // if (this.user != null) { + // this.checkUserAuthentication(type); + // } else { + // // if (this.loginTokenID != null) { + // this.sendActivationCode(type, authProv); + // // } else { + // //this.checkUserAuthentication(type); + // // } + // } + } + + // checkUserAuthentication(type) { + // // showLoader(true); + // // var req = getCommonRequest(type: type); + // // req.logInTokenID = ""; + + // // var request = CheckPatientAuthenticationReq.fromJson(req.toJson()); + + // // sharedPref.setObject(REGISTER_DATA_FOR_REGISTER, request); + // // authService + // // .checkPatientAuthentication(request) + // // .then((value) => { + // // GifLoaderDialogUtils.hideDialog(context), + // // if (value['isSMSSent']) + // // { + // // sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']), + // // this.loginTokenID = value['LogInTokenID'], + // // sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), + // // // Future.delayed(Duration(seconds: 1), () { + // // this.sendActivationCode(type) + // // // }) + // // } + // // else + // // { + // // if (value['IsAuthenticated']) {this.checkActivationCode()} + // // } + // // }) + // // .catchError((err) { + // // print(err); + // // GifLoaderDialogUtils.hideDialog(context); + // // }); + // } + Future _getAvailableBiometrics() async { + var availableBiometrics; + try { + availableBiometrics = await auth.getAvailableBiometrics(); + } on PlatformException catch (e) { + print(e); + } + if (!mounted) return; + + setState(() { + _availableBiometrics = availableBiometrics; + }); + } + + sendActivationCode(type, authProv) async { + sendActivationCodeByOtpNotificationType(type, authProv); + } + + startSMSService(type, authProv) { + sharedPref.setInt(OTP_TYPE, type); + new SMSOTP( + context, + type, + _loggedUser['MobileNumber'], + (value) { + showDialog( + context: context, + builder: (BuildContext context) { + return Center( + child: CircularProgressIndicator(), + ); + }); + + this.checkActivationCode(authProv, value: value); + }, + () => { + Navigator.pop(context), + print('Faild..'), + }, + ).displayDialog(context); + } + + loginWithFingurePrintFace(type, isActive, authProv) async { + if (isActive == 1) { + // this.startBiometricLoginIfAvailable(); + authenticated = await auth.authenticateWithBiometrics( + localizedReason: 'Scan your fingerprint to authenticate', + useErrorDialogs: true, + stickyAuth: true); + if (user.logInTypeID == 1 || user.logInTypeID == 2) { + this.onlySMSBox = true; + } else { + this.checkActivationCode(authProv); + } + + // if (authenticated == true) { + // if (user != null && (user.logInTypeID == 4 || user.logInTypeID == 3)) { + // //this.checkActivationCode(); + // } else { + // // var request = this.getCommonRequest(type: type); + // // this.getMobileInfo(request); + // } + // } + } + } + + checkActivationCode(AuthViewModel authProv, {value}) async { + CheckActivationCodeRequestModel checkActivationCodeForDoctorApp = + new CheckActivationCodeRequestModel( + zipCode: _loggedUser['ZipCode'], + mobileNumber: _loggedUser['MobileNumber'], + projectID: await sharedPref.getInt(PROJECT_ID), + logInTokenID: await sharedPref.getString(LOGIN_TOKEN_ID), + activationCode: value, + oTPSendType: await sharedPref.getInt(OTP_TYPE), + generalid: "Cs2020@2016\$2958"); + + authProv + .checkActivationCodeForDoctorApp(checkActivationCodeForDoctorApp) + .then((res) async { + widget.changeLoadingStata(false); + if (res['MessageStatus'] == 1) { + sharedPref.setString(TOKEN, res['AuthenticationTokenID']); + if (res['List_DoctorProfile'] != null) { + loginProcessCompleted(res['List_DoctorProfile'][0], authProv); + } else { + ClinicModel clinic = + ClinicModel.fromJson(res['List_DoctorsClinic'][0]); + getDocProfiles(clinic, authProv); + } + } else { + //changeLoadingStata(false); + helpers.showErrorToast(res['ErrorEndUserMessage']); + } + }).catchError((err) { + //changeLoadingStata(false); + helpers.showErrorToast(err); + }); + } + + loginProcessCompleted(Map profile, authProv) { + var doctor = DoctorProfileModel.fromJson(profile); + authProv.setDoctorProfile(doctor); + sharedPref.setObj(DOCTOR_PROFILE, profile); + projectsProvider.isLogin = true; + Navigator.of(context).pushReplacementNamed(HOME); + } + + getDocProfiles(ClinicModel clinicInfo, authProv) { + ProfileReqModel docInfo = new ProfileReqModel( + doctorID: clinicInfo.doctorID, + clinicID: clinicInfo.clinicID, + license: true, + projectID: clinicInfo.projectID, + tokenID: '', + languageID: 2); + authProv.getDocProfiles(docInfo.toJson()).then((res) { + if (res['MessageStatus'] == 1) { + loginProcessCompleted(res['DoctorProfileList'][0], authProv); + } else { + // changeLoadingStata(false); + helpers.showErrorToast(res['ErrorEndUserMessage']); + } + }).catchError((err) { + // changeLoadingStata(false); + helpers.showErrorToast(err); + }); + } } diff --git a/lib/widgets/otp/sms-popup.dart b/lib/widgets/otp/sms-popup.dart new file mode 100644 index 00000000..dfcb33cd --- /dev/null +++ b/lib/widgets/otp/sms-popup.dart @@ -0,0 +1,346 @@ +import 'dart:async'; + +import 'package:doctor_app_flutter/config/size_config.dart'; +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/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'dart:math'; + +import 'package:provider/provider.dart'; + +class SMSOTP { + final type; + final mobileNo; + final Function onSuccess; + final Function onFailure; + final context; + + int remainingTime = 600; + + Future timer; + + static BuildContext _context; + + static bool _loading; + + SMSOTP( + this.context, + this.type, + this.mobileNo, + this.onSuccess, + this.onFailure, + ); + + final verifyAccountForm = GlobalKey(); + + TextEditingController digit1 = TextEditingController(text: ""); + TextEditingController digit2 = TextEditingController(text: ""); + TextEditingController digit3 = TextEditingController(text: ""); + TextEditingController digit4 = TextEditingController(text: ""); + + Map verifyAccountFormValue = { + 'digit1': '', + 'digit2': '', + 'digit3': '', + 'digit4': '', + }; + final focusD1 = FocusNode(); + final focusD2 = FocusNode(); + final focusD3 = FocusNode(); + final focusD4 = FocusNode(); + String errorMsg; + ProjectViewModel projectProvider; + String displayTime = ''; + + displayDialog(BuildContext context) async { + return showDialog( + context: context, + builder: (context) { + projectProvider = Provider.of(context); + return AlertDialog( + title: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + IconButton( + icon: Icon(Icons.close), + onPressed: () { + Navigator.pop(context); + this.onFailure(); + }, + ) + ], + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0))), + content: StatefulBuilder(builder: (context, setState) { + if (displayTime == '') { + startTimer(setState); + } + return Container( + color: Colors.white, + height: SizeConfig.realScreenHeight * 0.5, + width: SizeConfig.realScreenWidth * 0.8, + child: Center( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + type == 1 + ? Image.asset('assets/images/login/103.png') + : Image.asset('assets/images/login/104.png'), + Padding( + padding: EdgeInsets.only(top: 5), + child: AppText( + TranslationBase.of(context).verificationMessage + + ' XXXXXX' + + mobileNo + .toString() + .substring(mobileNo.toString().length - 3), + textAlign: TextAlign.center, + )), + Form( + key: verifyAccountForm, + child: Padding( + padding: EdgeInsets.only(top: 20), + child: Directionality( + textDirection: TextDirection.ltr, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Container( + width: SizeConfig.realScreenWidth * 0.15, + child: TextFormField( + textInputAction: TextInputAction.next, + style: buildTextStyle(), + autofocus: true, + maxLength: 1, + controller: digit1, + textAlign: TextAlign.center, + keyboardType: TextInputType.number, + decoration: buildInputDecoration(context), + onSaved: (val) {}, + validator: validateCodeDigit, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD2); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus(focusD2); + verifyAccountFormValue['digit1'] = + val.trim(); + checkValue(); + } + }, + ), + ), + Container( + width: SizeConfig.realScreenWidth * 0.15, + child: TextFormField( + focusNode: focusD2, + textInputAction: TextInputAction.next, + maxLength: 1, + controller: digit2, + textAlign: TextAlign.center, + style: buildTextStyle(), + keyboardType: TextInputType.number, + decoration: buildInputDecoration(context), + onSaved: (val) {}, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD3); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus(focusD3); + verifyAccountFormValue['digit2'] = + val.trim(); + checkValue(); + } + }, + validator: validateCodeDigit), + ), + Container( + width: SizeConfig.realScreenWidth * 0.15, + child: TextFormField( + focusNode: focusD3, + textInputAction: TextInputAction.next, + maxLength: 1, + controller: digit3, + textAlign: TextAlign.center, + style: buildTextStyle(), + keyboardType: TextInputType.number, + decoration: + buildInputDecoration(context), + onSaved: (val) {}, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD4); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus(focusD4); + verifyAccountFormValue['digit3'] = + val.trim(); + checkValue(); + } + }, + validator: validateCodeDigit)), + Container( + width: SizeConfig.realScreenWidth * 0.15, + child: TextFormField( + focusNode: focusD4, + maxLength: 1, + textAlign: TextAlign.center, + style: buildTextStyle(), + controller: digit4, + keyboardType: TextInputType.number, + decoration: + buildInputDecoration(context), + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD4); + }, + onChanged: (val) { + if (val.length == 1) { + verifyAccountFormValue['digit4'] = + val.trim(); + checkValue(); + } + }, + validator: validateCodeDigit)), + ], + )), + ), + ), + Padding( + padding: EdgeInsets.only(top: 10), + child: AppText( + TranslationBase.of(context).validationMessage + + ' ' + + displayTime, + color: Colors.red, + textAlign: TextAlign.center, + )) + ], + ))), + ); + }), + ); + }); + } + + TextStyle buildTextStyle() { + return TextStyle( + fontSize: SizeConfig.textMultiplier * 3, + ); + } + + InputDecoration buildInputDecoration(BuildContext context) { + return InputDecoration( + counterText: " ", + // ts/images/password_icon.png + // contentPadding: EdgeInsets.only(top: 20, bottom: 20), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + borderSide: BorderSide(color: Colors.black), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).primaryColor), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).errorColor), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).errorColor), + ), + ); + } + + String validateCodeDigit(value) { + if (value.isEmpty) { + return ' '; + } else if (value.length == 3) { + print(value); + } else { + return null; + } + } + + checkValue() { + //print(verifyAccountFormValue); + if (verifyAccountForm.currentState.validate()) { + onSuccess(digit1.text.toString() + + digit2.text.toString() + + digit3.text.toString() + + digit4.text.toString()); + } + } + + getSecondsAsDigitalClock(int inputSeconds) { + var sec_num = + int.parse(inputSeconds.toString()); // don't forget the second param + var hours = (sec_num / 3600).floor(); + var minutes = ((sec_num - hours * 3600) / 60).floor(); + var seconds = sec_num - hours * 3600 - minutes * 60; + var minutesString = ""; + var secondsString = ""; + minutesString = + minutes < 10 ? "0" + minutes.toString() : minutes.toString(); + secondsString = + seconds < 10 ? "0" + seconds.toString() : seconds.toString(); + return minutesString + ":" + secondsString; + } + + startTimer(setState) { + this.remainingTime--; + setState(() { + displayTime = this.getSecondsAsDigitalClock(this.remainingTime); + }); + + timer = Future.delayed(Duration(seconds: 1), () { + if (this.remainingTime > 0) { + startTimer(setState); + } else { + Navigator.pop(context); + } + }); + } + + static void showLoadingDialog(BuildContext context, bool _loading) async { + _context = context; + + if (_loading == false) { + Navigator.of(context).pop(); + return; + } + _loading = true; + await showDialog( + context: _context, + barrierDismissible: false, + builder: (BuildContext context) { + return SimpleDialog( + elevation: 0.0, + backgroundColor: Colors.transparent, + children: [ + Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.black), + ), + ) + ], + ); + }); + } + + static void hideSMSBox(context) { + Navigator.pop(context); + } +} diff --git a/pubspec.lock b/pubspec.lock index 7f1d8c1d..4d8e049b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -316,6 +316,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "5.2.1" + firebase_core: + dependency: transitive + description: + name: firebase_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.3" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1+1" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + url: "https://pub.dartlang.org" + source: hosted + version: "7.0.3" fixnum: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 57ed4cbb..e0e4ce33 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,8 @@ dependencies: #Dependency Injection get_it: ^4.0.2 + #firebase + firebase_messaging: ^7.0.0 #Autocomplete TextField autocomplete_textfield: ^1.7.3 @@ -93,7 +95,7 @@ flutter: assets: - assets/images/ - assets/images/dashboard/ - + - assets/images/login/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. From 1f2aebde3366698d9629db47ce881a55b0f2d52d Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Tue, 12 Jan 2021 14:11:51 +0200 Subject: [PATCH 10/12] fix loader in login --- assets/images/progress-loading-red.gif | Bin 0 -> 142880 bytes lib/widgets/shared/app_loader_widget.dart | 16 ++++++- .../shared/loader/gif_loader_container.dart | 43 ++++++++++++++++++ .../loader/gif_loader_dialog_utils.dart | 14 ++++++ pubspec.lock | 7 +++ pubspec.yaml | 2 + 6 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 assets/images/progress-loading-red.gif create mode 100644 lib/widgets/shared/loader/gif_loader_container.dart create mode 100644 lib/widgets/shared/loader/gif_loader_dialog_utils.dart diff --git a/assets/images/progress-loading-red.gif b/assets/images/progress-loading-red.gif new file mode 100644 index 0000000000000000000000000000000000000000..517c3dab1055feb0aac5b16ea0d1dcd886e9bc58 GIT binary patch literal 142880 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Â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

`p-I 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 tHo$fM8&U9!WgP9a(Rq^8U(0{?Np7dZe { @override Widget build(BuildContext context) { - return Positioned(child: _progressHUD); + return Container( + height: MediaQuery.of(context).size.height, + + child: Stack( + children: [ + Container( + color: Colors.grey.withOpacity(0.6), + ), + Container(child: GifLoaderContainer(), margin: EdgeInsets.only( + bottom: MediaQuery.of(context).size.height * 0.09)) + ], + ), + ); } } diff --git a/lib/widgets/shared/loader/gif_loader_container.dart b/lib/widgets/shared/loader/gif_loader_container.dart new file mode 100644 index 00000000..b7a20339 --- /dev/null +++ b/lib/widgets/shared/loader/gif_loader_container.dart @@ -0,0 +1,43 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_gifimage/flutter_gifimage.dart'; + +class GifLoaderContainer extends StatefulWidget { + @override + _GifLoaderContainerState createState() => _GifLoaderContainerState(); +} + +class _GifLoaderContainerState extends State + with TickerProviderStateMixin { + GifController controller1; + + @override + void initState() { + controller1 = GifController(vsync: this); + + WidgetsBinding.instance.addPostFrameCallback((_) { + controller1.repeat( + min: 0, max: 11, period: Duration(milliseconds: 750), reverse: true); + }); + super.initState(); + } + + @override + void dispose() { + controller1.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Center( + //progress-loading.gif + child: Container( + // margin: EdgeInsets.only(bottom: 40), + child: GifImage( + controller: controller1, + image: AssetImage( + "assets/images/progress-loading-red.gif"), //NetworkImage("http://img.mp.itc.cn/upload/20161107/5cad975eee9e4b45ae9d3c1238ccf91e.jpg"), + ), + )); + } +} \ No newline at end of file diff --git a/lib/widgets/shared/loader/gif_loader_dialog_utils.dart b/lib/widgets/shared/loader/gif_loader_dialog_utils.dart new file mode 100644 index 00000000..9b45bba1 --- /dev/null +++ b/lib/widgets/shared/loader/gif_loader_dialog_utils.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; + +import 'gif_loader_container.dart'; + + +class GifLoaderDialogUtils { + static showMyDialog(BuildContext context) { + showDialog(context: context, child: GifLoaderContainer()); + } + + static hideDialog(BuildContext context) { + Navigator.of(context).pop(); + } +} diff --git a/pubspec.lock b/pubspec.lock index 7f1d8c1d..2ad55e08 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -342,6 +342,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.4" + flutter_gifimage: + dependency: "direct main" + description: + name: flutter_gifimage + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" flutter_localizations: dependency: "direct main" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 57ed4cbb..2a9f2e73 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,8 @@ dependencies: #Dependency Injection get_it: ^4.0.2 + #GIF image + flutter_gifimage: ^1.0.1 #Autocomplete TextField autocomplete_textfield: ^1.7.3 From 8726653ffbcc6d84a93c224c984f2f1a8d475f9a Mon Sep 17 00:00:00 2001 From: mosazaid Date: Tue, 12 Jan 2021 16:29:26 +0200 Subject: [PATCH 11/12] working on Referral feature --- lib/config/config.dart | 6 + .../patient-doctor-referral-service.dart | 29 + .../viewModel/patient-referral-viewmodel.dart | 20 +- .../referral/refer-patient-screen.dart | 558 +++++++++--------- .../patient-referral-item-widget.dart | 7 +- 5 files changed, 342 insertions(+), 278 deletions(-) diff --git a/lib/config/config.dart b/lib/config/config.dart index e6520b1e..743b09ad 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -71,6 +71,12 @@ const CREATE_REFERRAL_PATIENT = const RESPONSE_PENDING_REFERRAL_PATIENT = 'Services/DoctorApplication.svc/REST/CreateReferral'; +const GET_PATIENT_REFERRAL = + 'Services/DoctorApplication.svc/REST/GetRefferal'; + +const POST_UCAF = + 'Services/DoctorApplication.svc/REST/PostUCAF'; + const GET_DOCTOR_WORKING_HOURS_TABLE = 'Services/Doctors.svc/REST/GetDoctorWorkingHoursTable'; diff --git a/lib/core/service/patient-doctor-referral-service.dart b/lib/core/service/patient-doctor-referral-service.dart index 7eb8001b..2f18540a 100644 --- a/lib/core/service/patient-doctor-referral-service.dart +++ b/lib/core/service/patient-doctor-referral-service.dart @@ -18,6 +18,7 @@ class PatientReferralService extends LookupService { List doctorsList = []; List listMyReferredPatientModel = []; List pendingReferralList = []; + List patientReferralList = []; String setupID = "0"; Future getProjectsList() async { @@ -163,6 +164,33 @@ class PatientReferralService extends LookupService { ); } + Future getPatientReferral(PatiantInformtion patient) async { + hasError = false; + Map body = Map(); + body['PatientMRN'] = patient.patientMRN; + body['AppointmentNo'] = patient.appointmentNo; + + await baseAppClient.post( + GET_PATIENT_REFERRAL, + onSuccess: (dynamic response, int statusCode) { + patientReferralList.clear(); + + response['ReferralList']['entityList'].forEach((v) { + PendingReferral item = PendingReferral.fromJson(v); + item.isReferralDoctorSameBranch = + item.targetProjectId == item.sourceProjectId; + patientReferralList.add(item); + }); + }, + onFailure: (String error, int statusCode) { + patientReferralList.clear(); + hasError = true; + super.error = error; + }, + body: body, + ); + } + Future responseReferral(PendingReferral pendingReferral, bool isAccepted) async { hasError = false; DoctorProfileModel doctorProfile = await getDoctorProfile(); @@ -221,6 +249,7 @@ class PatientReferralService extends LookupService { CREATE_REFERRAL_PATIENT, onSuccess: (dynamic response, int statusCode) { print(response.toString()); + print("create referral status code = ${statusCode}"); }, onFailure: (String error, int statusCode) { hasError = true; diff --git a/lib/core/viewModel/patient-referral-viewmodel.dart b/lib/core/viewModel/patient-referral-viewmodel.dart index 028eac0d..a1fc73fb 100644 --- a/lib/core/viewModel/patient-referral-viewmodel.dart +++ b/lib/core/viewModel/patient-referral-viewmodel.dart @@ -27,9 +27,27 @@ class PatientReferralViewModel extends BaseViewModel { List get pendingReferral => _referralPatientService.pendingReferralList; + List get patientReferral => + _referralPatientService.patientReferralList; + List get patientArrivalList => _referralPatientService.patientArrivalList; + Future getPatientReferral(PatiantInformtion patient) async { + setState(ViewState.Busy); + await _referralPatientService.getPatientReferral(patient); + if (_referralPatientService.hasError) { + error = _referralPatientService.error; + setState(ViewState.Error); + } else { + if(patientReferral.length == 0){ + await getMasterLookup(MasterKeysService.physiotherapyGoals); + } else { + setState(ViewState.Idle); + } + } + } + Future getMasterLookup(MasterKeysService masterKeys) async { setState(ViewState.Busy); await _referralPatientService.getMasterLookup(masterKeys); @@ -37,7 +55,7 @@ class PatientReferralViewModel extends BaseViewModel { error = _referralPatientService.error; setState(ViewState.Error); } else - await getBranches(); + await getBranches(); } Future getBranches() async { diff --git a/lib/screens/patients/profile/referral/refer-patient-screen.dart b/lib/screens/patients/profile/referral/refer-patient-screen.dart index 62952108..2c5311cc 100644 --- a/lib/screens/patients/profile/referral/refer-patient-screen.dart +++ b/lib/screens/patients/profile/referral/refer-patient-screen.dart @@ -8,6 +8,7 @@ import 'package:doctor_app_flutter/screens/base/base_view.dart'; import 'package:doctor_app_flutter/util/date-utils.dart'; import 'package:doctor_app_flutter/util/dr_app_toast_msg.dart'; import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/patients/patient-referral-item-widget.dart'; import 'package:doctor_app_flutter/widgets/patients/profile/patient-page-header-widget.dart'; import 'package:doctor_app_flutter/widgets/shared/app_buttons_widget.dart'; import 'package:doctor_app_flutter/widgets/shared/app_loader_widget.dart'; @@ -50,16 +51,21 @@ class _PatientMakeReferralScreenState extends State { patient = routeArgs['patient']; referToList = List(); - dynamic sameBranch = {"id": 1, "name": TranslationBase.of(context).sameBranch}; - dynamic otherBranch = {"id": 2, "name": TranslationBase.of(context).otherBranch}; + dynamic sameBranch = { + "id": 1, + "name": TranslationBase.of(context).sameBranch + }; + dynamic otherBranch = { + "id": 2, + "name": TranslationBase.of(context).otherBranch + }; referToList.add(sameBranch); referToList.add(otherBranch); final screenSize = MediaQuery.of(context).size; return BaseView( - onModelReady: (model) => - model.getMasterLookup(MasterKeysService.physiotherapyGoals), + onModelReady: (model) => model.getPatientReferral(patient), builder: (_, model, w) => AppScaffold( baseViewModel: model, appBarTitle: TranslationBase.of(context).referPatient, @@ -86,279 +92,50 @@ class _PatientMakeReferralScreenState extends State { indent: 0, endIndent: 0, ), - Container( - margin: - EdgeInsets.symmetric(vertical: 16, horizontal: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: 16, - ), - AppText( - TranslationBase.of(context).referPatient, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - SizedBox( - height: 16, - ), - Container( - height: screenSize.height * 0.070, - child: InkWell( - onTap: referToList != null - ? () { - ListSelectDialog dialog = - ListSelectDialog( - list: referToList, - attributeName: 'name', - attributeValueId: 'id', - okText: TranslationBase.of(context).ok, - okFunction: (selectedValue) { - setState(() { - _referTo = selectedValue; - _selectedBranch = null; - _selectedClinic = null; - _selectedDoctor = null; - model - .getDoctorBranch() - .then((value) { - _selectedBranch = value; - if (_referTo['id'] == 1) { - model.getClinics( - _selectedBranch['ID']); - } - }); - }); - }, - ); - showDialog( - barrierDismissible: false, - context: context, - builder: (BuildContext context) { - return dialog; - }, - ); - } - : null, - child: TextField( - decoration: textFieldSelectorDecoration( - TranslationBase.of(context).referTo, - _referTo != null ? _referTo['name'] : null, - true), - enabled: false, - ), - ), - ), - SizedBox( - height: 10, - ), - Container( - height: screenSize.height * 0.070, - child: InkWell( - onTap: model.branchesList != null && - model.branchesList.length > 0 && - _referTo != null && - _referTo['id'] == 2 - ? () { - ListSelectDialog dialog = - ListSelectDialog( - list: model.branchesList, - attributeName: 'Desciption', - attributeValueId: 'ID', - okText: TranslationBase.of(context).ok, - okFunction: (selectedValue) { - setState(() { - _selectedBranch = selectedValue; - _selectedClinic = null; - _selectedDoctor = null; - model.getClinics( - _selectedBranch['ID']); - }); - }, - ); - showDialog( - barrierDismissible: false, - context: context, - builder: (BuildContext context) { - return dialog; - }, - ); - } - : null, - child: TextField( - decoration: textFieldSelectorDecoration( - TranslationBase.of(context).branch, - _selectedBranch != null - ? _selectedBranch['Desciption'] - : null, - true), - enabled: false, - ), - ), - ), - SizedBox( - height: 10, - ), - Container( - height: screenSize.height * 0.070, - child: InkWell( - onTap: _selectedBranch != null && - model.clinicsList != null && - model.clinicsList.length > 0 - ? () { - ListSelectDialog dialog = - ListSelectDialog( - list: model.clinicsList, - attributeName: 'ClinicDescription', - attributeValueId: 'ClinicID', - okText: TranslationBase.of(context).ok, - okFunction: (selectedValue) { - setState(() { - _selectedDoctor = null; - _selectedClinic = selectedValue; - model.getClinicDoctors( - _selectedClinic['ClinicID'] - .toString()); - }); - }, - ); - showDialog( - barrierDismissible: false, - context: context, - builder: (BuildContext context) { - return dialog; - }, - ); - } - : null, - child: TextField( - decoration: textFieldSelectorDecoration( - TranslationBase.of(context).clinic, - _selectedClinic != null - ? _selectedClinic['ClinicDescription'] - : null, - true), - enabled: false, - ), - ), - ), - SizedBox( - height: 10, - ), - Container( - height: screenSize.height * 0.070, - child: InkWell( - onTap: _selectedClinic != null && - model.doctorsList != null && - model.doctorsList.length > 0 - ? () { - ListSelectDialog dialog = - ListSelectDialog( - list: model.doctorsList, - attributeName: 'DoctorName', - attributeValueId: 'DoctorID', - okText: TranslationBase.of(context).ok, - okFunction: (selectedValue) { - setState(() { - _selectedDoctor = selectedValue; - }); - }, - ); - showDialog( - barrierDismissible: false, - context: context, - builder: (BuildContext context) { - return dialog; - }, - ); - } - : null, - child: TextField( - decoration: textFieldSelectorDecoration( - TranslationBase.of(context).doctor, - _selectedDoctor != null - ? _selectedDoctor['DoctorName'] - : null, - true), - enabled: false, - ), - ), - ), - SizedBox( - height: 10, - ), - Container( - height: screenSize.height * 0.070, - child: InkWell( - onTap: () => _selectDate(context, model), - child: TextField( - decoration: textFieldSelectorDecoration( - TranslationBase.of(context) - .chooseAppointment, - appointmentDate != null - ? "${DateUtils.convertDateToFormat(appointmentDate, "yyyy-MM-dd")}" - : null, - true, - suffixIcon: Icon( - Icons.calendar_today, - color: Colors.black, - )), - enabled: false, - ), - ), - ), - SizedBox( - height: 10, - ), - Container( - child: TextField( - decoration: textFieldSelectorDecoration( - TranslationBase.of(context).remarks, - null, - false), - enabled: true, - controller: _remarksController, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(ONLY_LETTERS)) - ], - keyboardType: TextInputType.text, - minLines: 4, - maxLines: 6, - )), - ], - ), + model.patientReferral.length == 0 + ? ReferralForm(model, screenSize) + : PatientReferralItemWidget( + patientName: model.patientReferral[0].patientName, + referralStatus: "${model.patientReferral[0].referralStatus}", + isReferredTo: true, + isSameBranch: model.patientReferral[0] + .isReferralDoctorSameBranch, + referralDoctorName: + model.patientReferral[0].referredByDoctorInfo, + clinicDescription: null, + remark: + model.patientReferral[0].remarksFromSource ), ], ), - Container( - margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: AppButton( - title: TranslationBase.of(context).refer, - color: HexColor("#B8382B"), - onPressed: () { - if (appointmentDate == null || - _selectedBranch == null || - _selectedClinic == null || - _selectedDoctor == null || - _remarksController.text == null) return; - model - .makeReferral( - patient, - appointmentDate.toIso8601String(), - _selectedBranch['ID'], - _selectedClinic['ClinicID'], - _selectedDoctor['DoctorID'], - _remarksController.text) - .then((_) { - DrAppToastMsg.showSuccesToast( - TranslationBase.of(context).referralSuccessMsg); - Navigator.pop(context); - }); - }, - ), - ) + if (model.patientReferral.length == 0) + Container( + margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: AppButton( + title: TranslationBase.of(context).refer, + color: HexColor("#B8382B"), + onPressed: () { + if (appointmentDate == null || + _selectedBranch == null || + _selectedClinic == null || + _selectedDoctor == null || + _remarksController.text == null) return; + model + .makeReferral( + patient, + appointmentDate.toIso8601String(), + _selectedBranch['ID'], + _selectedClinic['ClinicID'], + _selectedDoctor['DoctorID'], + _remarksController.text) + .then((_) { + DrAppToastMsg.showSuccesToast( + TranslationBase.of(context).referralSuccessMsg); + Navigator.pop(context); + }); + }, + ), + ) ], ), ), @@ -367,6 +144,239 @@ class _PatientMakeReferralScreenState extends State { ); } + Widget ReferralForm(PatientReferralViewModel model, Size screenSize) { + return Container( + margin: EdgeInsets.symmetric(vertical: 16, horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 16, + ), + AppText( + TranslationBase.of(context).referPatient, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + SizedBox( + height: 16, + ), + Container( + height: screenSize.height * 0.070, + child: InkWell( + onTap: referToList != null + ? () { + ListSelectDialog dialog = ListSelectDialog( + list: referToList, + attributeName: 'name', + attributeValueId: 'id', + okText: TranslationBase.of(context).ok, + okFunction: (selectedValue) { + setState(() { + _referTo = selectedValue; + _selectedBranch = null; + _selectedClinic = null; + _selectedDoctor = null; + model.getDoctorBranch().then((value) { + _selectedBranch = value; + if (_referTo['id'] == 1) { + model.getClinics(_selectedBranch['ID']); + } + }); + }); + }, + ); + showDialog( + barrierDismissible: false, + context: context, + builder: (BuildContext context) { + return dialog; + }, + ); + } + : null, + child: TextField( + decoration: textFieldSelectorDecoration( + TranslationBase.of(context).referTo, + _referTo != null ? _referTo['name'] : null, + true), + enabled: false, + ), + ), + ), + SizedBox( + height: 10, + ), + Container( + height: screenSize.height * 0.070, + child: InkWell( + onTap: model.branchesList != null && + model.branchesList.length > 0 && + _referTo != null && + _referTo['id'] == 2 + ? () { + ListSelectDialog dialog = ListSelectDialog( + list: model.branchesList, + attributeName: 'Desciption', + attributeValueId: 'ID', + okText: TranslationBase.of(context).ok, + okFunction: (selectedValue) { + setState(() { + _selectedBranch = selectedValue; + _selectedClinic = null; + _selectedDoctor = null; + model.getClinics(_selectedBranch['ID']); + }); + }, + ); + showDialog( + barrierDismissible: false, + context: context, + builder: (BuildContext context) { + return dialog; + }, + ); + } + : null, + child: TextField( + decoration: textFieldSelectorDecoration( + TranslationBase.of(context).branch, + _selectedBranch != null + ? _selectedBranch['Desciption'] + : null, + true), + enabled: false, + ), + ), + ), + SizedBox( + height: 10, + ), + Container( + height: screenSize.height * 0.070, + child: InkWell( + onTap: _selectedBranch != null && + model.clinicsList != null && + model.clinicsList.length > 0 + ? () { + ListSelectDialog dialog = ListSelectDialog( + list: model.clinicsList, + attributeName: 'ClinicDescription', + attributeValueId: 'ClinicID', + okText: TranslationBase.of(context).ok, + okFunction: (selectedValue) { + setState(() { + _selectedDoctor = null; + _selectedClinic = selectedValue; + model.getClinicDoctors( + _selectedClinic['ClinicID'].toString()); + }); + }, + ); + showDialog( + barrierDismissible: false, + context: context, + builder: (BuildContext context) { + return dialog; + }, + ); + } + : null, + child: TextField( + decoration: textFieldSelectorDecoration( + TranslationBase.of(context).clinic, + _selectedClinic != null + ? _selectedClinic['ClinicDescription'] + : null, + true), + enabled: false, + ), + ), + ), + SizedBox( + height: 10, + ), + Container( + height: screenSize.height * 0.070, + child: InkWell( + onTap: _selectedClinic != null && + model.doctorsList != null && + model.doctorsList.length > 0 + ? () { + ListSelectDialog dialog = ListSelectDialog( + list: model.doctorsList, + attributeName: 'DoctorName', + attributeValueId: 'DoctorID', + okText: TranslationBase.of(context).ok, + okFunction: (selectedValue) { + setState(() { + _selectedDoctor = selectedValue; + }); + }, + ); + showDialog( + barrierDismissible: false, + context: context, + builder: (BuildContext context) { + return dialog; + }, + ); + } + : null, + child: TextField( + decoration: textFieldSelectorDecoration( + TranslationBase.of(context).doctor, + _selectedDoctor != null + ? _selectedDoctor['DoctorName'] + : null, + true), + enabled: false, + ), + ), + ), + SizedBox( + height: 10, + ), + Container( + height: screenSize.height * 0.070, + child: InkWell( + onTap: () => _selectDate(context, model), + child: TextField( + decoration: textFieldSelectorDecoration( + TranslationBase.of(context).chooseAppointment, + appointmentDate != null + ? "${DateUtils.convertDateToFormat(appointmentDate, "yyyy-MM-dd")}" + : null, + true, + suffixIcon: Icon( + Icons.calendar_today, + color: Colors.black, + )), + enabled: false, + ), + ), + ), + SizedBox( + height: 10, + ), + Container( + child: TextField( + decoration: textFieldSelectorDecoration( + TranslationBase.of(context).remarks, null, false), + enabled: true, + controller: _remarksController, + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(ONLY_LETTERS)) + ], + keyboardType: TextInputType.text, + minLines: 4, + maxLines: 6, + )), + ], + ), + ); + } + _selectDate(BuildContext context, PatientReferralViewModel model) async { // https://medium.com/flutter-community/a-deep-dive-into-datepicker-in-flutter-37e84f7d8d6c good reference // https://stackoverflow.com/a/63147062/6246772 to customize a date picker diff --git a/lib/widgets/patients/patient-referral-item-widget.dart b/lib/widgets/patients/patient-referral-item-widget.dart index 662e7fee..17f33793 100644 --- a/lib/widgets/patients/patient-referral-item-widget.dart +++ b/lib/widgets/patients/patient-referral-item-widget.dart @@ -37,7 +37,7 @@ class PatientReferralItemWidget extends StatelessWidget { children: [ Center( child: AppText( - patientName, + "${patientName}", color: Colors.black, fontWeight: FontWeight.bold, fontSize: 16, @@ -48,9 +48,10 @@ class PatientReferralItemWidget extends StatelessWidget { color: Color(0xFF4BA821), padding: EdgeInsets.all(4), child: AppText( - referralStatus == "46" + referralStatus + /*referralStatus == "46" ? TranslationBase.of(context).approved - : TranslationBase.of(context).rejected, + : TranslationBase.of(context).rejected*/, color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12, From ad99cebf0245db324f38428b80a6ed772de12cfd Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Thu, 14 Jan 2021 16:25:11 +0300 Subject: [PATCH 12/12] login and drug to drug --- lib/client/base_app_client.dart | 11 ++- lib/config/config.dart | 8 +- lib/core/model/imei_details.dart | 56 +++++++++--- lib/core/model/insert_imei_model.dart | 82 +++++++++++++---- .../service/patient-vital-signs-service.dart | 20 ++--- lib/core/service/prescription_service.dart | 22 ++++- lib/core/viewModel/auth_view_model.dart | 22 ++++- .../viewModel/prescription_view_model.dart | 15 ++++ .../auth/send_activation_code_model2.dart | 60 +++++++++++++ lib/screens/dashboard_screen.dart | 37 +++++--- .../prescription/add_prescription_form.dart | 64 ++++++++----- lib/screens/prescription/drugtodrug.dart | 89 +++++++++++++++++++ lib/widgets/auth/verification_methods.dart | 74 ++++++++++++--- 13 files changed, 468 insertions(+), 92 deletions(-) create mode 100644 lib/models/auth/send_activation_code_model2.dart create mode 100644 lib/screens/prescription/drugtodrug.dart diff --git a/lib/client/base_app_client.dart b/lib/client/base_app_client.dart index e203c142..c1438159 100644 --- a/lib/client/base_app_client.dart +++ b/lib/client/base_app_client.dart @@ -71,9 +71,14 @@ class BaseAppClient { body['SessionID'] = SESSION_ID; body['IsLoginForDoctorApp'] = IS_LOGIN_FOR_DOCTOR_APP; body['PatientOutSA'] = 0; // PATIENT_OUT_SA; - body['VidaAuthTokenID'] = await sharedPref.getString(VIDA_AUTH_TOKEN_ID); - body['VidaRefreshTokenID'] = - await sharedPref.getString(VIDA_REFRESH_TOKEN_ID); + if (body['VidaAuthTokenID'] == null) { + body['VidaAuthTokenID'] = + await sharedPref.getString(VIDA_AUTH_TOKEN_ID); + } + if (body['VidaRefreshTokenID'] == null) { + body['VidaRefreshTokenID'] = + await sharedPref.getString(VIDA_REFRESH_TOKEN_ID); + } print("URL : $url"); print("Body : ${json.encode(body)}"); diff --git a/lib/config/config.dart b/lib/config/config.dart index 29ddfed6..1a25afa0 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -92,6 +92,8 @@ const SEND_ACTIVATION_CODE_BY_OTP_NOTIFICATION_TYPE = const SEND_ACTIVATION_CODE_FOR_DOCTOR_APP = 'Services/DoctorApplication.svc/REST/SendActivationCodeForDoctorApp'; +const SEND_ACTIVATION_CODE_FOR_VERIFICATION_SCREEN = + 'Services/DoctorApplication.svc/REST/SendVerificationCode'; const MEMBER_CHECK_ACTIVATION_CODE_NEW = 'Services/Sentry.svc/REST/MemberCheckActivationCode_New'; @@ -167,7 +169,8 @@ const GET_CHIEF_COMPLAINT = const GET_PHYSICAL_EXAM = 'Services/DoctorApplication.svc/REST/GetPhysicalExam'; const GET_PROGRESS_NOTE = 'Services/DoctorApplication.svc/REST/GetProgressNote'; const GET_ASSESSMENT = 'Services/DoctorApplication.svc/REST/GetAssessment'; -const GET_ORDER_PROCEDURE = 'Services/DoctorApplication.svc/REST/GetOrderedProcedure'; +const GET_ORDER_PROCEDURE = + 'Services/DoctorApplication.svc/REST/GetOrderedProcedure'; const GET_CATEGORISE_PROCEDURE = 'Services/DoctorApplication.svc/REST/GetProcedure'; @@ -175,7 +178,8 @@ const UPDATE_PROCEDURE = 'Services/DoctorApplication.svc/REST/PatchProcedure'; const UPDATE_PRESCRIPTION = 'Services/DoctorApplication.svc/REST/PatchPrescription'; const SEARCH_DRUG = 'Services/DoctorApplication.svc/REST/GetMedicationList'; - +const DRUG_TO_DRUG = + 'Services/DoctorApplication.svc/REST/DrugToDrugInteraction'; const GET_MEDICAL_FILE = 'Services/DoctorApplication.svc/REST/GetMedicalFile'; var selectedPatientType = 1; diff --git a/lib/core/model/imei_details.dart b/lib/core/model/imei_details.dart index 2cb0cd97..614ce67a 100644 --- a/lib/core/model/imei_details.dart +++ b/lib/core/model/imei_details.dart @@ -1,26 +1,36 @@ class GetIMEIDetailsModel { + int iD; String iMEI; int logInTypeID; bool outSA; String mobile; - String identificationNo; + Null identificationNo; int doctorID; String doctorName; String doctorNameN; int clinicID; String clinicDescription; - String clnicDescriptionN; + Null clinicDescriptionN; + int projectID; String projectName; String genderDescription; - String genderDescriptionN; + Null genderDescriptionN; String titleDescription; - String titleDescriptionN; + Null titleDescriptionN; + Null zipCode; + String createdOn; + Null createdBy; + String editedOn; + int editedBy; bool biometricEnabled; - int preferredLanguage; + Null preferredLanguage; bool isActive; + String vidaAuthTokenID; + String vidaRefreshTokenID; GetIMEIDetailsModel( - {this.iMEI, + {this.iD, + this.iMEI, this.logInTypeID, this.outSA, this.mobile, @@ -30,17 +40,26 @@ class GetIMEIDetailsModel { this.doctorNameN, this.clinicID, this.clinicDescription, - this.clnicDescriptionN, + this.clinicDescriptionN, + this.projectID, this.projectName, this.genderDescription, this.genderDescriptionN, this.titleDescription, this.titleDescriptionN, + this.zipCode, + this.createdOn, + this.createdBy, + this.editedOn, + this.editedBy, this.biometricEnabled, this.preferredLanguage, - this.isActive}); + this.isActive, + this.vidaAuthTokenID, + this.vidaRefreshTokenID}); GetIMEIDetailsModel.fromJson(Map json) { + iD = json['ID']; iMEI = json['IMEI']; logInTypeID = json['LogInTypeID']; outSA = json['OutSA']; @@ -51,19 +70,28 @@ class GetIMEIDetailsModel { doctorNameN = json['DoctorNameN']; clinicID = json['ClinicID']; clinicDescription = json['ClinicDescription']; - clnicDescriptionN = json['ClnicDescriptionN']; + clinicDescriptionN = json['ClinicDescriptionN']; + projectID = json['ProjectID']; projectName = json['ProjectName']; genderDescription = json['Gender_Description']; genderDescriptionN = json['Gender_DescriptionN']; titleDescription = json['Title_Description']; titleDescriptionN = json['Title_DescriptionN']; + zipCode = json['ZipCode']; + createdOn = json['CreatedOn']; + createdBy = json['CreatedBy']; + editedOn = json['EditedOn']; + editedBy = json['EditedBy']; biometricEnabled = json['BiometricEnabled']; preferredLanguage = json['PreferredLanguage']; isActive = json['IsActive']; + vidaAuthTokenID = json['VidaAuthTokenID']; + vidaRefreshTokenID = json['VidaRefreshTokenID']; } Map toJson() { final Map data = new Map(); + data['ID'] = this.iD; data['IMEI'] = this.iMEI; data['LogInTypeID'] = this.logInTypeID; data['OutSA'] = this.outSA; @@ -74,15 +102,23 @@ class GetIMEIDetailsModel { data['DoctorNameN'] = this.doctorNameN; data['ClinicID'] = this.clinicID; data['ClinicDescription'] = this.clinicDescription; - data['ClnicDescriptionN'] = this.clnicDescriptionN; + data['ClinicDescriptionN'] = this.clinicDescriptionN; + data['ProjectID'] = this.projectID; data['ProjectName'] = this.projectName; data['Gender_Description'] = this.genderDescription; data['Gender_DescriptionN'] = this.genderDescriptionN; data['Title_Description'] = this.titleDescription; data['Title_DescriptionN'] = this.titleDescriptionN; + data['ZipCode'] = this.zipCode; + data['CreatedOn'] = this.createdOn; + data['CreatedBy'] = this.createdBy; + data['EditedOn'] = this.editedOn; + data['EditedBy'] = this.editedBy; data['BiometricEnabled'] = this.biometricEnabled; data['PreferredLanguage'] = this.preferredLanguage; data['IsActive'] = this.isActive; + data['VidaAuthTokenID'] = this.vidaAuthTokenID; + data['VidaRefreshTokenID'] = this.vidaRefreshTokenID; return data; } } diff --git a/lib/core/model/insert_imei_model.dart b/lib/core/model/insert_imei_model.dart index c2285d92..40668dba 100644 --- a/lib/core/model/insert_imei_model.dart +++ b/lib/core/model/insert_imei_model.dart @@ -1,30 +1,42 @@ class InsertIMEIDetailsModel { String iMEI; int logInTypeID; - bool outSA; - String mobileNo; - String identificationNo; + Null outSA; + Null mobile; + Null identificationNo; int doctorID; String doctorName; String doctorNameN; int clinicID; String clinicDescription; - String clinicDescriptionN; + Null clinicDescriptionN; String projectName; - int projectID; String genderDescription; - String genderDescriptionN; + Null genderDescriptionN; String titleDescription; - String titleDescriptionN; + Null titleDescriptionN; bool bioMetricEnabled; - int preferredLanguage; + Null preferredLanguage; bool isActive; + int editedBy; + int projectID; + String tokenID; + int languageID; + String stamp; + String iPAdress; + double versionID; + int channel; + String sessionID; + bool isLoginForDoctorApp; + int patientOutSA; + String vidaAuthTokenID; + String vidaRefreshTokenID; InsertIMEIDetailsModel( {this.iMEI, this.logInTypeID, this.outSA, - this.mobileNo, + this.mobile, this.identificationNo, this.doctorID, this.doctorName, @@ -33,20 +45,32 @@ class InsertIMEIDetailsModel { this.clinicDescription, this.clinicDescriptionN, this.projectName, - this.projectID, this.genderDescription, this.genderDescriptionN, this.titleDescription, this.titleDescriptionN, this.bioMetricEnabled, this.preferredLanguage, - this.isActive}); + this.isActive, + this.editedBy, + this.projectID, + this.tokenID, + this.languageID, + this.stamp, + this.iPAdress, + this.versionID, + this.channel, + this.sessionID, + this.isLoginForDoctorApp, + this.patientOutSA, + this.vidaAuthTokenID, + this.vidaRefreshTokenID}); InsertIMEIDetailsModel.fromJson(Map json) { iMEI = json['IMEI']; logInTypeID = json['LogInTypeID']; outSA = json['OutSA']; - mobileNo = json['MobileNo']; + mobile = json['Mobile']; identificationNo = json['IdentificationNo']; doctorID = json['DoctorID']; doctorName = json['DoctorName']; @@ -55,14 +79,26 @@ class InsertIMEIDetailsModel { clinicDescription = json['ClinicDescription']; clinicDescriptionN = json['ClinicDescriptionN']; projectName = json['ProjectName']; - projectID = json['ProjectID']; genderDescription = json['GenderDescription']; genderDescriptionN = json['GenderDescriptionN']; titleDescription = json['TitleDescription']; - titleDescriptionN = json['TitleDescriptionN']; + titleDescriptionN = json['Title_DescriptionN']; bioMetricEnabled = json['BioMetricEnabled']; preferredLanguage = json['PreferredLanguage']; isActive = json['IsActive']; + editedBy = json['EditedBy']; + projectID = json['ProjectID']; + tokenID = json['TokenID']; + languageID = json['LanguageID']; + stamp = json['stamp']; + iPAdress = json['IPAdress']; + versionID = json['VersionID']; + channel = json['Channel']; + sessionID = json['SessionID']; + isLoginForDoctorApp = json['IsLoginForDoctorApp']; + patientOutSA = json['PatientOutSA']; + vidaAuthTokenID = json['VidaAuthTokenID']; + vidaRefreshTokenID = json['VidaRefreshTokenID']; } Map toJson() { @@ -70,7 +106,7 @@ class InsertIMEIDetailsModel { data['IMEI'] = this.iMEI; data['LogInTypeID'] = this.logInTypeID; data['OutSA'] = this.outSA; - data['MobileNo'] = this.mobileNo; + data['Mobile'] = this.mobile; data['IdentificationNo'] = this.identificationNo; data['DoctorID'] = this.doctorID; data['DoctorName'] = this.doctorName; @@ -79,14 +115,26 @@ class InsertIMEIDetailsModel { data['ClinicDescription'] = this.clinicDescription; data['ClinicDescriptionN'] = this.clinicDescriptionN; data['ProjectName'] = this.projectName; - data['ProjectID'] = this.projectID; data['GenderDescription'] = this.genderDescription; data['GenderDescriptionN'] = this.genderDescriptionN; data['TitleDescription'] = this.titleDescription; - data['TitleDescriptionN'] = this.titleDescriptionN; + data['Title_DescriptionN'] = this.titleDescriptionN; data['BioMetricEnabled'] = this.bioMetricEnabled; data['PreferredLanguage'] = this.preferredLanguage; data['IsActive'] = this.isActive; + data['EditedBy'] = this.editedBy; + data['ProjectID'] = this.projectID; + data['TokenID'] = this.tokenID; + data['LanguageID'] = this.languageID; + data['stamp'] = this.stamp; + data['IPAdress'] = this.iPAdress; + data['VersionID'] = this.versionID; + data['Channel'] = this.channel; + data['SessionID'] = this.sessionID; + data['IsLoginForDoctorApp'] = this.isLoginForDoctorApp; + data['PatientOutSA'] = this.patientOutSA; + data['VidaAuthTokenID'] = this.vidaAuthTokenID; + data['VidaRefreshTokenID'] = this.vidaRefreshTokenID; return data; } } diff --git a/lib/core/service/patient-vital-signs-service.dart b/lib/core/service/patient-vital-signs-service.dart index 8d0cfc31..a5e3a107 100644 --- a/lib/core/service/patient-vital-signs-service.dart +++ b/lib/core/service/patient-vital-signs-service.dart @@ -5,8 +5,7 @@ import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart'; import 'package:doctor_app_flutter/models/patient/vital_sign/patient-vital-sign-data.dart'; import 'package:doctor_app_flutter/models/patient/vital_sign/vital_sign_res_model.dart'; -class VitalSignsService extends BaseService{ - +class VitalSignsService extends BaseService { List patientVitalSignList = []; List patientVitalSignOrderdSubList = []; VitalSignData patientVitalSigns; @@ -15,16 +14,17 @@ class VitalSignsService extends BaseService{ patientVitalSigns = null; hasError = false; Map body = Map(); - body['PatientMRN'] = patient.patientMRN; - body['AppointmentNo'] = patient.appointmentNo; - body['EpisodeID'] = patient.episodeNo; - + body['PatientMRN'] = 2954208; //patient.patientMRN; + body['AppointmentNo'] = "2016055308"; //patient.appointmentNo; + body['EpisodeID'] = 210011002; //patient.episodeNo; await baseAppClient.post( GET_PATIENT_VITAL_SIGN_DATA, onSuccess: (dynamic response, int statusCode) { - if(response['VitalSignsList'] != null){ - if(response['VitalSignsList']['entityList'] != null && (response['VitalSignsList']['entityList'] as List).length > 0){ - patientVitalSigns = VitalSignData.fromJson(response['VitalSignsList']['entityList'][0]); + if (response['VitalSignsList'] != null) { + if (response['VitalSignsList']['entityList'] != null && + (response['VitalSignsList']['entityList'] as List).length > 0) { + patientVitalSigns = VitalSignData.fromJson( + response['VitalSignsList']['entityList'][0]); } } }, @@ -35,4 +35,4 @@ class VitalSignsService extends BaseService{ body: body, ); } -} \ No newline at end of file +} diff --git a/lib/core/service/prescription_service.dart b/lib/core/service/prescription_service.dart index 25aa98ea..14ae072d 100644 --- a/lib/core/service/prescription_service.dart +++ b/lib/core/service/prescription_service.dart @@ -5,6 +5,9 @@ import 'package:doctor_app_flutter/core/model/post_prescrition_req_model.dart'; import 'package:doctor_app_flutter/core/model/search_drug_model.dart'; import 'package:doctor_app_flutter/core/model/search_drug_request_model.dart'; import 'package:doctor_app_flutter/core/service/base/base_service.dart'; +import 'package:doctor_app_flutter/models/SOAP/GetAllergiesResModel.dart'; +import 'package:doctor_app_flutter/models/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/models/patient/vital_sign/patient-vital-sign-data.dart'; class PrescriptionService extends BaseService { List _prescriptionList = List(); @@ -13,6 +16,7 @@ class PrescriptionService extends BaseService { List get drugsList => _drugsList; List doctorsList = []; List specialityList = []; + List drugToDrug = []; PrescriptionReqModel _prescriptionReqModel = PrescriptionReqModel( //patientMRN: 3120877, @@ -20,8 +24,8 @@ class PrescriptionService extends BaseService { ); SearchDrugRequestModel _drugRequestModel = SearchDrugRequestModel( search: ["Acetaminophen"], - vidaAuthTokenID: - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMDAyIiwianRpIjoiY2QwOWU3MTEtZDEwYy00NjZhLWEwNDctMjc4MDBmNmRkMTYxIiwiZW1haWwiOiIiLCJpZCI6IjEwMDIiLCJOYW1lIjoiVEVNUCAtIERPQ1RPUiIsIkVtcGxveWVlSWQiOiI0NzA5IiwiRmFjaWxpdHlHcm91cElkIjoiMDEwMjY2IiwiRmFjaWxpdHlJZCI6IjE1IiwiUGhhcmFtY3lGYWNpbGl0eUlkIjoiNTUiLCJJU19QSEFSTUFDWV9DT05ORUNURUQiOiJUcnVlIiwiRG9jdG9ySWQiOiI0NzA5IiwiU0VTU0lPTklEIjoiMjE1OTYyMDMiLCJDbGluaWNJZCI6IjEiLCJyb2xlIjpbIkhFQUQgTlVSU0VTIiwiRE9DVE9SUyIsIkhFQUQgRE9DVE9SUyIsIkFETUlOSVNUUkFUT1JTIiwiUkVDRVBUSU9OSVNUIiwiRVIgTlVSU0UiLCJJVkYgUkVDRVBUSU9OSVNUIiwiRVIgUkVDRVBUSU9OSVNUIiwiUEhBUk1BQ1kgQUNDT1VOVCBTVEFGRiIsIlBIQVJNQUNZIE5VUlNFIiwiSU5QQVRJRU5UIFBIQVJNQUNJU1QiLCJBRE1JU1NJT04gU1RBRkYiLCJBUFBST1ZBTCBTVEFGRiIsIklWRiBET0NUT1IiLCJJVkYgTlVSU0UiLCJJVkYgQ09PUkRJTkFUT1IiLCJJVkYgTEFCIFNUQUZGIiwiQ09OU0VOVCAiLCJNRURJQ0FMIFJFUE9SVCAtIFNJQ0sgTEVBVkUgTUFOQUdFUiJdLCJuYmYiOjE2MDkyNjQ2MTQsImV4cCI6MTYxMDEyODYxNCwiaWF0IjoxNjA5MjY0NjE0fQ.xCJ0jGtSFf36G8uZpdmHVoLfXDyP6e9mBpuOPSlzuio", + // vidaAuthTokenID: + // "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMDAyIiwianRpIjoiY2QwOWU3MTEtZDEwYy00NjZhLWEwNDctMjc4MDBmNmRkMTYxIiwiZW1haWwiOiIiLCJpZCI6IjEwMDIiLCJOYW1lIjoiVEVNUCAtIERPQ1RPUiIsIkVtcGxveWVlSWQiOiI0NzA5IiwiRmFjaWxpdHlHcm91cElkIjoiMDEwMjY2IiwiRmFjaWxpdHlJZCI6IjE1IiwiUGhhcmFtY3lGYWNpbGl0eUlkIjoiNTUiLCJJU19QSEFSTUFDWV9DT05ORUNURUQiOiJUcnVlIiwiRG9jdG9ySWQiOiI0NzA5IiwiU0VTU0lPTklEIjoiMjE1OTYyMDMiLCJDbGluaWNJZCI6IjEiLCJyb2xlIjpbIkhFQUQgTlVSU0VTIiwiRE9DVE9SUyIsIkhFQUQgRE9DVE9SUyIsIkFETUlOSVNUUkFUT1JTIiwiUkVDRVBUSU9OSVNUIiwiRVIgTlVSU0UiLCJJVkYgUkVDRVBUSU9OSVNUIiwiRVIgUkVDRVBUSU9OSVNUIiwiUEhBUk1BQ1kgQUNDT1VOVCBTVEFGRiIsIlBIQVJNQUNZIE5VUlNFIiwiSU5QQVRJRU5UIFBIQVJNQUNJU1QiLCJBRE1JU1NJT04gU1RBRkYiLCJBUFBST1ZBTCBTVEFGRiIsIklWRiBET0NUT1IiLCJJVkYgTlVSU0UiLCJJVkYgQ09PUkRJTkFUT1IiLCJJVkYgTEFCIFNUQUZGIiwiQ09OU0VOVCAiLCJNRURJQ0FMIFJFUE9SVCAtIFNJQ0sgTEVBVkUgTUFOQUdFUiJdLCJuYmYiOjE2MDkyNjQ2MTQsImV4cCI6MTYxMDEyODYxNCwiaWF0IjoxNjA5MjY0NjE0fQ.xCJ0jGtSFf36G8uZpdmHVoLfXDyP6e9mBpuOPSlzuio", ); PostPrescriptionReqModel _postPrescriptionReqModel = @@ -87,4 +91,18 @@ class PrescriptionService extends BaseService { body: updatePrescriptionReqModel.toJson(), ); } + + Future getDrugToDrug( + VitalSignData vital, List allergy) async { + hasError = false; + var request = {}; + await baseAppClient.post(DRUG_TO_DRUG, + onSuccess: (dynamic response, int statusCode) { + drugToDrug = []; + //drugToDrug = //response['MedicationList']['entityList']; + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: _drugRequestModel.toJson()); + } } diff --git a/lib/core/viewModel/auth_view_model.dart b/lib/core/viewModel/auth_view_model.dart index 00089ef9..960462cd 100644 --- a/lib/core/viewModel/auth_view_model.dart +++ b/lib/core/viewModel/auth_view_model.dart @@ -7,6 +7,7 @@ import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart'; import 'package:doctor_app_flutter/locator.dart'; import 'package:doctor_app_flutter/models/auth/activation_Code_req_model.dart'; import 'package:doctor_app_flutter/models/auth/check_activation_code_request_model.dart'; +import 'package:doctor_app_flutter/models/auth/send_activation_code_model2.dart'; import 'package:doctor_app_flutter/models/doctor/clinic_model.dart'; import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; import 'package:doctor_app_flutter/models/doctor/doctor_profile_model.dart'; @@ -92,7 +93,9 @@ class AuthViewModel extends BaseViewModel { nRequest.titleDescription = request['Title_Description']; nRequest.titleDescriptionN = request['Title_DescriptionN']; nRequest.projectID = await sharedPref.getInt(PROJECT_ID); - + nRequest.vidaAuthTokenID = await sharedPref.getString(VIDA_AUTH_TOKEN_ID); + nRequest.vidaRefreshTokenID = + await sharedPref.getString(VIDA_REFRESH_TOKEN_ID); try { var localRes; await baseAppClient.post(INSERT_DEVICE_IMEI, @@ -210,4 +213,21 @@ class AuthViewModel extends BaseViewModel { throw error; } } + + Future sendActivationCodeVerificationScreen( + ActivationCodeModel2 activationCodeModel) async { + try { + var localRes; + await baseAppClient.post(SEND_ACTIVATION_CODE_FOR_VERIFICATION_SCREEN, + onSuccess: (dynamic response, int statusCode) { + localRes = response; + }, onFailure: (String error, int statusCode) { + throw error; + }, body: activationCodeModel.toJson()); + return Future.value(localRes); + } catch (error) { + print(error); + throw error; + } + } } diff --git a/lib/core/viewModel/prescription_view_model.dart b/lib/core/viewModel/prescription_view_model.dart index 3380d8c2..d7b8f409 100644 --- a/lib/core/viewModel/prescription_view_model.dart +++ b/lib/core/viewModel/prescription_view_model.dart @@ -5,6 +5,9 @@ import 'package:doctor_app_flutter/core/model/search_drug_model.dart'; import 'package:doctor_app_flutter/core/service/prescription_service.dart'; import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart'; import 'package:doctor_app_flutter/locator.dart'; +import 'package:doctor_app_flutter/models/SOAP/GetAllergiesResModel.dart'; +import 'package:doctor_app_flutter/models/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/models/patient/vital_sign/patient-vital-sign-data.dart'; class PrescriptionViewModel extends BaseViewModel { bool hasError = false; @@ -67,4 +70,16 @@ class PrescriptionViewModel extends BaseViewModel { } else setState(ViewState.Idle); } + + Future getDrugToDrug( + VitalSignData vital, List allergy) async { + hasError = false; + setState(ViewState.Busy); + await _prescriptionService.getDrugToDrug(vital, allergy); + if (_prescriptionService.hasError) { + error = _prescriptionService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } } diff --git a/lib/models/auth/send_activation_code_model2.dart b/lib/models/auth/send_activation_code_model2.dart new file mode 100644 index 00000000..794887b3 --- /dev/null +++ b/lib/models/auth/send_activation_code_model2.dart @@ -0,0 +1,60 @@ +class ActivationCodeModel2 { + int oTPSendType; + String mobileNumber; + String zipCode; + int channel; + int languageID; + double versionID; + int memberID; + int facilityId; + String generalid; + int isMobileFingerPrint; + String vidaAuthTokenID; + String vidaRefreshTokenID; + + ActivationCodeModel2( + {this.oTPSendType, + this.mobileNumber, + this.zipCode, + this.channel, + this.languageID, + this.versionID, + this.memberID, + this.facilityId, + this.generalid, + this.isMobileFingerPrint, + this.vidaAuthTokenID, + this.vidaRefreshTokenID}); + + ActivationCodeModel2.fromJson(Map json) { + oTPSendType = json['OTP_SendType']; + mobileNumber = json['MobileNumber']; + zipCode = json['ZipCode']; + channel = json['Channel']; + languageID = json['LanguageID']; + versionID = json['VersionID']; + memberID = json['MemberID']; + facilityId = json['facilityId']; + generalid = json['generalid']; + isMobileFingerPrint = json['IsMobileFingerPrint']; + vidaAuthTokenID = json['VidaAuthTokenID']; + vidaRefreshTokenID = json['VidaRefreshTokenID']; + } + + Map toJson() { + final Map data = new Map(); + data['OTP_SendType'] = this.oTPSendType; + data['MobileNumber'] = this.mobileNumber; + data['ZipCode'] = this.zipCode; + data['Channel'] = this.channel; + data['LanguageID'] = this.languageID; + data['VersionID'] = this.versionID; + data['MemberID'] = this.memberID; + data['facilityId'] = this.facilityId; + data['generalid'] = this.generalid; + data['IsMobileFingerPrint'] = this.isMobileFingerPrint; + data['VidaAuthTokenID'] = this.vidaAuthTokenID; + data['VidaRefreshTokenID'] = this.vidaRefreshTokenID; + return data; + } +} diff --git a/lib/screens/dashboard_screen.dart b/lib/screens/dashboard_screen.dart index 7b105148..8787eb42 100644 --- a/lib/screens/dashboard_screen.dart +++ b/lib/screens/dashboard_screen.dart @@ -20,6 +20,7 @@ import 'package:doctor_app_flutter/util/helpers.dart'; import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; import 'package:doctor_app_flutter/widgets/patients/profile/profile-welcome-widget.dart'; import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:hexcolor/hexcolor.dart'; @@ -48,6 +49,7 @@ class DashboardScreen extends StatefulWidget { } class _DashboardScreenState extends State { + final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); HospitalViewModel hospitalProvider; AuthViewModel authProvider; bool isLoading = false; @@ -62,13 +64,17 @@ class _DashboardScreenState extends State { projectsProvider = Provider.of(context); projectsProvider.getDoctorClinicsList(); - if (DEVICE_TOKEN != '') { - var request = await sharedPref.getObj(DOCTOR_PROFILE); - authProvider.insertDeviceImei(request).then((value) { - print(value['ReturnValue']); - changeIsLoading(false); - }); - } + _firebaseMessaging.setAutoInitEnabled(true); + _firebaseMessaging.getToken().then((String token) async { + if (token != '') { + DEVICE_TOKEN = token; + var request = await sharedPref.getObj(DOCTOR_PROFILE); + authProvider.insertDeviceImei(request).then((value) { + print(value['ReturnValue']); + changeIsLoading(false); + }); + } + }); } _isInit = false; } @@ -96,8 +102,10 @@ class _DashboardScreenState extends State { PatientMobileNumber: "0", PatientIdentificationID: "0", PatientID: 0, - From: DateUtils.convertDateToFormat(DateTime. now(), 'yyyy-MM-dd').toString(), - To: DateUtils.convertDateToFormat(DateTime. now(), 'yyyy-MM-dd').toString(), + From: DateUtils.convertDateToFormat(DateTime.now(), 'yyyy-MM-dd') + .toString(), + To: DateUtils.convertDateToFormat(DateTime.now(), 'yyyy-MM-dd') + .toString(), LanguageID: 2, stamp: "2020-03-02T13:56:39.170Z", IPAdress: "11.11.11.11", @@ -679,7 +687,7 @@ class _DashboardScreenState extends State { AppText( model.dashboardItemsList.length > 0 ? getPatientCount( - model.dashboardItemsList[7]) + model.dashboardItemsList[5]) : "", fontSize: SizeConfig.textMultiplier * 6, color: Colors.white, @@ -723,7 +731,7 @@ class _DashboardScreenState extends State { color: Colors.white, ), AppText( - TranslationBase.of(context).radiology, + TranslationBase.of(context).clinic, color: Colors.white, ) ], @@ -1017,7 +1025,9 @@ class _DashboardScreenState extends State { ); }, ), - SizedBox(width: 8,), + SizedBox( + width: 8, + ), DashboardItem( child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, @@ -1035,7 +1045,8 @@ class _DashboardScreenState extends State { ), hasBorder: true, onTap: () { - Navigator.of(context).pushNamed(PATIENTS, arguments: { + Navigator.of(context) + .pushNamed(PATIENTS, arguments: { "patientSearchForm": _patientSearchFormValues, "selectedType": "7" }); diff --git a/lib/screens/prescription/add_prescription_form.dart b/lib/screens/prescription/add_prescription_form.dart index 10b779e6..afd4136d 100644 --- a/lib/screens/prescription/add_prescription_form.dart +++ b/lib/screens/prescription/add_prescription_form.dart @@ -7,6 +7,7 @@ import 'package:doctor_app_flutter/core/viewModel/prescription_view_model.dart'; import 'package:doctor_app_flutter/models/livecare/transfer_to_admin.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/prescription/drugtodrug.dart'; import 'package:doctor_app_flutter/screens/prescription/prescription_screen.dart'; import 'package:doctor_app_flutter/screens/prescription/prescription_warnings.dart'; import 'package:doctor_app_flutter/util/date-utils.dart'; @@ -693,7 +694,8 @@ class _PrescriptionFormWidgetState extends State { .addMedication, onPressed: () { formKey.currentState.save(); - + // Navigator.pop(context); + // openDrugToDrug(); if (strength == null || route == null || frequency == null || @@ -708,26 +710,8 @@ class _PrescriptionFormWidgetState extends State { } if (formKey.currentState.validate()) { - postProcedure( - patient: widget.patient, - doseTimeIn: - doseTime['id'].toString(), - model: widget.model, - duration: - duration['id'].toString(), - frequency: - frequency['id'].toString(), - route: route['id'].toString(), - drugId: selectedDrug['ItemId'] - .toString(), - strength: - strength['id'].toString(), - indication: - indicationController.text, - instruction: - instructionController.text, - doseTime: selectedDate); Navigator.pop(context); + openDrugToDrug(); } { // Navigator.push( @@ -804,4 +788,44 @@ class _PrescriptionFormWidgetState extends State { ), ); } + + openDrugToDrug() { + showModalBottomSheet( + context: context, + builder: (context) { + return Container( + height: SizeConfig.realScreenHeight * .5, + width: SizeConfig.realScreenWidth, + child: SingleChildScrollView( + child: Column( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + DrugToDrug(widget.patient), + Container( + margin: EdgeInsets.all(SizeConfig.widthMultiplier * 2), + child: AppButton( + title: TranslationBase.of(context).addMedication, + onPressed: () { + postProcedure( + patient: widget.patient, + doseTimeIn: doseTime['id'].toString(), + model: widget.model, + duration: duration['id'].toString(), + frequency: frequency['id'].toString(), + route: route['id'].toString(), + drugId: selectedDrug['ItemId'].toString(), + strength: strength['id'].toString(), + indication: indicationController.text, + instruction: instructionController.text, + doseTime: selectedDate); + }, + )) + ], + )), + + //], + //) + ); + }); + } } diff --git a/lib/screens/prescription/drugtodrug.dart b/lib/screens/prescription/drugtodrug.dart new file mode 100644 index 00000000..8f51da80 --- /dev/null +++ b/lib/screens/prescription/drugtodrug.dart @@ -0,0 +1,89 @@ +import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/patient-vital-sign-viewmodel.dart'; +import 'package:doctor_app_flutter/core/viewModel/patient_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/prescription_view_model.dart'; +import 'package:doctor_app_flutter/models/SOAP/GeneralGetReqForSOAP.dart'; +import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/models/patient/vital_sign/vital_sign_req_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/medicine/medicine_search_screen.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/network_base_view.dart'; +import 'package:flutter/material.dart'; + +class DrugToDrug extends StatefulWidget { + final PatiantInformtion patient; + DrugToDrug(this.patient); + @override + _DrugToDrug createState() => _DrugToDrug(); +} + +class _DrugToDrug extends State { + int typeID = 1; + List> expandableList = [ + {'name': 'CRITICAL'}, + {'name': 'HIGH'}, + {'name': 'MODERATE'}, + {'name': 'LOW'}, + {'name': 'INFO'}, + ]; + + @override + void initState() { + getTypeID(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + GeneralGetReqForSOAP generalGetReqForSOAP = GeneralGetReqForSOAP( + patientMRN: 2954208, //widget.patient.patientMRN, + episodeId: 210011002, //widget.patient.episodeNo, + appointmentNo: 2016055308, //widget.patient.appointmentNo, + doctorID: '', + editedBy: ''); + + return BaseView( + onModelReady: (model) => model.getPatientVitalSign(widget.patient), + builder: (BuildContext context, model, Widget child) { + return BaseView( + onModelReady: (model2) => + model2.getPatientAllergy(generalGetReqForSOAP), + builder: (BuildContext context, model2, Widget child) { + return BaseView( + onModelReady: (model3) => model3.getDrugToDrug( + model.patientVitalSigns, model2.patientAllergiesList), + builder: (BuildContext context, + PrescriptionViewModel model3, Widget child) => + NetworkBaseView( + baseViewModel: model3, + child: Container( + height: SizeConfig.realScreenHeight * .45, + child: new ListView.builder( + itemCount: expandableList.length, + itemBuilder: (context, i) { + return new ExpansionTile( + title: new Text( + expandableList[i]['name'], + style: new TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic), + ), + children: [Text('Hi')], + ); + })))); + }); + }); + } + + getTypeID() async { + var type = await sharedPref.getString(SLECTED_PATIENT_TYPE) == '0' ? 2 : 1; + setState(() { + typeID = type; + }); + } +} diff --git a/lib/widgets/auth/verification_methods.dart b/lib/widgets/auth/verification_methods.dart index 0de81fdf..caee190d 100644 --- a/lib/widgets/auth/verification_methods.dart +++ b/lib/widgets/auth/verification_methods.dart @@ -5,6 +5,7 @@ import 'package:doctor_app_flutter/core/model/imei_details.dart'; import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; import 'package:doctor_app_flutter/models/auth/activation_Code_req_model.dart'; import 'package:doctor_app_flutter/models/auth/check_activation_code_request_model.dart'; +import 'package:doctor_app_flutter/models/auth/send_activation_code_model2.dart'; import 'package:doctor_app_flutter/models/doctor/clinic_model.dart'; import 'package:doctor_app_flutter/models/doctor/doctor_profile_model.dart'; import 'package:doctor_app_flutter/models/doctor/profile_req_Model.dart'; @@ -330,20 +331,7 @@ class _VerificationMethodsState extends State { widget.changeLoadingStata(true); int projectID = await sharedPref.getInt(PROJECT_ID); ActivationCodeModel activationCodeModel = ActivationCodeModel( - // facilityId: projectID != null ? projectID : 15, //user.projectID, - // generalid: "Cs2020@2016\$2958", - // memberID: _loggedUser != null - // ? _loggedUser['List_MemberInformation'][0]['MemberID'] - // : user.doctorID, - // zipCode: _loggedUser != null - // ? _loggedUser['ZipCode'] - // : user.outSA == true - // ? '966' - // : '971', - // mobileNumber: - // _loggedUser != null ? _loggedUser['MobileNumber'] : user.mobile, facilityId: projectID, - generalid: "Cs2020@2016\$2958", memberID: _loggedUser['List_MemberInformation'][0]['MemberID'], zipCode: _loggedUser['ZipCode'], mobileNumber: _loggedUser['MobileNumber'], @@ -389,6 +377,60 @@ class _VerificationMethodsState extends State { } } + sendActivationCodeVerificationScreen( + oTPSendType, AuthViewModel authProv) async { + // TODO : build enum for verfication method + if (oTPSendType == 1 || oTPSendType == 2) { + widget.changeLoadingStata(true); + ActivationCodeModel2 activationCodeModel = ActivationCodeModel2( + facilityId: user.projectID, + memberID: user.doctorID, + zipCode: user.outSA == true ? '971' : '966', + mobileNumber: user.mobile, + oTPSendType: oTPSendType, + isMobileFingerPrint: 1, + vidaAuthTokenID: user.vidaAuthTokenID, + vidaRefreshTokenID: user.vidaRefreshTokenID); + + try { + authProv + .sendActivationCodeVerificationScreen(activationCodeModel) + .then((res) { + widget.changeLoadingStata(false); + + if (res['MessageStatus'] == 1) { + print("VerificationCode : " + res["VerificationCode"]); + sharedPref.setString(VIDA_AUTH_TOKEN_ID, res["VidaAuthTokenID"]); + sharedPref.setString( + VIDA_REFRESH_TOKEN_ID, res["VidaRefreshTokenID"]); + sharedPref.setString(LOGIN_TOKEN_ID, res["LogInTokenID"]); + this.startSMSService(oTPSendType, authProv); + } else { + print(res['ErrorEndUserMessage']); + helpers.showErrorToast(res['ErrorEndUserMessage']); + } + }).catchError((err) { + print('$err'); + widget.changeLoadingStata(false); + + helpers.showErrorToast(); + }); + } catch (e) {} + } else { + // TODO route to this page with parameters to inicate we should present 2 option + if (Platform.isAndroid && oTPSendType == 3) { + helpers.showErrorToast('Your device not support this feature'); + } else { + // Navigator.of(context).push(MaterialPageRoute( + // builder: (BuildContext context) => + // VerificationMethodsScreen(password: widget.password,))); + + // Navigator.of(context).pushNamed(VERIFICATION_METHODS, + // arguments: {'verificationMethod': oTPSendType}); + } + } + } + Widget getButton(flag, authProv) { switch (flag) { case 2: @@ -679,7 +721,11 @@ class _VerificationMethodsState extends State { } sendActivationCode(type, authProv) async { - sendActivationCodeByOtpNotificationType(type, authProv); + if (user != null) { + sendActivationCodeVerificationScreen(type, authProv); + } else { + sendActivationCodeByOtpNotificationType(type, authProv); + } } startSMSService(type, authProv) {