diff --git a/assets/images/svg/invoice_list_icon.svg b/assets/images/svg/invoice_list_icon.svg
new file mode 100644
index 00000000..6b9e698f
--- /dev/null
+++ b/assets/images/svg/invoice_list_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json
index a1d22707..b0d67521 100644
--- a/assets/langs/ar-SA.json
+++ b/assets/langs/ar-SA.json
@@ -694,7 +694,7 @@
"retouch": "روتوش",
"bikini": "بيكيني",
"totalMinutes": "إجمالي الدقائق",
- "feedback": "ملاحظات",
+ "feedback": "رأيك يهمنا",
"likeToHear": "نود سماع ملاحظاتك، ومخاوفك بشأن خدمات الرعاية الصحية وتجربة الخدمات الإلكترونية. يرجى استخدام النموذج أدناه",
"emptySubject": "يرجى إدخال الموضوع",
"emptyMessage": "يرجى إدخال الرسالة",
@@ -702,10 +702,10 @@
"complainAppo": "شكوى بخصوص الموعد",
"complainAppoAlt": "شكوى بدون موعد",
"messageType": "نوع الرسالة",
- "feedbackType": "نوع الملاحظات",
+ "feedbackType": "نوع الرسالة",
"compliment": "تقدير",
"suggestion": "اقتراح",
- "yourFeedback": "تم إرسال ملاحظاتك",
+ "yourFeedback": "تم إرسال رأيك",
"selectPart": "يرجى اختيار الجزء الذي تشتكي منه",
"number": "رقم",
"notClassified": "غير مصنف",
@@ -1705,5 +1705,8 @@
"takePhotoWithCamera": "التقط صورة بالكاميرا",
"selectFromPhotoLibrary": "اختر من مكتبة الصور",
"selectDocumentFiles": "اختر ملفات المستندات",
- "profilePicture": "صورة الملف الشخصي"
+ "profilePicture": "صورة الملف الشخصي",
+ "aiDisclaimerRad": "سيتم مشاركة بيانات نتائج الأشعة الخاصة بك بشكل آمن مع محلل الذكاء الاصطناعي لدينا لتحليلها. يساعد هذا في توفير رؤى صحية مخصصة. هل ترغب في المتابعة؟",
+ "sendingAskDrRequest": "جارٍ إرسال الطلب...",
+ "askDrRequestSentSuccess": "تم إرسال الطلب بنجاح، وسيتواصل معك الطبيب قريباً."
}
diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json
index 3b1070d9..38ce9662 100644
--- a/assets/langs/en-US.json
+++ b/assets/langs/en-US.json
@@ -1697,5 +1697,8 @@
"takePhotoWithCamera": "Take a photo with your camera",
"selectFromPhotoLibrary": "Select from your photo library",
"selectDocumentFiles": "Select document files",
- "profilePicture": "Profile Picture"
+ "profilePicture": "Profile Picture",
+ "aiDisclaimerRad": "Your radiology result data will be securely shared with our AI Analyzer for analysis. This helps provide personalized health insights. Do you want to proceed?",
+ "sendingAskDrRequest": "Sending Request...",
+ "askDrRequestSentSuccess": "Request has been sent successfully, The doctor will get back to you soon."
}
diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart
index c74d9fd5..2b5abbe9 100644
--- a/lib/core/api_consts.dart
+++ b/lib/core/api_consts.dart
@@ -25,6 +25,7 @@ class ApiConsts {
static String GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid=';
static String QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
+ // static String QLINE_URL = "https://qline.hmg.com/api/PatientCall/PatientInQueue_Detail";
static String CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId=";
@@ -44,7 +45,7 @@ class ApiConsts {
GET_TAMARA_INSTALLMENTS_URL = "https://mdlaboratories.com/tamaralive/Home/GetInstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid=';
rcBaseUrl = 'https://rc.hmg.com/';
- QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
+ QLINE_URL = "https://qline.hmg.com/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId=";
break;
case AppEnvironmentTypeEnum.dev:
@@ -80,7 +81,7 @@ class ApiConsts {
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
rcBaseUrl = 'https://rc.hmg.com/';
- QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
+ QLINE_URL = "https://qline.hmg.com/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId=";
break;
case AppEnvironmentTypeEnum.qa:
@@ -475,7 +476,8 @@ var GET_ACTIVE_APPOINTMENTS_LIST_URL = "Services/Doctors.svc/Rest/Dr_GetAppointm
var GET_DOCTORS_LIST_URL = "Services/Doctors.svc/REST/SearchDoctorsByTime";
//URL to dental doctors list
-var GET_DENTAL_DOCTORS_LIST_URL = "Services/Doctors.svc/REST/Dental_DoctorChiefComplaintMapping";
+// var GET_DENTAL_DOCTORS_LIST_URL = "Services/Doctors.svc/REST/Dental_DoctorChiefComplaintMapping";
+var GET_DENTAL_DOCTORS_LIST_URL = "Services/Doctors.svc/REST/Dental_DoctorChiefComplaintMapping_Nearest";
//URL to get doctor free slots
var GET_DOCTOR_FREE_SLOTS = "Services/Doctors.svc/REST/GetDoctorFreeSlots";
diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart
index 14227fa6..5adc0cd5 100644
--- a/lib/core/app_assets.dart
+++ b/lib/core/app_assets.dart
@@ -357,6 +357,7 @@ class AppAssets {
static const String biometricLockIcon = '$svgBasePath/biometric_lock_icon.svg';
static const String imageIcon = '$svgBasePath/image_icon.svg';
static const String appointmentRatingIcon = '$svgBasePath/appointment_rating_icon.svg';
+ static const String invoiceListIcon = '$svgBasePath/invoice_list_icon.svg';
static const String open_camera = '$svgBasePath/open_camera.svg';
static const String gallery = '$svgBasePath/gallery.svg';
static const String files = '$svgBasePath/files.svg';
diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart
index 5bbf19aa..1b4a5e4d 100644
--- a/lib/core/app_state.dart
+++ b/lib/core/app_state.dart
@@ -10,14 +10,19 @@ import 'package:hmg_patient_app_new/features/authentication/models/resp_models/a
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/check_user_staus_nhic_response_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/select_device_by_imei.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
+import 'package:hmg_patient_app_new/services/cache_service.dart';
import '../features/authentication/models/request_models/registration_payload_model.dart';
class AppState {
NavigationService navigationService;
+ CacheService cacheService;
- AppState({required this.navigationService}){
+ static const String _profileImageKey = 'profile_image_data';
+
+ AppState({required this.navigationService, required this.cacheService}){
checkIfGMSAvailableOrNot();
+ _loadProfileImageFromCache();
}
double userLat = 0.0;
@@ -88,7 +93,30 @@ class AppState {
String? get getProfileImageData => _profileImageData;
- set setProfileImageData(String? value) => _profileImageData = value;
+ set setProfileImageData(String? value) {
+ print('📸 AppState: Setting profile image data - ${value != null && value.isNotEmpty ? "Has data (${value.length} chars)" : "Empty/null"}');
+ _profileImageData = value;
+ // Persist to cache
+ if (value != null && value.isNotEmpty) {
+ cacheService.saveString(key: _profileImageKey, value: value);
+ print('💾 AppState: Profile image saved to cache');
+ } else {
+ cacheService.remove(key: _profileImageKey);
+ print('🗑️ AppState: Profile image removed from cache');
+ }
+ }
+
+ /// Load profile image from cache on app initialization
+ void _loadProfileImageFromCache() {
+ _profileImageData = cacheService.getString(key: _profileImageKey);
+ print('📂 AppState: Loaded profile image from cache - ${_profileImageData != null && _profileImageData!.isNotEmpty ? "Has data (${_profileImageData!.length} chars)" : "Empty/null"}');
+ }
+
+ /// Clear profile image from cache (e.g., on logout)
+ void clearProfileImageCache() {
+ _profileImageData = null;
+ cacheService.remove(key: _profileImageKey);
+ }
SelectDeviceByImeiRespModelElement? _selectDeviceByImeiRespModelElement;
@@ -255,4 +283,18 @@ class AppState {
_userSwitchPayloads.clear();
_childSwitchCounter = 0;
}
+
+ void clearChildUsersKeepSuperUser() {
+ // Keep the super user payload
+ final superUserPayload = _userSwitchPayloads['superUser'];
+
+ // Clear all payloads
+ _userSwitchPayloads.clear();
+ _childSwitchCounter = 0;
+
+ // Restore super user if it existed
+ if (superUserPayload != null) {
+ _userSwitchPayloads['superUser'] = superUserPayload;
+ }
+ }
}
diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart
index 657d03ea..3b7253db 100644
--- a/lib/core/dependencies.dart
+++ b/lib/core/dependencies.dart
@@ -113,7 +113,12 @@ class AppDependencies {
getIt.registerLazySingleton(() => LocalAuthentication());
getIt.registerLazySingleton(() => GAnalytics());
- getIt.registerLazySingleton(() => AppState(navigationService: getIt()));
+
+ // Register CacheService before AppState so it can be injected
+ final sharedPreferences = await SharedPreferences.getInstance();
+ getIt.registerLazySingleton(() => CacheServiceImp(sharedPreferences: sharedPreferences, loggerService: getIt()));
+
+ getIt.registerLazySingleton(() => AppState(navigationService: getIt(), cacheService: getIt()));
getIt.registerLazySingleton(() => LocationUtils(
isShowConfirmDialog: false,
navigationService: getIt(),
@@ -126,8 +131,6 @@ class AppDependencies {
navigationService: getIt(),
));
- final sharedPreferences = await SharedPreferences.getInstance();
- getIt.registerLazySingleton(() => CacheServiceImp(sharedPreferences: sharedPreferences, loggerService: getIt()));
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
getIt.registerLazySingleton(() => NotificationServiceImp(
diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart
index 39d8e3ee..c355819e 100644
--- a/lib/features/authentication/authentication_repo.dart
+++ b/lib/features/authentication/authentication_repo.dart
@@ -314,7 +314,7 @@ class AuthenticationRepoImp implements AuthenticationRepo {
requestBody['PatientIdentificationID'] = "";
requestBody.removeWhere((key, value) => ['NationalID', 'isDentalAllowedBackend', 'ForRegisteration'].contains(key));
appState.setIsChildLoggedIn = false;
- appState.clearUserSwitchPayloads();
+ appState.clearChildUsersKeepSuperUser();
}
} else {
appState.setIsChildLoggedIn = true;
diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart
index 2e9426a0..d94b100b 100644
--- a/lib/features/authentication/authentication_view_model.dart
+++ b/lib/features/authentication/authentication_view_model.dart
@@ -631,6 +631,10 @@ class AuthenticationViewModel extends ChangeNotifier {
} else {
if (activation.list != null && activation.list!.isNotEmpty) {
if (isSwitchUser) {
+ // Clear profile image cache when switching users
+ _appState.clearProfileImageCache();
+ log("🔄 Switching user - cleared profile image cache");
+
if (_appState.getIsChildLoggedIn) {
_appState.setSuperUserID = null;
// _appState.setIsChildLoggedIn = false;
@@ -642,17 +646,20 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.addUserSwitchPayload(activation.list!.first.toJson(), isSuperUser: true);
}
} else {
- _appState.setSuperUserID = _appState.getAuthenticatedUser()?.patientId;
- // _appState.setIsChildLoggedIn = false;
+ var allUsersPayload = _appState.getUserSwitchPayloads;
+ _appState.setSuperUserID = allUsersPayload['superUser']?['PatientID'];
activation.list!.first.isParentUser = true;
_appState.addUserSwitchPayload(activation.list!.first.toJson(), isSuperUser: true);
}
// Fetch profile image after switching user
- _fetchProfileImage(activation.list!.first.patientId);
+ await _fetchProfileImage(activation.list!.first.patientId);
} else {
activation.list!.first.isParentUser = true;
_appState.addUserSwitchPayload(activation.list!.first.toJson(), isSuperUser: true);
+
+ // Fetch profile image after login
+ await _fetchProfileImage(activation.list!.first.patientId);
}
activation.list!.first.bloodGroup = activation.patientBloodType;
activation.list!.first.zipCode = selectedCountrySignup == CountryEnum.others ? '0' : selectedCountrySignup.countryCode;
@@ -660,8 +667,6 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.setPrivilegeModelList(activation.list!.first.listPrivilege!);
_appState.setUserBloodGroup = activation.patientBlodType ?? "N/A";
- // Fetch profile image after login
- _fetchProfileImage(activation.list!.first.patientId);
// Fetch patient blood type from new API
// await getPatientBloodTypeNew();
@@ -1179,6 +1184,7 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.setIsAuthenticated = false;
_appState.setAppAuthToken = "";
_appState.setUserBloodGroup = "";
+ _appState.clearProfileImageCache(); // Clear profile image cache
_appState.setSuperUserID = null;
_appState.setIsChildLoggedIn = false;
_appState.setFamilyFileTokenID = "";
@@ -1227,13 +1233,8 @@ class AuthenticationViewModel extends ChangeNotifier {
Future _fetchProfileImage(int? patientID) async {
if (patientID == null) return;
- // Skip if already loaded in AppState
- if (_appState.getProfileImageData != null && _appState.getProfileImageData!.isNotEmpty) {
- log("Profile image already cached, skipping API call");
- return;
- }
-
try {
+ log("Fetching profile image for patient ID: $patientID");
final profileSettingsRepo = GetIt.instance();
final result = await profileSettingsRepo.getProfileImage(patientID: patientID);
@@ -1246,17 +1247,23 @@ class AuthenticationViewModel extends ChangeNotifier {
if (apiResponse.data != null && apiResponse.data['Patient_GetProfileImageDataList'] != null) {
var imageList = apiResponse.data['Patient_GetProfileImageDataList'];
if (imageList is List && imageList.isNotEmpty) {
- String? imageData = imageList[0]['PatientsProfileImageData'];
+ String? imageData = imageList[0]['ImageData'];
if (imageData != null && imageData.isNotEmpty) {
_appState.setProfileImageData = imageData;
- log("Profile image loaded successfully");
+ log("✅ Profile image loaded and cached successfully");
+ } else {
+ log("⚠️ Profile image data is empty");
}
+ } else {
+ log("⚠️ Profile image list is empty");
}
+ } else {
+ log("⚠️ No profile image data in response");
}
},
);
} catch (e) {
- log("Error fetching profile image: $e");
+ log("❌ Error fetching profile image: $e");
}
}
}
diff --git a/lib/features/book_appointments/book_appointments_repo.dart b/lib/features/book_appointments/book_appointments_repo.dart
index 7a984399..0db37274 100644
--- a/lib/features/book_appointments/book_appointments_repo.dart
+++ b/lib/features/book_appointments/book_appointments_repo.dart
@@ -86,7 +86,7 @@ abstract class BookAppointmentsRepo {
{required int projectID, required int clinicID, required int patientID, Function(dynamic)? onSuccess, Function(String)? onError});
Future>>> getDentalChiefComplaintDoctorsList(int projectID, int chiefComplaintID,
- {Function(dynamic)? onSuccess, Function(String)? onError});
+ {bool isGetNearestAppointments, Function(dynamic)? onSuccess, Function(String)? onError});
Future>>> getLaserClinics(int laserCategoryID, int projectID, int languageID, {Function(dynamic)? onSuccess, Function(String)? onError});
@@ -877,12 +877,13 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
@override
Future>>> getDentalChiefComplaintDoctorsList(int projectID, int chiefComplaintID,
- {Function(dynamic)? onSuccess, Function(String)? onError}) async {
+ {bool isGetNearestAppointments = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
Map mapDevice = {
"ProjectID": projectID,
"ChiefComplaintID": chiefComplaintID,
"isDentalAllowedBackend": true,
"IsPublicRequest": true,
+ "IsGetNearAppointment": isGetNearestAppointments
};
try {
diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart
index 647b8632..7ac6ae45 100644
--- a/lib/features/book_appointments/book_appointments_view_model.dart
+++ b/lib/features/book_appointments/book_appointments_view_model.dart
@@ -1471,12 +1471,11 @@ class BookAppointmentsViewModel extends ChangeNotifier {
}
Future getDentalChiefComplaintDoctorsList({int projectID = 0, Function(dynamic)? onSuccess, Function(String)? onError}) async {
- setIsNearestAppointmentSelected(false);
doctorsList.clear();
notifyListeners();
projectID = currentlySelectedHospitalFromRegionFlow != null ? int.parse(currentlySelectedHospitalFromRegionFlow!) : projectID;
- final result = await bookAppointmentsRepo.getDentalChiefComplaintDoctorsList(projectID, selectedChiefComplaintID);
+ final result = await bookAppointmentsRepo.getDentalChiefComplaintDoctorsList(projectID, selectedChiefComplaintID, isGetNearestAppointments: isNearestAppointmentSelected);
result.fold(
(failure) async {
diff --git a/lib/features/my_appointments/models/resp_models/patient_queue_details_response_model.dart b/lib/features/my_appointments/models/resp_models/patient_queue_details_response_model.dart
index c36b9ec5..8ad174ff 100644
--- a/lib/features/my_appointments/models/resp_models/patient_queue_details_response_model.dart
+++ b/lib/features/my_appointments/models/resp_models/patient_queue_details_response_model.dart
@@ -6,6 +6,7 @@ class PatientQueueDetails {
String? roomNo;
String? calledOn;
bool? servingNow;
+ int? isClinicConfigured;
PatientQueueDetails(
{this.patientID,
@@ -14,7 +15,7 @@ class PatientQueueDetails {
this.callType,
this.roomNo,
this.calledOn,
- this.servingNow});
+ this.servingNow, this.isClinicConfigured});
PatientQueueDetails.fromJson(Map json) {
patientID = json['patientID'];
@@ -24,10 +25,11 @@ class PatientQueueDetails {
roomNo = json['roomNo'];
calledOn = json['calledOn'];
servingNow = json['servingNow'];
+ isClinicConfigured = json['isClinicConfigured'];
}
Map toJson() {
- final Map data = new Map();
+ final Map data = Map();
data['patientID'] = this.patientID;
data['patientName'] = this.patientName;
data['queueNo'] = this.queueNo;
@@ -35,6 +37,7 @@ class PatientQueueDetails {
data['roomNo'] = this.roomNo;
data['calledOn'] = this.calledOn;
data['servingNow'] = this.servingNow;
+ data['isClinicConfigured'] = this.isClinicConfigured;
return data;
}
}
diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart
index 45c28c45..7344bc22 100644
--- a/lib/features/my_appointments/my_appointments_repo.dart
+++ b/lib/features/my_appointments/my_appointments_repo.dart
@@ -77,7 +77,7 @@ abstract class MyAppointmentsRepo {
Future>> sendDoctorRate(
int rate, int appointmentNo, int projectID, int doctorID, int clinicID, String note, String appoDate, String docName, String projectName, String clinicName);
- Future>>> getPatientAppointmentQueueDetails({required int appointmentNo, required int patientID});
+ Future>>> getPatientAppointmentQueueDetails({required int appointmentNo, required int patientID, required int clinicID});
Future>> convertPatientToCash({required int projectID});
@@ -833,8 +833,8 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
}
@override
- Future>>> getPatientAppointmentQueueDetails({required int appointmentNo, required int patientID}) async {
- Map mapDevice = {"appointmentNo": appointmentNo, "patientID": patientID, "apiKey": "EE17D21C7943485D9780223CCE55DCE5"};
+ Future>>> getPatientAppointmentQueueDetails({required int appointmentNo, required int patientID, required int clinicID}) async {
+ Map mapDevice = {"appointmentNo": appointmentNo, "patientID": patientID, "clinicID": clinicID, "apiKey": "EE17D21C7943485D9780223CCE55DCE5"};
try {
GenericApiModel>? apiResponse;
Failure? failure;
@@ -842,6 +842,7 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
failure = failureType;
}, onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
+ // final list = response['data'];
final list = response['data'];
final queueList = list.map((item) => PatientQueueDetails.fromJson(item as Map)).toList().cast();
diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart
index bc0bfc74..a6f306ba 100644
--- a/lib/features/my_appointments/my_appointments_view_model.dart
+++ b/lib/features/my_appointments/my_appointments_view_model.dart
@@ -929,9 +929,11 @@ class MyAppointmentsViewModel extends ChangeNotifier {
//TODO: Discuss With Haroon, Is the User Has no data it return No Element Bad State;
isPatientHasQueueAppointment = false;
isAppointmentQueueDetailsLoading = true;
+ patientQueueDetailsList.clear();
notifyListeners();
final result = await myAppointmentsRepo.getPatientAppointmentQueueDetails(
+ clinicID: patientArrivedAppointmentsHistoryList.first.clinicID,
appointmentNo: patientArrivedAppointmentsHistoryList.first.appointmentNo, patientID: patientArrivedAppointmentsHistoryList.first.patientID);
isAppointmentQueueDetailsLoading = false;
@@ -948,8 +950,32 @@ class MyAppointmentsViewModel extends ChangeNotifier {
onError!(apiResponse.errorMessage!);
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data != null && apiResponse.data!.isNotEmpty) {
- isPatientHasQueueAppointment = true;
patientQueueDetailsList = apiResponse.data!;
+
+ if (patientQueueDetailsList.first.isClinicConfigured == 1) {
+ isPatientHasQueueAppointment = true;
+ for (var element in patientQueueDetailsList) {
+ if (element.patientID == patientArrivedAppointmentsHistoryList.first.patientID) {
+ currentPatientQueueDetails = element;
+ currentQueueStatus = element.callType!;
+ // currentQueueStatus = 2;
+ break;
+ }
+ }
+ // patientQueueDetailsList.first.callType = 1;
+ patientQueueDetailsList.removeWhere((element) => element.patientID == patientArrivedAppointmentsHistoryList.first.patientID);
+ } else {
+ isPatientHasQueueAppointment = false;
+ }
+ } else {
+ isPatientHasQueueAppointment = false;
+ }
+
+ if (apiResponse.data != null && apiResponse.data!.isNotEmpty) {
+ patientQueueDetailsList = apiResponse.data!;
+
+ // if (patientQueueDetailsList.first.isClinicConfigured == 1) {
+ isPatientHasQueueAppointment = true;
for (var element in patientQueueDetailsList) {
if (element.patientID == patientArrivedAppointmentsHistoryList.first.patientID) {
currentPatientQueueDetails = element;
@@ -959,8 +985,10 @@ class MyAppointmentsViewModel extends ChangeNotifier {
}
}
// patientQueueDetailsList.first.callType = 1;
-
patientQueueDetailsList.removeWhere((element) => element.patientID == patientArrivedAppointmentsHistoryList.first.patientID);
+ // } else {
+ // isPatientHasQueueAppointment = false;
+ // }
} else {
isPatientHasQueueAppointment = false;
}
diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart
index cd917683..2c0d5194 100644
--- a/lib/generated/locale_keys.g.dart
+++ b/lib/generated/locale_keys.g.dart
@@ -1697,5 +1697,7 @@ abstract class LocaleKeys {
static const selectFromPhotoLibrary = 'selectFromPhotoLibrary';
static const selectDocumentFiles = 'selectDocumentFiles';
static const profilePicture = 'profilePicture';
+ static const sendingAskDrRequest = 'sendingAskDrRequest';
+ static const askDrRequestSentSuccess = 'askDrRequestSentSuccess';
}
diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart
index 31cd5403..c668ebff 100644
--- a/lib/presentation/appointments/appointment_details_page.dart
+++ b/lib/presentation/appointments/appointment_details_page.dart
@@ -912,9 +912,9 @@ class _AppointmentDetailsPageState extends State {
],
).paddingOnly(left: 16.h, top: 24.h, right: 16.h, bottom: 0.h),
AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)
- ?
- (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! ||
- widget.patientAppointmentHistoryResponseModel.isExecludeDoctor! ||
+ ? (!(widget.patientAppointmentHistoryResponseModel.isActiveDoctor ?? true) ||
+ widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! ||
+ widget.patientAppointmentHistoryResponseModel.isExecludeDoctor! ||
!Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID))
? SizedBox.shrink()
: CustomButton(
diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart
index fb24f689..0542f76d 100644
--- a/lib/presentation/appointments/widgets/appointment_card.dart
+++ b/lib/presentation/appointments/widgets/appointment_card.dart
@@ -243,88 +243,88 @@ class AppointmentCard extends StatelessWidget {
(patientAppointmentHistoryResponseModel.isExecludeDoctor ?? false) ||
!Utils.isClinicAllowedForRebook(patientAppointmentHistoryResponseModel.clinicID ?? 0))) &&
AppointmentType.isArrived(patientAppointmentHistoryResponseModel)) {
- if (((patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) &&
- DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15)) {
- return Row(
- children: [
- Expanded(
- flex: 6,
- child: CustomButton(
- text: LocaleKeys.askDoctor.tr(context: context),
- onPressed: () async {
- LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context));
- await myAppointmentsViewModel.isDoctorAvailable(
- projectID: patientAppointmentHistoryResponseModel.projectID,
- doctorId: patientAppointmentHistoryResponseModel.doctorID,
- clinicId: patientAppointmentHistoryResponseModel.clinicID,
- onSuccess: (value) async {
- if (value) {
- await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) {
- LoaderBottomSheet.hideLoader();
- showCommonBottomSheetWithoutHeight(
- context,
- title: LocaleKeys.askDoctor.tr(context: context),
- child: AskDoctorRequestTypeSelect(
- askDoctorRequestTypeList: myAppointmentsViewModel.askDoctorRequestTypeList,
- myAppointmentsViewModel: myAppointmentsViewModel,
- patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
- ),
- callBackFunc: () {},
- isFullScreen: false,
- isCloseButtonVisible: true,
- );
- });
- } else {
- print("Doctor is not available");
- }
- });
- },
- backgroundColor: AppColors.secondaryLightRedColor,
- borderColor: AppColors.secondaryLightRedColor,
- textColor: AppColors.primaryRedColor,
- fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
- fontWeight: FontWeight.w600,
- borderRadius: 12.r,
- padding: EdgeInsets.symmetric(horizontal: 10.w),
- // height: isTablet || isFoldable ? 46.h : 40.h,
- height: 40.h,
- icon: AppAssets.ask_doctor_icon,
- iconColor: AppColors.primaryRedColor,
- iconSize: 16.h,
- ),
- ),
- SizedBox(width: 8.h),
- Expanded(
- flex: 1,
- child: Container(
- height: (isFoldable || isTablet) ? 50.h : 40.h,
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- color: AppColors.textColor,
- borderRadius: 10.h,
- side: BorderSide(
- color: AppColors.textColor,
- width: 1.2,
- ),
- ),
- child: Transform.flip(
- flipX: appState.isArabic(),
- child: Utils.buildSvgWithAssets(
- icon: AppAssets.forward_arrow_icon,
- iconColor: AppColors.whiteColor,
- width: 24.w,
- height: 24.h,
- fit: BoxFit.contain,
- ),
- ),
- ).toShimmer2(isShow: isLoading).onPress(() {
- _goToDetails(context);
- }),
- ),
- ],
- );
- } else {
- return CustomButton(
- text: isFromMedicalReport ? LocaleKeys.selectAppointment.tr(context: context) : LocaleKeys.viewDetails.tr(context: context),
+ // if (((patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) &&
+ // DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15)) {
+ // return Row(
+ // children: [
+ // Expanded(
+ // flex: 6,
+ // child: CustomButton(
+ // text: LocaleKeys.askDoctor.tr(context: context),
+ // onPressed: () async {
+ // LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context));
+ // await myAppointmentsViewModel.isDoctorAvailable(
+ // projectID: patientAppointmentHistoryResponseModel.projectID,
+ // doctorId: patientAppointmentHistoryResponseModel.doctorID,
+ // clinicId: patientAppointmentHistoryResponseModel.clinicID,
+ // onSuccess: (value) async {
+ // if (value) {
+ // await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) {
+ // LoaderBottomSheet.hideLoader();
+ // showCommonBottomSheetWithoutHeight(
+ // context,
+ // title: LocaleKeys.askDoctor.tr(context: context),
+ // child: AskDoctorRequestTypeSelect(
+ // askDoctorRequestTypeList: myAppointmentsViewModel.askDoctorRequestTypeList,
+ // myAppointmentsViewModel: myAppointmentsViewModel,
+ // patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
+ // ),
+ // callBackFunc: () {},
+ // isFullScreen: false,
+ // isCloseButtonVisible: true,
+ // );
+ // });
+ // } else {
+ // print("Doctor is not available");
+ // }
+ // });
+ // },
+ // backgroundColor: AppColors.secondaryLightRedColor,
+ // borderColor: AppColors.secondaryLightRedColor,
+ // textColor: AppColors.primaryRedColor,
+ // fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
+ // fontWeight: FontWeight.w600,
+ // borderRadius: 12.r,
+ // padding: EdgeInsets.symmetric(horizontal: 10.w),
+ // // height: isTablet || isFoldable ? 46.h : 40.h,
+ // height: 40.h,
+ // icon: AppAssets.ask_doctor_icon,
+ // iconColor: AppColors.primaryRedColor,
+ // iconSize: 16.h,
+ // ),
+ // ),
+ // SizedBox(width: 8.h),
+ // Expanded(
+ // flex: 1,
+ // child: Container(
+ // height: (isFoldable || isTablet) ? 50.h : 40.h,
+ // decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ // color: AppColors.textColor,
+ // borderRadius: 10.h,
+ // side: BorderSide(
+ // color: AppColors.textColor,
+ // width: 1.2,
+ // ),
+ // ),
+ // child: Transform.flip(
+ // flipX: appState.isArabic(),
+ // child: Utils.buildSvgWithAssets(
+ // icon: AppAssets.forward_arrow_icon,
+ // iconColor: AppColors.whiteColor,
+ // width: 24.w,
+ // height: 24.h,
+ // fit: BoxFit.contain,
+ // ),
+ // ),
+ // ).toShimmer2(isShow: isLoading).onPress(() {
+ // _goToDetails(context);
+ // }),
+ // ),
+ // ],
+ // );
+ // } else {
+ return CustomButton(
+ text: isFromMedicalReport ? LocaleKeys.selectAppointment.tr(context: context) : LocaleKeys.viewDetails.tr(context: context),
onPressed: () {
if (isFromMedicalReport) {
if (isForFeedback) {
@@ -359,7 +359,7 @@ class AppointmentCard extends StatelessWidget {
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
);
- }
+ // }
} else {
if (isFromMedicalReport) {
if (isForEyeMeasurements) {
@@ -390,8 +390,9 @@ class AppointmentCard extends StatelessWidget {
);
}
}
- return Row(
- children: [
+ return (patientAppointmentHistoryResponseModel.isActiveDoctor ?? true)
+ ? Row(
+ children: [
Expanded(
flex: 6,
child: (AppointmentType.isArrived(patientAppointmentHistoryResponseModel)
@@ -441,58 +442,85 @@ class AppointmentCard extends StatelessWidget {
}),
),
],
- );
+ )
+ : CustomButton(
+ text: LocaleKeys.viewDetails.tr(context: context),
+ onPressed: () {
+ Navigator.of(context)
+ .push(
+ CustomPageRoute(
+ page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel),
+ ),
+ )
+ .then((_) {
+ myAppointmentsViewModel.initAppointmentsViewModel();
+ myAppointmentsViewModel.getPatientAppointments(true, false);
+ });
+ },
+ backgroundColor: AppColors.secondaryLightRedColor,
+ borderColor: AppColors.secondaryLightRedColor,
+ textColor: AppColors.primaryRedColor,
+ fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
+ fontWeight: FontWeight.w600,
+ borderRadius: 12.r,
+ padding: EdgeInsets.symmetric(horizontal: 10.w),
+ // height: isTablet || isFoldable ? 46.h : 40.h,
+ height: 40.h,
+ icon: isFromMedicalReport ? AppAssets.checkmark_icon : null,
+ iconColor: AppColors.primaryRedColor,
+ iconSize: 16.h,
+ );
}
}
Widget _getArrivedButton(BuildContext context) {
- final isRecent = DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15;
-
- if (isRecent) {
- return CustomButton(
- text: LocaleKeys.askDoctor.tr(context: context),
- onPressed: () async {
- LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context));
- await myAppointmentsViewModel.isDoctorAvailable(
- projectID: patientAppointmentHistoryResponseModel.projectID,
- doctorId: patientAppointmentHistoryResponseModel.doctorID,
- clinicId: patientAppointmentHistoryResponseModel.clinicID,
- onSuccess: (value) async {
- if (value) {
- await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) {
- LoaderBottomSheet.hideLoader();
- showCommonBottomSheetWithoutHeight(
- context,
- title: LocaleKeys.askDoctor.tr(context: context),
- child: AskDoctorRequestTypeSelect(
- askDoctorRequestTypeList: myAppointmentsViewModel.askDoctorRequestTypeList,
- myAppointmentsViewModel: myAppointmentsViewModel,
- patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
- ),
- callBackFunc: () {},
- isFullScreen: false,
- isCloseButtonVisible: true,
- );
- });
- } else {
- print("Doctor is not available");
- }
- });
- },
- backgroundColor: AppColors.secondaryLightRedColor,
- borderColor: AppColors.secondaryLightRedColor,
- textColor: AppColors.primaryRedColor,
- fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
- fontWeight: FontWeight.w600,
- borderRadius: 12.r,
- padding: EdgeInsets.symmetric(horizontal: 10.w),
- // height: isTablet || isFoldable ? 46.h : 40.h,
- height: 40.h,
- icon: AppAssets.ask_doctor_icon,
- iconColor: AppColors.primaryRedColor,
- iconSize: 16.h,
- );
- }
+ // final isRecent = DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15;
+ //
+ // if (isRecent) {
+ // return CustomButton(
+ // text: LocaleKeys.askDoctor.tr(context: context),
+ // onPressed: () async {
+ // LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context));
+ // await myAppointmentsViewModel.isDoctorAvailable(
+ // projectID: patientAppointmentHistoryResponseModel.projectID,
+ // doctorId: patientAppointmentHistoryResponseModel.doctorID,
+ // clinicId: patientAppointmentHistoryResponseModel.clinicID,
+ // onSuccess: (value) async {
+ // if (value) {
+ // await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) {
+ // LoaderBottomSheet.hideLoader();
+ // showCommonBottomSheetWithoutHeight(
+ // context,
+ // title: LocaleKeys.askDoctor.tr(context: context),
+ // child: AskDoctorRequestTypeSelect(
+ // askDoctorRequestTypeList: myAppointmentsViewModel.askDoctorRequestTypeList,
+ // myAppointmentsViewModel: myAppointmentsViewModel,
+ // patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
+ // ),
+ // callBackFunc: () {},
+ // isFullScreen: false,
+ // isCloseButtonVisible: true,
+ // );
+ // });
+ // } else {
+ // print("Doctor is not available");
+ // }
+ // });
+ // },
+ // backgroundColor: AppColors.secondaryLightRedColor,
+ // borderColor: AppColors.secondaryLightRedColor,
+ // textColor: AppColors.primaryRedColor,
+ // fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
+ // fontWeight: FontWeight.w600,
+ // borderRadius: 12.r,
+ // padding: EdgeInsets.symmetric(horizontal: 10.w),
+ // // height: isTablet || isFoldable ? 46.h : 40.h,
+ // height: 40.h,
+ // icon: AppAssets.ask_doctor_icon,
+ // iconColor: AppColors.primaryRedColor,
+ // iconSize: 16.h,
+ // );
+ // }
return CustomButton(
borderSide: BorderSide(
diff --git a/lib/presentation/appointments/widgets/appointment_doctor_card.dart b/lib/presentation/appointments/widgets/appointment_doctor_card.dart
index 5de06455..4b5df07b 100644
--- a/lib/presentation/appointments/widgets/appointment_doctor_card.dart
+++ b/lib/presentation/appointments/widgets/appointment_doctor_card.dart
@@ -126,7 +126,7 @@ class AppointmentDoctorCard extends StatelessWidget {
DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate),
false,
)}"
- .toText10(isEnglishOnly: true),
+ .toText10(isBold: true),
),
),
AppCustomChipWidget(
@@ -142,8 +142,10 @@ class AppointmentDoctorCard extends StatelessWidget {
],
),
),
- Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).onPress(() async {
- DoctorsListResponseModel selectedDoctor = DoctorsListResponseModel();
+ patientAppointmentHistoryResponseModel.isLiveCareAppointment!
+ ? SizedBox.shrink()
+ : Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).onPress(() async {
+ DoctorsListResponseModel selectedDoctor = DoctorsListResponseModel();
selectedDoctor.doctorID = patientAppointmentHistoryResponseModel.doctorID;
selectedDoctor.doctorImageURL = patientAppointmentHistoryResponseModel.doctorImageURL;
selectedDoctor.name = patientAppointmentHistoryResponseModel.doctorNameObj;
@@ -265,7 +267,7 @@ class AppointmentDoctorCard extends StatelessWidget {
fontSize: 14.f,
isBold: true,
borderRadius: 12.r,
- height: 40.h,
+ height: 46.h,
icon: AppAssets.appointment_calendar_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
@@ -284,7 +286,7 @@ class AppointmentDoctorCard extends StatelessWidget {
fontSize: 14.f,
isBold: true,
borderRadius: 12.r,
- height: 40.h,
+ height: 46.h,
icon: AppAssets.cancel,
iconColor: AppColors.whiteColor,
iconSize: 16.h,
diff --git a/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart b/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart
index 35b15399..bf74863a 100644
--- a/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart
+++ b/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart
@@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
+import 'package:get_it/get_it.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';
@@ -10,6 +11,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/services/navigation_service.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/common_bottom_sheet.dart';
@@ -95,8 +97,8 @@ class AskDoctorRequestTypeSelect extends StatelessWidget {
child: CustomButton(
text: LocaleKeys.confirm.tr(),
onPressed: () async {
- Navigator.pop(context);
- LoaderBottomSheet.showLoader(loadingText: "Sending Request...");
+ Navigator.of(context).pop();
+ LoaderBottomSheet.showLoader(loadingText: LocaleKeys.sendingAskDrRequest.tr(context: context));
await myAppointmentsViewModel.sendAskDocCallRequest(
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
requestType: selectedParameterCodeValue.toString(),
@@ -104,17 +106,10 @@ class AskDoctorRequestTypeSelect extends StatelessWidget {
userMobileNumber: myAppointmentsViewModel.appState.getAuthenticatedUser()!.mobileNumber!,
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
- showCommonBottomSheetWithoutHeight(
- context,
- child: Utils.getSuccessWidget(loadingText: "Request has been sent successfully, you will be contacted soon."),
- callBackFunc: () {
- Navigator.of(context).pop();
- },
- title: "",
- isCloseButtonVisible: true,
- isDismissible: false,
- isFullScreen: false,
- );
+ showCommonBottomSheetWithoutHeight(GetIt.instance().navigatorKey.currentContext!,
+ child: Padding(padding: EdgeInsets.symmetric(horizontal: 24.h), child: Utils.getSuccessWidget(loadingText: LocaleKeys.askDrRequestSentSuccess.tr())), callBackFunc: () {
+ Navigator.of(context).pop();
+ }, title: "", isCloseButtonVisible: false, isDismissible: false, isFullScreen: false, isAutoDismiss: true);
},
onError: (errMessage) {
LoaderBottomSheet.hideLoader();
diff --git a/lib/presentation/authentication/saved_login_screen.dart b/lib/presentation/authentication/saved_login_screen.dart
index 4659972e..6d326939 100644
--- a/lib/presentation/authentication/saved_login_screen.dart
+++ b/lib/presentation/authentication/saved_login_screen.dart
@@ -92,7 +92,7 @@ class _SavedLogin extends State {
Container(
padding: EdgeInsets.all(16.h),
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: false, isCustomShadow: [
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: false, isCustomShadow: [
BoxShadow(color: Color(0x0D000000), blurRadius: 16.h, offset: Offset(0, 0), spreadRadius: 5.h),
]),
child: Column(
@@ -288,6 +288,7 @@ class _SavedLogin extends State {
child: CustomButton(
text: LocaleKeys.guest.tr(),
onPressed: () {
+ authVm.setIsInitialLoginNavigated(true);
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart
index bbc88214..47c4f968 100644
--- a/lib/presentation/book_appointment/book_appointment_page.dart
+++ b/lib/presentation/book_appointment/book_appointment_page.dart
@@ -355,10 +355,10 @@ class _BookAppointmentPageState extends State {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
- Utils.buildSvgWithAssets(icon: AppAssets.add_new_family_icon, height: 64.h, width: 64.h),
- SizedBox(
- width: 80.w,
- child: LocaleKeys.add.tr(context: context).toText12(
+ Utils.buildSvgWithAssets(icon: AppAssets.add_new_family_icon, height: 64.h, width: 64.h, applyThemeColor: false),
+ SizedBox(
+ width: 80.w,
+ child: LocaleKeys.add.tr(context: context).toText12(
color: AppColors.textColor,
isBold: true,
isCenter: true,
diff --git a/lib/presentation/book_appointment/select_doctor_page.dart b/lib/presentation/book_appointment/select_doctor_page.dart
index de2e2ae8..d9012573 100644
--- a/lib/presentation/book_appointment/select_doctor_page.dart
+++ b/lib/presentation/book_appointment/select_doctor_page.dart
@@ -220,8 +220,9 @@ class _SelectDoctorPageState extends State {
],
).paddingSymmetrical(0.h, 0.h),
if (bookAppointmentsViewModel.isGetDocForHealthCal && bookAppointmentsVM.showSortFilterButtons) SizedBox(height: 16.h),
- bookAppointmentsVM.doctorsListGrouped.isNotEmpty
- ? Row(
+ // bookAppointmentsVM.doctorsListGrouped.isNotEmpty
+ // ?
+ Row(
mainAxisSize: MainAxisSize.max,
children: [
Column(
@@ -243,8 +244,8 @@ class _SelectDoctorPageState extends State {
},
),
],
- )
- : SizedBox.shrink(),
+ ),
+ // : SizedBox.shrink(),
ListView.separated(
padding: EdgeInsets.only(top: 16.h),
shrinkWrap: true,
diff --git a/lib/presentation/book_appointment/widgets/doctor_card.dart b/lib/presentation/book_appointment/widgets/doctor_card.dart
index 11042a57..7b9ce848 100644
--- a/lib/presentation/book_appointment/widgets/doctor_card.dart
+++ b/lib/presentation/book_appointment/widgets/doctor_card.dart
@@ -159,10 +159,12 @@ class DoctorCard extends StatelessWidget {
],
),
),
- Expanded(
- flex: 1,
- child: Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).toShimmer2(isShow: isLoading),
- ),
+ (doctorsListResponseModel.isLiveCare ?? true)
+ ? SizedBox.shrink()
+ : Expanded(
+ flex: 1,
+ child: Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).toShimmer2(isShow: isLoading),
+ ),
],
),
SizedBox(height: 16.h),
diff --git a/lib/presentation/home/data/landing_page_data.dart b/lib/presentation/home/data/landing_page_data.dart
index 33b12855..00142c23 100644
--- a/lib/presentation/home/data/landing_page_data.dart
+++ b/lib/presentation/home/data/landing_page_data.dart
@@ -142,6 +142,16 @@ class LandingPageData {
textColor: AppColors.blackColor,
isBold: false,
),
+ ServiceCardData(
+ serviceName: "my_invoice",
+ icon: AppAssets.invoiceListIcon,
+ title: LocaleKeys.invoiceList,
+ subtitle: LocaleKeys.myDoctorSubtitle,
+ backgroundColor: AppColors.whiteColor,
+ iconColor: AppColors.blackColor,
+ textColor: AppColors.blackColor,
+ isBold: false,
+ ),
];
static List get getServiceCardsList => [
diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart
index 298bca81..c89727fa 100644
--- a/lib/presentation/home/landing_page.dart
+++ b/lib/presentation/home/landing_page.dart
@@ -105,9 +105,13 @@ class _LandingPageState extends State {
final ScrollController _horizontalScrollController = ScrollController();
+ final ScrollController _scrollController = ScrollController();
+ double _scrollOpacity = 0.0;
+
@override
void dispose() {
_horizontalScrollController.dispose();
+ _scrollController.dispose();
super.dispose();
}
@@ -123,6 +127,17 @@ class _LandingPageState extends State {
showQuickLogin(context);
});
}
+
+ _scrollController.addListener(() {
+ final scrollOffset = _scrollController.offset;
+ final newOpacity = (scrollOffset / 50).clamp(0.0, 1.0);
+ if (_scrollOpacity != newOpacity) {
+ setState(() {
+ _scrollOpacity = newOpacity;
+ });
+ }
+ });
+
scheduleMicrotask(() async {
if (!appState.isAuthenticated) {
// LoaderBottomSheet.showLoader();
@@ -189,7 +204,7 @@ class _LandingPageState extends State {
// Refresh Appointments Data
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
- myAppointmentsViewModel.getPatientAppointments(true, false);
+ myAppointmentsViewModel.getPatientAppointments(true, true);
// Refresh Appointments Data
habibWalletVM.initHabibWalletProvider();
@@ -204,6 +219,7 @@ class _LandingPageState extends State {
}
},
child: SingleChildScrollView(
+ controller: _scrollController,
physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.only(
top: (appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown)
@@ -242,6 +258,7 @@ class _LandingPageState extends State {
width: 42.w,
height: 42.h,
fit: BoxFit.cover,
+ isCircular: true,
),
).expanded
: CustomButton(
@@ -697,8 +714,8 @@ class _LandingPageState extends State {
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
- duration: const Duration(milliseconds: 1000),
- child: SlideAnimation(
+ duration: const Duration(milliseconds: 500),
+ child: SlideAnimation(
horizontalOffset: 100.0,
child: FadeInAnimation(
child: SmallServiceCard(
@@ -829,6 +846,25 @@ class _LandingPageState extends State {
),
),
),
+ AnimatedOpacity(
+ opacity: _scrollOpacity,
+ duration: Duration(milliseconds: 200),
+ child: Container(
+ height: MediaQuery.paddingOf(context).top + 10.h,
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.topCenter,
+ end: Alignment.bottomCenter,
+ colors: [
+ AppColors.scaffoldBgColor,
+ AppColors.scaffoldBgColor.withValues(alpha: 0.9),
+ AppColors.scaffoldBgColor.withValues(alpha: 0.0),
+ ],
+ stops: [0.0, 0.7, 1.0],
+ ),
+ ),
+ ),
+ ),
(appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown)
? Container(
height: MediaQuery.paddingOf(context).top + 50.h,
@@ -1038,7 +1074,7 @@ class _LandingPageState extends State {
// Queue Card: Currently serving section
Widget _buildServingNowSection() {
if (myAppointmentsViewModel.patientQueueDetailsList.isEmpty) {
- return SizedBox(height: 12.h);
+ return SizedBox(height: 24.h);
}
final servingQueue = myAppointmentsViewModel.patientQueueDetailsList.first;
diff --git a/lib/presentation/home/widgets/small_service_card.dart b/lib/presentation/home/widgets/small_service_card.dart
index ff834204..45023c3b 100644
--- a/lib/presentation/home/widgets/small_service_card.dart
+++ b/lib/presentation/home/widgets/small_service_card.dart
@@ -16,6 +16,7 @@ import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_orders_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/patient_sickleaves_list_page.dart';
+import 'package:hmg_patient_app_new/presentation/my_invoices/my_invoices_list.dart';
import 'package:hmg_patient_app_new/presentation/parking/paking_page.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
@@ -92,6 +93,13 @@ class SmallServiceCard extends StatelessWidget {
),
);
break;
+ case "my_invoice":
+ Navigator.of(context).push(
+ CustomPageRoute(
+ page: MyInvoicesList(),
+ ),
+ );
+ break;
case "prescriptions":
Navigator.of(context).push(
CustomPageRoute(
diff --git a/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart b/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart
index 6fb0f393..4debd41b 100644
--- a/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart
+++ b/lib/presentation/lab/lab_result_via_clinic/lab_ai_analysis_detailed_page.dart
@@ -351,7 +351,7 @@ class _LabAiAnalysisDetailedPageState extends State {
if (priority == null) return AppColors.primaryRedColor;
switch (priority.toLowerCase()) {
case 'high':
- return Color(0xFFED1C2B).withOpacity(.10);
+ return AppColors.secondaryLightRedColor;
case 'medium' || 'moderate':
return AppColors.lightGreenButtonColor;
case 'low':
diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart
index 76c0d083..7bbfc936 100644
--- a/lib/presentation/medical_file/medical_file_page.dart
+++ b/lib/presentation/medical_file/medical_file_page.dart
@@ -247,6 +247,7 @@ class _MedicalFilePageState extends State {
width: 56.w,
height: 56.h,
fit: BoxFit.cover,
+ isCircular: true,
),
SizedBox(width: 8.w),
Column(
diff --git a/lib/presentation/my_family/widget/family_cards.dart b/lib/presentation/my_family/widget/family_cards.dart
index 1938daba..b3081dc1 100644
--- a/lib/presentation/my_family/widget/family_cards.dart
+++ b/lib/presentation/my_family/widget/family_cards.dart
@@ -181,6 +181,7 @@ class _FamilyCardsState extends State {
width: 56.w,
height: 56.h,
fit: BoxFit.cover,
+ isCircular: true,
),
SizedBox(width: 8.w),
Column(
@@ -199,7 +200,7 @@ class _FamilyCardsState extends State {
children: [
AppCustomChipWidget(
icon: AppAssets.file_icon,
- richText: "${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}".toText10(isEnglishOnly: true),
+ richText: "${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}".toText10(isBold: true),
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
),
AppCustomChipWidget(
@@ -319,7 +320,6 @@ class _FamilyCardsState extends State {
final profile = widget.profileViewList![index];
final isActive = (profile.responseId == appState.getAuthenticatedUser()?.patientId);
final isParentUser = appState.getAuthenticatedUser()?.isParentUser ?? false;
- print(jsonEncode(appState.getUserSwitchPayloads));
final isSuperUser = appState.getUserSwitchPayloads;
// TODO: canSwitch functionality is currently disabled - set to true to allow all switches
// Original logic: final canSwitch = isParentUser || (!isParentUser && profile.responseId == appState.getSuperUserID);
@@ -340,6 +340,8 @@ class _FamilyCardsState extends State {
gender: profile.gender,
age: profile.age,
fit: BoxFit.cover,
+ customProfileImageData: "", // Prevent showing logged-in user's image for family members
+ isCircular: true,
),
SizedBox(height: 8.h),
(profile.patientName ?? "Unknown").toText14(isBold: true, isCenter: true, maxlines: 1),
diff --git a/lib/presentation/my_invoices/my_invoices_list.dart b/lib/presentation/my_invoices/my_invoices_list.dart
index a935f0d1..5a8e9c70 100644
--- a/lib/presentation/my_invoices/my_invoices_list.dart
+++ b/lib/presentation/my_invoices/my_invoices_list.dart
@@ -20,6 +20,7 @@ import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
+import 'package:open_filex/open_filex.dart';
import 'package:provider/provider.dart';
import '../../widgets/buttons/custom_button.dart';
@@ -215,23 +216,36 @@ class _MyInvoicesListState extends State {
child: InvoiceListCard(
getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index],
onTap: () async {
- myInvoicesVM.setInvoiceDetailLoading();
- LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingInvoiceDetails.tr(context: context));
- await myInvoicesVM.getInvoiceDetails(
- appointmentNo: myInvoicesVM.allInvoicesList[index].appointmentNo!,
+ if (Utils.isVidaPlusProject(myInvoicesVM.allInvoicesList[index].projectId ?? 0)) {
+ LoaderBottomSheet.showLoader(loadingText: LocaleKeys.sendingEmailPleaseWait.tr(context: context));
+ await myInvoicesViewModel.sendInvoiceEmail(
+ appointmentNo: myInvoicesVM.allInvoicesList[index].appointmentNo!,
+ projectID: myInvoicesVM.allInvoicesList[index].projectId!,
+ onSuccess: (val) {
+ LoaderBottomSheet.hideLoader();
+ showCommonBottomSheetWithoutHeight(context,
+ child: Utils.getSuccessWidget(loadingText: LocaleKeys.emailSentSuccessfullyMessage.tr(context: context)),
+ callBackFunc: () {},
+ isFullScreen: false,
+ isCloseButtonVisible: true,
+ isAutoDismiss: true);
+ },
+ onError: (err) {
+ LoaderBottomSheet.hideLoader();
+ showCommonBottomSheetWithoutHeight(
+ context,
+ child: Utils.getErrorWidget(loadingText: err),
+ callBackFunc: () {},
+ isFullScreen: false,
+ isCloseButtonVisible: true,
+ );
+ });
+ } else {
+ LoaderBottomSheet.showLoader(loadingText: LocaleKeys.loadingText.tr(context: context));
+ myInvoicesViewModel.downloadInvoicePDF(
+ setupId: myInvoicesVM.allInvoicesList[index].setupId!,
invoiceNo: myInvoicesVM.allInvoicesList[index].invoiceNo!,
projectID: myInvoicesVM.allInvoicesList[index].projectId!,
- onSuccess: (val) {
- LoaderBottomSheet.hideLoader();
- Navigator.of(context).push(
- CustomPageRoute(
- page: MyInvoicesDetailsPage(
- getInvoiceDetailsResponseModel: myInvoicesVM.invoiceDetailsResponseModel,
- getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index],
- ),
- ),
- );
- },
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
@@ -241,8 +255,56 @@ class _MyInvoicesListState extends State {
isFullScreen: false,
isCloseButtonVisible: true,
);
- });
+ },
+ onSuccess: (value) async {
+ LoaderBottomSheet.hideLoader();
+ if (myInvoicesViewModel.downloadInvoicePDFBase64!.isNotEmpty) {
+ String path = await Utils.createFileFromString(myInvoicesViewModel.downloadInvoicePDFBase64!, "pdf");
+ try {
+ OpenFilex.open(path);
+ } catch (ex) {
+ showCommonBottomSheetWithoutHeight(
+ context,
+ child: Utils.getErrorWidget(loadingText: "Cannot open file"),
+ callBackFunc: () {},
+ isFullScreen: false,
+ isCloseButtonVisible: true,
+ );
+ }
+ }
+ },
+ );
+ }
},
+ // onTap: () async {
+ // myInvoicesVM.setInvoiceDetailLoading();
+ // LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingInvoiceDetails.tr(context: context));
+ // await myInvoicesVM.getInvoiceDetails(
+ // appointmentNo: myInvoicesVM.allInvoicesList[index].appointmentNo!,
+ // invoiceNo: myInvoicesVM.allInvoicesList[index].invoiceNo!,
+ // projectID: myInvoicesVM.allInvoicesList[index].projectId!,
+ // onSuccess: (val) {
+ // LoaderBottomSheet.hideLoader();
+ // Navigator.of(context).push(
+ // CustomPageRoute(
+ // page: MyInvoicesDetailsPage(
+ // getInvoiceDetailsResponseModel: myInvoicesVM.invoiceDetailsResponseModel,
+ // getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index],
+ // ),
+ // ),
+ // );
+ // },
+ // onError: (err) {
+ // LoaderBottomSheet.hideLoader();
+ // showCommonBottomSheetWithoutHeight(
+ // context,
+ // child: Utils.getErrorWidget(loadingText: err),
+ // callBackFunc: () {},
+ // isFullScreen: false,
+ // isCloseButtonVisible: true,
+ // );
+ // });
+ // },
),
),
),
diff --git a/lib/presentation/my_invoices/widgets/invoice_list_card.dart b/lib/presentation/my_invoices/widgets/invoice_list_card.dart
index 3aacb85c..42d2fd92 100644
--- a/lib/presentation/my_invoices/widgets/invoice_list_card.dart
+++ b/lib/presentation/my_invoices/widgets/invoice_list_card.dart
@@ -140,7 +140,8 @@ class InvoiceListCard extends StatelessWidget {
),
SizedBox(height: 16.h),
CustomButton(
- text: LocaleKeys.viewInvoiceDetails.tr(context: context),
+ // text: LocaleKeys.viewInvoiceDetails.tr(context: context),
+ text: Utils.isVidaPlusProject(getInvoicesListResponseModel.projectId ?? 0) ? LocaleKeys.sendEmail.tr(context: context) : LocaleKeys.downloadInvoice.tr(context: context),
onPressed: () {
if (onTap != null) {
onTap!();
diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart
index 0abcfd81..377014ac 100644
--- a/lib/presentation/profile_settings/profile_settings.dart
+++ b/lib/presentation/profile_settings/profile_settings.dart
@@ -459,6 +459,7 @@ class FamilyCardWidget extends StatelessWidget {
gender: profile.gender,
age: profile.age,
fit: BoxFit.cover,
+ isCircular: true,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
diff --git a/lib/presentation/profile_settings/widgets/family_card_widget.dart b/lib/presentation/profile_settings/widgets/family_card_widget.dart
index 97039de1..768fe538 100644
--- a/lib/presentation/profile_settings/widgets/family_card_widget.dart
+++ b/lib/presentation/profile_settings/widgets/family_card_widget.dart
@@ -56,6 +56,8 @@ class FamilyCardWidget extends StatelessWidget {
gender: profile.gender,
age: profile.age,
fit: BoxFit.cover,
+ customProfileImageData: "",
+ isCircular: true,// Prevent showing logged-in user's image for family members
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
diff --git a/lib/presentation/profile_settings/widgets/preferred_language_widget.dart b/lib/presentation/profile_settings/widgets/preferred_language_widget.dart
index 5b6fe7f9..4cecc651 100644
--- a/lib/presentation/profile_settings/widgets/preferred_language_widget.dart
+++ b/lib/presentation/profile_settings/widgets/preferred_language_widget.dart
@@ -47,9 +47,9 @@ class _PreferredLanguageWidgetState extends State {
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: Column(
children: [
- languageItem("English", "2"),
- 1.divider,
languageItem("العربية", "1"),
+ 1.divider,
+ languageItem("English", "2"),
],
),
),
@@ -104,7 +104,7 @@ class _PreferredLanguageWidgetState extends State {
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
- title.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1, fontFamily: _value == "1" ? 'GESSTwo' : 'Poppins').expanded,
+ title.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1, fontFamily: _value == "1" ? 'CairoArabic' : 'Poppins').expanded,
],
).paddingOnly(left: 16, right: 16).onPress(() {
setState(() {
diff --git a/lib/widgets/app_language_change.dart b/lib/widgets/app_language_change.dart
index a6769b3e..f041cd85 100644
--- a/lib/widgets/app_language_change.dart
+++ b/lib/widgets/app_language_change.dart
@@ -103,7 +103,7 @@ class _AppLanguageChangeState extends State {
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
- title.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1, fontFamily: _value == "ar" ? 'GESSTwo' : 'Poppins').expanded,
+ title.toText16(isBold: true, textOverflow: TextOverflow.ellipsis, maxlines: 1, fontFamily: _value == "ar" ? 'CairoArabic' : 'Poppins').expanded,
],
).paddingOnly(left: 16, right: 16).onPress(() {
setState(() {
diff --git a/lib/widgets/common_bottom_sheet.dart b/lib/widgets/common_bottom_sheet.dart
index 85d50b48..d47971d7 100644
--- a/lib/widgets/common_bottom_sheet.dart
+++ b/lib/widgets/common_bottom_sheet.dart
@@ -238,7 +238,7 @@ void showCommonBottomSheetWithoutHeight(
duration: Duration(milliseconds: 500),
reverseDuration: Duration(milliseconds: 300),
),
- constraints: BoxConstraints(maxWidth: MediaQuery.sizeOf(context).width //MediaQuery.of(context).size.width, // Full width
+ constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width //MediaQuery.of(context).size.width, // Full width
),
context: context,
isScrollControlled: true,
diff --git a/lib/widgets/user_avatar_widget.dart b/lib/widgets/user_avatar_widget.dart
index 6a17160a..56545a0d 100644
--- a/lib/widgets/user_avatar_widget.dart
+++ b/lib/widgets/user_avatar_widget.dart
@@ -36,6 +36,12 @@ class UserAvatarWidget extends StatelessWidget {
// Use custom profile image data if provided, otherwise use AppState data
final profileImageData = customProfileImageData ?? appState.getProfileImageData;
+ // Debug logging
+ print('🖼️ UserAvatarWidget build - Has profile image: ${profileImageData != null && profileImageData.isNotEmpty}');
+ if (profileImageData != null && profileImageData.isNotEmpty) {
+ print('🖼️ Profile image data length: ${profileImageData.length} characters');
+ }
+
// Determine the default image based on gender and age
final String defaultImage;
if (userGender == 1) {