Merge branch 'master' into fatima

fatima
Fatimah.Alshammari 1 month ago
commit 0d6d23dbbc

@ -1496,10 +1496,6 @@
"someRemarksAboutPrescription": "ستجدون هنا بعض الملاحظات حول الوصفة الطبية", "someRemarksAboutPrescription": "ستجدون هنا بعض الملاحظات حول الوصفة الطبية",
"notifyMeBeforeConsumptionTime": "أبلغني قبل وقت الاستهلاك", "notifyMeBeforeConsumptionTime": "أبلغني قبل وقت الاستهلاك",
"noMedicationsToday": "لا أدوية اليوم", "noMedicationsToday": "لا أدوية اليوم",
"route": "Route: {route}",
"frequency": "Frequency: {frequency}",
"instruction": "Instruction: {instruction}",
"duration": "Duration: {days}",
"reminders": "تذكيرات", "reminders": "تذكيرات",
"reminderAddedToCalendar": "تمت إضافة تذكير إلى التقويم ✅", "reminderAddedToCalendar": "تمت إضافة تذكير إلى التقويم ✅",
"errorWhileSettingCalendar": "حدث خطأ أثناء ضبط التقويم:{error}", "errorWhileSettingCalendar": "حدث خطأ أثناء ضبط التقويم:{error}",

@ -1487,10 +1487,8 @@
"someRemarksAboutPrescription": "some remarks about the prescription will be here", "someRemarksAboutPrescription": "some remarks about the prescription will be here",
"notifyMeBeforeConsumptionTime": "Notify me before the consumption time", "notifyMeBeforeConsumptionTime": "Notify me before the consumption time",
"noMedicationsToday": "No medications today", "noMedicationsToday": "No medications today",
"route": "Route: {route}", "route": "Route",
"frequency": "Frequency: {frequency}", "frequency": "Frequency",
"instruction": "Instruction: {instruction}",
"duration": "Duration: {days}",
"reminders": "Reminders", "reminders": "Reminders",
"reminderAddedToCalendar": "Reminder added to calendar ✅", "reminderAddedToCalendar": "Reminder added to calendar ✅",
"errorWhileSettingCalendar": "Error while setting calendar: {error}", "errorWhileSettingCalendar": "Error while setting calendar: {error}",

@ -182,9 +182,8 @@ class ApiClientImp implements ApiClient {
} }
// body['TokenID'] = "@dm!n"; // body['TokenID'] = "@dm!n";
// body['PatientID'] = 4769038; // body['PatientID'] = 4768663;
// body['PatientTypeID'] = 1; // body['PatientTypeID'] = 1;
//
// body['PatientOutSA'] = 0; // body['PatientOutSA'] = 0;
// body['SessionID'] = "45786230487560q"; // body['SessionID'] = "45786230487560q";
} }

@ -680,7 +680,7 @@ const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard';
class ApiConsts { class ApiConsts {
static const maxSmallScreen = 660; static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT

@ -977,4 +977,5 @@ class Utils {
return checkDate == today; return checkDate == today;
} }
} }

@ -605,7 +605,7 @@ class AuthenticationViewModel extends ChangeNotifier {
} }
// _appState.setUserBloodGroup = (activation.patientBlodType ?? ""); // _appState.setUserBloodGroup = (activation.patientBlodType ?? "");
_appState.setAppAuthToken = activation.authenticationTokenId; _appState.setAppAuthToken = activation.authenticationTokenId;
myAppointmentsVM.getActiveAppointmentsCount(); // myAppointmentsVM.getActiveAppointmentsCount();
final request = RequestUtils.getAuthanticatedCommonRequest().toJson(); final request = RequestUtils.getAuthanticatedCommonRequest().toJson();
bool isUserAgreedBefore = await checkIfUserAgreedBefore(request: request); bool isUserAgreedBefore = await checkIfUserAgreedBefore(request: request);

@ -30,6 +30,8 @@ abstract class BookAppointmentsRepo {
Future<Either<Failure, GenericApiModel<DoctorsProfileResponseModel>>> getDoctorProfile(int clinicID, int projectID, int doctorId, {Function(dynamic)? onSuccess, Function(String)? onError}); Future<Either<Failure, GenericApiModel<DoctorsProfileResponseModel>>> getDoctorProfile(int clinicID, int projectID, int doctorId, {Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorRatingDetails(int doctorId, {Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorFreeSlots(int clinicID, int projectID, int doctorId, bool isBookingForLiveCare, Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorFreeSlots(int clinicID, int projectID, int doctorId, bool isBookingForLiveCare,
{bool continueDentalPlan = false, Function(dynamic)? onSuccess, Function(String)? onError}); {bool continueDentalPlan = false, Function(dynamic)? onSuccess, Function(String)? onError});
@ -298,6 +300,52 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo {
} }
} }
@override
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorRatingDetails(int doctorId, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
Map<String, dynamic> mapDevice = {
"DoctorID": doctorId,
"PatientID": 0,
"License": true,
"IsRegistered": true,
"isDentalAllowedBackend": false,
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
GET_DOCTOR_RATING_DETAILS,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
if (onError != null) {
onError(error);
}
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response,
);
if (onSuccess != null) {
onSuccess(response);
}
} 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()));
}
}
//TODO: Implement the logic for Dental & laser clinics //TODO: Implement the logic for Dental & laser clinics
@override @override
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorFreeSlots(int clinicID, int projectID, int doctorId, bool isBookingForLiveCare, Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorFreeSlots(int clinicID, int projectID, int doctorId, bool isBookingForLiveCare,

@ -17,6 +17,7 @@ import 'package:hmg_patient_app_new/features/book_appointments/models/free_slot.
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/appointment_nearest_gate_response_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/appointment_nearest_gate_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/dental_chief_complaints_response_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/dental_chief_complaints_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctor_profile_response_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctor_profile_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctor_rating_details_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_clinic_list_response_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_clinic_list_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_patient_dental_plan_response_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_patient_dental_plan_response_model.dart';
@ -92,6 +93,9 @@ class BookAppointmentsViewModel extends ChangeNotifier {
late DoctorsProfileResponseModel doctorsProfileResponseModel; late DoctorsProfileResponseModel doctorsProfileResponseModel;
bool isDoctorRatingDetailsLoading = false;
List<DoctorRateDetails> doctorDetailsList = [];
List<FreeSlot> slotsList = []; List<FreeSlot> slotsList = [];
List<TimeSlot> docFreeSlots = []; List<TimeSlot> docFreeSlots = [];
List<TimeSlot> dayEvents = []; List<TimeSlot> dayEvents = [];
@ -340,6 +344,14 @@ class BookAppointmentsViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
setIsLiveCareDoctorsListLoading(bool value) {
if (value) {
liveCareDoctorsList.clear();
}
isDoctorsListLoading = value;
notifyListeners();
}
setIsClinicsListLoading(bool value) { setIsClinicsListLoading(bool value) {
if (value) { if (value) {
clinicsList.clear(); clinicsList.clear();
@ -467,10 +479,10 @@ class BookAppointmentsViewModel extends ChangeNotifier {
} }
Future<void> getLiveCareDoctorsList({Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getLiveCareDoctorsList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
doctorsList.clear(); liveCareDoctorsList.clear();
notifyListeners();
final result = final result =
await bookAppointmentsRepo.getLiveCareDoctorsList(selectedLiveCareClinic.serviceID!, _appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!, onError: onError); await bookAppointmentsRepo.getLiveCareDoctorsList(selectedLiveCareClinic.serviceID!, _appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!, onError: onError);
result.fold( result.fold(
(failure) async { (failure) async {
onError!(LocaleKeys.noDoctorFound.tr()); onError!(LocaleKeys.noDoctorFound.tr());
@ -614,6 +626,46 @@ class BookAppointmentsViewModel extends ChangeNotifier {
); );
} }
Future<void> getDoctorRatingDetails({Function(dynamic)? onSuccess, Function(String)? onError}) async {
isDoctorRatingDetailsLoading = true;
doctorDetailsList.clear();
notifyListeners();
final result = await bookAppointmentsRepo.getDoctorRatingDetails(selectedDoctor.doctorID ?? 0, onSuccess: onSuccess, onError: onError);
result.fold(
(failure) async {
if (onError != null) {
onError("Failed to load doctor rating details");
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
if (onError != null) {
onError(apiResponse.errorMessage ?? "Unknown error occurred");
}
isDoctorRatingDetailsLoading = false;
} else if (apiResponse.messageStatus == 1) {
try {
apiResponse.data['DoctorRatingDetailsList'].forEach((v) {
doctorDetailsList.add(DoctorRateDetails.fromJson(v));
});
isDoctorRatingDetailsLoading = false;
// doctorRatingDetails = DoctorRateDetails.fromJson(apiResponse.data);
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse.data);
}
} catch (e) {
if (onError != null) {
onError("Failed to parse rating details: ${e.toString()}");
}
}
}
},
);
}
Future<void> getDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
docFreeSlots.clear(); docFreeSlots.clear();
DateTime date; DateTime date;

@ -0,0 +1,36 @@
class DoctorRateDetails {
dynamic doctorID;
dynamic projectID;
dynamic clinicID;
dynamic rate;
dynamic patientNumber;
dynamic ratio;
DoctorRateDetails(
{this.doctorID,
this.projectID,
this.clinicID,
this.rate,
this.patientNumber,
this.ratio});
DoctorRateDetails.fromJson(Map<String, dynamic> json) {
doctorID = json['DoctorID'];
projectID = json['ProjectID'];
clinicID = json['ClinicID'];
rate = json['Rate'];
patientNumber = json['PatientNumber'];
ratio = json['Ratio'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['DoctorID'] = this.doctorID;
data['ProjectID'] = this.projectID;
data['ClinicID'] = this.clinicID;
data['Rate'] = this.rate;
data['PatientNumber'] = this.patientNumber;
data['Ratio'] = this.ratio;
return data;
}
}

@ -9,6 +9,7 @@ class HabibWalletViewModel extends ChangeNotifier {
bool isWalletAmountLoading = false; bool isWalletAmountLoading = false;
num habibWalletAmount = 0; num habibWalletAmount = 0;
num walletRechargeAmount = 0; num walletRechargeAmount = 0;
String notesText = "";
bool isBottomSheetContentLoading = false; bool isBottomSheetContentLoading = false;
@ -60,6 +61,11 @@ class HabibWalletViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
setNotesText(String notes) {
notesText = notes;
notifyListeners();
}
setDepositorDetails(String fileNum, String depositor, String mobile) { setDepositorDetails(String fileNum, String depositor, String mobile) {
fileNumber = fileNum; fileNumber = fileNum;
depositorName = depositor; depositorName = depositor;

@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patien
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_card_history.dart'; import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_card_history.dart';
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_details_response_model.dart'; import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_details_response_model.dart';
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_update_response_model.dart'; import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_update_response_model.dart';
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/upload_insurance_card_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class InsuranceRepo { abstract class InsuranceRepo {
@ -17,6 +18,14 @@ abstract class InsuranceRepo {
Future<Either<Failure, GenericApiModel<PatientInsuranceUpdateResponseModel>>> getPatientInsuranceDetailsForUpdate({required String patientId, required String identificationNo}); Future<Either<Failure, GenericApiModel<PatientInsuranceUpdateResponseModel>>> getPatientInsuranceDetailsForUpdate({required String patientId, required String identificationNo});
Future<Either<Failure, GenericApiModel<List<InsuranceApprovalResponseModel>>>> getPatientInsuranceApprovalsList(); Future<Either<Failure, GenericApiModel<List<InsuranceApprovalResponseModel>>>> getPatientInsuranceApprovalsList();
Future<Either<Failure, GenericApiModel<dynamic>>> updatePatientInsuranceCard({
required int patientID,
required int patientType,
required String mobileNo,
required String patientIdentificationID,
required String insuranceCardImage,
});
} }
class InsuranceRepoImp implements InsuranceRepo { class InsuranceRepoImp implements InsuranceRepo {
@ -183,4 +192,52 @@ class InsuranceRepoImp implements InsuranceRepo {
return Left(UnknownFailure(e.toString())); return Left(UnknownFailure(e.toString()));
} }
} }
@override
Future<Either<Failure, GenericApiModel<dynamic>>> updatePatientInsuranceCard({
required int patientID,
required int patientType,
required String mobileNo,
required String patientIdentificationID,
required String insuranceCardImage,
}) async {
Map<String, dynamic> mapDevice = {
"PatientID": patientID,
"PatientType": patientType,
"MobileNo": mobileNo,
"PatientIdentificationID": patientIdentificationID,
"InsuranceCardImage": insuranceCardImage,
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
UPLOAD_INSURANCE_CARD,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// final uploadResponse = UploadInsuranceCardResponseModel.fromJson(response);
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: apiResponse,
);
} 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()));
}
}
} }

@ -5,6 +5,7 @@ import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patien
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_card_history.dart'; import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_card_history.dart';
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_details_response_model.dart'; import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_details_response_model.dart';
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_update_response_model.dart'; import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_update_response_model.dart';
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/upload_insurance_card_response_model.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class InsuranceViewModel extends ChangeNotifier { class InsuranceViewModel extends ChangeNotifier {
@ -171,4 +172,44 @@ class InsuranceViewModel extends ChangeNotifier {
}, },
); );
} }
Future<void> updatePatientInsuranceCard({
required int patientID,
required int patientType,
required String mobileNo,
required String patientIdentificationID,
required String insuranceCardImage,
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
final result = await insuranceRepo.updatePatientInsuranceCard(
patientID: patientID,
patientType: patientType,
mobileNo: mobileNo,
patientIdentificationID: patientIdentificationID,
insuranceCardImage: insuranceCardImage,
);
result.fold(
(failure) async {
notifyListeners();
if (onError != null) {
onError(failure.toString());
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
notifyListeners();
if (onError != null) {
onError(apiResponse.errorMessage ?? "Error updating insurance card");
}
} else if (apiResponse.messageStatus == 1) {
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
} }

@ -240,6 +240,9 @@ class LabViewModel extends ChangeNotifier {
model: item)) model: item))
}; };
uniqueTestsList = uniqueTests.toList(); uniqueTestsList = uniqueTests.toList();
uniqueTestsList = Utils.uniqueBy(uniqueTestsList, (p) => p.testCode);
uniqueTestsList.sort((a, b) { uniqueTestsList.sort((a, b) {
return a.description!.toLowerCase().compareTo(b.description!.toLowerCase()); return a.description!.toLowerCase().compareTo(b.description!.toLowerCase());
}); });

@ -41,6 +41,7 @@ class MedicalFileViewModel extends ChangeNotifier {
List<SickLeaveList> patientSickLeavesViewList = []; List<SickLeaveList> patientSickLeavesViewList = [];
bool isSickLeavesSortByClinic = true; bool isSickLeavesSortByClinic = true;
bool isSickLeavesDataNeedsReloading = true;
List<GetAllergiesResponseModel> patientAllergiesList = []; List<GetAllergiesResponseModel> patientAllergiesList = [];
@ -163,15 +164,15 @@ class MedicalFileViewModel extends ChangeNotifier {
} }
setIsPatientSickLeaveListLoading(bool val) { setIsPatientSickLeaveListLoading(bool val) {
if (val) { if (val && isSickLeavesDataNeedsReloading) {
patientSickLeaveList.clear(); patientSickLeaveList.clear();
patientSickLeavesByClinic.clear(); patientSickLeavesByClinic.clear();
patientSickLeavesByHospital.clear(); patientSickLeavesByHospital.clear();
patientSickLeavesViewList.clear(); patientSickLeavesViewList.clear();
patientSickLeavePDFBase64 = ""; patientSickLeavePDFBase64 = "";
isSickLeavesSortByClinic = true; isSickLeavesSortByClinic = true;
isPatientSickLeaveListLoading = val;
} }
isPatientSickLeaveListLoading = val;
notifyListeners(); notifyListeners();
} }
@ -267,6 +268,10 @@ class MedicalFileViewModel extends ChangeNotifier {
} }
Future<void> getPatientSickLeaveList({Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getPatientSickLeaveList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
if (!isSickLeavesDataNeedsReloading) {
return;
}
patientSickLeaveList.clear(); patientSickLeaveList.clear();
final result = await medicalFileRepo.getPatientSickLeavesList(); final result = await medicalFileRepo.getPatientSickLeavesList();
@ -309,6 +314,7 @@ class MedicalFileViewModel extends ChangeNotifier {
} }
} }
patientSickLeavesViewList = patientSickLeavesByClinic; patientSickLeavesViewList = patientSickLeavesByClinic;
isSickLeavesDataNeedsReloading = false;
notifyListeners(); notifyListeners();
if (onSuccess != null) { if (onSuccess != null) {

@ -47,20 +47,24 @@ class PrescriptionsViewModel extends ChangeNotifier {
late GeocodeResponse locationGeocodeResponse; late GeocodeResponse locationGeocodeResponse;
bool isPrescriptionsDeliveryOrdersLoading = false; bool isPrescriptionsDeliveryOrdersLoading = false;
bool isPrescriptionsDataNeedsReloading = true;
List<PrescriptionDeliveryResponseModel> prescriptionsOrderList = []; List<PrescriptionDeliveryResponseModel> prescriptionsOrderList = [];
PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService, required this.navServices}); PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService, required this.navServices});
initPrescriptionsViewModel() { initPrescriptionsViewModel() {
patientPrescriptionOrders.clear(); if (isPrescriptionsDataNeedsReloading) {
patientPrescriptionOrdersByClinic.clear(); patientPrescriptionOrders.clear();
patientPrescriptionOrdersByHospital.clear(); patientPrescriptionOrdersByClinic.clear();
patientPrescriptionOrdersViewList.clear(); patientPrescriptionOrdersByHospital.clear();
prescriptionsOrderList.clear(); patientPrescriptionOrdersViewList.clear();
isPrescriptionsOrdersLoading = true; prescriptionsOrderList.clear();
isPrescriptionsOrdersLoading = true;
getPatientPrescriptionOrders();
}
isSortByClinic = true; isSortByClinic = true;
isPrescriptionsDeliveryOrdersLoading = true; isPrescriptionsDeliveryOrdersLoading = true;
getPatientPrescriptionOrders();
notifyListeners(); notifyListeners();
} }
@ -98,6 +102,10 @@ class PrescriptionsViewModel extends ChangeNotifier {
} }
Future<void> getPatientPrescriptionOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getPatientPrescriptionOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async {
if (!isPrescriptionsDataNeedsReloading) {
return;
}
final result = await prescriptionsRepo.getPatientPrescriptionOrders(patientId: "1231755"); final result = await prescriptionsRepo.getPatientPrescriptionOrders(patientId: "1231755");
result.fold( result.fold(
@ -131,6 +139,7 @@ class PrescriptionsViewModel extends ChangeNotifier {
} }
} }
patientPrescriptionOrdersViewList = patientPrescriptionOrdersByClinic; patientPrescriptionOrdersViewList = patientPrescriptionOrdersByClinic;
isPrescriptionsDataNeedsReloading = false;
notifyListeners(); notifyListeners();
if (onSuccess != null) { if (onSuccess != null) {
onSuccess(apiResponse); onSuccess(apiResponse);

@ -13,17 +13,20 @@ class TodoSectionViewModel extends ChangeNotifier {
String? notificationsCount = "0"; String? notificationsCount = "0";
initializeTodoSectionViewModel() async { initializeTodoSectionViewModel() async {
patientAncillaryOrdersList.clear(); if (isAncillaryOrdersNeedReloading) {
isAncillaryOrdersLoading = true; patientAncillaryOrdersList.clear();
isAncillaryDetailsProceduresLoading = true; isAncillaryOrdersLoading = true;
notificationsCount = "0"; isAncillaryDetailsProceduresLoading = true;
getPatientOnlineAncillaryOrderList(); notificationsCount = "0";
getPatientOnlineAncillaryOrderList();
}
getPatientDashboard(); getPatientDashboard();
} }
bool isAncillaryOrdersLoading = false; bool isAncillaryOrdersLoading = false;
bool isAncillaryDetailsProceduresLoading = false; bool isAncillaryDetailsProceduresLoading = false;
bool isProcessingPayment = false; bool isProcessingPayment = false;
bool isAncillaryOrdersNeedReloading = true;
List<AncillaryOrderItem> patientAncillaryOrdersList = []; List<AncillaryOrderItem> patientAncillaryOrdersList = [];
List<AncillaryOrderProcedureItem> patientAncillaryOrderProceduresList = []; List<AncillaryOrderProcedureItem> patientAncillaryOrderProceduresList = [];
@ -32,6 +35,11 @@ class TodoSectionViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void setIsAncillaryOrdersNeedReloading(bool value) {
isAncillaryOrdersNeedReloading = value;
notifyListeners();
}
Future<void> getPatientDashboard({Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getPatientDashboard({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await todoSectionRepo.getPatientDashboard(); final result = await todoSectionRepo.getPatientDashboard();
@ -55,6 +63,10 @@ class TodoSectionViewModel extends ChangeNotifier {
} }
Future<void> getPatientOnlineAncillaryOrderList({Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getPatientOnlineAncillaryOrderList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
if (!isAncillaryOrdersNeedReloading) {
return;
}
patientAncillaryOrdersList.clear(); patientAncillaryOrdersList.clear();
isAncillaryOrdersLoading = true; isAncillaryOrdersLoading = true;
notifyListeners(); notifyListeners();
@ -71,6 +83,7 @@ class TodoSectionViewModel extends ChangeNotifier {
} else if (apiResponse.messageStatus == 1) { } else if (apiResponse.messageStatus == 1) {
patientAncillaryOrdersList = apiResponse.data!; patientAncillaryOrdersList = apiResponse.data!;
isAncillaryOrdersLoading = false; isAncillaryOrdersLoading = false;
isAncillaryOrdersNeedReloading = false;
notifyListeners(); notifyListeners();
if (onSuccess != null) { if (onSuccess != null) {
onSuccess(apiResponse); onSuccess(apiResponse);

@ -15,6 +15,7 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart'; import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/features/contact_us/models/feedback_type.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
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/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/features/my_appointments/my_appointments_view_model.dart';
@ -92,6 +93,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
title: LocaleKeys.appointmentDetails.tr(context: context), title: LocaleKeys.appointmentDetails.tr(context: context),
report: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) report: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)
? () { ? () {
contactUsViewModel.setSelectedFeedbackType(FeedbackType(id: 1, nameEN: "Complaint for appointment", nameAR: 'شكوى على موعد'));
contactUsViewModel.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel); contactUsViewModel.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel);
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
@ -214,11 +216,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
borderRadius: BorderRadius.circular(24.r), borderRadius: BorderRadius.circular(24.r),
// Todo: what is this???? Api Key??? 😲 // Todo: what is this???? Api Key??? 😲
child: Image.network( child: Image.network(
"https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=${(MediaQuery.of(context).size.width * 1.5).toInt()}x165&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=${ApiKeyConstants.googleMapsApiKey}", "https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=${(MediaQuery.of(context).size.width * 1.5).toInt()}x${(MediaQuery.of(context).size.height * 0.35).toInt()}&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=${ApiKeyConstants.googleMapsApiKey}",
fit: BoxFit.contain, fit: BoxFit.contain,
// errorBuilder: (cxt, child, tr) {
// return SizedBox.shrink();
// },
), ),
), ),
Positioned( Positioned(
@ -756,9 +755,10 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
], ],
).paddingOnly(left: 16.h, top: 24.h, right: 16.h, bottom: 0.h), ).paddingOnly(left: 16.h, top: 24.h, right: 16.h, bottom: 0.h),
AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)
? CustomButton( ? !widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!
text: LocaleKeys.rebookAppointment.tr(context: context), ? CustomButton(
onPressed: () { text: LocaleKeys.rebookAppointment.tr(context: context),
onPressed: () {
openDoctorScheduleCalendar(); openDoctorScheduleCalendar();
}, },
backgroundColor: AppColors.successColor, backgroundColor: AppColors.successColor,
@ -772,7 +772,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
icon: AppAssets.add_icon, icon: AppAssets.add_icon,
iconColor: AppColors.whiteColor, iconColor: AppColors.whiteColor,
iconSize: 18.h, iconSize: 18.h,
).paddingSymmetrical(16.h, 24.h) ).paddingSymmetrical(16.h, 24.h)
: SizedBox.shrink()
: CustomButton( : CustomButton(
text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction), text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction),
onPressed: () { onPressed: () {

@ -153,7 +153,7 @@ class AppointmentCard extends StatelessWidget {
SizedBox(height: 2.h), SizedBox(height: 2.h),
(isFoldable || isTablet) (isFoldable || isTablet)
? "${patientAppointmentHistoryResponseModel.decimalDoctorRate}".toText9(isBold: true, color: AppColors.textColor) ? "${patientAppointmentHistoryResponseModel.decimalDoctorRate}".toText9(isBold: true, color: AppColors.textColor)
: "${patientAppointmentHistoryResponseModel.decimalDoctorRate}".toText11(isBold: true, color: AppColors.textColor), : "${patientAppointmentHistoryResponseModel.decimalDoctorRate ?? "0.0"}".toText11(isBold: true, color: AppColors.textColor),
], ],
), ),
).circle(100).toShimmer2(isShow: isLoading), ).circle(100).toShimmer2(isShow: isLoading),
@ -228,18 +228,27 @@ class AppointmentCard extends StatelessWidget {
Widget _buildActionArea(BuildContext context, AppState appState) { Widget _buildActionArea(BuildContext context, AppState appState) {
if ((patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) && AppointmentType.isArrived(patientAppointmentHistoryResponseModel)) { if ((patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) && AppointmentType.isArrived(patientAppointmentHistoryResponseModel)) {
return CustomButton( return CustomButton(
text: LocaleKeys.viewDetails.tr(context: context), text: isFromMedicalReport ? LocaleKeys.selectAppointment.tr(context: context) : LocaleKeys.viewDetails.tr(context: context),
onPressed: () { onPressed: () {
Navigator.of(context) if (isFromMedicalReport) {
.push( if (isForFeedback) {
CustomPageRoute( contactUsViewModel!.setPatientFeedbackSelectedAppointment(patientAppointmentHistoryResponseModel);
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel), } else {
), medicalFileViewModel!.setSelectedMedicalReportAppointment(patientAppointmentHistoryResponseModel);
) }
.then((_) { Navigator.pop(context, false);
myAppointmentsViewModel.initAppointmentsViewModel(); } else {
myAppointmentsViewModel.getPatientAppointments(true, false); Navigator.of(context)
}); .push(
CustomPageRoute(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel),
),
)
.then((_) {
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
});
}
}, },
backgroundColor: AppColors.secondaryLightRedColor, backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor,
@ -250,6 +259,9 @@ class AppointmentCard extends StatelessWidget {
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
// height: isTablet || isFoldable ? 46.h : 40.h, // height: isTablet || isFoldable ? 46.h : 40.h,
height: 40.h, height: 40.h,
icon: isFromMedicalReport ? AppAssets.checkmark_icon : null,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
); );
} else { } else {
if (isFromMedicalReport) { if (isFromMedicalReport) {

@ -159,8 +159,9 @@ class AppointmentDoctorCard extends StatelessWidget {
icon: AppAssets.ask_doctor_icon, icon: AppAssets.ask_doctor_icon,
iconColor: AppColors.primaryRedColor, iconColor: AppColors.primaryRedColor,
) )
: CustomButton( : !patientAppointmentHistoryResponseModel.isLiveCareAppointment!
text: LocaleKeys.rebookSameDoctor.tr(), ? CustomButton(
text: LocaleKeys.rebookSameDoctor.tr(),
onPressed: () { onPressed: () {
onRescheduleTap(); onRescheduleTap();
}, },
@ -175,7 +176,8 @@ class AppointmentDoctorCard extends StatelessWidget {
icon: AppAssets.rebook_appointment_icon, icon: AppAssets.rebook_appointment_icon,
iconColor: AppColors.blackColor, iconColor: AppColors.blackColor,
iconSize: 14.h, iconSize: 14.h,
); )
: SizedBox.shrink();
} else { } else {
return patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false return patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false
? CustomButton( ? CustomButton(

@ -263,13 +263,20 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
Row( Row(
children: [ children: [
Text( Text(
LocaleKeys.iAcceptThe.tr(), "${LocaleKeys.iAcceptThe.tr()} ",
style: context.dynamicTextStyle(fontSize: 14.f, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), style: context.dynamicTextStyle(fontSize: 14.f, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)),
), ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
// Navigate to terms and conditions page // Navigate to terms and conditions page
Navigator.of(context).pushNamed('/terms'); // Navigator.of(context).pushNamed('/terms');
appState.isArabic()
? Utils.openWebView(
url: 'https://hmg.com/ar/Pages/Terms.aspx',
)
: Utils.openWebView(
url: 'https://hmg.com/en/Pages/Terms.aspx',
);
}, },
child: Text( child: Text(
LocaleKeys.termsConditoins.tr(), LocaleKeys.termsConditoins.tr(),

@ -11,6 +11,7 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/doctor_rating_details.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.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/buttons/custom_button.dart';
@ -108,9 +109,21 @@ class DoctorProfilePage extends StatelessWidget {
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Ratings".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), "Ratings".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate.toString().toText16(isBold: true, color: AppColors.textColor), bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate
.toString()
.toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor),
], ],
), ).onPress(() {
bookAppointmentsViewModel.getDoctorRatingDetails();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.doctorRating.tr(context: context),
context,
child: DoctorRatingDetails(),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}),
SizedBox(width: 36.w), SizedBox(width: 36.w),
Column( Column(
children: [ children: [
@ -122,15 +135,28 @@ class DoctorProfilePage extends StatelessWidget {
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Reviews".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), "Reviews".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate.toString().toText16(isBold: true, color: AppColors.textColor), bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate
.toString()
.toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor),
], ],
), ).onPress(() {
bookAppointmentsViewModel.getDoctorRatingDetails();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.doctorRating.tr(context: context),
context,
child: DoctorRatingDetails(),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}),
], ],
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Biography".toText14(weight: FontWeight.w600, color: AppColors.textColor), LocaleKeys.docInfo.tr(context: context).toText14(weight: FontWeight.w600, color: AppColors.textColor),
SizedBox(height: 6.h),
bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo!.toText12(fontWeight: FontWeight.w600, color: AppColors.greyTextColor), bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo!.toText12(fontWeight: FontWeight.w600, color: AppColors.greyTextColor),
], ],
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),

@ -33,71 +33,30 @@ import 'package:smooth_corner/smooth_corner.dart';
class ImmediateLiveCarePaymentDetails extends StatelessWidget { class ImmediateLiveCarePaymentDetails extends StatelessWidget {
ImmediateLiveCarePaymentDetails({super.key}); ImmediateLiveCarePaymentDetails({super.key});
late ImmediateLiveCareViewModel immediateLiveCareViewModel; // late ImmediateLiveCareViewModel immediateLiveCareViewModel;
late AppState appState; late AppState appState;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
immediateLiveCareViewModel = Provider.of<ImmediateLiveCareViewModel>(context, listen: false); // immediateLiveCareViewModel = Provider.of<ImmediateLiveCareViewModel>(context, listen: false);
appState = getIt.get<AppState>(); appState = getIt.get<AppState>();
return Scaffold( return Scaffold(
backgroundColor: AppColors.scaffoldBgColor, backgroundColor: AppColors.scaffoldBgColor,
body: Column( body: Consumer<ImmediateLiveCareViewModel>(builder: (context, immediateLiveCareVM, child) {
children: [ return Column(
Expanded( children: [
child: CollapsingListView( Expanded(
title: LocaleKeys.reviewLiveCareRequest.tr(context: context), child: CollapsingListView(
child: SingleChildScrollView( title: LocaleKeys.reviewLiveCareRequest.tr(context: context),
padding: EdgeInsets.symmetric(horizontal: 24.h), child: SingleChildScrollView(
child: Column( padding: EdgeInsets.symmetric(horizontal: 24.h),
crossAxisAlignment: CrossAxisAlignment.start, child: Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
SizedBox(height: 24.h), children: [
LocaleKeys.patientInfo.tr(context: context).toText16(isBold: true), SizedBox(height: 24.h),
SizedBox(height: 16.h), LocaleKeys.patientInfo.tr(context: context).toText16(isBold: true),
Container( SizedBox(height: 16.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( Container(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Row(
children: [
Image.asset(
appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg,
width: 52.h,
height: 52.h,
),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText16(isBold: true),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} ${LocaleKeys.yearsOld.tr(context: context)}"),
AppCustomChipWidget(
labelText:
"${LocaleKeys.clinic.tr()}: ${(appState.isArabic() ? immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceNameN : immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceName)!}"),
],
),
],
),
],
),
),
),
SizedBox(height: 24.h),
LocaleKeys.selectedLiveCareType.tr(context: context).toText16(isBold: true),
SizedBox(height: 16.h),
Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, color: AppColors.whiteColor,
borderRadius: 24.h, borderRadius: 24.h,
@ -106,217 +65,262 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
child: Padding( child: Padding(
padding: EdgeInsets.all(16.h), padding: EdgeInsets.all(16.h),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Row( Image.asset(
appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg,
width: 52.h,
height: 52.h,
),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Utils.buildSvgWithAssets(icon: AppAssets.livecare_clinic_icon, width: 32.h, height: 32.h, fit: BoxFit.contain), "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText16(isBold: true),
SizedBox(width: 8.h), SizedBox(height: 8.h),
getLiveCareType(context, immediateLiveCareViewModel.liveCareSelectedCallType).toText16(isBold: true), Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} ${LocaleKeys.yearsOld.tr(context: context)}"),
AppCustomChipWidget(
labelText:
"${LocaleKeys.clinic.tr()}: ${(appState.isArabic() ? immediateLiveCareVM.immediateLiveCareSelectedClinic.serviceNameN : immediateLiveCareVM.immediateLiveCareSelectedClinic.serviceName)!}"),
],
),
], ],
), ),
Utils.buildSvgWithAssets(icon: AppAssets.edit_icon, width: 24.h, height: 24.h, fit: BoxFit.contain),
], ],
), ),
), ),
).onPress(() { ),
showCommonBottomSheetWithoutHeight(context, child: SelectLiveCareCallType(immediateLiveCareViewModel: immediateLiveCareViewModel), callBackFunc: () async { SizedBox(height: 24.h),
debugPrint("Selected Call Type: ${immediateLiveCareViewModel.liveCareSelectedCallType}"); LocaleKeys.selectedLiveCareType.tr(context: context).toText16(isBold: true),
}, title: LocaleKeys.selectLiveCareCallType.tr(context: context), isCloseButtonVisible: true, isFullScreen: false); SizedBox(height: 16.h),
}); Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
}), return Container(
SizedBox(height: 24.h) decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
], color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.livecare_clinic_icon, width: 32.h, height: 32.h, fit: BoxFit.contain),
SizedBox(width: 8.h),
getLiveCareType(context, immediateLiveCareVM.liveCareSelectedCallType).toText16(isBold: true),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.edit_icon, width: 24.h, height: 24.h, fit: BoxFit.contain),
],
),
),
).onPress(() {
showCommonBottomSheetWithoutHeight(context, child: SelectLiveCareCallType(immediateLiveCareViewModel: immediateLiveCareVM), callBackFunc: () async {
debugPrint("Selected Call Type: ${immediateLiveCareVM.liveCareSelectedCallType}");
}, title: LocaleKeys.selectLiveCareCallType.tr(context: context), isCloseButtonVisible: true, isFullScreen: false);
});
}),
SizedBox(height: 24.h)
],
),
), ),
), ),
), ),
), Container(
Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor,
color: AppColors.whiteColor, borderRadius: 24.h,
borderRadius: 24.h, hasShadow: false,
hasShadow: false, ),
), child: Column(
child: Column( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ (immediateLiveCareVM.liveCareImmediateAppointmentFeesList.isCash ?? true)
(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.isCash ?? true) ? Container(
? Container( height: 50.h,
height: 50.h, decoration: ShapeDecoration(
decoration: ShapeDecoration( color: AppColors.secondaryLightRedBorderColor,
color: AppColors.secondaryLightRedBorderColor, shape: SmoothRectangleBorder(
shape: SmoothRectangleBorder( borderRadius: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)),
borderRadius: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)), smoothness: 1,
smoothness: 1, ),
), ),
), child: Row(
child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
children: [ LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h),
LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h), CustomButton(
CustomButton( text: LocaleKeys.updateInsurance.tr(context: context),
text: LocaleKeys.updateInsurance.tr(context: context), onPressed: () {
onPressed: () { Navigator.of(context).push(
Navigator.of(context).push(
CustomPageRoute(
page: InsuranceHomePage(),
),
);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.secondaryLightRedBorderColor,
textColor: AppColors.whiteColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(15, 0, 15, 0),
height: 30.h,
).paddingSymmetrical(24.h, 0.h),
],
),
)
: const SizedBox(),
SizedBox(height: 24.h),
LocaleKeys.totalAmountToPay.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.amount!.toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
],
).paddingSymmetrical(24.h, 0.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.vat15.tr(context: context).toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol(
immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.tax!.toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13,
isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(width: 150.h, child: Utils.getPaymentMethods()),
Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total!.toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
],
).paddingSymmetrical(24.h, 0.h),
(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total == "0" || immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total == "0.0")
? CustomButton(
text: LocaleKeys.confirmLiveCare.tr(context: context),
onPressed: () async {
await askVideoCallPermission(context).then((val) async {
if (val) {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingLiveCareRequest.tr(context: context));
await immediateLiveCareViewModel.addNewCallRequestForImmediateLiveCare("${appState.getAuthenticatedUser()!.patientId}${DateTime.now().millisecondsSinceEpoch}");
await immediateLiveCareViewModel.getPatientLiveCareHistory();
LoaderBottomSheet.hideLoader();
if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) {
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute( CustomPageRoute(
page: LandingNavigation(), page: InsuranceHomePage(),
), ),
);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.secondaryLightRedBorderColor,
textColor: AppColors.whiteColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(15, 0, 15, 0),
height: 30.h,
).paddingSymmetrical(24.h, 0.h),
],
),
)
: const SizedBox(),
SizedBox(height: 24.h),
LocaleKeys.totalAmountToPay.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.amount!.toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
],
).paddingSymmetrical(24.h, 0.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.vat15.tr(context: context).toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol(
immediateLiveCareVM.liveCareImmediateAppointmentFeesList.tax!.toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13,
isSaudiCurrency: immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(width: 150.h, child: Utils.getPaymentMethods()),
Utils.getPaymentAmountWithSymbol(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total!.toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
],
).paddingSymmetrical(24.h, 0.h),
(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total == "0" || immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total == "0.0")
? CustomButton(
text: LocaleKeys.confirmLiveCare.tr(context: context),
onPressed: () async {
await askVideoCallPermission(context).then((val) async {
if (val) {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingLiveCareRequest.tr(context: context));
await immediateLiveCareVM.addNewCallRequestForImmediateLiveCare("${appState.getAuthenticatedUser()!.patientId}${DateTime
.now()
.millisecondsSinceEpoch}");
await immediateLiveCareVM.getPatientLiveCareHistory();
LoaderBottomSheet.hideLoader();
if (immediateLiveCareVM.patientHasPendingLiveCareRequest) {
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false); (r) => false);
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: ImmediateLiveCarePendingRequestPage(), page: ImmediateLiveCarePendingRequestPage(),
), ),
); );
} else {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.unknownErrorOccurred.tr(context: context)),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
} else { } else {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: context),
context, context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.unknownErrorOccurred.tr(context: context)), child: Utils.getWarningWidget(
loadingText: LocaleKeys.liveCarePermissionsMessage.tr(context: context),
isShowActionButtons: true,
onCancelTap: () {
Navigator.pop(context);
},
onConfirmTap: () async {
openAppSettings();
}),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
); );
} }
} else { });
showCommonBottomSheetWithoutHeight( },
title: LocaleKeys.notice.tr(context: context), backgroundColor: AppColors.successColor,
context, borderColor: AppColors.successColor,
child: Utils.getWarningWidget( textColor: AppColors.whiteColor,
loadingText: LocaleKeys.liveCarePermissionsMessage.tr(context: context), fontSize: 16,
isShowActionButtons: true, fontWeight: FontWeight.w500,
onCancelTap: () { borderRadius: 12,
Navigator.pop(context); padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
}, height: 50.h,
onConfirmTap: () async { icon: AppAssets.livecare_book_icon,
openAppSettings(); iconColor: AppColors.whiteColor,
}), iconSize: 18.h,
callBackFunc: () {}, ).paddingSymmetrical(24.h, 24.h)
isFullScreen: false, : CustomButton(
isCloseButtonVisible: true, text: LocaleKeys.payNow.tr(context: context),
); onPressed: () async {
} await askVideoCallPermission(context).then((val) {
}); if (val) {
}, Navigator.of(context).push(
backgroundColor: AppColors.successColor, CustomPageRoute(
borderColor: AppColors.successColor, page: ImmediateLiveCarePaymentPage(),
textColor: AppColors.whiteColor, ),
fontSize: 16, );
fontWeight: FontWeight.w500, }
borderRadius: 12, // else {
padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // showCommonBottomSheetWithoutHeight(
height: 50.h, // title: LocaleKeys.notice.tr(context: context),
icon: AppAssets.livecare_book_icon, // context,
iconColor: AppColors.whiteColor, // child: Utils.getWarningWidget(
iconSize: 18.h, // loadingText: LocaleKeys.liveCarePermissionsMessage.tr(context: context),
).paddingSymmetrical(24.h, 24.h) // isShowActionButtons: true,
: CustomButton( // onCancelTap: () {
text: LocaleKeys.payNow.tr(context: context), // Navigator.pop(context);
onPressed: () async { // },
await askVideoCallPermission(context).then((val) { // onConfirmTap: () async {
if (val) { // openAppSettings();
Navigator.of(context).push( // }),
CustomPageRoute( // callBackFunc: () {},
page: ImmediateLiveCarePaymentPage(), // isFullScreen: false,
), // isCloseButtonVisible: true,
); // );
} // }
// else { });
// showCommonBottomSheetWithoutHeight( },
// title: LocaleKeys.notice.tr(context: context), backgroundColor: AppColors.infoColor,
// context, borderColor: AppColors.infoColor,
// child: Utils.getWarningWidget( textColor: AppColors.whiteColor,
// loadingText: LocaleKeys.liveCarePermissionsMessage.tr(context: context), fontSize: 16,
// isShowActionButtons: true, fontWeight: FontWeight.w500,
// onCancelTap: () { borderRadius: 12,
// Navigator.pop(context); padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
// }, height: 50.h,
// onConfirmTap: () async { icon: AppAssets.appointment_pay_icon,
// openAppSettings(); iconColor: AppColors.whiteColor,
// }), iconSize: 18.h,
// callBackFunc: () {}, ).paddingSymmetrical(24.h, 24.h),
// isFullScreen: false, ],
// isCloseButtonVisible: true, ),
// );
// }
});
},
backgroundColor: AppColors.infoColor,
borderColor: AppColors.infoColor,
textColor: AppColors.whiteColor,
fontSize: 16,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h,
icon: AppAssets.appointment_pay_icon,
iconColor: AppColors.whiteColor,
iconSize: 18.h,
).paddingSymmetrical(24.h, 24.h),
],
), ),
), ],
], );
), }),
); );
} }

@ -941,7 +941,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
void onLiveCareClinicSelected(GetLiveCareClinicsResponseModel clinic) { void onLiveCareClinicSelected(GetLiveCareClinicsResponseModel clinic) {
bookAppointmentsViewModel.setLiveCareSelectedClinic(clinic); bookAppointmentsViewModel.setLiveCareSelectedClinic(clinic);
bookAppointmentsViewModel.setIsDoctorsListLoading(true); bookAppointmentsViewModel.setIsLiveCareDoctorsListLoading(true);
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: SelectDoctorPage(), page: SelectDoctorPage(),

@ -95,9 +95,59 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
child: Padding( child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.h), padding: EdgeInsets.symmetric(horizontal: 24.h),
child: Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) { child: Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
return Column( return bookAppointmentsViewModel.isLiveCareSchedule
crossAxisAlignment: CrossAxisAlignment.start, ? Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListView.separated(
padding: EdgeInsets.only(top: 16.h),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: bookAppointmentsVM.isDoctorsListLoading ? 5 : (bookAppointmentsVM.liveCareDoctorsList.isNotEmpty ? bookAppointmentsVM.liveCareDoctorsList.length : 1),
itemBuilder: (context, index) {
// final isExpanded = bookAppointmentsVM.expandedGroupIndex == index;
final isExpanded = true;
return bookAppointmentsVM.isDoctorsListLoading
? DoctorCard(
doctorsListResponseModel: DoctorsListResponseModel(),
isLoading: true,
bookAppointmentsViewModel: bookAppointmentsViewModel,
)
: bookAppointmentsVM.liveCareDoctorsList.isEmpty
? Utils.getNoDataWidget(context, noDataText: LocaleKeys.noDoctorFound.tr())
: 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,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: Padding(
padding: EdgeInsets.all(16.h),
child: DoctorCard(
isLoading: bookAppointmentsVM.isClinicsListLoading,
doctorsListResponseModel: bookAppointmentsVM.liveCareDoctorsList[index],
bookAppointmentsViewModel: bookAppointmentsViewModel,
).onPress(() {
// onLiveCareClinicSelected(bookAppointmentsVM.liveCareClinicsList[index]);
}),
),
),
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
SizedBox(height: 24.h),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 16.h), SizedBox(height: 16.h),
Row( Row(
spacing: 8.h, spacing: 8.h,

@ -90,7 +90,7 @@ class DoctorCard extends StatelessWidget {
Row( Row(
children: [ children: [
SizedBox( SizedBox(
width: MediaQuery.of(context).size.width * 0.49, width: MediaQuery.of(context).size.width * 0.55,
child: (isLoading ? "Dr John Smith" : "${doctorsListResponseModel.doctorTitle} ${doctorsListResponseModel.name}") child: (isLoading ? "Dr John Smith" : "${doctorsListResponseModel.doctorTitle} ${doctorsListResponseModel.name}")
.toString() .toString()
.toText16(isBold: true, maxlines: 1), .toText16(isBold: true, maxlines: 1),
@ -99,14 +99,14 @@ class DoctorCard extends StatelessWidget {
), ),
SizedBox(height: 2.h), SizedBox(height: 2.h),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
SizedBox( SizedBox(
width: MediaQuery.of(context).size.width * 0.45,
child: (isLoading child: (isLoading
? "Consultant Cardiologist" ? "Consultant Cardiologist"
: doctorsListResponseModel.speciality!.isNotEmpty : doctorsListResponseModel.speciality!.isNotEmpty
? doctorsListResponseModel.speciality!.first ? (doctorsListResponseModel.speciality!.first.length > 32
? '${doctorsListResponseModel.speciality!.first.substring(0, 32)}...'
: doctorsListResponseModel.speciality!.first)
: "") : "")
.toString() .toString()
.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor, maxLine: 2) .toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor, maxLine: 2)
@ -121,6 +121,29 @@ class DoctorCard extends StatelessWidget {
).toShimmer2(isShow: isLoading), ).toShimmer2(isShow: isLoading),
], ],
), ),
SizedBox(height: 6.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(
labelText: "${isLoading ? "Cardiologist" : doctorsListResponseModel.clinicName}",
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: "${isLoading ? "Olaya Hospital" : doctorsListResponseModel.projectName}",
).toShimmer2(isShow: isLoading),
bookAppointmentsViewModel.isNearestAppointmentSelected
? doctorsListResponseModel.nearestFreeSlot != null
? AppCustomChipWidget(
labelText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot)),
backgroundColor: AppColors.successColor,
textColor: AppColors.whiteColor,
).toShimmer2(isShow: isLoading)
: SizedBox.shrink()
: SizedBox.shrink(),
],
),
], ],
), ),
), ),
@ -131,28 +154,6 @@ class DoctorCard extends StatelessWidget {
), ),
], ],
), ),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(
labelText: "${isLoading ? "Cardiologist" : doctorsListResponseModel.clinicName}",
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(
labelText: "${isLoading ? "Olaya Hospital" : doctorsListResponseModel.projectName}",
).toShimmer2(isShow: isLoading),
bookAppointmentsViewModel.isNearestAppointmentSelected
? doctorsListResponseModel.nearestFreeSlot != null
? AppCustomChipWidget(
labelText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot)),
backgroundColor: AppColors.successColor,
textColor: AppColors.whiteColor,
).toShimmer2(isShow: isLoading)
: SizedBox.shrink()
: SizedBox.shrink(),
],
),
SizedBox(height: 12.h), SizedBox(height: 12.h),
CustomButton( CustomButton(
text: LocaleKeys.bookAppo.tr(context: context), text: LocaleKeys.bookAppo.tr(context: context),

@ -0,0 +1,195 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.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/features/book_appointments/book_appointments_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:provider/provider.dart';
class DoctorRatingDetails extends StatelessWidget {
const DoctorRatingDetails({super.key});
@override
Widget build(BuildContext context) {
return Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
return bookAppointmentsVM.isDoctorRatingDetailsLoading
? Utils.getLoadingWidget()
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
bookAppointmentsVM.doctorsProfileResponseModel.actualDoctorRate!.ceilToDouble().toString().toText44(isBold: true),
SizedBox(height: 4.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${bookAppointmentsVM.doctorsProfileResponseModel.noOfPatientsRate} ${LocaleKeys.reviews.tr(context: context)}"
.toText16(weight: FontWeight.w500, color: AppColors.greyInfoTextColor),
RatingBar(
initialRating: bookAppointmentsVM.doctorsProfileResponseModel.actualDoctorRate!.toDouble(),
direction: Axis.horizontal,
allowHalfRating: true,
itemCount: 5,
itemSize: 20.h,
ignoreGestures: true,
ratingWidget: RatingWidget(
full: Icon(
Icons.star,
color: AppColors.ratingColorYellow,
size: 24.h,
),
half: Icon(
Icons.star_half,
color: AppColors.ratingColorYellow,
),
empty: Icon(
Icons.star,
color: AppColors.ratingColorYellow,
),
),
tapOnlyMode: true,
unratedColor: Colors.grey[500],
itemPadding: EdgeInsets.symmetric(horizontal: 4.0),
onRatingUpdate: (rating) {
print(rating);
},
),
],
),
SizedBox(height: 8.h),
Container(
margin: EdgeInsets.only(top: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 100.0,
margin: EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0),
child: Text(LocaleKeys.excellent.tr(context: context), style: TextStyle(fontSize: 13.0, color: Colors.black, fontWeight: FontWeight.w600))),
getRatingLine(bookAppointmentsVM.doctorDetailsList[0].ratio, Colors.green[700]!),
],
),
Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${getRatingWidth(bookAppointmentsVM.doctorDetailsList[0].ratio).round()}%", style: TextStyle(fontSize: 14.0, color: Colors.black, fontWeight: FontWeight.w600)),
),
],
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 100.0,
margin: EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0),
child: Text(LocaleKeys.vGood.tr(context: context), style: TextStyle(fontSize: 13.0, color: Colors.black, fontWeight: FontWeight.w600))),
getRatingLine(bookAppointmentsVM.doctorDetailsList[1].ratio, Color(0xffB7B723)),
],
),
Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${bookAppointmentsVM.doctorDetailsList[1].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: Colors.black, fontWeight: FontWeight.w600)),
),
],
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 100.0,
margin: EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0),
child: Text(LocaleKeys.good.tr(context: context), style: TextStyle(fontSize: 13.0, color: Colors.black, fontWeight: FontWeight.w600))),
getRatingLine(bookAppointmentsVM.doctorDetailsList[2].ratio, Color(0xffEBA727)),
],
),
Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${bookAppointmentsVM.doctorDetailsList[2].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: Colors.black, fontWeight: FontWeight.w600)),
),
],
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 100.0,
margin: EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0),
child: Text(LocaleKeys.average.tr(context: context), style: TextStyle(fontSize: 13.0, color: Colors.black, fontWeight: FontWeight.w600))),
getRatingLine(bookAppointmentsVM.doctorDetailsList[3].ratio, Color(0xffEB7227)),
],
),
Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${bookAppointmentsVM.doctorDetailsList[3].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: Colors.black, fontWeight: FontWeight.w600)),
),
],
),
),
Container(
margin: EdgeInsets.only(bottom: 30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 100.0,
margin: EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0),
child: Text(LocaleKeys.average.tr(context: context), style: TextStyle(fontSize: 13.0, color: Colors.black, fontWeight: FontWeight.w600))),
getRatingLine(bookAppointmentsVM.doctorDetailsList[4].ratio, Color(0xffE20C0C)),
],
),
Container(
margin: EdgeInsets.only(top: 10.0, left: 10.0, right: 10.0),
child: Text("${bookAppointmentsVM.doctorDetailsList[4].ratio.round()}%", style: TextStyle(fontSize: 14.0, color: Colors.black, fontWeight: FontWeight.w600)),
),
],
),
),
],
);
});
}
double getRatingWidth(num patientNumber) {
var width = patientNumber;
return width.roundToDouble();
}
Widget getRatingLine(double patientNumber, Color color) {
return Container(
margin: EdgeInsets.only(top: 10.0),
child: Stack(children: [
SizedBox(
width: 150.0,
height: 7.h,
child: Container(
color: Colors.grey[300],
),
),
SizedBox(
width: patientNumber * 1.55,
height: 7.h,
child: Container(
color: color,
),
),
]),
);
}
}

@ -526,8 +526,8 @@ class CallAmbulancePage extends StatelessWidget {
textPlaceInput(context) { textPlaceInput(context) {
return Consumer<LocationViewModel>(builder: (_, vm, __) { return Consumer<LocationViewModel>(builder: (_, vm, __) {
print("the data is ${vm.geocodeResponse?.results.first.formattedAddress ?? vm.selectedPrediction?.description}"); // print("the data is ${vm.geocodeResponse?.results.first.formattedAddress ?? vm.selectedPrediction?.description}");
return SizedBox( return (vm.geocodeResponse != null && vm.geocodeResponse!.results.isNotEmpty) ? SizedBox(
width: MediaQuery.sizeOf(context).width, width: MediaQuery.sizeOf(context).width,
child: TextInputWidget( child: TextInputWidget(
labelText: LocaleKeys.enterPickupLocationManually.tr(context: context), labelText: LocaleKeys.enterPickupLocationManually.tr(context: context),
@ -549,7 +549,7 @@ class CallAmbulancePage extends StatelessWidget {
).onPress(() { ).onPress(() {
openLocationInputBottomSheet(context); openLocationInputBottomSheet(context);
}), }),
); ) : SizedBox.shrink();
}); });
} }

@ -159,6 +159,15 @@ class ErOnlineCheckinHome extends StatelessWidget {
await vm.getPatientERPaymentInformation(onSuccess: (response) { await vm.getPatientERPaymentInformation(onSuccess: (response) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
vm.navigateToEROnlineCheckInPaymentPage(); vm.navigateToEROnlineCheckInPaymentPage();
}, onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}); });
}, },
onHospitalSearch: (value) { onHospitalSearch: (value) {

@ -36,6 +36,7 @@ class _RechargeWalletPageState extends State<RechargeWalletPage> {
late HabibWalletViewModel habibWalletVM; late HabibWalletViewModel habibWalletVM;
late AppState appState; late AppState appState;
final TextEditingController amountTextController = TextEditingController(); final TextEditingController amountTextController = TextEditingController();
final TextEditingController notesTextController = TextEditingController();
@override @override
void initState() { void initState() {
@ -209,23 +210,20 @@ class _RechargeWalletPageState extends State<RechargeWalletPage> {
SizedBox(height: 16.h), SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Row( TextInputWidget(
mainAxisAlignment: MainAxisAlignment.spaceBetween, labelText: LocaleKeys.notes.tr(context: context),
children: [ hintText: "",
Row( controller: notesTextController,
children: [ keyboardType: TextInputType.text,
Utils.buildSvgWithAssets(icon: AppAssets.notes_icon, width: 40.h, height: 40.h), isEnable: true,
SizedBox(width: 8.h), prefix: null,
Column( autoFocus: true,
crossAxisAlignment: CrossAxisAlignment.start, isAllowRadius: true,
children: [ isBorderAllowed: false,
LocaleKeys.notes.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), isAllowLeadingIcon: true,
"Lorem Ipsum".toText14(color: AppColors.textColor, weight: FontWeight.w500, letterSpacing: -0.2), leadingIcon: AppAssets.notes_icon,
], errorMessage: LocaleKeys.enterValidIDorIqama.tr(context: context),
), hasError: false,
],
),
],
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
], ],
@ -271,6 +269,7 @@ class _RechargeWalletPageState extends State<RechargeWalletPage> {
); );
} else { } else {
habibWalletVM.setWalletRechargeAmount(num.parse(amountTextController.text)); habibWalletVM.setWalletRechargeAmount(num.parse(amountTextController.text));
habibWalletVM.setNotesText(notesTextController.text);
// habibWalletVM.setDepositorDetails(appState.getAuthenticatedUser()!.patientId.toString(), "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}", // habibWalletVM.setDepositorDetails(appState.getAuthenticatedUser()!.patientId.toString(), "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
// appState.getAuthenticatedUser()!.mobileNumber!); // appState.getAuthenticatedUser()!.mobileNumber!);
Navigator.of(context).push( Navigator.of(context).push(

@ -28,6 +28,8 @@ 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/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/family_file_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
@ -145,6 +147,10 @@ class _MultiPageBottomSheetState extends State<MultiPageBottomSheet> {
], ],
).paddingAll(16.h), ).paddingAll(16.h),
).onPress(() { ).onPress(() {
habibWalletVM.setDepositorDetails(appState.getAuthenticatedUser()!.patientId!.toString(),
"${appState.getAuthenticatedUser()!.firstName.toString()} ${appState.getAuthenticatedUser()!.lastName.toString()}", appState.getAuthenticatedUser()!.mobileNumber!.toString());
habibWalletVM.setCurrentIndex(0);
habibWalletVM.setSelectedRechargeType(1);
Navigator.of(context).pop(); Navigator.of(context).pop();
}), }),
SizedBox(height: 16.h), SizedBox(height: 16.h),
@ -167,7 +173,24 @@ class _MultiPageBottomSheetState extends State<MultiPageBottomSheet> {
Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h), Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h),
], ],
).paddingAll(16.h), ).paddingAll(16.h),
), ).onPress(() {
DialogService dialogService = getIt.get<DialogService>();
dialogService.showFamilyBottomSheetWithoutH(
label: LocaleKeys.familyTitle.tr(context: context),
message: "",
isShowManageButton: false,
isForWalletRecharge: true,
onSwitchPress: (FamilyFileResponseModelLists profile) {
habibWalletVM.setDepositorDetails(profile.responseId.toString(), profile.patientName.toString(), profile.mobileNumber.toString());
habibWalletVM.setCurrentIndex(0);
habibWalletVM.setSelectedRechargeType(2);
Navigator.of(context).pop();
Navigator.of(context).pop();
// medicalFileViewModel.switchFamilyFiles(responseID: profile.responseId, patientID: profile.patientId, phoneNumber: profile.mobileNumber);
},
profiles: getIt.get<MedicalFileViewModel>().patientFamilyFiles);
}),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Container( Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(

@ -204,7 +204,7 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
crossAxisCount: 3, // 4 icons per row crossAxisCount: 3, // 4 icons per row
crossAxisSpacing: 16.w, crossAxisSpacing: 16.w,
mainAxisSpacing: 16.w, mainAxisSpacing: 16.w,
childAspectRatio: 0.80), childAspectRatio: 0.85),
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,
itemCount: type == HealthCalculatorEnum.general ? generalHealthServices.length : womenHealthServices.length, itemCount: type == HealthCalculatorEnum.general ? generalHealthServices.length : womenHealthServices.length,
@ -214,6 +214,7 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
icon: type == HealthCalculatorEnum.general ? generalHealthServices[index].icon : womenHealthServices[index].icon, icon: type == HealthCalculatorEnum.general ? generalHealthServices[index].icon : womenHealthServices[index].icon,
labelText: type == HealthCalculatorEnum.general ? generalHealthServices[index].title : womenHealthServices[index].title, labelText: type == HealthCalculatorEnum.general ? generalHealthServices[index].title : womenHealthServices[index].title,
onTap: () { onTap: () {
Navigator.pop(context);
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: HealthCalculatorDetailedPage( page: HealthCalculatorDetailedPage(

@ -157,15 +157,15 @@ class ServicesPage extends StatelessWidget {
true, true,
route: AppRoutes.bloodDonationPage, route: AppRoutes.bloodDonationPage,
), ),
HmgServicesComponentModel( // HmgServicesComponentModel(
3, // 3,
"My Child Vaccine".needTranslation, // "My Child Vaccine".needTranslation,
"".needTranslation, // "".needTranslation,
AppAssets.my_child_vaccine_icon, // AppAssets.my_child_vaccine_icon,
bgColor: AppColors.myChildVaccineCardColor, // bgColor: AppColors.myChildVaccineCardColor,
true, // true,
route: AppRoutes.myChildVaccine, // route: AppRoutes.myChildVaccine,
), // ),
// HmgServicesComponentModel( // HmgServicesComponentModel(
// 11, // 11,
// "Covid 19 Test".needTranslation, // "Covid 19 Test".needTranslation,

@ -1,6 +1,8 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.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/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@ -11,16 +13,20 @@ import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/theme/colors.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/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.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:provider/provider.dart'; import 'package:provider/provider.dart';
class PatientInsuranceCardUpdateCard extends StatelessWidget { class PatientInsuranceCardUpdateCard extends StatelessWidget {
PatientInsuranceCardUpdateCard({super.key}); PatientInsuranceCardUpdateCard({super.key});
late InsuranceViewModel insuranceViewModel; late InsuranceViewModel insuranceViewModel;
late AppState appState;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
insuranceViewModel = Provider.of<InsuranceViewModel>(context); insuranceViewModel = Provider.of<InsuranceViewModel>(context);
appState = getIt.get<AppState>();
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -49,7 +55,7 @@ class PatientInsuranceCardUpdateCard extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Haroon Amjad".toText16(weight: FontWeight.w600), insuranceViewModel.patientInsuranceUpdateResponseModel!.memberName!.toText16(weight: FontWeight.w600),
"Policy: ${insuranceViewModel.patientInsuranceUpdateResponseModel!.policyNumber}".toText12(isBold: true, color: AppColors.lightGrayColor), "Policy: ${insuranceViewModel.patientInsuranceUpdateResponseModel!.policyNumber}".toText12(isBold: true, color: AppColors.lightGrayColor),
SizedBox(height: 8.h), SizedBox(height: 8.h),
Row( Row(
@ -99,7 +105,41 @@ class PatientInsuranceCardUpdateCard extends StatelessWidget {
iconColor: AppColors.whiteColor, iconColor: AppColors.whiteColor,
iconSize: 20.w, iconSize: 20.w,
text: "${LocaleKeys.updateInsurance.tr(context: context)} ${LocaleKeys.updateInsuranceSubtitle.tr(context: context)}", text: "${LocaleKeys.updateInsurance.tr(context: context)} ${LocaleKeys.updateInsuranceSubtitle.tr(context: context)}",
onPressed: () {}, onPressed: () {
LoaderBottomSheet.showLoader();
insuranceViewModel.updatePatientInsuranceCard(
patientID: appState.getAuthenticatedUser()!.patientId!,
patientType: appState.getAuthenticatedUser()!.patientType!,
patientIdentificationID: appState.getAuthenticatedUser()!.patientIdentificationNo!,
mobileNo: appState.getAuthenticatedUser()!.mobileNumber!,
insuranceCardImage: "",
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.success.tr(context: context),
context,
child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr(context: context)),
callBackFunc: () {
Navigator.pop(context);
},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: context),
context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {
Navigator.pop(context);
},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
backgroundColor: insuranceViewModel.patientInsuranceUpdateResponseModel != null ? AppColors.successColor : AppColors.lightGrayBGColor, backgroundColor: insuranceViewModel.patientInsuranceUpdateResponseModel != null ? AppColors.successColor : AppColors.lightGrayBGColor,
borderColor: AppColors.successColor.withOpacity(0.01), borderColor: AppColors.successColor.withOpacity(0.01),
textColor: AppColors.whiteColor, textColor: AppColors.whiteColor,

@ -203,7 +203,6 @@ class _AlphabetScrollPageState extends State<AlphabeticScroll> {
verticalOffset: 100.0, verticalOffset: 100.0,
child: FadeInAnimation( child: FadeInAnimation(
child: LabOrderByTest( child: LabOrderByTest(
appState: getIt<AppState>(), appState: getIt<AppState>(),
onTap: () { onTap: () {
if (items[itemIndex].model != null) { if (items[itemIndex].model != null) {

@ -17,6 +17,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.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/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:open_filex/open_filex.dart'; import 'package:open_filex/open_filex.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -197,49 +198,23 @@ class _PatientSickleavesListPageState extends State<PatientSickleavesListPage> {
], ],
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
Row( Wrap(
direction: Axis.horizontal,
spacing: 6.h,
runSpacing: 6.h,
children: [ children: [
CustomButton( AppCustomChipWidget(
text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(sickLeave.appointmentDate), false), labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(sickLeave.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), AppCustomChipWidget(
CustomButton( labelText: model.isSickLeavesSortByClinic ? sickLeave.projectName! : sickLeave.clinicName!,
text: model.isSickLeavesSortByClinic ? sickLeave.projectName! : sickLeave.clinicName!,
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), AppCustomChipWidget(
CustomButton( labelText: "${sickLeave.sickLeaveDays} Days",
text: "${sickLeave.sickLeaveDays} 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: 24.h,
), ),
], ],
), ),
SizedBox(height: 8.h), SizedBox(height: 12.h),
Row( Row(
children: [ children: [
Expanded( Expanded(

@ -80,7 +80,10 @@ class MonthlyReport extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.email.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), LocaleKeys.email.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
"${appState.getAuthenticatedUser()!.emailAddress}".toText16(color: AppColors.textColor, weight: FontWeight.w500), SizedBox(
width: MediaQuery.of(context).size.width * 0.7,
child: "${appState.getAuthenticatedUser()!.emailAddress}".toText16(color: AppColors.textColor, weight: FontWeight.w500, maxlines: 2),
),
], ],
), ),
], ],

@ -8,6 +8,7 @@ import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/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/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/family_file_response_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/models/family_file_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart';
@ -25,6 +26,7 @@ class FamilyCards extends StatefulWidget {
final bool isRequestDesign; final bool isRequestDesign;
final bool isLeftAligned; final bool isLeftAligned;
final bool isShowRemoveButton; final bool isShowRemoveButton;
final bool isForWalletRecharge;
const FamilyCards( const FamilyCards(
{super.key, {super.key,
@ -35,6 +37,7 @@ class FamilyCards extends StatefulWidget {
this.isBottomSheet = false, this.isBottomSheet = false,
this.isRequestDesign = false, this.isRequestDesign = false,
this.isLeftAligned = false, this.isLeftAligned = false,
this.isForWalletRecharge = false,
this.isShowRemoveButton = false}); this.isShowRemoveButton = false});
@override @override
@ -206,7 +209,21 @@ class _FamilyCardsState extends State<FamilyCards> {
height: 4.h, height: 4.h,
), ),
Spacer(), Spacer(),
CustomButton( widget.isForWalletRecharge ? CustomButton(
height: 40.h,
onPressed: () {
widget.onSelect(profile);
// if (canSwitch) widget.onSelect(profile);
},
text: LocaleKeys.select.tr(context: context),
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 13.h,
icon: AppAssets.activeCheck,
iconColor: isActive || !canSwitch ? (isActive ? null : AppColors.greyTextColor) : AppColors.primaryRedColor,
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 0),
).paddingOnly(top: 0, bottom: 0) : CustomButton(
height: 40.h, height: 40.h,
onPressed: () { onPressed: () {
if (canSwitch) widget.onSelect(profile); if (canSwitch) widget.onSelect(profile);

@ -148,7 +148,7 @@ class _PrescriptionDetailPageState extends State<PrescriptionDetailPage> {
text: LocaleKeys.downloadPrescription.tr(context: context), text: LocaleKeys.downloadPrescription.tr(context: context),
onPressed: () async { onPressed: () async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingPrescriptionPDFPleaseWait.tr(context: context)); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingPrescriptionPDFPleaseWait.tr(context: context));
await prescriptionVM.getPrescriptionPDFBase64(widget.prescriptionsResponseModel).then((val) async { await prescriptionVM.getPrescriptionPDFBase64(widget.prescriptionsResponseModel, onSuccess: (value) async {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
if (prescriptionVM.prescriptionPDFBase64Data.isNotEmpty) { if (prescriptionVM.prescriptionPDFBase64Data.isNotEmpty) {
String path = await Utils.createFileFromString(prescriptionVM.prescriptionPDFBase64Data, "pdf"); String path = await Utils.createFileFromString(prescriptionVM.prescriptionPDFBase64Data, "pdf");
@ -164,6 +164,15 @@ class _PrescriptionDetailPageState extends State<PrescriptionDetailPage> {
); );
} }
} }
}, onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}); });
}, },
backgroundColor: AppColors.successColor.withValues(alpha: 0.15), backgroundColor: AppColors.successColor.withValues(alpha: 0.15),

@ -10,6 +10,7 @@ import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_mo
import 'package:hmg_patient_app_new/generated/locale_keys.g.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/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.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/loader/bottomsheet_loader.dart';
@ -56,74 +57,18 @@ class PrescriptionItemView extends StatelessWidget {
spacing: 6.h, spacing: 6.h,
runSpacing: 6.h, runSpacing: 6.h,
children: [ children: [
Row( AppCustomChipWidget(
mainAxisSize: MainAxisSize.min, labelText: "${LocaleKeys.route.tr(context: context)}: ${isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].route}",
children: [ ).toShimmer2(isShow: isLoading),
CustomButton( AppCustomChipWidget(
text: "${LocaleKeys.route.tr(context: context)}: ${isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].route}", labelText: "${LocaleKeys.frequency.tr(context: context)}: ${isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].frequency}",
onPressed: () {}, ).toShimmer2(isShow: isLoading),
backgroundColor: AppColors.greyColor, AppCustomChipWidget(
borderColor: AppColors.greyColor, labelText: "${LocaleKeys.dailyDoses.tr(context: context)}: ${isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].doseDailyQuantity}",
textColor: AppColors.blackColor, ).toShimmer2(isShow: isLoading),
fontSize: 10, AppCustomChipWidget(
fontWeight: FontWeight.w500, labelText: "${LocaleKeys.days.tr(context: context)}: ${isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].days}",
borderRadius: 8, ).toShimmer2(isShow: isLoading),
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h,
).toShimmer2(isShow: isLoading),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
text: "${LocaleKeys.frequency.tr(context: context)}: ${isLoading ? "" : 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,
).toShimmer2(isShow: isLoading),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
text: "${LocaleKeys.dailyDoses.tr(context: context)}: ${isLoading ? "" : 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,
).toShimmer2(isShow: isLoading),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
text: "${LocaleKeys.days.tr(context: context)}: ${isLoading ? "" : 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,
).toShimmer2(isShow: isLoading),
],
),
], ],
).paddingSymmetrical(16.h, 0.h), ).paddingSymmetrical(16.h, 0.h),
SizedBox(height: 8.h), SizedBox(height: 8.h),

@ -19,6 +19,7 @@ import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.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/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.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:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -207,32 +208,16 @@ class _PrescriptionsListPageState extends State<PrescriptionsListPage> {
], ],
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
Row( Wrap(
direction: Axis.horizontal,
spacing: 6.h,
runSpacing: 6.h,
children: [ children: [
CustomButton( AppCustomChipWidget(
text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescription.appointmentDate), false), labelText: 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), AppCustomChipWidget(
CustomButton( labelText: model.isSortByClinic ? prescription.name! : prescription.clinicDescription!,
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,
), ),
], ],
), ),

@ -658,6 +658,7 @@ class _AncillaryOrderDetailsListState extends State<AncillaryOrderDetailsList> {
text: LocaleKeys.proceedToPayment.tr(context: context), text: LocaleKeys.proceedToPayment.tr(context: context),
onPressed: () { onPressed: () {
// Navigate to payment page with selected procedures // Navigate to payment page with selected procedures
todoSectionViewModel.setIsAncillaryOrdersNeedReloading(true);
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: AncillaryOrderPaymentPage( page: AncillaryOrderPaymentPage(

@ -71,19 +71,12 @@ class AncillaryOrdersList extends StatelessWidget {
return Center( return Center(
child: Padding( child: Padding(
padding: EdgeInsets.symmetric(vertical: 40.h), padding: EdgeInsets.symmetric(vertical: 40.h),
child: Container( child: Utils.getNoDataWidget(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( context,
color: AppColors.whiteColor, noDataText: LocaleKeys.youDontHaveAnyAncillaryOrdersYet.tr(context: context),
borderRadius: 12.r, isSmallWidget: true,
hasShadow: false, width: 62.w,
), height: 62.h,
child: Utils.getNoDataWidget(
context,
noDataText: LocaleKeys.youDontHaveAnyAncillaryOrdersYet.tr(context: context),
isSmallWidget: true,
width: 62.w,
height: 62.h,
),
), ),
), ),
); );

@ -32,7 +32,8 @@ abstract class DialogService {
required String message, required String message,
required Function(FamilyFileResponseModelLists response) onSwitchPress, required Function(FamilyFileResponseModelLists response) onSwitchPress,
required List<FamilyFileResponseModelLists> profiles, required List<FamilyFileResponseModelLists> profiles,
bool isShowManageButton = false}); bool isShowManageButton = false,
bool isForWalletRecharge = false});
Future<void> showFamilyBottomSheetWithoutHWithChild({String? label, required String message, Widget? child, required Function() onOkPressed, Function()? onCancelPressed}); Future<void> showFamilyBottomSheetWithoutHWithChild({String? label, required String message, Widget? child, required Function() onOkPressed, Function()? onCancelPressed});
@ -143,7 +144,8 @@ class DialogServiceImp implements DialogService {
required String message, required String message,
required Function(FamilyFileResponseModelLists response) onSwitchPress, required Function(FamilyFileResponseModelLists response) onSwitchPress,
required List<FamilyFileResponseModelLists> profiles, required List<FamilyFileResponseModelLists> profiles,
bool isShowManageButton = false}) async { bool isShowManageButton = false,
bool isForWalletRecharge = false}) async {
final context = navigationService.navigatorKey.currentContext; final context = navigationService.navigatorKey.currentContext;
if (context == null) return; if (context == null) return;
showCommonBottomSheetWithoutHeight(context, showCommonBottomSheetWithoutHeight(context,
@ -161,6 +163,7 @@ class DialogServiceImp implements DialogService {
}, },
onRemove: (FamilyFileResponseModelLists profile) {}, onRemove: (FamilyFileResponseModelLists profile) {},
isShowDetails: false, isShowDetails: false,
isForWalletRecharge: isForWalletRecharge,
), ),
SizedBox(height: isShowManageButton ? 15.h : 24.h), SizedBox(height: isShowManageButton ? 15.h : 24.h),
if (isShowManageButton) if (isShowManageButton)

Loading…
Cancel
Save