diff --git a/assets/images/bg_graphic.png b/assets/images/bg_graphic.png new file mode 100644 index 00000000..01525404 Binary files /dev/null and b/assets/images/bg_graphic.png differ diff --git a/assets/images/timeline_bg.png b/assets/images/timeline_bg.png new file mode 100644 index 00000000..d7afc4b1 Binary files /dev/null and b/assets/images/timeline_bg.png differ diff --git a/lib/config/config.dart b/lib/config/config.dart index b3e12498..685d0d7d 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -5,7 +5,7 @@ import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; const MAX_SMALL_SCREEN = 660; -const BASE_URL = 'https://hmgwebservices.com/Services'; +const BASE_URL = 'https://uat.hmgwebservices.com/Services'; const GET_PROJECT = '/Lists.svc/REST/GetProject'; @@ -49,6 +49,10 @@ const GET_PATIENT_VITAL_SIGN = '/Doctors.svc/REST/Doctor_GetPatientVitalSign'; const REPORTS = '/Doctors.svc/REST/GetPatientMedicalReportStatusInfo'; const INSERT_REQUEST_FOR_MEDICAL_REPORT = '/Doctors.svc/REST/InsertRequestForMedicalReport'; +///Rate +const IS_LAST_APPOITMENT_RATED = '/Doctors.svc/REST/IsLastAppoitmentRated'; +const GET_APPOINTMENT_DETAILS_BY_NO = '/MobileNotifications.svc/REST/GetAppointmentDetailsByApptNo'; + //const BASE_URL = 'https://hmgwebservices.com/'; // Production Environment //const BASE_URL = 'https://hmgwebservices.com/Services'; // Production Environment @@ -107,7 +111,7 @@ const SEND_CALL_REQUEST = '/Doctors.svc/REST/InsertCallInfo'; const CHANNEL = 3; const GENERAL_ID = 'Cs2020@2016\$2958'; const IP_ADDRESS = '10.20.10.20'; -const VERSION_ID = 5.5; +const VERSION_ID = 5.6; const SETUP_ID = '91877'; const LANGUAGE = 1; const PATIENT_OUT_SA = 0; diff --git a/lib/core/model/rate/appointment_details.dart b/lib/core/model/rate/appointment_details.dart new file mode 100644 index 00000000..30280b4a --- /dev/null +++ b/lib/core/model/rate/appointment_details.dart @@ -0,0 +1,64 @@ +class AppointmentDetails { + String setupID; + int projectID; + int patientID; + int appointmentNo; + int clinicID; + int doctorID; + String startTime; + String endTime; + String appointmentDate; + String clinicName; + String doctorImageURL; + String doctorName; + String projectName; + + AppointmentDetails( + {this.setupID, + this.projectID, + this.patientID, + this.appointmentNo, + this.clinicID, + this.doctorID, + this.startTime, + this.endTime, + this.appointmentDate, + this.clinicName, + this.doctorImageURL, + this.doctorName, + this.projectName}); + + AppointmentDetails.fromJson(Map json) { + setupID = json['SetupID']; + projectID = json['ProjectID']; + patientID = json['PatientID']; + appointmentNo = json['AppointmentNo']; + clinicID = json['ClinicID']; + doctorID = json['DoctorID']; + startTime = json['StartTime']; + endTime = json['EndTime']; + appointmentDate = json['AppointmentDate']; + clinicName = json['ClinicName']; + doctorImageURL = json['DoctorImageURL']; + doctorName = json['DoctorName']; + projectName = json['ProjectName']; + } + + Map toJson() { + final Map data = new Map(); + data['SetupID'] = this.setupID; + data['ProjectID'] = this.projectID; + data['PatientID'] = this.patientID; + data['AppointmentNo'] = this.appointmentNo; + data['ClinicID'] = this.clinicID; + data['DoctorID'] = this.doctorID; + data['StartTime'] = this.startTime; + data['EndTime'] = this.endTime; + data['AppointmentDate'] = this.appointmentDate; + data['ClinicName'] = this.clinicName; + data['DoctorImageURL'] = this.doctorImageURL; + data['DoctorName'] = this.doctorName; + data['ProjectName'] = this.projectName; + return data; + } +} diff --git a/lib/core/model/rate/appointment_rate.dart b/lib/core/model/rate/appointment_rate.dart new file mode 100644 index 00000000..abb249f4 --- /dev/null +++ b/lib/core/model/rate/appointment_rate.dart @@ -0,0 +1,100 @@ +class AppointmentRate { + int rate; + int appointmentNo; + int projectID; + int doctorID; + int clinicID; + String note; + String mobileNumber; + int createdBy; + int editedBy; + double versionID; + int channel; + int languageID; + String iPAdress; + String generalid; + int patientOutSA; + String sessionID; + bool isDentalAllowedBackend; + int deviceTypeID; + int patientID; + String tokenID; + int patientTypeID; + int patientType; + + AppointmentRate( + {this.rate, + this.appointmentNo, + this.projectID, + this.doctorID, + this.clinicID, + this.note, + this.mobileNumber, + this.createdBy, + this.editedBy, + this.versionID, + this.channel, + this.languageID, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID, + this.patientID, + this.tokenID, + this.patientTypeID, + this.patientType}); + + AppointmentRate.fromJson(Map json) { + rate = json['Rate']; + appointmentNo = json['AppointmentNo']; + projectID = json['ProjectID']; + doctorID = json['DoctorID']; + clinicID = json['ClinicID']; + note = json['Note']; + mobileNumber = json['MobileNumber']; + createdBy = json['CreatedBy']; + editedBy = json['EditedBy']; + versionID = json['VersionID']; + channel = json['Channel']; + languageID = json['LanguageID']; + iPAdress = json['IPAdress']; + generalid = json['generalid']; + patientOutSA = json['PatientOutSA']; + sessionID = json['SessionID']; + isDentalAllowedBackend = json['isDentalAllowedBackend']; + deviceTypeID = json['DeviceTypeID']; + patientID = json['PatientID']; + tokenID = json['TokenID']; + patientTypeID = json['PatientTypeID']; + patientType = json['PatientType']; + } + + Map toJson() { + final Map data = new Map(); + data['Rate'] = this.rate; + data['AppointmentNo'] = this.appointmentNo; + data['ProjectID'] = this.projectID; + data['DoctorID'] = this.doctorID; + data['ClinicID'] = this.clinicID; + data['Note'] = this.note; + data['MobileNumber'] = this.mobileNumber; + data['CreatedBy'] = this.createdBy; + data['EditedBy'] = this.editedBy; + data['VersionID'] = this.versionID; + data['Channel'] = this.channel; + data['LanguageID'] = this.languageID; + data['IPAdress'] = this.iPAdress; + data['generalid'] = this.generalid; + data['PatientOutSA'] = this.patientOutSA; + data['SessionID'] = this.sessionID; + data['isDentalAllowedBackend'] = this.isDentalAllowedBackend; + data['DeviceTypeID'] = this.deviceTypeID; + data['PatientID'] = this.patientID; + data['TokenID'] = this.tokenID; + data['PatientTypeID'] = this.patientTypeID; + data['PatientType'] = this.patientType; + return data; + } +} diff --git a/lib/core/model/rate/appoitment_rated.dart b/lib/core/model/rate/appoitment_rated.dart new file mode 100644 index 00000000..95358b23 --- /dev/null +++ b/lib/core/model/rate/appoitment_rated.dart @@ -0,0 +1,160 @@ +class AppoitmentRated { + String setupID; + int projectID; + int appointmentNo; + String appointmentDate; + String appointmentDateN; + int appointmentType; + String bookDate; + int patientType; + int patientID; + int clinicID; + int doctorID; + String endDate; + String startTime; + String endTime; + int status; + int visitType; + int visitFor; + int patientStatusType; + int companyID; + int bookedBy; + String bookedOn; + int confirmedBy; + String confirmedOn; + int arrivalChangedBy; + String arrivedOn; + int editedBy; + String editedOn; + Null doctorName; + String doctorNameN; + String statusDesc; + String statusDescN; + bool vitalStatus; + Null vitalSignAppointmentNo; + int episodeID; + String doctorTitle; + bool isAppoitmentLiveCare; + + AppoitmentRated( + {this.setupID, + this.projectID, + this.appointmentNo, + this.appointmentDate, + this.appointmentDateN, + this.appointmentType, + this.bookDate, + this.patientType, + this.patientID, + this.clinicID, + this.doctorID, + this.endDate, + this.startTime, + this.endTime, + this.status, + this.visitType, + this.visitFor, + this.patientStatusType, + this.companyID, + this.bookedBy, + this.bookedOn, + this.confirmedBy, + this.confirmedOn, + this.arrivalChangedBy, + this.arrivedOn, + this.editedBy, + this.editedOn, + this.doctorName, + this.doctorNameN, + this.statusDesc, + this.statusDescN, + this.vitalStatus, + this.vitalSignAppointmentNo, + this.episodeID, + this.doctorTitle, + this.isAppoitmentLiveCare}); + + AppoitmentRated.fromJson(Map json) { + try { + setupID = json['SetupID']; + projectID = json['ProjectID']; + appointmentNo = json['AppointmentNo']; + appointmentDate = json['AppointmentDate']; + appointmentDateN = json['AppointmentDateN']; + appointmentType = json['AppointmentType']; + bookDate = json['BookDate']; + patientType = json['PatientType']; + patientID = json['PatientID']; + clinicID = json['ClinicID']; + doctorID = json['DoctorID']; + endDate = json['EndDate']; + startTime = json['StartTime']; + endTime = json['EndTime']; + status = json['Status']; + visitType = json['VisitType']; + visitFor = json['VisitFor']; + patientStatusType = json['PatientStatusType']; + companyID = json['CompanyID']; + bookedBy = json['BookedBy']; + bookedOn = json['BookedOn']; + confirmedBy = json['ConfirmedBy']; + confirmedOn = json['ConfirmedOn']; + arrivalChangedBy = json['ArrivalChangedBy']; + arrivedOn = json['ArrivedOn']; + editedBy = json['EditedBy']; + editedOn = json['EditedOn']; + doctorName = json['DoctorName']; + doctorNameN = json['DoctorNameN']; + statusDesc = json['StatusDesc']; + statusDescN = json['StatusDescN']; + vitalStatus = json['VitalStatus']; + vitalSignAppointmentNo = json['VitalSignAppointmentNo']; + episodeID = json['EpisodeID']; + doctorTitle = json['DoctorTitle']; + isAppoitmentLiveCare = json['IsAppoitmentLiveCare']; + } catch (e) { + print(e); + } + } + + Map toJson() { + final Map data = new Map(); + data['SetupID'] = this.setupID; + data['ProjectID'] = this.projectID; + data['AppointmentNo'] = this.appointmentNo; + data['AppointmentDate'] = this.appointmentDate; + data['AppointmentDateN'] = this.appointmentDateN; + data['AppointmentType'] = this.appointmentType; + data['BookDate'] = this.bookDate; + data['PatientType'] = this.patientType; + data['PatientID'] = this.patientID; + data['ClinicID'] = this.clinicID; + data['DoctorID'] = this.doctorID; + data['EndDate'] = this.endDate; + data['StartTime'] = this.startTime; + data['EndTime'] = this.endTime; + data['Status'] = this.status; + data['VisitType'] = this.visitType; + data['VisitFor'] = this.visitFor; + data['PatientStatusType'] = this.patientStatusType; + data['CompanyID'] = this.companyID; + data['BookedBy'] = this.bookedBy; + data['BookedOn'] = this.bookedOn; + data['ConfirmedBy'] = this.confirmedBy; + data['ConfirmedOn'] = this.confirmedOn; + data['ArrivalChangedBy'] = this.arrivalChangedBy; + data['ArrivedOn'] = this.arrivedOn; + data['EditedBy'] = this.editedBy; + data['EditedOn'] = this.editedOn; + data['DoctorName'] = this.doctorName; + data['DoctorNameN'] = this.doctorNameN; + data['StatusDesc'] = this.statusDesc; + data['StatusDescN'] = this.statusDescN; + data['VitalStatus'] = this.vitalStatus; + data['VitalSignAppointmentNo'] = this.vitalSignAppointmentNo; + data['EpisodeID'] = this.episodeID; + data['DoctorTitle'] = this.doctorTitle; + data['IsAppoitmentLiveCare'] = this.isAppoitmentLiveCare; + return data; + } +} diff --git a/lib/core/service/appointment_rate_service.dart b/lib/core/service/appointment_rate_service.dart new file mode 100644 index 00000000..a0c2b208 --- /dev/null +++ b/lib/core/service/appointment_rate_service.dart @@ -0,0 +1,71 @@ +import 'package:diplomaticquarterapp/config/config.dart'; +import 'package:diplomaticquarterapp/core/model/rate/appointment_rate.dart'; +import 'package:diplomaticquarterapp/core/model/rate/appoitment_rated.dart'; +import 'package:diplomaticquarterapp/core/model/rate/appointment_details.dart'; +import 'package:diplomaticquarterapp/core/service/base_service.dart'; + +class AppointmentRateService extends BaseService { + List appointmentRatedList = List(); + AppointmentDetails appointmentDetails; + + Future getIsLastAppointmentRatedList() async { + hasError = false; + await baseAppClient.post(IS_LAST_APPOITMENT_RATED, + onSuccess: (dynamic response, int statusCode) { + appointmentRatedList.clear(); + response['IsLastAppoitmentRatedList'].forEach((appoint) { + appointmentRatedList.add(AppoitmentRated.fromJson(appoint)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: Map()); + } + + Future getAppointmentDetails() async { + hasError = false; + Map bodyData = Map(); + bodyData['AppointmentNumber'] = appointmentRatedList[0].appointmentNo; + bodyData['ProjectID'] = appointmentRatedList[0].projectID; + await baseAppClient.post(GET_APPOINTMENT_DETAILS_BY_NO, + onSuccess: (dynamic response, int statusCode) { + if (response['AppointmentDetails'] != null) + appointmentDetails = + AppointmentDetails.fromJson(response['AppointmentDetails']); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: bodyData); + } + + Future sendAppointmentRate(int rate, int appointmentNo, int projectID, + int doctorID, int clinicID, String note) async { + hasError = false; + AppointmentRate appointmentRate = AppointmentRate(); + appointmentRate.rate = rate; + appointmentRate.appointmentNo = appointmentNo; + appointmentRate.projectID = projectID; + appointmentRate.doctorID = doctorID; + appointmentRate.clinicID = clinicID; + appointmentRate.note = note; + + await baseAppClient.post(GET_APPOINTMENT_DETAILS_BY_NO, + onSuccess: (dynamic response, int statusCode) {}, + onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: appointmentRate.toJson()); + } + + AppoitmentRated get lastAppointmentRated { + if (appointmentRatedList.length > 0) + return appointmentRatedList[appointmentRatedList.length - 1]; + return null; + } + + deleteAppointmentRated(AppoitmentRated appointmentRated) { + appointmentRatedList.remove(appointmentRated); + } + + deleteAllAppAppointmentRate() => appointmentRatedList.clear(); +} diff --git a/lib/core/service/dashboard_service.dart b/lib/core/service/dashboard_service.dart new file mode 100644 index 00000000..a15a4b39 --- /dev/null +++ b/lib/core/service/dashboard_service.dart @@ -0,0 +1,7 @@ +import 'package:diplomaticquarterapp/config/config.dart'; +import 'package:diplomaticquarterapp/core/model/rate/appoitment_rated.dart'; +import 'package:diplomaticquarterapp/core/service/base_service.dart'; + +class DashboardService extends BaseService { + +} diff --git a/lib/core/viewModels/appointment_rate_view_model.dart b/lib/core/viewModels/appointment_rate_view_model.dart new file mode 100644 index 00000000..23d00366 --- /dev/null +++ b/lib/core/viewModels/appointment_rate_view_model.dart @@ -0,0 +1,68 @@ +import 'package:diplomaticquarterapp/core/enum/viewstate.dart'; +import 'package:diplomaticquarterapp/core/model/rate/appointment_details.dart'; +import 'package:diplomaticquarterapp/core/model/rate/appoitment_rated.dart'; +import 'package:diplomaticquarterapp/core/service/appointment_rate_service.dart'; +import 'package:diplomaticquarterapp/core/viewModels/base_view_model.dart'; +import '../../locator.dart'; + +class AppointmentRateViewModel extends BaseViewModel { + AppointmentRateService _appointmentRateService = + locator(); + bool isHaveAppointmentNotRate = false; + + AppointmentDetails get appointmentDetails => _appointmentRateService.appointmentDetails; + + + Future getIsLastAppointmentRatedList() async { + isHaveAppointmentNotRate = false; + setState(ViewState.Busy); + await _appointmentRateService.getIsLastAppointmentRatedList(); + if (_appointmentRateService.hasError) { + error = _appointmentRateService.error; + setState(ViewState.Error); + } else { + if(_appointmentRateService.appointmentRatedList.length>0) + await getAppointmentDetails(); + } + } + + getAppointmentDetails() async { + await _appointmentRateService.getAppointmentDetails(); + if (_appointmentRateService.hasError) { + error = _appointmentRateService.error; + setState(ViewState.Error); + } else { + if (_appointmentRateService.appointmentDetails != null) + isHaveAppointmentNotRate = true; + setState(ViewState.Idle); + } + } + + Future sendAppointmentRate(int rate, int appointmentNo, int projectID, + int doctorID, int clinicID, String note) async { + setState(ViewState.BusyLocal); + await _appointmentRateService.sendAppointmentRate( + rate, appointmentNo, projectID, doctorID, clinicID, note); + if (_appointmentRateService.hasError) { + error = _appointmentRateService.error; + setState(ViewState.ErrorLocal); + } else { + setState(ViewState.Idle); + _appointmentRateService.deleteAllAppAppointmentRate(); + } + } + + AppoitmentRated get lastAppointmentRated => + _appointmentRateService.lastAppointmentRated; + + deleteAppointmentRated(AppoitmentRated appointmentRated) => + _appointmentRateService.deleteAppointmentRated(appointmentRated); + + deleteAppAppointmentRate() => + _appointmentRateService.deleteAllAppAppointmentRate(); + + setIsRated(bool isRated) { + this.isHaveAppointmentNotRate = isRated; + notifyListeners(); + } +} diff --git a/lib/core/viewModels/dashboard_view_model.dart b/lib/core/viewModels/dashboard_view_model.dart new file mode 100644 index 00000000..647d92b7 --- /dev/null +++ b/lib/core/viewModels/dashboard_view_model.dart @@ -0,0 +1,8 @@ +import 'package:diplomaticquarterapp/core/enum/viewstate.dart'; +import 'package:diplomaticquarterapp/core/service/dashboard_service.dart'; +import 'package:diplomaticquarterapp/core/viewModels/base_view_model.dart'; +import '../../locator.dart'; + +class DashboardViewModel extends BaseViewModel { + +} diff --git a/lib/locator.dart b/lib/locator.dart index 2695379f..961429bd 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -1,7 +1,10 @@ +import 'package:diplomaticquarterapp/core/viewModels/dashboard_view_model.dart'; import 'package:diplomaticquarterapp/routes.dart'; import 'package:get_it/get_it.dart'; +import 'core/service/appointment_rate_service.dart'; +import 'core/service/dashboard_service.dart'; import 'core/service/feedback/feedback_service.dart'; import 'core/service/hospital_service.dart'; import 'core/service/medical/labs_service.dart'; @@ -10,6 +13,7 @@ import 'core/service/medical/my_doctor_service.dart'; import 'core/service/medical/prescriptions_service.dart'; import 'core/service/medical/radiology_service.dart'; import 'core/service/medical/vital_sign_service.dart'; +import 'core/viewModels/appointment_rate_view_model.dart'; import 'core/viewModels/feedback/feedback_view_model.dart'; import 'core/service/medical/reports_service.dart'; import 'core/viewModels/hospital_view_model.dart'; @@ -41,6 +45,8 @@ void setupLocator() { locator.registerLazySingleton(() => VitalSignService()); locator.registerLazySingleton(() => MedicalService()); locator.registerLazySingleton(() => ReportsService()); + locator.registerLazySingleton(() => DashboardService()); + locator.registerLazySingleton(() => AppointmentRateService()); /// View Model locator.registerFactory(() => HospitalViewModel()); @@ -54,4 +60,6 @@ void setupLocator() { locator.registerFactory(() => VitalSignViewModel()); locator.registerFactory(() => InsuranceViewModel()); locator.registerFactory(() => MedicalViewModel()); + locator.registerFactory(() => DashboardViewModel()); + locator.registerFactory(() => AppointmentRateViewModel()); } diff --git a/lib/pages/login/login.dart b/lib/pages/login/login.dart index 83d10fe6..f223f91f 100644 --- a/lib/pages/login/login.dart +++ b/lib/pages/login/login.dart @@ -1,11 +1,15 @@ import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/core/viewModels/appointment_rate_view_model.dart'; +import 'package:diplomaticquarterapp/locator.dart'; import 'package:diplomaticquarterapp/models/Authentication/check_activation_code_request.dart'; import 'package:diplomaticquarterapp/models/Authentication/check_activation_code_response.dart'; import 'package:diplomaticquarterapp/models/Authentication/check_paitent_authentication_req.dart'; import 'package:diplomaticquarterapp/core/service/client/base_app_client.dart'; import 'package:diplomaticquarterapp/models/Authentication/select_device_imei_res.dart'; +import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; import 'package:diplomaticquarterapp/pages/login/login-type.dart'; +import 'package:diplomaticquarterapp/pages/rateAppointment/rate_appointment_doctor.dart'; import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart'; import 'package:diplomaticquarterapp/routes.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; @@ -19,6 +23,7 @@ import 'package:diplomaticquarterapp/widgets/mobile-no/mobile_no.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:diplomaticquarterapp/widgets/progress_indicator/app_circular_progress_Indeicator.dart'; import 'package:diplomaticquarterapp/widgets/text/app_texts_widget.dart'; +import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; @@ -38,6 +43,8 @@ class _Login extends State { final authService = new AuthProvider(); var sharedPref = new AppSharedPreferences(); bool isLoading = false; + AppointmentRateViewModel appointmentRateViewModel = + locator(); @override void initState() { @@ -184,20 +191,37 @@ class _Login extends State { request['PatientID'] = int.parse(nationalIDorFile.text); } // request.isRegister = false; - this - .authService - .checkActivationCode(request, code) - .then((result) => { - result = CheckActivationCode.fromJson(result), - this.sharedPref.setObject(USER_PROFILE, result.list), - this.sharedPref.setObject(LOGIN_TOKEN_ID, result.logInTokenID), - this.sharedPref.setString(TOKEN, result.authenticationTokenID), - //this.checkIfUserAgreedBefore(result), - Navigator.of(context).pushNamed( - HOME, - ) - // SMSOTP.showLoadingDialog(context, false), - }); + this.authService.checkActivationCode(request, code).then((result) => { + result = CheckActivationCode.fromJson(result), + this.sharedPref.setObject(USER_PROFILE, result.list), + this.sharedPref.setObject(LOGIN_TOKEN_ID, result.logInTokenID), + this.sharedPref.setString(TOKEN, result.authenticationTokenID), + + appointmentRateViewModel + .getIsLastAppointmentRatedList() + .then((value) => { + if (appointmentRateViewModel.isHaveAppointmentNotRate) + { + Navigator.pushReplacement( + context, + FadePage( + page: RateAppointmentDoctor(), + ), + ) + } + else + { + Navigator.pushReplacement( + context, + FadePage( + page: LandingPage(), + ), + ) + } + }) + + // SMSOTP.showLoadingDialog(context, false), + }); } showLoader(bool isTrue) { diff --git a/lib/pages/medical/medical_profile_page.dart b/lib/pages/medical/medical_profile_page.dart index 1e6a3b61..87486ce5 100644 --- a/lib/pages/medical/medical_profile_page.dart +++ b/lib/pages/medical/medical_profile_page.dart @@ -45,18 +45,34 @@ class _MedicalProfilePageState extends State { children: [ Container( width: double.infinity, - color: Colors.grey, height: 210, - child: ListView.builder( - itemBuilder: (context, index) => TimeLineWidget( - isUp: index % 2 == 1, - appoitmentAllHistoryResul: - model.appoitmentAllHistoryResultList[index], + decoration: BoxDecoration( + image: DecorationImage( + image: ExactAssetImage( + 'assets/images/timeline_bg.png'), + fit: BoxFit.cover ), - itemCount: - model.appoitmentAllHistoryResultList.length, - scrollDirection: Axis.horizontal, - reverse: true, + + ), + child: Stack( + children: [ + Image.asset( + 'assets/images/timeline_bg.png', + fit: BoxFit.cover, + width: double.infinity, + ), + ListView.builder( + itemBuilder: (context, index) => TimeLineWidget( + isUp: index % 2 == 1, + appoitmentAllHistoryResul: model + .appoitmentAllHistoryResultList[index], + ), + itemCount: + model.appoitmentAllHistoryResultList.length, + scrollDirection: Axis.horizontal, + reverse: true, + ), + ], ), ), Padding( @@ -417,6 +433,11 @@ class _MedicalProfilePageState extends State { border: Border.all( color: Colors.transparent, width: 0.5), borderRadius: BorderRadius.all(Radius.circular(9)), + image: DecorationImage( + image: ExactAssetImage( + 'assets/images/bg_graphic.png'), + fit: BoxFit.cover + ) ), child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -441,9 +462,15 @@ class _MedicalProfilePageState extends State { ), ), ), - - Positioned(top: 10,left: 10, - child: Texts('Time Line ',color: Colors.white,fontSize: 14,fontWeight: FontWeight.normal,), + Positioned( + top: 2, + left: 10, + child: Texts( + 'Time Line ', + color: Colors.white, + fontSize: 14, + fontWeight: FontWeight.normal, + ), ) ], ), diff --git a/lib/pages/rateAppointment/rate_appointment_clinic.dart b/lib/pages/rateAppointment/rate_appointment_clinic.dart new file mode 100644 index 00000000..74f134ae --- /dev/null +++ b/lib/pages/rateAppointment/rate_appointment_clinic.dart @@ -0,0 +1,240 @@ +import 'package:diplomaticquarterapp/core/enum/viewstate.dart'; +import 'package:diplomaticquarterapp/core/model/rate/appointment_details.dart'; +import 'package:diplomaticquarterapp/core/model/rate/appoitment_rated.dart'; +import 'package:diplomaticquarterapp/core/viewModels/appointment_rate_view_model.dart'; +import 'package:diplomaticquarterapp/pages/base/base_view.dart'; +import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; +import 'package:diplomaticquarterapp/uitl/app_toast.dart'; +import 'package:diplomaticquarterapp/widgets/avatar/large_avatar.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/button.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/secondary_button.dart'; +import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; +import 'package:diplomaticquarterapp/widgets/drawer/app_drawer_widget.dart'; +import 'package:diplomaticquarterapp/widgets/input/text_field.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; +import 'package:eva_icons_flutter/eva_icons_flutter.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; + +class RateAppointmentClinic extends StatefulWidget { + final AppointmentDetails appointmentDetails; + final String doctorNote; + final int doctorRate; + + RateAppointmentClinic( + {this.appointmentDetails, this.doctorRate, this.doctorNote}); + + @override + _RateAppointmentClinicState createState() => _RateAppointmentClinicState(); +} + +class _RateAppointmentClinicState extends State { + final formKey = GlobalKey(); + String note = ""; + int rating = 0; + + @override + Widget build(BuildContext context) { + return BaseView( + builder: (_, model, w) => AppScaffold( + baseViewModel: model, + body: Scaffold( + backgroundColor: Colors.grey[200], + appBar: AppBar( + elevation: 0, + textTheme: TextTheme( + headline6: + TextStyle(color: Colors.white, fontWeight: FontWeight.bold), + ), + title: Text('Rate'), + leading: Builder( + builder: (BuildContext context) { + return IconButton( + icon: Icon(Icons.menu), + color: Colors.white, + onPressed: () => Scaffold.of(context).openDrawer(), + ); + }, + ), + centerTitle: true, + ), + drawer: SafeArea(child: AppDrawer()), + body: FractionallySizedBox( + widthFactor: 1, + child: SingleChildScrollView( + child: Container( + padding: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox( + height: 25, + ), + Texts( + 'How would you rate your last visit to the Clinic', + bold: true, + color: Colors.black, + ), + SizedBox( + height: 25, + ), + Container( + width: double.infinity, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + color: Colors.white, + shape: BoxShape.rectangle, + border: Border.all(color: Colors.white, width: 0.5), + ), + child: Column( + children: [ + SizedBox( + height: 8, + ), + LargeAvatar( + name: model.appointmentDetails.clinicName, + width: 110, + height: 110, + ), + SizedBox( + height: 22, + ), + Texts( + model.appointmentDetails.projectName, + bold: true, + ), + SizedBox( + height: 4, + ), + Texts( + model.appointmentDetails.clinicName, + bold: true, + ), + SizedBox( + height: 8, + ) + ], + ), + ), + SizedBox( + height: 12, + ), + Center( + child: Texts( + 'Please rate the Clinic', + textAlign: TextAlign.center, + )), + SizedBox( + height: 12, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ...List.generate( + 5, + (index) => AnimatedSwitcher( + duration: Duration(milliseconds: 1000), + switchInCurve: Curves.elasticOut, + switchOutCurve: Curves.elasticIn, + transitionBuilder: + (Widget child, Animation animation) { + return ScaleTransition( + child: child, scale: animation); + }, + child: Container( + key: ValueKey(rating), + child: IconButton( + iconSize: 55.0, + onPressed: () { + setState(() { + rating = index + 1; + }); + }, + color: rating >= (index + 1) + ? Color.fromRGBO(255, 186, 0, 1.0) + : Colors.grey[400], + // Theme.of(context).hintColor, + icon: Icon(rating >= (index + 1) + ? EvaIcons.star + : EvaIcons.star)), + ), + ), + ) + ], + ), + SizedBox(height: 12), + SizedBox( + height: 12, + ), + ], + ), + ), + ), + ), + bottomSheet: Container( + height: MediaQuery.of(context).size.height * 0.15, + width: double.infinity, + color: Colors.grey[200], + child: Column( + children: [ + Container( + width: MediaQuery.of(context).size.width * 0.9, + child: SecondaryButton( + onTap: () async { + if (rating > 0) { + model + .sendAppointmentRate( + rating, + widget.appointmentDetails.appointmentNo, + widget.appointmentDetails.projectID, + widget.appointmentDetails.doctorID, + widget.appointmentDetails.clinicID, + note) + .then( + (value) => { + Navigator.pushReplacement( + context, + FadePage( + page: LandingPage(), + ), + ) + }, + ); + } else { + AppToast.showErrorToast( + message: 'please rate the clinic'); + } + }, + label: "Rate", + disabled: model.state == ViewState.BusyLocal, + loading: model.state == ViewState.BusyLocal, + textColor: Theme.of(context).backgroundColor), + ), + SizedBox( + height: 12, + ), + InkWell( + onTap: () { + Navigator.pushReplacement( + context, + FadePage( + page: LandingPage(), + ), + ); + }, + child: Texts( + 'Later', + decoration: TextDecoration.underline, + color: Hexcolor('#151DFE'), + fontSize: 18, + ), + ) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/pages/rateAppointment/rate_appointment_doctor.dart b/lib/pages/rateAppointment/rate_appointment_doctor.dart new file mode 100644 index 00000000..1583f033 --- /dev/null +++ b/lib/pages/rateAppointment/rate_appointment_doctor.dart @@ -0,0 +1,241 @@ +import 'package:diplomaticquarterapp/core/enum/viewstate.dart'; +import 'package:diplomaticquarterapp/core/model/rate/appointment_details.dart'; +import 'package:diplomaticquarterapp/core/viewModels/appointment_rate_view_model.dart'; +import 'package:diplomaticquarterapp/pages/base/base_view.dart'; +import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; +import 'package:diplomaticquarterapp/pages/rateAppointment/rate_appointment_clinic.dart'; +import 'package:diplomaticquarterapp/widgets/avatar/large_avatar.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/secondary_button.dart'; +import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; +import 'package:diplomaticquarterapp/widgets/drawer/app_drawer_widget.dart'; +import 'package:diplomaticquarterapp/widgets/input/text_field.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; +import 'package:eva_icons_flutter/eva_icons_flutter.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; + +class RateAppointmentDoctor extends StatefulWidget { + @override + _RateAppointmentDoctorState createState() => _RateAppointmentDoctorState(); +} + +class _RateAppointmentDoctorState extends State { + final formKey = GlobalKey(); + String note = ""; + int rating = 0; + + @override + Widget build(BuildContext context) { + return BaseView( + builder: (_, model, w) => AppScaffold( + baseViewModel: model, + body: Scaffold( + backgroundColor: Colors.grey[200], + appBar: AppBar( + elevation: 0, + textTheme: TextTheme( + headline6: + TextStyle(color: Colors.white, fontWeight: FontWeight.bold), + ), + title: Text('Rate'), + leading: Builder( + builder: (BuildContext context) { + return IconButton( + icon: Icon(Icons.menu), + color: Colors.white, + onPressed: () => Scaffold.of(context).openDrawer(), + ); + }, + ), + centerTitle: true, + ), + drawer: SafeArea(child: AppDrawer()), + body: FractionallySizedBox( + widthFactor: 1, + child: SingleChildScrollView( + child: Container( + padding: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox( + height: 25, + ), + Texts( + 'How would you rate your last visit to the doctor', + bold: true, + color: Colors.black, + ), + SizedBox( + height: 25, + ), + Container( + width: double.infinity, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + color: Colors.white, + shape: BoxShape.rectangle, + border: Border.all(color: Colors.white, width: 0.5), + ), + child: Column( + children: [ + SizedBox( + height: 8, + ), + LargeAvatar( + name: model.appointmentDetails.doctorName, + url: model.appointmentDetails.doctorImageURL, + width: 110, + height: 110, + ), + SizedBox( + height: 22, + ), + Texts( + model.appointmentDetails.doctorName, + bold: true, + ), + SizedBox( + height: 4, + ), + Texts( + model.appointmentDetails.clinicName, + bold: true, + ), + SizedBox( + height: 8, + ) + ], + ), + ), + SizedBox( + height: 12, + ), + Center( + child: Texts( + 'Please rate the doctor', + textAlign: TextAlign.center, + )), + SizedBox( + height: 12, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ...List.generate( + 5, + (index) => AnimatedSwitcher( + duration: Duration(milliseconds: 1000), + switchInCurve: Curves.elasticOut, + switchOutCurve: Curves.elasticIn, + transitionBuilder: + (Widget child, Animation animation) { + return ScaleTransition( + child: child, scale: animation); + }, + child: Container( + key: ValueKey(rating), + child: IconButton( + iconSize: 55.0, + onPressed: () { + setState(() { + rating = index + 1; + }); + }, + color: rating >= (index + 1) + ? Color.fromRGBO(255, 186, 0, 1.0) + : Colors.grey[400], + // Theme.of(context).hintColor, + icon: Icon(rating >= (index + 1) + ? EvaIcons.star + : EvaIcons.star)), + ), + ), + ) + ], + ), + SizedBox( + height: 12, + ), + Form( + key: formKey, + child: TextFields( + hintText: "Notes", + minLines: 4, + maxLines: 4, + validator: (value) { + if (value.isEmpty) + return 'Please enter your note'; + else if (rating == 0) return 'Rating cannot be \"0\"'; + return null; + }, + onChanged: (value) { + setState(() { + note = value; + }); + }, + ), + ), + SizedBox(height: 12,), + Container( + width: double.infinity, + child: Column( + children: [ + Container( + width: MediaQuery.of(context).size.width * 0.9, + child: SecondaryButton( + onTap: () async { + final form = formKey.currentState; + if (form.validate()) { + form.save(); + Navigator.push( + context, + FadePage( + page: RateAppointmentClinic( + appointmentDetails: + model.appointmentDetails, + doctorNote: note, + doctorRate: rating, + ), + ), + ); + } + }, + label: "Next", + disabled: model.state == ViewState.BusyLocal, + loading: model.state == ViewState.BusyLocal, + textColor: Theme.of(context).backgroundColor), + ), + SizedBox( + height: 12, + ), + InkWell( + onTap: () { + Navigator.pushReplacement( + context, + FadePage( + page: LandingPage(), + ), + ); + }, + child: Texts( + 'Later', + decoration: TextDecoration.underline, + color: Hexcolor('#151DFE'), + fontSize: 18, + ), + ) + ], + ), + ) + ], + ), + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/routes.dart b/lib/routes.dart index d4e38a9a..4c890806 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -7,10 +7,8 @@ import 'package:diplomaticquarterapp/pages/login/welcome.dart'; import 'package:diplomaticquarterapp/pages/login/login-type.dart'; import 'package:diplomaticquarterapp/pages/login/login.dart'; import 'package:diplomaticquarterapp/pages/login/register.dart'; -import 'package:flutter/material.dart'; const String INIT_ROUTE = '/'; -const String ROOT = 'root'; const String HOME = '/'; const String LOGIN = 'login'; const String WELCOME_LOGIN = 'welcome-login'; @@ -22,7 +20,6 @@ const String CONFIRM_LOGIN = 'confrim-login'; const String REGISTER_INFO = 'register-info'; const String MY_FAMILIY = 'my-family'; var routes = { - // ROOT: (_) => RootPage(), HOME: (_) => LandingPage(), WELCOME_LOGIN: (_) => WelcomeLogin(), LOGIN_TYPE: (_) => LoginType(), diff --git a/lib/widgets/buttons/secondary_button.dart b/lib/widgets/buttons/secondary_button.dart index a63f027f..d805fc94 100644 --- a/lib/widgets/buttons/secondary_button.dart +++ b/lib/widgets/buttons/secondary_button.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; /// SecondaryButton widget /// [label] button label @@ -17,7 +18,7 @@ class SecondaryButton extends StatefulWidget { this.label = "", this.icon, this.iconOnly = false, - this.color, + this.color: const Color.fromRGBO(63, 72, 74, 1), this.textColor, this.onTap, this.loading: false, @@ -215,7 +216,8 @@ class _SecondaryButtonState extends State width: 19.0, child: CircularProgressIndicator( backgroundColor: Colors.white, - valueColor: AlwaysStoppedAnimation( + valueColor: + AlwaysStoppedAnimation( Colors.grey[300], ), ), @@ -224,12 +226,14 @@ class _SecondaryButtonState extends State : Padding( padding: EdgeInsets.only( bottom: widget.small ? 4.0 : 3.0), - child: Text(widget.label, - style: TextStyle( - color: widget.textColor, - fontSize: 17.0, - fontWeight: FontWeight.w800, - fontFamily: "WorkSans")), + child: Text( + widget.label, + style: TextStyle( + color: widget.textColor, + fontSize: 17.0, + fontWeight: FontWeight.w800, + fontFamily: "WorkSans"), + ), ) ], ) diff --git a/lib/widgets/data_display/medical/time_line_widget.dart b/lib/widgets/data_display/medical/time_line_widget.dart index 18887bd2..bbbbfeb2 100644 --- a/lib/widgets/data_display/medical/time_line_widget.dart +++ b/lib/widgets/data_display/medical/time_line_widget.dart @@ -20,7 +20,7 @@ class TimeLineWidget extends StatelessWidget { Container( width: 140, height: 190, - color: Colors.grey, + color: Colors.transparent, child: Center( child: Divider( color: Colors.white, diff --git a/lib/widgets/data_display/text.dart b/lib/widgets/data_display/text.dart index 4357b291..17ddf05b 100644 --- a/lib/widgets/data_display/text.dart +++ b/lib/widgets/data_display/text.dart @@ -21,6 +21,7 @@ class Texts extends StatefulWidget { final double marginRight; final double marginBottom; final double marginLeft; + final TextDecoration decoration; Texts(this.text, {Key key, @@ -42,7 +43,8 @@ class Texts extends StatefulWidget { this.marginBottom, this.marginLeft, this.marginRight, - this.marginTop}) + this.marginTop, + this.decoration}) : super(key: key); @override @@ -198,34 +200,35 @@ class _TextsState extends State { Stack( children: [ Text( - !hidden - ? text - : (text.substring( - 0, - text.length > widget.maxLength - ? widget.maxLength - : text.length)), - textAlign: widget.textAlign, - overflow: widget.maxLines != null - ? ((widget.maxLines > 1) - ? TextOverflow.fade - : TextOverflow.ellipsis) - : null, - maxLines: widget.maxLines ?? null, - style: widget.style != null - ? _getFontStyle().copyWith( - fontStyle: widget.italic ? FontStyle.italic : null, - color: widget.color != null ? widget.color : null, - fontWeight: widget.fontWeight?? _getFontWeight(), - ) - : TextStyle( - fontStyle: widget.italic ? FontStyle.italic : null, - color: widget.color ?? Colors.black, - fontSize: widget.fontSize ?? _getFontSize(), - letterSpacing: - widget.variant == "overline" ? 1.5 : null, - fontWeight: widget.fontWeight?? _getFontWeight(), - )), + !hidden + ? text + : (text.substring( + 0, + text.length > widget.maxLength + ? widget.maxLength + : text.length)), + textAlign: widget.textAlign, + overflow: widget.maxLines != null + ? ((widget.maxLines > 1) + ? TextOverflow.fade + : TextOverflow.ellipsis) + : null, + maxLines: widget.maxLines ?? null, + style: widget.style != null + ? _getFontStyle().copyWith( + fontStyle: widget.italic ? FontStyle.italic : null, + color: widget.color != null ? widget.color : null, + fontWeight: widget.fontWeight ?? _getFontWeight(), + ) + : TextStyle( + decoration: widget.decoration, + fontStyle: widget.italic ? FontStyle.italic : null, + color: widget.color ?? Colors.black, + fontSize: widget.fontSize ?? _getFontSize(), + letterSpacing: widget.variant == "overline" ? 1.5 : null, + fontWeight: widget.fontWeight ?? _getFontWeight(), + ), + ), if (widget.readMore && text.length > widget.maxLength && hidden) Positioned( bottom: 0,