diff --git a/assets/images/svg/doctor_calendar_icon.svg b/assets/images/svg/doctor_calendar_icon.svg
new file mode 100644
index 0000000..f76c49f
--- /dev/null
+++ b/assets/images/svg/doctor_calendar_icon.svg
@@ -0,0 +1,8 @@
+
diff --git a/assets/images/svg/forward_arrow_icon.svg b/assets/images/svg/forward_arrow_icon.svg
new file mode 100644
index 0000000..d8a3d51
--- /dev/null
+++ b/assets/images/svg/forward_arrow_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/svg/prescription_refill_icon.svg b/assets/images/svg/prescription_refill_icon.svg
new file mode 100644
index 0000000..7a9706b
--- /dev/null
+++ b/assets/images/svg/prescription_refill_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/svg/prescription_remarks_icon.svg b/assets/images/svg/prescription_remarks_icon.svg
new file mode 100644
index 0000000..a8d7adb
--- /dev/null
+++ b/assets/images/svg/prescription_remarks_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/svg/prescription_reminder_icon.svg b/assets/images/svg/prescription_reminder_icon.svg
new file mode 100644
index 0000000..3a854c3
--- /dev/null
+++ b/assets/images/svg/prescription_reminder_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/svg/rating_icon.svg b/assets/images/svg/rating_icon.svg
new file mode 100644
index 0000000..dee25d4
--- /dev/null
+++ b/assets/images/svg/rating_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json
index 304dba1..91d5d4f 100644
--- a/assets/langs/ar-SA.json
+++ b/assets/langs/ar-SA.json
@@ -780,5 +780,10 @@
"loginOrRegister": "تسجيل الدخول أو التسجيل",
"myFiles" : "ملفاتي",
"resultsPending": "النتائج معلقة",
- "resultsAvailable": "النتائج متاحة"
+ "resultsAvailable": "النتائج متاحة",
+ "viewReport": "عرض التقرير",
+ "prescriptionDeliveryError": "هذه العيادة لا تدعم إعادة التعبئة والتسليم.",
+
+ "checkAvailability": "التحقق من التوفر",
+ "readInstructions": "قراءة التعليمات"
}
\ No newline at end of file
diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json
index e369613..f91d98b 100644
--- a/assets/langs/en-US.json
+++ b/assets/langs/en-US.json
@@ -665,7 +665,7 @@
"healthWeatherIndicators": "Health Weather Indicators",
"healthTipsBasedOnCurrentWeather": "Health Tips Based On Current Weather",
"moreDetails": "More details",
- "resendOrder": "Refill & Delivery",
+ "resendOrder": "Refill and Delivery",
"ports": "Ports",
"way": "Way",
"dailyDoses": "Daily Doses",
@@ -776,5 +776,9 @@
"loginOrRegister": "Login or Register",
"myFiles": "My Files",
"resultsPending": "Results Pending",
- "resultsAvailable": "Results Available"
+ "resultsAvailable": "Results Available",
+ "viewReport": "View Report",
+ "prescriptionDeliveryError": "This clinic doesn't support refill",
+ "checkAvailability": "Check Availability",
+ "readInstructions": "Read Instructions"
}
\ No newline at end of file
diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart
index 6e1e92a..11c44ba 100644
--- a/lib/core/api_consts.dart
+++ b/lib/core/api_consts.dart
@@ -749,7 +749,6 @@ class ApiConsts {
static final String sendActivationCode = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType';
-
static setBackendURLs() {
if (isDevelopment) {
baseUrl = "https://uat.hmgwebservices.com/";
diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart
index 53adac7..7d32262 100644
--- a/lib/core/app_assets.dart
+++ b/lib/core/app_assets.dart
@@ -62,6 +62,12 @@ class AppAssets {
static const String eye_result_icon = '$svgBasePath/eye_results_icon.svg';
static const String search_icon = '$svgBasePath/search_icon.svg';
static const String view_report_icon = '$svgBasePath/view_report_icon.svg';
+ static const String forward_arrow_icon = '$svgBasePath/forward_arrow_icon.svg';
+ static const String prescription_refill_icon = '$svgBasePath/prescription_refill_icon.svg';
+ static const String rating_icon = '$svgBasePath/rating_icon.svg';
+ static const String doctor_calendar_icon = '$svgBasePath/doctor_calendar_icon.svg';
+ static const String prescription_remarks_icon = '$svgBasePath/prescription_remarks_icon.svg';
+ static const String prescription_reminder_icon = '$svgBasePath/prescription_reminder_icon.svg';
//bottom navigation//
@@ -71,7 +77,6 @@ class AppAssets {
static const String toDoBottom = '$svgBasePath/todo_bottom.svg';
static const String servicesBottom = '$svgBasePath/services_bottom.svg';
-
// PNGS //
static const String hmg_logo = '$pngBasePath/hmg_logo.png';
static const String livecare_service = '$pngBasePath/livecare_service.png';
diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart
index dca08fc..65fd2c6 100644
--- a/lib/core/dependencies.dart
+++ b/lib/core/dependencies.dart
@@ -9,6 +9,10 @@ import 'package:hmg_patient_app_new/features/common/common_repo.dart';
import 'package:hmg_patient_app_new/features/lab/lab_repo.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
+import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
+import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
@@ -59,6 +63,8 @@ class AppDependencies {
getIt.registerLazySingleton(() => BookAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt()));
getIt.registerLazySingleton(() => MyAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt()));
getIt.registerLazySingleton(() => LabRepoImp(loggerService: getIt(), apiClient: getIt()));
+ getIt.registerLazySingleton(() => RadiologyRepoImp(loggerService: getIt(), apiClient: getIt()));
+ getIt.registerLazySingleton(() => PrescriptionsRepoImp(loggerService: getIt(), apiClient: getIt()));
// ViewModels
// Global/shared VMs → LazySingleton
@@ -70,6 +76,20 @@ class AppDependencies {
),
);
+ getIt.registerLazySingleton(
+ () => RadiologyViewModel(
+ radiologyRepo: getIt(),
+ errorHandlerService: getIt(),
+ ),
+ );
+
+ getIt.registerLazySingleton(
+ () => PrescriptionsViewModel(
+ prescriptionsRepo: getIt(),
+ errorHandlerService: getIt(),
+ ),
+ );
+
getIt.registerLazySingleton(
() => AuthenticationViewModel(
authenticationRepo: getIt(),
diff --git a/lib/core/utils/calendar_utils.dart b/lib/core/utils/calendar_utils.dart
index 39c7a14..8786f7f 100644
--- a/lib/core/utils/calendar_utils.dart
+++ b/lib/core/utils/calendar_utils.dart
@@ -4,8 +4,6 @@ import 'dart:io';
import 'dart:ui';
import 'package:device_calendar/device_calendar.dart';
-import 'package:easy_localization/easy_localization.dart';
-import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:manage_calendar_events/manage_calendar_events.dart' as ios;
import 'package:timezone/data/latest.dart' as tzl;
@@ -137,14 +135,12 @@ class CalendarUtils {
print("catchError " + e.toString());
}).whenComplete(() {
print("whenComplete Calender ID " + eventId!);
- // Utils.showToast(LocaleKeys.appoReminderSuccess.tr());
});
} else {
await _myPlugin.createEvent(calendarId: writableCalendars.id!, event: iosCalEvent).catchError((e) {
print("catchError " + e.toString());
}).whenComplete(() {
print("whenComplete Calender ID iOS " + eventId!);
- // Utils.showToast(LocaleKeys.appoReminderSuccess.tr());
});
}
}
diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart
index d118d08..a224526 100644
--- a/lib/extensions/string_extensions.dart
+++ b/lib/extensions/string_extensions.dart
@@ -11,13 +11,16 @@ extension CapExtension on String {
String get allInCaps => this.toUpperCase();
- String get capitalizeFirstofEach => this.trim().length > 0 ? this.trim().toLowerCase().split(" ").map((str) => str.inCaps).join(" ") : "";
+ String get capitalizeFirstofEach =>
+ this.trim().length > 0 ? this.trim().toLowerCase().split(" ").map((str) => str.inCaps).join(" ") : "";
}
extension EmailValidator on String {
Widget get toWidget => Text(this);
- Widget toText8({Color? color, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) => Text(
+ Widget toText8(
+ {Color? color, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) =>
+ Text(
this,
maxLines: maxlines,
overflow: textOverflow,
@@ -30,7 +33,14 @@ extension EmailValidator on String {
),
);
- Widget toText10({Color? color, bool isBold = false, bool isUnderLine = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) => Text(
+ Widget toText10(
+ {Color? color,
+ bool isBold = false,
+ bool isUnderLine = false,
+ int? maxlines,
+ FontStyle? fontStyle,
+ TextOverflow? textOverflow}) =>
+ Text(
this,
maxLines: maxlines,
overflow: textOverflow,
@@ -44,7 +54,15 @@ extension EmailValidator on String {
decorationColor: color ?? AppColors.blackColor),
);
- Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isCenter = false, bool isBold = false, int maxLine = 0, double letterSpacing = 0.64}) => Text(
+ Widget toText11(
+ {Color? color,
+ FontWeight? weight,
+ bool isUnderLine = false,
+ bool isCenter = false,
+ bool isBold = false,
+ int maxLine = 0,
+ double letterSpacing = 0.64}) =>
+ Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
@@ -58,21 +76,33 @@ extension EmailValidator on String {
),
);
- Widget toText12({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => Text(
+ Widget toText12(
+ {Color? color,
+ bool isUnderLine = false,
+ bool isBold = false,
+ FontWeight? fontWeight,
+ bool isCenter = false,
+ double? height,
+ int maxLine = 0}) =>
+ Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
style: TextStyle(
+
fontSize: 12.fSize,
- fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
+ fontWeight: fontWeight ?? (isBold ? FontWeight.bold : FontWeight.normal),
color: color ?? AppColors.blackColor,
letterSpacing: -0.4,
+ height: height,
decorationColor: isUnderLine ? AppColors.blackColor : null,
decoration: isUnderLine ? TextDecoration.underline : null,
),
);
- Widget toText12Auto({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => AutoSizeText(
+ Widget toText12Auto(
+ {Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) =>
+ AutoSizeText(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
@@ -133,7 +163,14 @@ extension EmailValidator on String {
decoration: isUnderLine ? TextDecoration.underline : null),
);
- Widget toText14({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, FontWeight? weight, int? maxlines}) => Text(
+ Widget toText14(
+ {Color? color,
+ bool isUnderLine = false,
+ bool isBold = false,
+ bool isCenter = false,
+ FontWeight? weight,
+ int? maxlines}) =>
+ Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: maxlines,
@@ -145,7 +182,14 @@ extension EmailValidator on String {
decoration: isUnderLine ? TextDecoration.underline : null),
);
- Widget toText15({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, FontWeight? weight, int? maxlines}) => Text(
+ Widget toText15(
+ {Color? color,
+ bool isUnderLine = false,
+ bool isBold = false,
+ bool isCenter = false,
+ FontWeight? weight,
+ int? maxlines}) =>
+ Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: maxlines,
@@ -183,53 +227,93 @@ extension EmailValidator on String {
Widget toText17({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
- style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 17.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(
+ color: color ?? AppColors.blackColor,
+ fontSize: 17.fSize,
+ letterSpacing: -0.4,
+ fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText18({Color? color, bool isBold = false, bool isCenter = false, int? maxlines}) => Text(
maxLines: maxlines,
textAlign: isCenter ? TextAlign.center : null,
this,
- style: TextStyle(fontSize: 18.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
+ style: TextStyle(
+ fontSize: 18.fSize,
+ fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
+ color: color ?? AppColors.blackColor,
+ letterSpacing: -0.4),
);
Widget toText19({Color? color, bool isBold = false}) => Text(
this,
- style: TextStyle(fontSize: 19.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
+ style: TextStyle(
+ fontSize: 19.fSize,
+ fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
+ color: color ?? AppColors.blackColor,
+ letterSpacing: -0.4),
);
Widget toText20({Color? color, bool isBold = false}) => Text(
this,
- style: TextStyle(fontSize: 20.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
+ style: TextStyle(
+ fontSize: 20.fSize,
+ fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
+ color: color ?? AppColors.blackColor,
+ letterSpacing: -0.4),
);
Widget toText21({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text(
this,
maxLines: maxlines,
- style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 21.fSize, letterSpacing: -0.4, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
+ style: TextStyle(
+ color: color ?? AppColors.blackColor,
+ fontSize: 21.fSize,
+ letterSpacing: -0.4,
+ fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
);
Widget toText22({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
- style: TextStyle(height: 1, color: color ?? AppColors.blackColor, fontSize: 22.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(
+ height: 1,
+ color: color ?? AppColors.blackColor,
+ fontSize: 22.fSize,
+ letterSpacing: -0.4,
+ fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText24({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
- style: TextStyle(height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(
+ height: 23 / 24,
+ color: color ?? AppColors.blackColor,
+ fontSize: 24.fSize,
+ letterSpacing: -0.4,
+ fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText32({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
- style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(
+ height: 32 / 32,
+ color: color ?? AppColors.blackColor,
+ fontSize: 32.fSize,
+ letterSpacing: -0.4,
+ fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText44({Color? color, bool isBold = false}) => Text(
this,
- style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(
+ height: 32 / 32,
+ color: color ?? AppColors.blackColor,
+ fontSize: 44.fSize,
+ letterSpacing: -0.4,
+ fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) {
@@ -265,7 +349,9 @@ extension EmailValidator on String {
}
bool isValidEmail() {
- return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this);
+ return RegExp(
+ r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$')
+ .hasMatch(this);
}
String toFormattedDate() {
diff --git a/lib/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart b/lib/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart
new file mode 100644
index 0000000..7b1d879
--- /dev/null
+++ b/lib/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart
@@ -0,0 +1,174 @@
+class PatientPrescriptionsResponseModel {
+ String? setupID;
+ int? projectID;
+ int? patientID;
+ int? appointmentNo;
+ String? appointmentDate;
+ String? doctorName;
+ String? clinicDescription;
+ String? name;
+ int? episodeID;
+ num? actualDoctorRate;
+ int? admission;
+ int? clinicID;
+ String? companyName;
+ num? decimalDoctorRate;
+ String? despensedStatus;
+ String? dischargeDate;
+ int? dischargeNo;
+ int? doctorID;
+ String? doctorImageURL;
+ num? doctorRate;
+ num? doctorStarsRate;
+ String? doctorTitle;
+ int? gender;
+ String? genderDescription;
+ bool? isActiveDoctorProfile;
+ bool? isDoctorAllowVedioCall;
+ bool? isExecludeDoctor;
+ bool? isHomeMedicineDeliverySupported;
+ bool? isInOutPatient;
+ String? isInOutPatientDescription;
+ String? isInOutPatientDescriptionN;
+ bool? isInsurancePatient;
+ bool? isLiveCareAppointment;
+ String? nationalityFlagURL;
+ int? noOfPatientsRate;
+ String? qR;
+
+ // List? speciality;
+ String? strAppointmentDate;
+
+ PatientPrescriptionsResponseModel(
+ {this.setupID,
+ this.projectID,
+ this.patientID,
+ this.appointmentNo,
+ this.appointmentDate,
+ this.doctorName,
+ this.clinicDescription,
+ this.name,
+ this.episodeID,
+ this.actualDoctorRate,
+ this.admission,
+ this.clinicID,
+ this.companyName,
+ this.decimalDoctorRate,
+ this.despensedStatus,
+ this.dischargeDate,
+ this.dischargeNo,
+ this.doctorID,
+ this.doctorImageURL,
+ this.doctorRate,
+ this.doctorStarsRate,
+ this.doctorTitle,
+ this.gender,
+ this.genderDescription,
+ this.isActiveDoctorProfile,
+ this.isDoctorAllowVedioCall,
+ this.isExecludeDoctor,
+ this.isHomeMedicineDeliverySupported,
+ this.isInOutPatient,
+ this.isInOutPatientDescription,
+ this.isInOutPatientDescriptionN,
+ this.isInsurancePatient,
+ this.isLiveCareAppointment,
+ this.nationalityFlagURL,
+ this.noOfPatientsRate,
+ this.qR,
+ // this.speciality,
+ this.strAppointmentDate});
+
+ PatientPrescriptionsResponseModel.fromJson(Map json) {
+ setupID = json['SetupID'];
+ projectID = json['ProjectID'];
+ patientID = json['PatientID'];
+ appointmentNo = json['AppointmentNo'];
+ appointmentDate = json['AppointmentDate'];
+ doctorName = json['DoctorName'];
+ clinicDescription = json['ClinicDescription'];
+ name = json['Name'];
+ episodeID = json['EpisodeID'];
+ actualDoctorRate = json['ActualDoctorRate'];
+ admission = json['Admission'];
+ clinicID = json['ClinicID'];
+ companyName = json['CompanyName'];
+ decimalDoctorRate = json['DecimalDoctorRate'];
+ despensedStatus = json['Despensed_Status'];
+ dischargeDate = json['DischargeDate'];
+ dischargeNo = json['DischargeNo'];
+ doctorID = json['DoctorID'];
+ doctorImageURL = json['DoctorImageURL'];
+ doctorRate = json['DoctorRate'];
+ doctorStarsRate = json['DoctorStarsRate'];
+ doctorTitle = json['DoctorTitle'];
+ gender = json['Gender'];
+ genderDescription = json['GenderDescription'];
+ isActiveDoctorProfile = json['IsActiveDoctorProfile'];
+ isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall'];
+ isExecludeDoctor = json['IsExecludeDoctor'];
+ isHomeMedicineDeliverySupported = json['IsHomeMedicineDeliverySupported'];
+ isInOutPatient = json['IsInOutPatient'];
+ isInOutPatientDescription = json['IsInOutPatientDescription'];
+ isInOutPatientDescriptionN = json['IsInOutPatientDescriptionN'];
+ isInsurancePatient = json['IsInsurancePatient'];
+ isLiveCareAppointment = json['IsLiveCareAppointment'];
+ nationalityFlagURL = json['NationalityFlagURL'];
+ noOfPatientsRate = json['NoOfPatientsRate'];
+ qR = json['QR'];
+ // speciality = json['Speciality'].cast();
+ strAppointmentDate = json['StrAppointmentDate'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['SetupID'] = this.setupID;
+ data['ProjectID'] = this.projectID;
+ data['PatientID'] = this.patientID;
+ data['AppointmentNo'] = this.appointmentNo;
+ data['AppointmentDate'] = this.appointmentDate;
+ data['DoctorName'] = this.doctorName;
+ data['ClinicDescription'] = this.clinicDescription;
+ data['Name'] = this.name;
+ data['EpisodeID'] = this.episodeID;
+ data['ActualDoctorRate'] = this.actualDoctorRate;
+ data['Admission'] = this.admission;
+ data['ClinicID'] = this.clinicID;
+ data['CompanyName'] = this.companyName;
+ data['DecimalDoctorRate'] = this.decimalDoctorRate;
+ data['Despensed_Status'] = this.despensedStatus;
+ data['DischargeDate'] = this.dischargeDate;
+ data['DischargeNo'] = this.dischargeNo;
+ data['DoctorID'] = this.doctorID;
+ data['DoctorImageURL'] = this.doctorImageURL;
+ data['DoctorRate'] = this.doctorRate;
+ data['DoctorStarsRate'] = this.doctorStarsRate;
+ data['DoctorTitle'] = this.doctorTitle;
+ data['Gender'] = this.gender;
+ data['GenderDescription'] = this.genderDescription;
+ data['IsActiveDoctorProfile'] = this.isActiveDoctorProfile;
+ data['IsDoctorAllowVedioCall'] = this.isDoctorAllowVedioCall;
+ data['IsExecludeDoctor'] = this.isExecludeDoctor;
+ data['IsHomeMedicineDeliverySupported'] = this.isHomeMedicineDeliverySupported;
+ data['IsInOutPatient'] = this.isInOutPatient;
+ data['IsInOutPatientDescription'] = this.isInOutPatientDescription;
+ data['IsInOutPatientDescriptionN'] = this.isInOutPatientDescriptionN;
+ data['IsInsurancePatient'] = this.isInsurancePatient;
+ data['IsLiveCareAppointment'] = this.isLiveCareAppointment;
+ data['NationalityFlagURL'] = this.nationalityFlagURL;
+ data['NoOfPatientsRate'] = this.noOfPatientsRate;
+ data['QR'] = this.qR;
+ // data['Speciality'] = this.speciality;
+ data['StrAppointmentDate'] = this.strAppointmentDate;
+ return data;
+ }
+}
+
+class PrescriptionsList {
+ String? filterName = "";
+ List? prescriptionsList = [];
+
+ PrescriptionsList({this.filterName, PatientPrescriptionsResponseModel? prescriptions}) {
+ prescriptionsList!.add(prescriptions!);
+ }
+}
diff --git a/lib/features/prescriptions/models/resp_models/prescription_detail_response_model.dart b/lib/features/prescriptions/models/resp_models/prescription_detail_response_model.dart
new file mode 100644
index 0000000..b35cfef
--- /dev/null
+++ b/lib/features/prescriptions/models/resp_models/prescription_detail_response_model.dart
@@ -0,0 +1,147 @@
+class PrescriptionDetailResponseModel {
+ String? address;
+ num? appointmentNo;
+ String? clinic;
+ dynamic companyName;
+ num? days;
+ String? doctorName;
+ num? doseDailyQuantity;
+ String? frequency;
+ num? frequencyNumber;
+ dynamic image;
+ dynamic imageExtension;
+ String? imageSRCUrl;
+ dynamic imageString;
+ String? imageThumbUrl;
+ String? isCovered;
+ String? itemDescription;
+ num? itemID;
+ String? orderDate;
+ num? patientID;
+ String? patientName;
+ String? phoneOffice1;
+ dynamic prescriptionQR;
+ num? prescriptionTimes;
+ dynamic productImage;
+ dynamic productImageBase64;
+ String? productImageString;
+ num? projectID;
+ String? projectName;
+ String? remarks;
+ String? route;
+ String? sKU;
+ num? scaleOffset;
+ String? startDate;
+ bool? hasReminder;
+
+ PrescriptionDetailResponseModel(
+ {this.address,
+ this.appointmentNo,
+ this.clinic,
+ this.companyName,
+ this.days,
+ this.doctorName,
+ this.doseDailyQuantity,
+ this.frequency,
+ this.frequencyNumber,
+ this.image,
+ this.imageExtension,
+ this.imageSRCUrl,
+ this.imageString,
+ this.imageThumbUrl,
+ this.isCovered,
+ this.itemDescription,
+ this.itemID,
+ this.orderDate,
+ this.patientID,
+ this.patientName,
+ this.phoneOffice1,
+ this.prescriptionQR,
+ this.prescriptionTimes,
+ this.productImage,
+ this.productImageBase64,
+ this.productImageString,
+ this.projectID,
+ this.projectName,
+ this.remarks,
+ this.route,
+ this.sKU,
+ this.scaleOffset,
+ this.startDate,
+ this.hasReminder = false});
+
+ PrescriptionDetailResponseModel.fromJson(Map json) {
+ address = json['Address'];
+ appointmentNo = json['AppointmentNo'];
+ clinic = json['Clinic'];
+ companyName = json['CompanyName'];
+ days = json['Days'];
+ doctorName = json['DoctorName'];
+ doseDailyQuantity = json['DoseDailyQuantity'];
+ frequency = json['Frequency'];
+ frequencyNumber = json['FrequencyNumber'];
+ image = json['Image'];
+ imageExtension = json['ImageExtension'];
+ imageSRCUrl = json['ImageSRCUrl'];
+ imageString = json['ImageString'];
+ imageThumbUrl = json['ImageThumbUrl'];
+ isCovered = json['IsCovered'];
+ itemDescription = json['ItemDescription'];
+ itemID = json['ItemID'];
+ orderDate = json['OrderDate'];
+ patientID = json['PatientID'];
+ patientName = json['PatientName'];
+ phoneOffice1 = json['PhoneOffice1'];
+ prescriptionQR = json['PrescriptionQR'];
+ prescriptionTimes = json['PrescriptionTimes'];
+ productImage = json['ProductImage'];
+ productImageBase64 = json['ProductImageBase64'];
+ productImageString = json['ProductImageString'];
+ projectID = json['ProjectID'];
+ projectName = json['ProjectName'];
+ remarks = json['Remarks'];
+ route = json['Route'];
+ sKU = json['SKU'];
+ scaleOffset = json['ScaleOffset'];
+ startDate = json['StartDate'];
+ hasReminder = false;
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['Address'] = address;
+ data['AppointmentNo'] = appointmentNo;
+ data['Clinic'] = clinic;
+ data['CompanyName'] = companyName;
+ data['Days'] = days;
+ data['DoctorName'] = doctorName;
+ data['DoseDailyQuantity'] = doseDailyQuantity;
+ data['Frequency'] = frequency;
+ data['FrequencyNumber'] = frequencyNumber;
+ data['Image'] = image;
+ data['ImageExtension'] = imageExtension;
+ data['ImageSRCUrl'] = imageSRCUrl;
+ data['ImageString'] = imageString;
+ data['ImageThumbUrl'] = imageThumbUrl;
+ data['IsCovered'] = isCovered;
+ data['ItemDescription'] = itemDescription;
+ data['ItemID'] = itemID;
+ data['OrderDate'] = orderDate;
+ data['PatientID'] = patientID;
+ data['PatientName'] = patientName;
+ data['PhoneOffice1'] = phoneOffice1;
+ data['PrescriptionQR'] = prescriptionQR;
+ data['PrescriptionTimes'] = prescriptionTimes;
+ data['ProductImage'] = productImage;
+ data['ProductImageBase64'] = productImageBase64;
+ data['ProductImageString'] = productImageString;
+ data['ProjectID'] = projectID;
+ data['ProjectName'] = projectName;
+ data['Remarks'] = remarks;
+ data['Route'] = route;
+ data['SKU'] = sKU;
+ data['ScaleOffset'] = scaleOffset;
+ data['StartDate'] = startDate;
+ return data;
+ }
+}
diff --git a/lib/features/prescriptions/prescriptions_repo.dart b/lib/features/prescriptions/prescriptions_repo.dart
new file mode 100644
index 0000000..de7bc4b
--- /dev/null
+++ b/lib/features/prescriptions/prescriptions_repo.dart
@@ -0,0 +1,141 @@
+import 'package:hmg_patient_app_new/core/api/api_client.dart';
+import 'package:hmg_patient_app_new/core/api_consts.dart';
+import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
+import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
+import 'package:dartz/dartz.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_detail_response_model.dart';
+import 'package:hmg_patient_app_new/services/logger_service.dart';
+
+abstract class PrescriptionsRepo {
+ Future>>> getPatientPrescriptionOrders({required String patientId});
+
+ Future>>> getPatientPrescriptionDetails({required PatientPrescriptionsResponseModel prescriptionsResponseModel});
+}
+
+class PrescriptionsRepoImp implements PrescriptionsRepo {
+ final ApiClient apiClient;
+ final LoggerService loggerService;
+
+ PrescriptionsRepoImp({required this.loggerService, required this.apiClient});
+
+ @override
+ Future>>> getPatientPrescriptionOrders({required String patientId}) async {
+ final mapDevice = {
+ "isDentalAllowedBackend": false,
+ "VersionID": 50.0,
+ "Channel": 3,
+ "LanguageID": 2,
+ "IPAdress": "10.20.10.20",
+ "generalid": "Cs2020@2016\$2958",
+ "Latitude": 0.0,
+ "Longitude": 0.0,
+ "DeviceTypeID": 1,
+ "PatientType": 1,
+ "PatientTypeID": 1,
+ "TokenID": "@dm!n",
+ "PatientID": "1018977",
+ "PatientOutSA": "0",
+ "SessionID": "03478TYC02N80874CTYN04883475!?"
+ };
+
+ try {
+ GenericApiModel>? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ PRESCRIPTIONS,
+ body: mapDevice,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus}) {
+ try {
+ final list = response['PatientPrescriptionList'];
+ if (list == null || list.isEmpty) {
+ throw Exception("lab list is empty");
+ }
+
+ final prescriptionOrders = list.map((item) => PatientPrescriptionsResponseModel.fromJson(item as Map)).toList().cast();
+
+ apiResponse = GenericApiModel>(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: prescriptionOrders,
+ );
+ } catch (e) {
+ failure = DataParsingFailure(e.toString());
+ }
+ },
+ );
+ if (failure != null) return Left(failure!);
+ if (apiResponse == null) return Left(ServerFailure("Unknown error"));
+ return Right(apiResponse!);
+ } catch (e) {
+ return Left(UnknownFailure(e.toString()));
+ }
+ }
+
+ @override
+ Future>>> getPatientPrescriptionDetails({required PatientPrescriptionsResponseModel prescriptionsResponseModel}) async {
+ final mapDevice = {
+ "AppointmentNo": prescriptionsResponseModel.appointmentNo.toString(),
+ "SetupID": prescriptionsResponseModel.setupID,
+ "EpisodeID": prescriptionsResponseModel.episodeID.toString(),
+ "ClinicID": prescriptionsResponseModel.clinicID.toString(),
+ "ProjectID": prescriptionsResponseModel.projectID.toString(),
+ "DischargeNo": prescriptionsResponseModel.dischargeNo.toString(),
+ "isDentalAllowedBackend": false,
+ "VersionID": 50.0,
+ "Channel": 3,
+ "LanguageID": 2,
+ "IPAdress": "10.20.10.20",
+ "generalid": "Cs2020@2016\$2958",
+ "Latitude": 0.0,
+ "Longitude": 0.0,
+ "DeviceTypeID": 1,
+ "PatientType": 1,
+ "PatientTypeID": 1,
+ "TokenID": "@dm!n",
+ "PatientID": "1018977",
+ "PatientOutSA": "0",
+ "SessionID": "03478TYC02N80874CTYN04883475!?"
+ };
+
+ try {
+ GenericApiModel>? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ prescriptionsResponseModel.isInOutPatient! ? GET_PRESCRIPTION_REPORT_ENH : GET_PRESCRIPTION_REPORT,
+ body: mapDevice,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus}) {
+ try {
+ final list = prescriptionsResponseModel.isInOutPatient! ? response['ListPRM'] : response['INP_GetPrescriptionReport_List'];
+ if (list == null || list.isEmpty) {
+ throw Exception("prescription list is empty");
+ }
+
+ final prescriptionOrders = list.map((item) => PrescriptionDetailResponseModel.fromJson(item as Map)).toList().cast();
+
+ apiResponse = GenericApiModel>(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: prescriptionOrders,
+ );
+ } catch (e) {
+ failure = DataParsingFailure(e.toString());
+ }
+ },
+ );
+ if (failure != null) return Left(failure!);
+ if (apiResponse == null) return Left(ServerFailure("Unknown error"));
+ return Right(apiResponse!);
+ } catch (e) {
+ return Left(UnknownFailure(e.toString()));
+ }
+ }
+}
diff --git a/lib/features/prescriptions/prescriptions_view_model.dart b/lib/features/prescriptions/prescriptions_view_model.dart
new file mode 100644
index 0000000..ff93f84
--- /dev/null
+++ b/lib/features/prescriptions/prescriptions_view_model.dart
@@ -0,0 +1,122 @@
+import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_detail_response_model.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
+import 'package:hmg_patient_app_new/services/error_handler_service.dart';
+
+class PrescriptionsViewModel extends ChangeNotifier {
+ bool isPrescriptionsOrdersLoading = false;
+ bool isPrescriptionsDetailsLoading = false;
+
+ PrescriptionsRepo prescriptionsRepo;
+ ErrorHandlerService errorHandlerService;
+
+ // Prescription Orders Lists
+ List patientPrescriptionOrders = [];
+
+ List patientPrescriptionOrdersByClinic = [];
+ List patientPrescriptionOrdersByHospital = [];
+ List patientPrescriptionOrdersViewList = [];
+
+ // Prescription Details List
+ List prescriptionDetailsList = [];
+
+ bool isSortByClinic = true;
+
+ PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService});
+
+ initPrescriptionsViewModel() {
+ patientPrescriptionOrders.clear();
+ patientPrescriptionOrdersByClinic.clear();
+ patientPrescriptionOrdersByHospital.clear();
+ patientPrescriptionOrdersViewList.clear();
+ isPrescriptionsOrdersLoading = true;
+ isPrescriptionsDetailsLoading = true;
+ isSortByClinic = true;
+ getPatientPrescriptionOrders();
+ notifyListeners();
+ }
+
+ setPrescriptionsDetailsLoading() {
+ isPrescriptionsDetailsLoading = true;
+ prescriptionDetailsList.clear();
+ notifyListeners();
+ }
+
+ setPrescriptionItemReminder(bool value, PrescriptionDetailResponseModel item) {
+ int index = prescriptionDetailsList.indexOf(item);
+ if (index != -1) {
+ prescriptionDetailsList[index].hasReminder = value;
+ notifyListeners();
+ }
+ }
+
+ setIsSortByClinic(bool value) {
+ isSortByClinic = value;
+ if (isSortByClinic) {
+ patientPrescriptionOrdersViewList = patientPrescriptionOrdersByClinic;
+ } else {
+ patientPrescriptionOrdersViewList = patientPrescriptionOrdersByHospital;
+ }
+ notifyListeners();
+ }
+
+ Future getPatientPrescriptionOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async {
+ final result = await prescriptionsRepo.getPatientPrescriptionOrders(patientId: "1231755");
+
+ result.fold(
+ (failure) async => await errorHandlerService.handleError(failure: failure),
+ (apiResponse) {
+ if (apiResponse.messageStatus == 2) {
+ // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
+ } else if (apiResponse.messageStatus == 1) {
+ patientPrescriptionOrders = apiResponse.data!;
+ isPrescriptionsOrdersLoading = false;
+
+ for (var element in patientPrescriptionOrders) {
+ List prescriptionsByClinic = patientPrescriptionOrdersByClinic.where((elementClinic) => elementClinic.filterName == element.clinicDescription).toList();
+
+ if (prescriptionsByClinic.isNotEmpty) {
+ patientPrescriptionOrdersByClinic[patientPrescriptionOrdersByClinic.indexOf(prescriptionsByClinic[0])].prescriptionsList!.add(element);
+ } else {
+ patientPrescriptionOrdersByClinic.add(PrescriptionsList(filterName: element.clinicDescription, prescriptions: element));
+ }
+
+ List prescriptionsByHospital = patientPrescriptionOrdersByHospital.where((elementClinic) => elementClinic.filterName == element.name).toList();
+
+ if (prescriptionsByHospital.isNotEmpty) {
+ patientPrescriptionOrdersByHospital[patientPrescriptionOrdersByHospital.indexOf(prescriptionsByHospital[0])].prescriptionsList!.add(element);
+ } else {
+ patientPrescriptionOrdersByHospital.add(PrescriptionsList(filterName: element.name, prescriptions: element));
+ }
+ }
+ patientPrescriptionOrdersViewList = patientPrescriptionOrdersByClinic;
+ notifyListeners();
+ if (onSuccess != null) {
+ onSuccess(apiResponse);
+ }
+ }
+ },
+ );
+ }
+
+ Future getPrescriptionDetails(PatientPrescriptionsResponseModel prescriptionsResponseModel, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
+ final result = await prescriptionsRepo.getPatientPrescriptionDetails(prescriptionsResponseModel: prescriptionsResponseModel);
+
+ result.fold(
+ (failure) async => await errorHandlerService.handleError(failure: failure),
+ (apiResponse) {
+ if (apiResponse.messageStatus == 2) {
+ // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
+ } else if (apiResponse.messageStatus == 1) {
+ prescriptionDetailsList = apiResponse.data!;
+ isPrescriptionsDetailsLoading = false;
+ notifyListeners();
+ if (onSuccess != null) {
+ onSuccess(apiResponse);
+ }
+ }
+ },
+ );
+ }
+}
diff --git a/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart b/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart
new file mode 100644
index 0000000..b5568bf
--- /dev/null
+++ b/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart
@@ -0,0 +1,232 @@
+class PatientRadiologyResponseModel {
+ String? setupID;
+ int? projectID;
+ dynamic patientID;
+ int? invoiceLineItemNo;
+ int? invoiceNo;
+ int? doctorID;
+ int? clinicID;
+ String? orderDate;
+ String? reportData;
+ String? imageURL;
+ String? procedureID;
+ int? appointmentNo;
+ dynamic dIAPacsURL;
+ bool? isRead;
+ String? readOn;
+ dynamic admissionNo;
+ bool? isInOutPatient;
+ int? actualDoctorRate;
+ dynamic admissionDate;
+ dynamic admissionNumber;
+ dynamic appointmentDate;
+ dynamic appointmentNumber;
+ dynamic appointmentTime;
+ String? clinicDescription;
+ String? dIAPACSURL;
+ dynamic decimalDoctorRate;
+ String? description;
+ String? doctorImageURL;
+ String? doctorName;
+ num? doctorRate;
+ num? doctorStarsRate;
+ String? doctorTitle;
+ String? examId;
+ int? gender;
+ dynamic genderDescription;
+ int? invoiceNoVP;
+ String? invoiceType;
+ bool? isActiveDoctorProfile;
+ bool? isExecludeDoctor;
+ String? isInOutPatientDescription;
+ String? isInOutPatientDescriptionN;
+ bool? isLiveCareAppointment;
+ dynamic nationalityFlagURL;
+ int? noOfPatientsRate;
+ int? orderNo;
+ dynamic procedureName;
+ String? projectName;
+ String? qR;
+ String? reportDataHTML;
+ String? reportDataTextString;
+ dynamic strAppointmentDate;
+ dynamic strOrderDate;
+ bool? isCVI;
+ bool? isRadMedicalReport;
+ dynamic vida3Id;
+
+ PatientRadiologyResponseModel(
+ {this.setupID,
+ this.projectID,
+ this.patientID,
+ this.invoiceLineItemNo,
+ this.invoiceNo,
+ this.doctorID,
+ this.clinicID,
+ this.orderDate,
+ this.reportData,
+ this.imageURL,
+ this.procedureID,
+ this.appointmentNo,
+ this.dIAPacsURL,
+ this.isRead,
+ this.readOn,
+ this.admissionNo,
+ this.isInOutPatient,
+ this.actualDoctorRate,
+ this.admissionDate,
+ this.admissionNumber,
+ this.appointmentDate,
+ this.appointmentNumber,
+ this.appointmentTime,
+ this.clinicDescription,
+ this.dIAPACSURL,
+ this.decimalDoctorRate,
+ this.description,
+ this.doctorImageURL,
+ this.doctorName,
+ this.doctorRate,
+ this.doctorStarsRate,
+ this.doctorTitle,
+ this.examId,
+ this.gender,
+ this.genderDescription,
+ this.invoiceNoVP,
+ this.invoiceType,
+ this.isActiveDoctorProfile,
+ this.isExecludeDoctor,
+ this.isInOutPatientDescription,
+ this.isInOutPatientDescriptionN,
+ this.isLiveCareAppointment,
+ this.nationalityFlagURL,
+ this.noOfPatientsRate,
+ this.orderNo,
+ this.procedureName,
+ this.projectName,
+ this.qR,
+ this.reportDataHTML,
+ this.reportDataTextString,
+ this.strAppointmentDate,
+ this.strOrderDate,
+ this.isCVI,
+ this.isRadMedicalReport,
+ this.vida3Id});
+
+ PatientRadiologyResponseModel.fromJson(Map json) {
+ setupID = json['SetupID'];
+ projectID = json['ProjectID'];
+ patientID = json['PatientID'];
+ invoiceLineItemNo = json['InvoiceLineItemNo'];
+ invoiceNo = json['InvoiceNo'];
+ doctorID = json['DoctorID'];
+ clinicID = json['ClinicID'];
+ orderDate = json['OrderDate'];
+ reportData = json['ReportData'];
+ imageURL = json['ImageURL'];
+ procedureID = json['ProcedureID'];
+ appointmentNo = json['AppointmentNo'];
+ dIAPacsURL = json['DIAPacsURL'];
+ isRead = json['IsRead'];
+ readOn = json['ReadOn'];
+ admissionNo = json['AdmissionNo'];
+ isInOutPatient = json['IsInOutPatient'];
+ actualDoctorRate = json['ActualDoctorRate'];
+ admissionDate = json['AdmissionDate'];
+ admissionNumber = json['AdmissionNumber'];
+ appointmentDate = json['AppointmentDate'];
+ appointmentNumber = json['AppointmentNumber'];
+ appointmentTime = json['AppointmentTime'];
+ clinicDescription = json['ClinicDescription'];
+ dIAPACSURL = json['DIA_PACS_URL'];
+ decimalDoctorRate = json['DecimalDoctorRate'];
+ description = json['Description'];
+ doctorImageURL = json['DoctorImageURL'];
+ doctorName = json['DoctorName'];
+ doctorRate = json['DoctorRate'];
+ doctorStarsRate = json['DoctorStarsRate'];
+ doctorTitle = json['DoctorTitle'];
+ examId = json['Exam_id'];
+ gender = json['Gender'];
+ genderDescription = json['GenderDescription'];
+ invoiceNoVP = json['InvoiceNo_VP'];
+ invoiceType = json['InvoiceType'];
+ isActiveDoctorProfile = json['IsActiveDoctorProfile'];
+ isExecludeDoctor = json['IsExecludeDoctor'];
+ isInOutPatientDescription = json['IsInOutPatientDescription'];
+ isInOutPatientDescriptionN = json['IsInOutPatientDescriptionN'];
+ isLiveCareAppointment = json['IsLiveCareAppointment'];
+ nationalityFlagURL = json['NationalityFlagURL'];
+ noOfPatientsRate = json['NoOfPatientsRate'];
+ orderNo = json['OrderNo'];
+ procedureName = json['ProcedureName'];
+ projectName = json['ProjectName'];
+ qR = json['QR'];
+ reportDataHTML = json['ReportDataHTML'];
+ reportDataTextString = json['ReportDataTextString'];
+ strAppointmentDate = json['StrAppointmentDate'];
+ strOrderDate = json['StrOrderDate'];
+ isCVI = json['isCVI'];
+ isRadMedicalReport = json['isRadMedicalReport'];
+ vida3Id = json['vida3Id'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['SetupID'] = this.setupID;
+ data['ProjectID'] = this.projectID;
+ data['PatientID'] = this.patientID;
+ data['InvoiceLineItemNo'] = this.invoiceLineItemNo;
+ data['InvoiceNo'] = this.invoiceNo;
+ data['DoctorID'] = this.doctorID;
+ data['ClinicID'] = this.clinicID;
+ data['OrderDate'] = this.orderDate;
+ data['ReportData'] = this.reportData;
+ data['ImageURL'] = this.imageURL;
+ data['ProcedureID'] = this.procedureID;
+ data['AppointmentNo'] = this.appointmentNo;
+ data['DIAPacsURL'] = this.dIAPacsURL;
+ data['IsRead'] = this.isRead;
+ data['ReadOn'] = this.readOn;
+ data['AdmissionNo'] = this.admissionNo;
+ data['IsInOutPatient'] = this.isInOutPatient;
+ data['ActualDoctorRate'] = this.actualDoctorRate;
+ data['AdmissionDate'] = this.admissionDate;
+ data['AdmissionNumber'] = this.admissionNumber;
+ data['AppointmentDate'] = this.appointmentDate;
+ data['AppointmentNumber'] = this.appointmentNumber;
+ data['AppointmentTime'] = this.appointmentTime;
+ data['ClinicDescription'] = this.clinicDescription;
+ data['DIA_PACS_URL'] = this.dIAPACSURL;
+ data['DecimalDoctorRate'] = this.decimalDoctorRate;
+ data['Description'] = this.description;
+ data['DoctorImageURL'] = this.doctorImageURL;
+ data['DoctorName'] = this.doctorName;
+ data['DoctorRate'] = this.doctorRate;
+ data['DoctorStarsRate'] = this.doctorStarsRate;
+ data['DoctorTitle'] = this.doctorTitle;
+ data['Exam_id'] = this.examId;
+ data['Gender'] = this.gender;
+ data['GenderDescription'] = this.genderDescription;
+ data['InvoiceNo_VP'] = this.invoiceNoVP;
+ data['InvoiceType'] = this.invoiceType;
+ data['IsActiveDoctorProfile'] = this.isActiveDoctorProfile;
+ data['IsExecludeDoctor'] = this.isExecludeDoctor;
+ data['IsInOutPatientDescription'] = this.isInOutPatientDescription;
+ data['IsInOutPatientDescriptionN'] = this.isInOutPatientDescriptionN;
+ data['IsLiveCareAppointment'] = this.isLiveCareAppointment;
+ data['NationalityFlagURL'] = this.nationalityFlagURL;
+ data['NoOfPatientsRate'] = this.noOfPatientsRate;
+ data['OrderNo'] = this.orderNo;
+ data['ProcedureName'] = this.procedureName;
+ data['ProjectName'] = this.projectName;
+ data['QR'] = this.qR;
+ data['ReportDataHTML'] = this.reportDataHTML;
+ data['ReportDataTextString'] = this.reportDataTextString;
+ data['StrAppointmentDate'] = this.strAppointmentDate;
+ data['StrOrderDate'] = this.strOrderDate;
+ data['isCVI'] = this.isCVI;
+ data['isRadMedicalReport'] = this.isRadMedicalReport;
+ data['vida3Id'] = this.vida3Id;
+ return data;
+ }
+}
diff --git a/lib/features/radiology/radiology_repo.dart b/lib/features/radiology/radiology_repo.dart
new file mode 100644
index 0000000..d3e4f3d
--- /dev/null
+++ b/lib/features/radiology/radiology_repo.dart
@@ -0,0 +1,77 @@
+import 'package:hmg_patient_app_new/core/api/api_client.dart';
+import 'package:hmg_patient_app_new/core/api_consts.dart';
+import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
+import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
+import 'package:dartz/dartz.dart';
+import 'package:hmg_patient_app_new/features/radiology/models/resp_models/patient_radiology_response_model.dart';
+import 'package:hmg_patient_app_new/services/logger_service.dart';
+
+abstract class RadiologyRepo {
+ Future>>> getPatientRadiologyOrders({required String patientId});
+}
+
+class RadiologyRepoImp implements RadiologyRepo {
+ final ApiClient apiClient;
+ final LoggerService loggerService;
+
+ RadiologyRepoImp({required this.loggerService, required this.apiClient});
+
+ @override
+ Future>>> getPatientRadiologyOrders({required String patientId}) async {
+ final mapDevice = {
+ "isDentalAllowedBackend": false,
+ "VersionID": 50.0,
+ "Channel": 3,
+ "LanguageID": 2,
+ "IPAdress": "10.20.10.20",
+ "generalid": "Cs2020@2016\$2958",
+ "Latitude": 0.0,
+ "Longitude": 0.0,
+ "DeviceTypeID": 1,
+ "PatientType": 1,
+ "PatientTypeID": 1,
+ "TokenID": "@dm!n",
+ "PatientID": "1018977",
+ "PatientOutSA": "0",
+ "SessionID": "03478TYC02N80874CTYN04883475!?"
+ };
+
+ try {
+ GenericApiModel>? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ GET_PATIENT_ORDERS,
+ body: mapDevice,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus}) {
+ final radOrders;
+ try {
+ if (response['FinalRadiologyList'] != null && response['FinalRadiologyList'].length != 0) {
+ final list = response['FinalRadiologyList'];
+ radOrders = list.map((item) => PatientRadiologyResponseModel.fromJson(item as Map)).toList().cast();
+ } else {
+ final list = response['FinalRadiologyListAPI'];
+ radOrders = list.map((item) => PatientRadiologyResponseModel.fromJson(item as Map)).toList().cast();
+ }
+
+ apiResponse = GenericApiModel>(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: radOrders,
+ );
+ } catch (e) {
+ failure = DataParsingFailure(e.toString());
+ }
+ },
+ );
+ if (failure != null) return Left(failure!);
+ if (apiResponse == null) return Left(ServerFailure("Unknown error"));
+ return Right(apiResponse!);
+ } catch (e) {
+ return Left(UnknownFailure(e.toString()));
+ }
+ }
+}
diff --git a/lib/features/radiology/radiology_view_model.dart b/lib/features/radiology/radiology_view_model.dart
new file mode 100644
index 0000000..1bdba04
--- /dev/null
+++ b/lib/features/radiology/radiology_view_model.dart
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
+import 'package:hmg_patient_app_new/services/error_handler_service.dart';
+
+import 'models/resp_models/patient_radiology_response_model.dart';
+
+class RadiologyViewModel extends ChangeNotifier {
+ bool isRadiologyOrdersLoading = false;
+
+ RadiologyRepo radiologyRepo;
+ ErrorHandlerService errorHandlerService;
+
+ List patientRadiologyOrders = [];
+
+ RadiologyViewModel({required this.radiologyRepo, required this.errorHandlerService});
+
+ initRadiologyProvider() {
+ patientRadiologyOrders.clear();
+ isRadiologyOrdersLoading = true;
+ getPatientRadiologyOrders();
+ notifyListeners();
+ }
+
+ Future getPatientRadiologyOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async {
+ final result = await radiologyRepo.getPatientRadiologyOrders(patientId: "1231755");
+
+ result.fold(
+ (failure) async => await errorHandlerService.handleError(failure: failure),
+ (apiResponse) {
+ if (apiResponse.messageStatus == 2) {
+ // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
+ } else if (apiResponse.messageStatus == 1) {
+ patientRadiologyOrders = apiResponse.data!;
+ isRadiologyOrdersLoading = false;
+ notifyListeners();
+ if (onSuccess != null) {
+ onSuccess(apiResponse);
+ }
+ }
+ },
+ );
+ }
+}
diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart
index a1082b3..cd59c15 100644
--- a/lib/generated/locale_keys.g.dart
+++ b/lib/generated/locale_keys.g.dart
@@ -779,5 +779,9 @@ abstract class LocaleKeys {
static const myFiles = 'myFiles';
static const resultsPending = 'resultsPending';
static const resultsAvailable = 'resultsAvailable';
+ static const viewReport = 'viewReport';
+ static const prescriptionDeliveryError = 'prescriptionDeliveryError';
+ static const checkAvailability = 'checkAvailability';
+ static const readInstructions = 'readInstructions';
}
diff --git a/lib/main.dart b/lib/main.dart
index 3f09649..035c6bf 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -8,6 +8,8 @@ import 'package:flutter/services.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
+import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@@ -57,6 +59,18 @@ void main() async {
errorHandlerService: getIt(),
),
),
+ ChangeNotifierProvider(
+ create: (_) => RadiologyViewModel(
+ radiologyRepo: getIt(),
+ errorHandlerService: getIt(),
+ ),
+ ),
+ ChangeNotifierProvider(
+ create: (_) => PrescriptionsViewModel(
+ prescriptionsRepo: getIt(),
+ errorHandlerService: getIt(),
+ ),
+ ),
ChangeNotifierProvider(
create: (_) => AuthenticationViewModel(
authenticationRepo: getIt(),
diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart
index da3249a..6594f85 100644
--- a/lib/presentation/home/landing_page.dart
+++ b/lib/presentation/home/landing_page.dart
@@ -17,7 +17,6 @@ import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card
import 'package:hmg_patient_app_new/presentation/home/widgets/small_service_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
-import 'package:hmg_patient_app_new/widgets/bottom_navigation/bottom_navigation.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart' show CustomTabBar;
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
@@ -31,6 +30,7 @@ class LandingPage extends StatefulWidget {
}
class _LandingPageState extends State {
+
@override
Widget build(BuildContext context) {
AppState appState = getIt.get();
@@ -276,7 +276,6 @@ class _LandingPageState extends State {
),
),
),
- bottomNavigationBar: BottomNavigation(),
);
}
}
diff --git a/lib/presentation/home/navigation_screen.dart b/lib/presentation/home/navigation_screen.dart
new file mode 100644
index 0000000..f3e088b
--- /dev/null
+++ b/lib/presentation/home/navigation_screen.dart
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/presentation/home/landing_page.dart';
+import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart';
+import 'package:hmg_patient_app_new/widgets/bottom_navigation/bottom_navigation.dart';
+
+class LandingNavigation extends StatefulWidget {
+ const LandingNavigation({super.key});
+
+ @override
+ State createState() => _LandingNavigationState();
+}
+
+class _LandingNavigationState extends State {
+ int _currentIndex = 0;
+ final PageController _pageController = PageController();
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: PageView(
+ controller: _pageController,
+ physics: const NeverScrollableScrollPhysics(),
+ children: const [
+ LandingPage(),
+ MedicalFilePage(),
+ LandingPage(),
+ LandingPage(),
+ LandingPage(),
+ ],
+ ),
+ bottomNavigationBar: BottomNavigation(
+ currentIndex: _currentIndex,
+ onTap: (index) {
+ setState(() => _currentIndex = index);
+ _pageController.animateToPage(
+ index,
+ duration: const Duration(milliseconds: 300),
+ curve: Curves.easeInOut);
+ },
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/home/widgets/small_service_card.dart b/lib/presentation/home/widgets/small_service_card.dart
index 0983a06..297ed2b 100644
--- a/lib/presentation/home/widgets/small_service_card.dart
+++ b/lib/presentation/home/widgets/small_service_card.dart
@@ -3,10 +3,12 @@ import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_orders_page.dart';
+import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import '../../../core/utils/utils.dart';
import '../../../theme/colors.dart';
+import '../../radiology/radiology_orders_page.dart' show RadiologyOrdersPage;
class SmallServiceCard extends StatelessWidget {
final String serviceName;
@@ -62,8 +64,18 @@ class SmallServiceCard extends StatelessWidget {
);
break;
case "radiology_results":
+ Navigator.of(context).push(
+ FadePage(
+ page: RadiologyOrdersPage(),
+ ),
+ );
break;
case "prescriptions":
+ Navigator.of(context).push(
+ FadePage(
+ page: PrescriptionsListPage(),
+ ),
+ );
break;
case "insurance_update":
break;
diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart
index a60f3cf..8a0ce26 100644
--- a/lib/presentation/lab/lab_orders_page.dart
+++ b/lib/presentation/lab/lab_orders_page.dart
@@ -28,14 +28,6 @@ class _LabOrdersPageState extends State {
int? expandedIndex;
- // Sample data for demonstration
- final List labOrders = [
- 'Mohammad Al Harbi',
- 'Mohammad Al Harbi',
- 'Mohammad Al Harbi',
- 'Mohammad Al Harbi',
- ];
-
@override
void initState() {
scheduleMicrotask(() {
@@ -50,7 +42,7 @@ class _LabOrdersPageState extends State {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
appBar: AppBar(
- title: const Text('Lab Results'),
+ title: LocaleKeys.labResults.tr(context: context).toText18(),
backgroundColor: AppColors.bgScaffoldColor,
),
body: Padding(
@@ -169,46 +161,59 @@ class _LabOrdersPageState extends State {
],
),
),
- AnimatedCrossFade(
- firstChild: SizedBox.shrink(),
- secondChild: Padding(
- padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- ...model.patientLabOrders[index].testDetails!.map((detail) {
- return Padding(
- padding: EdgeInsets.only(bottom: 8.h),
- child: '● ${detail.description}'.toText14(weight: FontWeight.w500),
- );
- }).toList(),
- SizedBox(height: 16.h),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- SizedBox(),
- CustomButton(
- icon: AppAssets.view_report_icon,
- iconColor: AppColors.primaryRedColor,
- iconSize: 16.h,
- text: "View Report",
- onPressed: () {},
- backgroundColor: AppColors.secondaryLightRedColor,
- borderColor: AppColors.secondaryLightRedColor,
- textColor: AppColors.primaryRedColor,
- fontSize: 14,
- fontWeight: FontWeight.bold,
- borderRadius: 12,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 40.h,
- ),
- ],
- ),
- ],
- ),
- ),
- crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst,
+ AnimatedSwitcher(
duration: Duration(milliseconds: 300),
+ switchInCurve: Curves.easeIn,
+ switchOutCurve: Curves.easeOut,
+ transitionBuilder: (Widget child, Animation animation) {
+ return FadeTransition(
+ opacity: animation,
+ child: SizeTransition(
+ sizeFactor: animation,
+ axisAlignment: 0.0,
+ child: child,
+ ),
+ );
+ },
+ child: isExpanded
+ ? Container(
+ key: ValueKey(index),
+ padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ ...model.patientLabOrders[index].testDetails!.map((detail) {
+ return Padding(
+ padding: EdgeInsets.only(bottom: 8.h),
+ child: '● ${detail.description}'.toText14(weight: FontWeight.w500),
+ );
+ }).toList(),
+ SizedBox(height: 16.h),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ SizedBox(),
+ CustomButton(
+ icon: AppAssets.view_report_icon,
+ iconColor: AppColors.primaryRedColor,
+ iconSize: 16.h,
+ text: LocaleKeys.viewReport.tr(context: context),
+ onPressed: () {},
+ backgroundColor: AppColors.secondaryLightRedColor,
+ borderColor: AppColors.secondaryLightRedColor,
+ textColor: AppColors.primaryRedColor,
+ fontSize: 14,
+ fontWeight: FontWeight.bold,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ ],
+ ),
+ ],
+ ),
+ )
+ : SizedBox.shrink(key: ValueKey(-index)),
),
],
),
diff --git a/lib/presentation/prescriptions/prescription_detail_page.dart b/lib/presentation/prescriptions/prescription_detail_page.dart
new file mode 100644
index 0000000..65dc550
--- /dev/null
+++ b/lib/presentation/prescriptions/prescription_detail_page.dart
@@ -0,0 +1,401 @@
+import 'dart:async';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
+import 'package:hmg_patient_app_new/core/app_assets.dart';
+import 'package:hmg_patient_app_new/core/utils/date_util.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/core/utils/utils.dart';
+import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
+import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
+import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
+import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
+import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
+import 'package:provider/provider.dart';
+
+class PrescriptionDetailPage extends StatefulWidget {
+ PrescriptionDetailPage({super.key, required this.prescriptionsResponseModel});
+
+ PatientPrescriptionsResponseModel prescriptionsResponseModel;
+
+ @override
+ State createState() => _PrescriptionDetailPageState();
+}
+
+class _PrescriptionDetailPageState extends State {
+ late PrescriptionsViewModel prescriptionsViewModel;
+
+ bool _isSwitched = false; // Initial state of the switch
+
+ @override
+ void initState() {
+ scheduleMicrotask(() {
+ prescriptionsViewModel.getPrescriptionDetails(widget.prescriptionsResponseModel);
+ });
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ prescriptionsViewModel = Provider.of(context, listen: false);
+ return Scaffold(
+ backgroundColor: AppColors.bgScaffoldColor,
+ appBar: AppBar(
+ title: LocaleKeys.prescriptions.tr(context: context).toText18(),
+ backgroundColor: AppColors.bgScaffoldColor,
+ ),
+ body: Column(
+ children: [
+ Expanded(
+ child: SingleChildScrollView(
+ child: Consumer(builder: (context, prescriptionVM, child) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.prescriptions.tr(context: context).toText24(isBold: true).paddingSymmetrical(24.h, 0.h),
+ SizedBox(height: 24.h),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 20.h,
+ hasShadow: true,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Image.network(
+ widget.prescriptionsResponseModel.doctorImageURL!,
+ width: 24.h,
+ height: 24.h,
+ fit: BoxFit.fill,
+ ).circle(100),
+ SizedBox(width: 8.h),
+ Expanded(child: widget.prescriptionsResponseModel.doctorName!.toText16(isBold: true)),
+ ],
+ ),
+ SizedBox(height: 16.h),
+ Wrap(
+ direction: Axis.horizontal,
+ spacing: 6.h,
+ runSpacing: 6.h,
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ icon: AppAssets.doctor_calendar_icon,
+ iconColor: AppColors.textColor,
+ iconSize: 13.h,
+ text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.prescriptionsResponseModel.appointmentDate), false),
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ text: widget.prescriptionsResponseModel.clinicDescription!,
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ icon: AppAssets.rating_icon,
+ iconColor: AppColors.ratingColorYellow,
+ iconSize: 13.h,
+ text: "Rating: ${widget.prescriptionsResponseModel.decimalDoctorRate}",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ text: widget.prescriptionsResponseModel.name!,
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ).paddingSymmetrical(24.h, 0.h),
+ SizedBox(height: 16.h),
+ ListView.builder(
+ shrinkWrap: true,
+ physics: NeverScrollableScrollPhysics(),
+ itemCount: prescriptionVM.isPrescriptionsDetailsLoading ? 5 : prescriptionVM.prescriptionDetailsList.length,
+ itemBuilder: (context, index) {
+ return prescriptionVM.isPrescriptionsDetailsLoading
+ ? const MoviesShimmerWidget()
+ : AnimationConfiguration.staggeredList(
+ position: index,
+ duration: const Duration(milliseconds: 500),
+ child: SlideAnimation(
+ verticalOffset: 100.0,
+ child: FadeInAnimation(
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ margin: EdgeInsets.symmetric(vertical: 8.h),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SizedBox(height: 16.h),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Image.network(
+ prescriptionVM.prescriptionDetailsList[index].imageThumbUrl!,
+ width: 60.h,
+ height: 60.h,
+ fit: BoxFit.fill,
+ ).circle(100),
+ SizedBox(width: 8.h),
+ Expanded(
+ child: prescriptionVM.prescriptionDetailsList[index].itemDescription!.toText16(isBold: true, maxlines: 2),
+ ),
+ ],
+ ).paddingSymmetrical(16.h, 0.h),
+ SizedBox(height: 16.h),
+ Wrap(
+ direction: Axis.horizontal,
+ spacing: 6.h,
+ runSpacing: 6.h,
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ text: "${LocaleKeys.route.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].route}",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ text: "${LocaleKeys.frequency.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].frequency}",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ text: "${LocaleKeys.dailyDoses.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].doseDailyQuantity}",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ text: "${LocaleKeys.days.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].days}",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ ],
+ ).paddingSymmetrical(16.h, 0.h),
+ SizedBox(height: 8.h),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Utils.buildSvgWithAssets(icon: AppAssets.prescription_remarks_icon, width: 18.h, height: 18.h),
+ SizedBox(width: 9.h),
+ Expanded(child: "${LocaleKeys.remarks.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].remarks!}".toText10(isBold: true)),
+ ],
+ ).paddingSymmetrical(16.h, 0.h),
+ SizedBox(height: 14.h),
+ Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
+ SizedBox(height: 14.h),
+ Row(
+ mainAxisSize: MainAxisSize.max,
+ children: [
+ Utils.buildSvgWithAssets(icon: AppAssets.prescription_reminder_icon, width: 35.h, height: 35.h),
+ SizedBox(width: 8.h),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.setReminder.tr(context: context).toText13(isBold: true),
+ "Notify me before the consumption time".toText10(color: AppColors.textColorLight),
+ ],
+ ),
+ SizedBox(width: 12.h),
+ Switch(
+ activeColor: AppColors.successColor,
+ value: prescriptionVM.prescriptionDetailsList[index].hasReminder!,
+ onChanged: (newValue) {
+ setState(() {
+ prescriptionVM.setPrescriptionItemReminder(newValue, prescriptionVM.prescriptionDetailsList[index]);
+ });
+ },
+ ),
+ ],
+ ).paddingSymmetrical(16.h, 0.h),
+ SizedBox(height: 14.h),
+ Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
+ Row(
+ children: [
+ Expanded(
+ child: CustomButton(
+ text: LocaleKeys.checkAvailability.tr(context: context),
+ onPressed: () {},
+ backgroundColor: AppColors.primaryRedColor.withOpacity(0.1),
+ borderColor: AppColors.primaryRedColor.withOpacity(0.0),
+ textColor: AppColors.primaryRedColor,
+ fontSize: 13,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ ),
+ SizedBox(width: 16.h),
+ Expanded(
+ child: CustomButton(
+ text: LocaleKeys.readInstructions.tr(context: context),
+ onPressed: () {},
+ backgroundColor: AppColors.primaryRedColor,
+ borderColor: AppColors.primaryRedColor,
+ textColor: AppColors.whiteColor,
+ fontSize: 13,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ ),
+ ],
+ ).paddingSymmetrical(16.h, 16.h),
+ ],
+ )
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+ },
+ ).paddingSymmetrical(24.h, 0.h),
+ ],
+ );
+ }),
+ ),
+ ),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 24.h,
+ hasShadow: true,
+ ),
+ child: CustomButton(
+ text: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? LocaleKeys.resendOrder.tr(context: context) : LocaleKeys.prescriptionDeliveryError.tr(context: context),
+ onPressed: () {},
+ backgroundColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.greyF7Color,
+ borderColor: AppColors.successColor.withOpacity(0.01),
+ textColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? AppColors.whiteColor : AppColors.textColor.withOpacity(0.35),
+ fontSize: 16,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 50.h,
+ icon: AppAssets.prescription_refill_icon,
+ iconColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? AppColors.whiteColor : AppColors.textColor.withOpacity(0.35),
+ iconSize: 20.h,
+ ).paddingSymmetrical(24.h, 24.h),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/prescriptions/prescriptions_list_page.dart b/lib/presentation/prescriptions/prescriptions_list_page.dart
new file mode 100644
index 0000000..9574f28
--- /dev/null
+++ b/lib/presentation/prescriptions/prescriptions_list_page.dart
@@ -0,0 +1,299 @@
+import 'dart:async';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
+import 'package:hmg_patient_app_new/core/app_assets.dart';
+import 'package:hmg_patient_app_new/core/utils/date_util.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/core/utils/utils.dart';
+import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
+import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
+import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
+import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
+import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
+import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
+import 'package:provider/provider.dart';
+
+class PrescriptionsListPage extends StatefulWidget {
+ const PrescriptionsListPage({super.key});
+
+ @override
+ State createState() => _PrescriptionsListPageState();
+}
+
+class _PrescriptionsListPageState extends State {
+ int? expandedIndex;
+
+ late PrescriptionsViewModel prescriptionsViewModel;
+
+ @override
+ void initState() {
+ scheduleMicrotask(() {
+ prescriptionsViewModel.initPrescriptionsViewModel();
+ });
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ prescriptionsViewModel = Provider.of(context, listen: false);
+ return Scaffold(
+ backgroundColor: AppColors.bgScaffoldColor,
+ appBar: AppBar(
+ title: LocaleKeys.prescriptions.tr(context: context).toText18(),
+ backgroundColor: AppColors.bgScaffoldColor,
+ ),
+ body: SingleChildScrollView(
+ child: Consumer(builder: (context, model, child) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.prescriptions.tr(context: context).toText24(isBold: true).paddingSymmetrical(24.h, 0.h),
+ SizedBox(height: 16.h),
+ // Build Tab Bar
+ SizedBox(height: 16.h),
+ // Clinic & Hospital Sort
+ Row(
+ children: [
+ CustomButton(
+ text: LocaleKeys.byClinic.tr(context: context),
+ onPressed: () {
+ model.setIsSortByClinic(true);
+ },
+ backgroundColor: model.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
+ borderColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
+ textColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 10,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ SizedBox(width: 8.h),
+ CustomButton(
+ text: LocaleKeys.byHospital.tr(context: context),
+ onPressed: () {
+ model.setIsSortByClinic(false);
+ },
+ backgroundColor: model.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor,
+ borderColor: model.isSortByClinic ? AppColors.textColor.withOpacity(0.2) : AppColors.primaryRedColor,
+ textColor: model.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 10,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ ],
+ ).paddingSymmetrical(24.h, 0.h),
+ SizedBox(height: 20.h),
+ // Expandable list
+ ListView.builder(
+ itemCount: model.isPrescriptionsOrdersLoading ? 4 : model.patientPrescriptionOrdersViewList.length,
+ physics: NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
+ padding: const EdgeInsets.only(left: 0, right: 8),
+ itemBuilder: (context, index) {
+ final isExpanded = expandedIndex == index;
+ return model.isPrescriptionsOrdersLoading
+ ? const MoviesShimmerWidget()
+ : AnimationConfiguration.staggeredList(
+ position: index,
+ duration: const Duration(milliseconds: 500),
+ child: SlideAnimation(
+ verticalOffset: 100.0,
+ child: FadeInAnimation(
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ margin: EdgeInsets.symmetric(vertical: 8.h),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
+ child: InkWell(
+ onTap: () {
+ setState(() {
+ expandedIndex = isExpanded ? null : index;
+ });
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomButton(
+ text: "${model.patientPrescriptionOrdersViewList[index].prescriptionsList!.length} Prescriptions Available",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ model.patientPrescriptionOrdersViewList[index].filterName!.toText16(isBold: true)
+ ],
+ ),
+ ),
+ AnimatedSwitcher(
+ duration: Duration(milliseconds: 500),
+ switchInCurve: Curves.easeIn,
+ switchOutCurve: Curves.easeOut,
+ transitionBuilder: (Widget child, Animation animation) {
+ return FadeTransition(
+ opacity: animation,
+ child: SizeTransition(
+ sizeFactor: animation,
+ axisAlignment: 0.0,
+ child: child,
+ ),
+ );
+ },
+ child: isExpanded
+ ? Container(
+ key: ValueKey(index),
+ padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ ...model.patientPrescriptionOrdersViewList[index].prescriptionsList!.map((prescription) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Image.network(
+ prescription.doctorImageURL!,
+ width: 24.h,
+ height: 24.h,
+ fit: BoxFit.fill,
+ ).circle(100),
+ SizedBox(width: 8.h),
+ Expanded(child: prescription.doctorName!.toText14(weight: FontWeight.w500)),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ CustomButton(
+ text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescription.appointmentDate), false),
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 24.h,
+ ),
+ SizedBox(width: 8.h),
+ CustomButton(
+ text: model.isSortByClinic ? prescription.name! : prescription.clinicDescription!,
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 24.h,
+ ),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ Expanded(
+ flex: 6,
+ child: CustomButton(
+ text: prescription.isHomeMedicineDeliverySupported!
+ ? LocaleKeys.resendOrder.tr(context: context)
+ : LocaleKeys.prescriptionDeliveryError.tr(context: context),
+ onPressed: () {},
+ backgroundColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor.withOpacity(0.15) : AppColors.greyF7Color,
+ borderColor: AppColors.successColor.withOpacity(0.01),
+ textColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35),
+ fontSize: prescription.isHomeMedicineDeliverySupported! ? 14 : 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ icon: AppAssets.prescription_refill_icon,
+ iconColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35),
+ iconSize: 14.h,
+ ),
+ ),
+ SizedBox(width: 8.h),
+ Expanded(
+ flex: 1,
+ child: Container(
+ height: 40.h,
+ width: 40.h,
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.textColor,
+ borderRadius: 10.h,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(8.h),
+ child: Utils.buildSvgWithAssets(
+ icon: AppAssets.forward_arrow_icon,
+ width: 10.h,
+ height: 10.h,
+ fit: BoxFit.contain,
+ ),
+ ),
+ ).onPress(() {
+ model.setPrescriptionsDetailsLoading();
+ Navigator.of(context).push(
+ FadePage(
+ page: PrescriptionDetailPage(prescriptionsResponseModel: prescription),
+ ),
+ );
+ }),
+ ),
+ ],
+ ),
+ SizedBox(height: 12.h),
+ Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
+ SizedBox(height: 12.h),
+ ],
+ );
+ }).toList(),
+ ],
+ ),
+ )
+ : SizedBox.shrink(),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ },
+ ).paddingSymmetrical(24.h, 0.h),
+ ],
+ );
+ }),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/radiology/radiology_orders_page.dart b/lib/presentation/radiology/radiology_orders_page.dart
new file mode 100644
index 0000000..d1b3830
--- /dev/null
+++ b/lib/presentation/radiology/radiology_orders_page.dart
@@ -0,0 +1,251 @@
+import 'dart:async';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
+import 'package:hmg_patient_app_new/core/app_assets.dart';
+import 'package:hmg_patient_app_new/core/utils/date_util.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/core/utils/utils.dart';
+import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
+import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
+import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
+import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
+import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
+import 'package:provider/provider.dart';
+
+import '../../features/radiology/radiology_view_model.dart';
+
+class RadiologyOrdersPage extends StatefulWidget {
+ const RadiologyOrdersPage({super.key});
+
+ @override
+ State createState() => _RadiologyOrdersPageState();
+}
+
+class _RadiologyOrdersPageState extends State {
+ late RadiologyViewModel radiologyViewModel;
+
+ int? expandedIndex;
+
+ @override
+ void initState() {
+ scheduleMicrotask(() {
+ radiologyViewModel.initRadiologyProvider();
+ });
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ radiologyViewModel = Provider.of(context);
+ return Scaffold(
+ backgroundColor: AppColors.bgScaffoldColor,
+ appBar: AppBar(
+ title: LocaleKeys.radiology.tr(context: context).toText18(),
+ backgroundColor: AppColors.bgScaffoldColor,
+ ),
+ body: Padding(
+ padding: EdgeInsets.all(24.h),
+ child: SingleChildScrollView(
+ child: Consumer(
+ builder: (context, model, child) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ LocaleKeys.radiology.tr(context: context).toText24(isBold: true),
+ Utils.buildSvgWithAssets(icon: AppAssets.search_icon),
+ ],
+ ),
+ SizedBox(height: 16.h),
+ // Build Tab Bar
+ SizedBox(height: 16.h),
+ // Expandable list
+ ListView.builder(
+ shrinkWrap: true,
+ physics: NeverScrollableScrollPhysics(),
+ itemCount: model.isRadiologyOrdersLoading ? 5 : model.patientRadiologyOrders.length,
+ itemBuilder: (context, index) {
+ final isExpanded = expandedIndex == index;
+ return model.isRadiologyOrdersLoading
+ ? const MoviesShimmerWidget()
+ : AnimationConfiguration.staggeredList(
+ position: index,
+ duration: const Duration(milliseconds: 500),
+ child: SlideAnimation(
+ verticalOffset: 100.0,
+ child: FadeInAnimation(
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ margin: EdgeInsets.symmetric(vertical: 8.h),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
+ child: InkWell(
+ onTap: () {
+ setState(() {
+ expandedIndex = isExpanded ? null : index;
+ });
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomButton(
+ text: LocaleKeys.resultsAvailable.tr(context: context),
+ onPressed: () {},
+ backgroundColor: AppColors.successColor.withOpacity(0.15),
+ borderColor: AppColors.successColor.withOpacity(0.01),
+ textColor: AppColors.successColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ Image.network(
+ model.patientRadiologyOrders[index].doctorImageURL!,
+ width: 24.h,
+ height: 24.h,
+ fit: BoxFit.fill,
+ ).circle(100),
+ SizedBox(width: 4.h),
+ model.patientRadiologyOrders[index].doctorName!.toText16(isBold: true)
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ CustomButton(
+ text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(model.patientRadiologyOrders[index].orderDate), false),
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 24.h,
+ ),
+ SizedBox(width: 8.h),
+ CustomButton(
+ text: model.patientRadiologyOrders[index].clinicDescription!,
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 24.h,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ AnimatedCrossFade(
+ firstChild: SizedBox.shrink(),
+ secondChild: Padding(
+ padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: EdgeInsets.only(bottom: 8.h),
+ child: '● ${model.patientRadiologyOrders[index].description}'.toText14(weight: FontWeight.w500),
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ SizedBox(),
+ CustomButton(
+ icon: AppAssets.view_report_icon,
+ iconColor: AppColors.primaryRedColor,
+ iconSize: 16.h,
+ text: LocaleKeys.viewReport.tr(context: context),
+ onPressed: () {},
+ backgroundColor: AppColors.secondaryLightRedColor,
+ borderColor: AppColors.secondaryLightRedColor,
+ textColor: AppColors.primaryRedColor,
+ fontSize: 14,
+ fontWeight: FontWeight.bold,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst,
+ duration: Duration(milliseconds: 300),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ },
+ ),
+ ],
+ );
+ },
+ ),
+ ),
+ ),
+ );
+ }
+
+ Color getLabOrderStatusColor(num status) {
+ switch (status) {
+ case 44:
+ return AppColors.warningColorYellow;
+ case 45:
+ return AppColors.warningColorYellow;
+ case 16:
+ return AppColors.successColor;
+ case 17:
+ return AppColors.successColor;
+ default:
+ return AppColors.greyColor;
+ }
+ }
+
+ String getLabOrderStatusText(num status) {
+ switch (status) {
+ case 44:
+ return LocaleKeys.resultsPending.tr(context: context);
+ case 45:
+ return LocaleKeys.resultsPending.tr(context: context);
+ case 16:
+ return LocaleKeys.resultsAvailable.tr(context: context);
+ case 17:
+ return LocaleKeys.resultsAvailable.tr(context: context);
+ default:
+ return "";
+ }
+ }
+}
diff --git a/lib/splashPage.dart b/lib/splashPage.dart
index bc3e542..6136d22 100644
--- a/lib/splashPage.dart
+++ b/lib/splashPage.dart
@@ -11,6 +11,7 @@ import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
// import 'package:hmg_patient_app_new/presentation/authantication/login.dart';
import 'package:hmg_patient_app_new/presentation/home/landing_page.dart';
+import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
@@ -37,7 +38,7 @@ class _SplashScreenState extends State {
LocalNotification.init(onNotificationClick: (payload) {});
Navigator.of(context).pushReplacement(
FadePage(
- page: LandingPage(),
+ page: LandingNavigation(),
// page: LoginScreen(),
),
);
diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart
index 5e9dbdc..61938b0 100644
--- a/lib/theme/colors.dart
+++ b/lib/theme/colors.dart
@@ -29,9 +29,11 @@ class AppColors {
static const Color bgRedLightColor = Color(0xFFFEE9EA);
static const Color bgGreenColor = Color(0xFF18C273);
static const Color textColor = Color(0xFF2E3039);
+ static const Color textColorLight = Color(0xFF5E5E5E);
static const Color borderOnlyColor = Color(0xFF2E3039);
static const Color dividerColor = Color(0xFFD2D2D2);
static const Color warningColorYellow = Color(0xFFF4A308);
+ static const Color ratingColorYellow = Color(0xFFFFAF15);
//Chips
static const Color successColor = Color(0xff18C273);
@@ -41,12 +43,12 @@ static const Color infoColor = Color(0xFF0B85F7);
static const Color warningColor = Color(0xFFFFCC00);
static const Color greyColor = Color(0xFFEFEFF0);
-static const Color successLightColor = Color(0xFF18C27326);
-static const Color errorLightColor = Color(0xFFED1C2B1A);
-static const Color alertLightColor = Color(0xFFD48D0526);
-static const Color infoLightColor = Color(0xFF0B85F726);
-static const Color warningLightColor = Color(0xFFFFCC0026);
-static const Color greyLightColor = Color(0xFFEFEFF026);
+static const Color successLightColor = Color(0xFF18C273);
+static const Color errorLightColor = Color(0xFFED1C2B);
+static const Color alertLightColor = Color(0xFFD48D05);
+static const Color infoLightColor = Color(0xFF0B85F7);
+static const Color warningLightColor = Color(0xFFFFCC00);
+static const Color greyLightColor = Color(0xFFEFEFF0);
static const Color bottomNAVBorder = Color(0xFFEEEEEE);
}
diff --git a/lib/widgets/bottom_navigation/bottom_navigation.dart b/lib/widgets/bottom_navigation/bottom_navigation.dart
index a052bc6..7f45464 100644
--- a/lib/widgets/bottom_navigation/bottom_navigation.dart
+++ b/lib/widgets/bottom_navigation/bottom_navigation.dart
@@ -1,59 +1,103 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
+import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class BottomNavigation extends StatelessWidget {
- const BottomNavigation({super.key});
+ final int currentIndex;
+ final ValueChanged onTap;
+
+ const BottomNavigation({
+ super.key,
+ required this.currentIndex,
+ required this.onTap,
+ });
@override
Widget build(BuildContext context) {
- return Container(
- padding: const EdgeInsets.symmetric(vertical: 12),
- decoration: const BoxDecoration(
- color: Colors.white,
- border: Border(
- top: BorderSide(color: AppColors.bottomNAVBorder, width: 0.5),
- ),
-
+ final items = [
+ BottomNavItem(icon: AppAssets.homeBottom, label: LocaleKeys.home.tr()),
+ BottomNavItem(icon: AppAssets.myFilesBottom, label: LocaleKeys.myFiles.tr()),
+ BottomNavItem(
+ icon: AppAssets.bookAppoBottom,
+ label: LocaleKeys.appointment.tr(),
+ iconSize: 27,
+ isSpecial: true,
),
+ BottomNavItem(icon: AppAssets.toDoBottom, label: LocaleKeys.todoList.tr()),
+ BottomNavItem(icon: AppAssets.servicesBottom, label: LocaleKeys.services2.tr()),
+ ];
+
+ return Container(
+ decoration: _containerDecoration,
+ padding: _containerPadding,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: [
- _buildNavItem(AppAssets.homeBottom, LocaleKeys.home.tr()),
- _buildNavItem(AppAssets.myFilesBottom, LocaleKeys.myFiles.tr()),
- _buildNavItem(AppAssets.bookAppoBottom, LocaleKeys.appointment.tr(), iconSize: 32),
- _buildNavItem(AppAssets.toDoBottom, LocaleKeys.todoList.tr()),
- _buildNavItem(AppAssets.servicesBottom, LocaleKeys.services2.tr()),
- ],
+ children: List.generate(
+ items.length,
+ (index) => _buildNavItem(items[index], index),
+ ),
),
);
}
- Widget _buildNavItem(String iconName, String label,{ double iconSize = 24}) {
- return Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Container(
- padding: const EdgeInsets.all(10),
- child: Utils.buildSvgWithAssets(
- icon: iconName,
- height: iconSize,
- width: iconSize
- ),
- ),
- // const SizedBox(height: 4),
- Text(
- label,
- style: TextStyle(
- fontSize: 13,
- fontWeight: FontWeight.w500,
- color: Colors.black87,
+ Widget _buildNavItem(BottomNavItem item, int index) {
+ final bool isSelected = currentIndex == index;
+
+ return GestureDetector(
+ onTap: () => onTap(index),
+ behavior: HitTestBehavior.opaque,
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Center(
+ child: Utils.buildSvgWithAssets(
+ icon: item.icon,
+ height: item.iconSize.h,
+ width: item.iconSize.h,
+ // iconColor: isSelected ? Colors.black87 : Colors.black87,
+ ),
+ ),
+ const SizedBox(height: 10),
+ item.label.toText12(
+ fontWeight:FontWeight.w500,
+ // color: Colors.black87,
+ // textAlign: TextAlign.center,
),
- ),
- ],
+ SizedBox(height: item.isSpecial ? 5:0 )
+ ],
+
+ ),
);
}
}
+
+class BottomNavItem {
+ final String icon;
+ final String label;
+ final double iconSize;
+ final bool isSpecial;
+
+ const BottomNavItem({
+ required this.icon,
+ required this.label,
+ this.iconSize = 21,
+ this.isSpecial = false,
+ });
+}
+
+// Constants
+const EdgeInsets _containerPadding = EdgeInsets.all(15);
+const BoxDecoration _containerDecoration = BoxDecoration(
+ color: Colors.white,
+ border: Border(
+ top: BorderSide(
+ color: AppColors.bottomNAVBorder,
+ width: 0.5,
+ ),
+ ),
+);
diff --git a/pubspec.yaml b/pubspec.yaml
index 4c2b81f..1263e33 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -98,8 +98,8 @@ flutter:
# weight: 700
- asset: assets/fonts/poppins/Poppins-SemiBold.ttf
weight: 600
-# - asset: assets/fonts/poppins/Poppins-Medium.ttf
-# weight: 500
+ - asset: assets/fonts/poppins/Poppins-Medium.ttf
+ weight: 500
- asset: assets/fonts/poppins/Poppins-Regular.ttf
weight: 400
# - asset: assets/fonts/poppins/Poppins-Light.ttf
@@ -114,8 +114,8 @@ flutter:
fonts:
- asset: assets/fonts/gess_two/GE_SS_Two_Bold.otf
weight: 600
-# - asset: assets/fonts/gess_two/GE_SS_Two_Medium.otf
-# weight: 500
+ - asset: assets/fonts/gess_two/GE_SS_Two_Medium.otf
+ weight: 500
- asset: assets/fonts/gess_two/GE_SS_Two_Light.otf
weight: 400