Compare commits

...

74 Commits

Author SHA1 Message Date
Sultan khan 7d8537fae6 Merge branch 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into dev_sultan 12 hours ago
Sultan khan 1edeff439e notifications page updates 12 hours ago
Haroon6138 a1beacc36e Merge pull request 'haroon_dev' (#159) from haroon_dev into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/159
13 hours ago
haroon amjad 3e6ee8c10c Merge branch 'master' into haroon_dev
# Conflicts:
#	lib/routes/app_routes.dart
24 hours ago
haroon amjad 87422e8e05 translation updates 24 hours ago
Haroon6138 179b86b2b0 Merge pull request 'fatima' (#158) from fatima into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/158
1 day ago
Fatimah.Alshammari f6aa1fc7ac Merge branch 'refs/heads/master' into fatima 1 day ago
Fatimah.Alshammari 9795276ef9 fixed errors 1 day ago
haroon amjad 96ccb40f36 Merge branch 'master' into haroon_dev 1 day ago
Haroon6138 bb7c05493a Merge pull request 'fatima' (#157) from fatima into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/157
1 day ago
haroon amjad 169215fd7b translation changes 1 day ago
Fatimah.Alshammari 97a47ce4e8 Merge branch 'refs/heads/master' into fatima
# Conflicts:
#	lib/core/dependencies.dart
#	lib/routes/app_routes.dart
1 day ago
Fatimah.Alshammari 287e2b9562 fixed QR 1 day ago
Sultan khan 8b5c4d7575 Merge branch 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into dev_sultan
# Conflicts:
#	lib/core/dependencies.dart
#	lib/routes/app_routes.dart
2 days ago
Sultan khan 8c92df8648 contact us page fix 2 days ago
haroon amjad 8f428297cb Arabic translations added 2 days ago
Haroon6138 e9d3b3680a Merge pull request 'haroon_dev' (#156) from haroon_dev into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/156
2 days ago
haroon amjad a0008c9104 Nearest Appointment sorting fixed 2 days ago
Fatimah.Alshammari 1d224702ac Merge branch 'refs/heads/master' into fatima 2 days ago
Fatimah.Alshammari 69666a6f6c fixed button 2 days ago
haroon amjad 475a9b9acb Merge branch 'master' into haroon_dev 2 days ago
Haroon6138 06c67a0409 Merge pull request 'dev_aamir' (#153) from dev_aamir into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/153
2 days ago
Haroon6138 d1b1bbf777 Merge pull request 'dev_sultan' (#154) from dev_sultan into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/154
2 days ago
Sultan khan 0ddaa6899d Merge branch 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into dev_sultan
* 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New:
  fixed parking qr
  added parking part
  added monthly report
  added monthly report
  added monthly report
  fix error
  monthly report
  fix toggle
  fix toggle
  active medication
  active medication
  active medication
3 days ago
Sultan khan 42222804fd fix graph dot and bp graph. 3 days ago
aamir-csol bf210e664d Merge branch 'master' into dev_aamir 3 days ago
aamir-csol 6725ab028d doctor search filter design update & switch user bug fix. 3 days ago
haroon amjad 609ae6ab83 updates 3 days ago
haroon amjad 344adf23c0 Merge branch 'master' into haroon_dev
# Conflicts:
#	lib/core/dependencies.dart
#	lib/main.dart
#	lib/presentation/hmg_services/services_page.dart
#	lib/presentation/home/landing_page.dart
3 days ago
haroon amjad 44ce353dac updates 3 days ago
Haroon6138 b5753769b7 Merge pull request 'fatima' (#152) from fatima into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/152
3 days ago
Fatimah.Alshammari 250af1506c Merge branch 'master' into fatima
# Conflicts:
#	lib/core/dependencies.dart
#	lib/presentation/medical_file/medical_file_page.dart
#	lib/routes/app_routes.dart
#	lib/services/dialog_service.dart
#	lib/theme/colors.dart
3 days ago
haroon amjad fc750174fe Merge branch 'master' into haroon_dev 3 days ago
haroon amjad d848291930 updates 3 days ago
Haroon6138 aee496b7c3 Merge pull request 'dev_sultan' (#151) from dev_sultan into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/151
3 days ago
Sultan khan 16da0f4d0a Merge branch 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into dev_sultan 3 days ago
Sultan khan 8ee0e3b4ea no message 3 days ago
Sultan khan 0c68ca4438 Merge branch 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into dev_sultan
* 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New:
  Added 'send report to email' feature
  Completed the health Tracker Module, Only the email part is left.
  only explain api left.
  Triage Completed. Explain API left
  Till Triage Completed
  refactoring

# Conflicts:
#	lib/presentation/medical_file/medical_file_page.dart
3 days ago
haroon amjad e454c9c991 Merge branch 'master' into haroon_dev
# Conflicts:
#	lib/core/api_consts.dart
#	lib/core/dependencies.dart
3 days ago
Haroon6138 96ebc3c7e9 Merge pull request 'dev_aamir' (#149) from dev_aamir into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/149
3 days ago
Haroon6138 2240c6cc65 Merge pull request 'Health Trackers Feature (faiz_dev)' (#150) from faiz_dev into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/150
3 days ago
Sultan khan 0514716910 no message 3 days ago
Sultan khan e903f9c418 Merge branch 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into dev_sultan
* 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New:
  search filter on select doctor page.
  family file fix
  blood group
3 days ago
Sultan khan ac0d72b3ff vital sign finalized. 3 days ago
aamir-csol f62c7c9b20 Merge branch 'master' into dev_aamir 3 days ago
aamir-csol c11e859df1 search doctor by name filter. 3 days ago
haroon amjad 91c16f13d1 Merge branch 'master' into haroon_dev
# Conflicts:
#	lib/core/app_assets.dart
3 days ago
haroon amjad 1c0842ab95 updates 3 days ago
haroon amjad 02930a901e Indoor navigation implementation & Landing page swiper card updates 1 week ago
Fatimah.Alshammari 20e4f82df3 Merge branch 'master' into fatima
# Conflicts:
#	lib/core/dependencies.dart
#	lib/main.dart
#	lib/presentation/hmg_services/services_page.dart
#	lib/presentation/medical_file/medical_file_page.dart
#	lib/routes/app_routes.dart
1 week ago
Fatimah.Alshammari 8ae81d2b24 fixed parking qr 1 week ago
Sultan khan 34e8386ca1 Merge branch 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into dev_sultan 1 week ago
Sultan khan cc255e9c9a vital sign detail page 1 week ago
Fatimah.Alshammari 11de01e079 Merge branch 'refs/heads/master' into fatima
# Conflicts:
#	lib/presentation/hmg_services/services_page.dart
#	lib/routes/app_routes.dart
#	lib/theme/colors.dart
2 weeks ago
Fatimah.Alshammari 62bb667cb8 added parking part 2 weeks ago
Fatimah.Alshammari f3674ba06f Merge branch 'refs/heads/master' into fatima
# Conflicts:
#	lib/core/dependencies.dart
#	lib/presentation/hmg_services/services_page.dart
#	lib/routes/app_routes.dart
3 weeks ago
Fatimah.Alshammari a53602dc8c added monthly report 3 weeks ago
Fatimah.Alshammari 7a03242396 added monthly report 3 weeks ago
Fatimah.Alshammari 68f044de52 added monthly report 3 weeks ago
Fatimah.Alshammari c9de23347a fix error 1 month ago
Fatimah.Alshammari 190492a191 Merge branch 'refs/heads/master' into fatima
# Conflicts:
#	lib/routes/app_routes.dart
1 month ago
Fatimah.Alshammari 3d8daeb58d Merge branch 'refs/heads/master' into fatima
# Conflicts:
#	lib/core/app_assets.dart
#	lib/core/dependencies.dart
#	lib/core/utils/calendar_utils.dart
#	lib/features/hmg_services/models/ui_models/hmg_services_component_model.dart
#	lib/main.dart
#	lib/presentation/hmg_services/services_page.dart
#	lib/presentation/hmg_services/services_view.dart
#	lib/presentation/medical_file/medical_file_page.dart
#	lib/routes/app_routes.dart
#	lib/theme/colors.dart
#	pubspec.yaml
1 month ago
Fatimah.Alshammari 0b3fea230f monthly report 1 month ago
Fatimah.Alshammari 86a91ab383 Merge branch 'refs/heads/master' into fatima 2 months ago
Fatimah.Alshammari 89ff10f506 Merge branch 'refs/heads/master' into fatima
# Conflicts:
#	lib/core/dependencies.dart
#	lib/main.dart
#	lib/theme/colors.dart
2 months ago
Fatimah.Alshammari 8191852f4d Merge branch 'refs/heads/master' into fatima
# Conflicts:
#	lib/core/dependencies.dart
#	lib/main.dart
2 months ago
Fatimah.Alshammari e17d3cde87 fix toggle 2 months ago
Fatimah.Alshammari 77242825bb fix toggle 2 months ago
Fatimah.Alshammari 27ad4e0764 Merge branch 'refs/heads/master' into fatima
# Conflicts:
#	lib/core/utils/utils.dart
#	lib/presentation/emergency_services/call_ambulance/tracking_screen.dart
#	lib/presentation/home/landing_page.dart
2 months ago
Fatimah.Alshammari eae16eec44 active medication 2 months ago
Fatimah.Alshammari 3f123d12d6 Merge remote-tracking branch 'refs/remotes/origin/master' into fatima
# Conflicts:
#	lib/core/api_consts.dart
#	lib/core/utils/utils.dart
#	lib/main.dart
3 months ago
Fatimah.Alshammari de8c7bc605 active medication 3 months ago
Fatimah.Alshammari cb56503622 Merge remote-tracking branch 'refs/remotes/origin/master' into fatima 3 months ago
Fatimah.Alshammari e8319a0d3f active medication 3 months ago

@ -160,6 +160,7 @@ dependencies {
annotationProcessor("com.github.bumptech.glide:compiler:4.16.0") annotationProcessor("com.github.bumptech.glide:compiler:4.16.0")
implementation("com.mapbox.maps:android:11.5.0") implementation("com.mapbox.maps:android:11.5.0")
implementation("com.mapbox.mapboxsdk:mapbox-sdk-turf:7.3.1")
// implementation("com.mapbox.maps:android:11.4.0") // implementation("com.mapbox.maps:android:11.4.0")
// AARs // AARs

@ -21,7 +21,7 @@ class PenguinNavigator() {
val postToken = PostToken(clientID, clientKey) val postToken = PostToken(clientID, clientKey)
getToken(mContext, postToken, object : RefIdDelegate { getToken(mContext, postToken, object : RefIdDelegate {
override fun onRefByIDSuccess(PoiId: String?) { override fun onRefByIDSuccess(PoiId: String?) {
Log.e("navigateTo", "PoiId is+++++++ $PoiId") Log.e("navigateTo", "PoiId is+++++++ $refID")
PlugAndPlaySDK.navigateTo(mContext, refID, object : RefIdDelegate { PlugAndPlaySDK.navigateTo(mContext, refID, object : RefIdDelegate {
override fun onRefByIDSuccess(PoiId: String?) { override fun onRefByIDSuccess(PoiId: String?) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.98978 14.0362H21.2589C22.0592 14.0362 22.7076 13.3877 22.7076 12.5874C22.7076 11.7871 22.0592 11.1387 21.2589 11.1387H1.98978C1.18949 11.1387 0.541029 11.7871 0.541029 12.5874C0.541029 13.3877 1.18949 14.0362 1.98978 14.0362Z" fill="#2E3039"/>
<path d="M14.6241 20.8879C14.9764 20.8879 15.3299 20.7598 15.6087 20.5013L22.9973 13.6488C23.2952 13.3723 23.4638 12.9835 23.4609 12.5767C23.458 12.1704 23.2847 11.7833 22.9828 11.511L15.3914 4.65838C14.7974 4.12234 13.8812 4.16928 13.3451 4.76327C12.8091 5.35726 12.856 6.27345 13.45 6.80949L19.8663 12.601L13.6384 18.3769C13.0519 18.921 13.0171 19.8378 13.5613 20.4243C13.847 20.732 14.2347 20.8879 14.6241 20.8879Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 803 B

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.0102 14.0362H2.74111C1.94082 14.0362 1.29236 13.3877 1.29236 12.5874C1.29236 11.7871 1.94082 11.1387 2.74111 11.1387H22.0102C22.8105 11.1387 23.459 11.7871 23.459 12.5874C23.459 13.3877 22.8105 14.0362 22.0102 14.0362Z" fill="#2E3039"/>
<path d="M9.3759 20.8879C9.02357 20.8879 8.67007 20.7598 8.39133 20.5013L1.0027 13.6488C0.704836 13.3723 0.536202 12.9835 0.539099 12.5767C0.541997 12.1704 0.715267 11.7833 1.01719 11.511L8.60864 4.65838C9.20263 4.12234 10.1188 4.16928 10.6549 4.76327C11.1909 5.35726 11.144 6.27345 10.55 6.80949L4.13374 12.601L10.3616 18.3769C10.9481 18.921 10.9829 19.8378 10.4387 20.4243C10.153 20.732 9.76533 20.8879 9.3759 20.8879Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 800 B

@ -525,7 +525,7 @@
"payOnline": "الدفع عبر الإنترنت", "payOnline": "الدفع عبر الإنترنت",
"cancelOrder": "إلغاء الطلب", "cancelOrder": "إلغاء الطلب",
"confirmAddress": "تأكيد العنوان ", "confirmAddress": "تأكيد العنوان ",
"confirmLocation": "<EFBFBD><EFBFBD>أكيد الموقع ", "confirmLocation": "أكيد الموقع ",
"conditionsHMG": "الشروط والأحكام ", "conditionsHMG": "الشروط والأحكام ",
"conditions": "الشروط والأحكام لكوم", "conditions": "الشروط والأحكام لكوم",
"confirmDeleteMsg": "هل أنت متأكد! تريد الحذف ", "confirmDeleteMsg": "هل أنت متأكد! تريد الحذف ",
@ -694,11 +694,7 @@
"bikini": "بيكيني", "bikini": "بيكيني",
"totalMinutes": "إجمالي الدقائق", "totalMinutes": "إجمالي الدقائق",
"feedback": "ملاحظات", "feedback": "ملاحظات",
"send": "أرسل",
"status": "الحالة",
"likeToHear": "نود سماع ملاحظاتك، ومخاوفك بشأن خدمات الرعاية الصحية وتجربة الخدمات الإلكترونية. يرجى استخدام النموذج أدناه", "likeToHear": "نود سماع ملاحظاتك، ومخاوفك بشأن خدمات الرعاية الصحية وتجربة الخدمات الإلكترونية. يرجى استخدام النموذج أدناه",
"subject": "الموضوع",
"message": "رسالة",
"emptySubject": "يرجى إدخال الموضوع", "emptySubject": "يرجى إدخال الموضوع",
"emptyMessage": "يرجى إدخال الرسالة", "emptyMessage": "يرجى إدخال الرسالة",
"selectAttachment": "اختر المرفق", "selectAttachment": "اختر المرفق",
@ -877,5 +873,345 @@
"walkin": "زيارة بدون موعد", "walkin": "زيارة بدون موعد",
"laserClinic": "عيادة الليزر", "laserClinic": "عيادة الليزر",
"continueString": "يكمل", "continueString": "يكمل",
"covid_info": "تجري مستشفيات د. سليمان الحبيب فحص فيروس كورونا المستجد وتصدر شهادات السفر على مدار الساعة، طوال أيام الأسبوع، وبسرعة ودقة عالية. يمكن للراغبين في الاستفادة من هذه الخدمة زيارة أحد فروع مستشفيات د. سليمان الحبيب وإجراء فحص كورونا خلال بضع دقائق والحصول على النتائج خلال عدة ساعات خدمة فحص فيروس كورونا Covid 19 بتقنية PCR للكشف عن الفيروس وفقاً لأعلى المعايير العالمية وبأحدث أجهزة RT-PCR عالية الدقة (GeneXpert الأمريكي وغيره)، وهي طرق معتمدة من قبل هيئة الغذاء والدواء وكذلك من قبل المركز السعودي للوقاية من الأمراض المُعدية" "covid_info": "تجري مستشفيات د. سليمان الحبيب فحص فيروس كورونا المستجد وتصدر شهادات السفر على مدار الساعة، طوال أيام الأسبوع، وبسرعة ودقة عالية. يمكن للراغبين في الاستفادة من هذه الخدمة زيارة أحد فروع مستشفيات د. سليمان الحبيب وإجراء فحص كورونا خلال بضع دقائق والحصول على النتائج خلال عدة ساعات خدمة فحص فيروس كورونا Covid 19 بتقنية PCR للكشف عن الفيروس وفقاً لأعلى المعايير العالمية وبأحدث أجهزة RT-PCR عالية الدقة (GeneXpert الأمريكي وغيره)، وهي طرق معتمدة من قبل هيئة الغذاء والدواء وكذلك من قبل المركز السعودي للوقاية من الأمراض المُعدية",
"appointmentDetails": "تفاصيل الموعد",
"checkingDoctorAvailability": "جاري التحقق من توفر الطبيب...",
"cancellingAppointmentPleaseWait": "جاري إلغاء الموعد، يرجى الانتظار...",
"appointmentCancelledSuccessfully": "تم إلغاء الموعد بنجاح",
"notConfirmed": "غير مؤكد",
"appointmentStatus": "حالة الموعد",
"doctorWillCallYou": "سيتصل بك الطبيب عندما يقترب موعدك.",
"getDirections": "الحصول على الاتجاهات",
"notifyMeBeforeAppointment": "أبلغني قبل الموعد",
"fetchingLabResults": "جاري جلب نتائج المختبر...",
"fetchingRadiologyResults": "جاري جلب نتائج الأشعة...",
"fetchingAppointmentPrescriptions": "جاري جلب وصفات الموعد...",
"noPrescriptionsForAppointment": "ليس لديك أي وصفات طبية لهذا الموعد.",
"amountBeforeTax": "المبلغ قبل الضريبة",
"rebookAppointment": "إعادة حجز الموعد",
"fetchingDoctorSchedulePleaseWait": "جاري جلب جدول الطبيب، يرجى الانتظار...",
"pickADate": "اختر تاريخاً",
"confirmingAppointmentPleaseWait": "جاري تأكيد الموعد، يرجى الانتظار...",
"appointmentConfirmedSuccessfully": "تم تأكيد الموعد بنجاح",
"appointmentPayment": "دفع الموعد",
"checkingPaymentStatusPleaseWait": "جاري التحقق من حالة الدفع، يرجى الانتظار...",
"paymentFailedPleaseTryAgain": "فشل الدفع! يرجى المحاولة مرة أخرى.",
"appointmentCheckIn": "تسجيل حضور الموعد",
"insuranceExpiredOrInactive": "التأمين منتهي الصلاحية أو غير نشط",
"totalAmountToPay": "المبلغ الإجمالي المستحق",
"vat15": "ضريبة القيمة المضافة 15%",
"general": "عام",
"liveCare": "لايف كير",
"recentVisits": "الزيارات الأخيرة",
"searchByClinic": "البحث حسب العيادة",
"tapToSelectClinic": "انقر لاختيار العيادة",
"searchByDoctor": "البحث حسب الطبيب",
"tapToSelect": "انقر للاختيار",
"searchByRegion": "البحث حسب المنطقة",
"centralRegion": "المنطقة الوسطى",
"immediateConsultation": "استشارة فورية",
"scheduledConsultation": "استشارة مجدولة",
"pharmaLiveCare": "لايف كير الصيدلية",
"notSureHelpMeChooseClinic": "غير متأكد؟ ساعدني في اختيار عيادة!",
"mentionYourSymptomsAndFindDoctors": "اذكر أعراضك واعثر على قائمة الأطباء وفقاً لذلك",
"immediateService": "خدمة فورية",
"noNeedToWaitGetMedicalConsultation": "لا حاجة للانتظار، ستحصل على استشارة طبية فورية عبر مكالمة فيديو",
"noVisitRequired": "لا حاجة للزيارة",
"doctorWillContact": "سيتصل بك الطبيب",
"specialisedDoctorWillContactYou": "سيتصل بك طبيب متخصص وسيكون قادراً على الاطلاع على تاريخك الطبي",
"freeMedicineDelivery": "توصيل مجاني للأدوية",
"offersFreeMedicineDelivery": "يوفر توصيل مجاني للأدوية لموعد لايف كير",
"dentalChiefComplaints": "الشكاوى الرئيسة للأسنان",
"viewAvailableAppointments": "عرض المواعيد المتاحة",
"doctorProfile": "الملف للطبيب",
"waitingAppointment": "موعد الانتظار",
"hospitalInformation": "معلومات المستشفى",
"fetchingAppointmentShare": "جاري جلب تفاصيل الموعد...",
"bookingYourAppointment": "جاري حجز موعدك...",
"selectLiveCareClinic": "اختر عيادة لايف كير",
"checkingForExistingDentalPlan": "جاري التحقق من وجود خطة أسنان حالية، يرجى الانتظار...",
"dentalTreatmentPlan": "خطة علاج الأسنان",
"youHaveExistingTreatmentPlan": "لديك خطة علاج حالية: ",
"mins": "دقيقة",
"totalTimeRequired": "إجمالي الوقت المطلوب",
"wouldYouLikeToContinue": "هل تريد متابعتها؟",
"chooseDoctor": "اختر الطبيب",
"viewNearestAppos": "عرض أقرب المواعيد المتاحة",
"noDoctorFound": "لم يتم العثور على طبيب مطابق للمعايير المحددة...",
"yesPleasImInAHurry": "نعم من فضلك، أنا في عجلة من أمري",
"fetchingFeesPleaseWait": "جاري جلب الرسوم، يرجى الانتظار...",
"noThanksPhysicalVisit": "لا، شكراً. أفضل الزيارة الشخصية",
"offline": "غير متصل",
"videoCall": "مكالمة فيديو",
"liveVideoCallWithHMGDoctors": "مكالمة فيديو مباشرة مع أطباء مجموعة الحبيب الطبية",
"audioCall": "مكالمة صوتية",
"phoneCall": "مكالمة هاتفية",
"livePhoneCallWithHMGDoctors": "مكالمة هاتفية مباشرة مع أطباء مجموعة الحبيب الطبية",
"reviewLiveCareRequest": "مراجعة طلب لايف كير",
"selectedLiveCareType": "نوع لايف كير المحدد",
"selectLiveCareCallType": "اختر نوع مكالمة لايف كير",
"confirmingLiveCareRequest": "جاري تأكيد طلب لايف كير، يرجى الانتظار...",
"unknownErrorOccurred": "حدث خطأ غير معروف...",
"liveCarePermissionsMessage": "يتطلب لايف كير أذونات الكاميرا والميكروفون والموقع والإشعارات لتمكين الاستشارة الافتراضية بين المريض والطبيب، يرجى السماح بهذه الأذونات للمتابعة.",
"liveCarePayment": "دفع لايف كير",
"mada": "مدى",
"visaOrMastercard": "فيزا أو ماستركارد",
"tamara": "تمارا",
"fetchingApplePayDetails": "جاري جلب تفاصيل Apple Pay، يرجى الانتظار...",
"liveCarePendingRequest": "لايف كير حية معلق",
"callLiveCareSupport": "اتصل بدعم لايف كير",
"whatIsWaitingAppointment": "ما هو موعد الانتظار؟",
"waitingAppointmentsFeature": "تتيح لك ميزة مواعيد الانتظار حجز موعد أثناء تواجدك داخل مبنى المستشفى، وفي حال عدم توفر فتحة متاحة في جدول الطبيب.",
"appointmentWithDoctorConfirmed": "الموعد مع الطبيب مؤكد، ولكن وقت الدخول غير محدد.",
"paymentWithinTenMinutes": "ملاحظة: يجب عليك الدفع خلال 10 دقائق من الحجز، وإلا سيتم إلغاء موعدك تلقائياً",
"liveLocation": "الموقع المباشر",
"verifyYourLocationAtHospital": "تحقق من موقعك في المستشفى لتسجيل الحضور",
"error": "خطأ",
"ensureWithinHospitalLocation": "يرجى التأكد من أنك داخل موقع المستشفى لإجراء تسجيل الحضور عبر الإنترنت.",
"nfcNearFieldCommunication": "NFC (الاتصال قريب المدى)",
"scanPhoneViaNFC": "امسح هاتفك عبر لوحة NFC لتسجيل الحضور",
"qrCode": "رمز QR",
"scanQRCodeToCheckIn": "امسح رمز QR بالكاميرا لتسجيل الحضور",
"processingCheckIn": "جاري معالجة تسجيل الحضور...",
"bookingWaitingAppointment": "جاري حجز موعد الانتظار، يرجى الانتظار...",
"enterValidIDorIqama": "يرجى إدخال رقم هوية وطنية أو رقم ملف صالح",
"selectAppointment": "حدد الموعد",
"rebookSameDoctor": "أعد الحجز مع نفس الطبيب",
"queueing": "قائمة الانتظار",
"inQueue": "في قائمة الانتظار",
"yourTurn": "دورك",
"halaFirstName": "هلا {firstName}!!!",
"thankYouForPatience": "شكراً لصبرك، هذا هو رقم قائمة الانتظار الخاص بك.",
"servingNow": "يُخدم الآن",
"callForVitalSigns": "نداء للعلامات الحيوية",
"callForDoctor": "نداء للطبيب",
"thingsToAskDoctor": "أشياء تسأل طبيبك عنها اليوم",
"improveOverallHealth": "ماذا يمكنني أن أفعل لتحسين صحتي العامة؟",
"routineScreenings": "هل هناك أي فحوصات روتينية يجب أن أجريها؟",
"whatIsThisMedicationFor": "لماذا هذا الدواء؟",
"sideEffectsToKnow": "هل هناك أي آثار جانبية يجب أن أعرفها؟",
"whenFollowUp": "متى يجب أن أعود للمتابعة؟",
"goToHomepage": "الذهاب إلى الصفحة الرئيسية",
"appointmentsList": "قائمة المواعيد",
"allAppt": "جميع المواعيد",
"upcoming": "القادمة",
"completed": "المكتملة",
"noAppointmentsYet": "ليس لديك أي مواعيد بعد.",
"viewProfile": "عرض الملف الشخصي",
"choosePreferredHospitalForService": "اختر المستشفى المفضل لديك للخدمة",
"noHospitalsFound": "لم يتم العثور على مستشفيات",
"cancelOrderConfirmation": "هل أنت متأكد أنك تريد إلغاء هذا الطلب؟",
"orderCancelledSuccessfully": "تم إلغاء الطلب بنجاح",
"requestID": "معرف الطلب:",
"noCMCOrdersYet": "ليس لديك أي طلبات فحص شامل بعد.",
"cmcOrders": "طلبات الفحص الشامل",
"summary": "الملخص",
"selectedService": "الخدمة المحددة",
"requestSubmittedSuccessfully": "تم إرسال طلبك بنجاح.",
"hereIsYourRequestNumber": "هذا هو رقم طلبك #: ",
"pleaseSelectHospitalToContinue": "يرجى اختيار مستشفى للمتابعة",
"confirmSubmitRequest": "هل أنت متأكد أنك تريد إرسال هذا الطلب؟",
"pendingOrderWait": "لديك طلب معلق. يرجى الانتظار حتى تتم معالجته.",
"noServicesAvailable": "لا توجد خدمات متاحة",
"selectAService": "اختر خدمة",
"comprehensiveCheckup": "الفحص الشامل",
"viewNearestHMGLocations": "عرض أقرب مواقع مجموعة الحبيب الطبية",
"provideFeedbackOnServices": "قدم ملاحظاتك على خدماتنا",
"liveChatWithHMG": "خيار الدردشة المباشرة مع مجموعة الحبيب الطبية",
"send": "إرسال",
"status": "الحالة",
"sendingFeedback": "جاري إرسال الملاحظات...",
"selectFeedbackType": "اختر نوع الملاحظات",
"loadingAppointmentsList": "جاري تحميل قائمة المواعيد...",
"noAppointmentsForFeedback": "ليس لديك أي مواعيد لتقديم ملاحظات عنها.",
"selectedAppointment": "الموعد المحدد:",
"subject": "الموضوع",
"enterSubjectHere": "أدخل الموضوع هنا",
"message": "الرسالة",
"enterMessageHere": "أدخل الرسالة هنا",
"filesSelected": "تم تحديد {count} ملف(ات)",
"otherDetails": "تفاصيل أخرى",
"medicalReport": "التقرير الطبي",
"medicalReportNumber": "التقرير الطبي {number}",
"patientIsInsured": "المريض مؤمن عليه",
"insuranceDocument": "وثيقة التأمين",
"selectBranch": "اختر الفرع",
"patientInformation": "معلومات المريض",
"patientLocation": "أين يتواجد المريض",
"identificationNumber": "رقم الهوية",
"enterIdentificationNumber": "أدخل رقم الهوية*",
"patientName": "اسم المريض*",
"referralRequesterInformation": "معلومات مقدم طلب الإحالة",
"enterReferralRequesterName": "أدخل اسم مقدم طلب الإحالة*",
"requesterName": "اسم مقدم الطلب",
"relationship": "العلاقة",
"selectRelation": "اختر العلاقة",
"otherName": "اسم آخر",
"otherNameHint": "اسم آخر*",
"requesterNameRequired": "اسم مقدم طلب الإحالة مطلوب",
"selectRelationshipRequired": "يرجى اختيار العلاقة",
"otherRelationshipNameRequired": "اسم العلاقة الأخرى مطلوب",
"identificationNumberRequired": "رقم الهوية مطلوب",
"patientNameRequired": "اسم المريض مطلوب",
"enterPatientPhoneRequired": "يرجى إدخال رقم هاتف المريض",
"selectPatientCityRequired": "يرجى اختيار مدينة المريض",
"medicalReportRequired": "مطلوب تقرير طبي واحد على الأقل",
"selectBranchRequired": "يرجى اختيار الفرع",
"insuranceDocumentRequired": "وثيقة التأمين مطلوبة للمرضى المؤمن عليهم",
"searchResult": "نتيجة البحث",
"referralNo": "رقم الإحالة {number}",
"eReferral": "الإحالة الإلكترونية",
"referralCreatedSuccessfully": "تم إنشاء إحالتك بنجاح.",
"hereIsYourReferralNumber": "هذا هو رقم الإحالة الخاص بك #: ",
"searchEReferral": "البحث عن إحالة إلكترونية",
"enterRequiredInfoToSearch": "يرجى إدخال المعلومات المطلوبة للبحث عن إحالة إلكترونية",
"selectPickupDirection": "اختر اتجاه الاستلام",
"selectDirection": "اختر الاتجاه",
"toHospital": "إلى المستشفى",
"fromHospital": "من المستشفى",
"selectWay": "اختر الطريقة",
"oneWay": "اتجاه واحد",
"twoWay": "اتجاهين",
"selectPickupDetails": "اختر تفاصيل الاستلام",
"pleaseSelectDetailsOfPickup": " يرجى تحديد تفاصيل الاستلام",
"selectDetails": "اختر التفاصيل",
"work": "العمل",
"pick": "استلام",
"insideTheHome": "داخل المنزل",
"haveAnyAppointment": "هل لديك أي موعد",
"amountPaidAtHospital": "سيتم دفع المبلغ في المستشفى",
"submitRequest": "إرسال الطلب",
"enterPickupLocationManually": "أدخل موقع الاستلام يدوياً",
"enterPickupLocation": "أدخل موقع الاستلام",
"trackingDetails": "تفاصيل التتبع",
"cancelRequest": "إلغاء الطلب",
"shareLocationWhatsapp": "مشاركة موقعك المباشر على واتساب",
"pleaseWaitForCall": "يرجى انتظار المكالمة",
"toHospitalLower": "إلى المستشفى",
"contact": "اتصال",
"failed": "فشل",
"confirmationCall": "مكالمة التأكيد",
"pickupFromHome": "الاستلام من المنزل",
"onTheWayToHospital": " في الطريق إلى المستشفى",
"arrivedAtHospital": "وصل إلى المستشفى",
"orderCancel": "إلغاء الطلب",
"emergencyCheckIn": "تسجيل الطوارئ الإلكتروني",
"erOnlineCheckInDescription": "تتيح هذه الخدمة للمرضى تسجيل موعد الطوارئ قبل الوصول.",
"erOnlineCheckInSuccess": "تم تسجيل وصول الطوارئ بنجاح. الرجاء التوجه إلى منطقة الانتظار.",
"erOnlineCheckInError": "حدث خطأ غير متوقع أثناء عملية التسجيل. يرجى التواصل مع الدعم.",
"fetchingHospitalsList": "جاري جلب قائمة المستشفيات...",
"fetchingPaymentInformation": "جاري جلب معلومات الدفع...",
"erVisitDetails": "تفاصيل زيارة الطوارئ",
"erClinic": "عيادة الطوارئ",
"vatWithAmount": "الضريبة 15% ({amount})",
"erAppointmentBookedSuccess": "تم حجز موعدك بنجاح. يرجى إتمام إجراءات تسجيل الوصول عند وصولك إلى المستشفى.",
"underProcessing": "قيد المعالجة",
"canceledByPatient": "ملغى بواسطة المريض",
"rapidResponseTeam": "فريق الاستجابة السريع",
"allFacilities": "جميع المرافق",
"selectLocation": "اختر الموقع",
"pleaseSelectTheLocation": "يرجى اختيار الموقع",
"viewLocationGoogleMaps": "عرض الموقع على خرائط جوجل",
"callAmbulance": "استدعاء سيارة إسعاف",
"requestAmbulanceInEmergency": "طلب سيارة إسعاف في حالة الطوارئ من المنزل أو المستشفى",
"confirmation": "تأكيد",
"areYouSureYouWantToCallAmbulance": "هل أنت متأكد أنك تريد استدعاء سيارة إسعاف؟",
"getDetailsOfNearestBranch": "احصل على تفاصيل أقرب فرع بما في ذلك الاتجاهات",
"areYouSureYouWantToCallRRT": "هل أنت متأكد أنك تريد استدعاء فريق الاستجابة السريعة (RRT)؟",
"priorERCheckInToSkipLine": "تسجيل الوصول المسبق في الطوارئ لتجاوز الطابور والدفع في الاستقبال.",
"areYouSureYouWantToMakeERCheckIn": "هل أنت متأكد أنك تريد إجراء تسجيل وصول الطوارئ؟",
"checkingYourERAppointmentStatus": "جاري التحقق من حالة موعد الطوارئ الخاص بك...",
"transportOptions": "خيارات النقل",
"selectHospitalForAdvancePayment": "يرجى اختيار المستشفى الذي ترغب في دفع مبلغ مقدم له.",
"recharge": "إعادة الشحن",
"activityLevel": "مستوى النشاط",
"selectActivityLevel": "حدد مستوى النشاط",
"caloriesPerDay": "السعرات الحرارية في اليوم الواحد",
"dietType": "نوع النظام الغذائي",
"selectDietType": "حدد نوع النظام الغذائي",
"bodyFrameSize": "حجم إطار الجسم",
"selectBodyFrameSize": "حدد حجم إطار الجسم",
"averageCycleLength": "متوسط طول الدورة الشهرية (عادةً 28 يومًا)",
"averageLutealPhase": "متوسط طول المرحلة الأصفرية (عادةً 14 يومًا)",
"convert": "يتحول",
"calculate": "احسب",
"healthCalculators": "حاسبات الصحة",
"healthConverters": "محولات الصحة",
"generalHealth": "الصحة العامة",
"relatedToBMICalories": "متعلق بمؤشر كتلة الجسم والسعرات الحرارية ودهون الجسم وما إلى ذلك للبقاء على اطلاع دائم بصحتك.",
"selectCalculator": "اختر الآلة الحاسبة",
"womensHealth": "صحة المرأة",
"relatedToPeriodsOvulation": "متعلق بالدورة الشهرية والإباضة والحمل ومواضيع أخرى.",
"bloodSugar": "سكر الدم",
"trackYourGlucoseLevels": "تتبع مستويات الجلوكوز لديك، وفهم الاتجاهات، واحصل على رؤى مخصصة لصحة أفضل.",
"bloodCholesterol": "كوليسترول الدم",
"monitorCholesterolLevels": "راقب مستويات الكوليسترول، وقيّم مخاطر صحة القلب، واتخذ خطوات استباقية للرفاهية.",
"triglyceridesFatBlood": "الدهون الثلاثية في الدم",
"understandTriglyceridesImpact": "افهم تأثير الدهون الثلاثية على صحة القلب مع رؤى مخصصة وتوصيات الخبراء.",
"bmiCalculator": "حاسبة\nمؤشر كتلة الجسم",
"caloriesCalculator": "حاسبة\nالسعرات الحرارية",
"bmrCalculator": "حاسبة\nمعدل الأيض الأساسي",
"idealBodyWeight": "الوزن المثالي\nللجسم",
"bodyFatCalculator": "حاسبة\nدهون الجسم",
"carbsProteinFat": "الكربوهيدرات\nالبروتين والدهون",
"ovulationPeriod": "فترة\nالإباضة",
"deliveryDueDate": "تاريخ الولادة\nالمتوقع",
"low": "منخفض",
"preDiabetic": "ما قبل السكري",
"high": "مرتفع",
"elevated": "مرتفع قليلاً",
"recorded": "مسجل",
"noRecordsYet": "لا توجد سجلات بعد",
"lastRecord": "آخر سجل",
"addBloodSugar": "إضافة سكر الدم",
"addBloodPressure": "إضافة ضغط الدم",
"addWeight": "إضافة الوزن",
"bloodSugarDataSavedSuccessfully": "تم حفظ بيانات سكر الدم بنجاح",
"bloodPressureDataSavedSuccessfully": "تم حفظ بيانات ضغط الدم بنجاح",
"weightDataSavedSuccessfully": "تم حفظ بيانات الوزن بنجاح",
"pleaseWait": "يرجى الانتظار",
"selectUnit": "اختر الوحدة",
"selectMeasureTime": "اختر وقت القياس",
"selectArm": "اختر الذراع",
"enterBloodSugar": "أدخل سكر الدم",
"enterSystolicValue": "أدخل القيمة الانقباضية",
"enterDiastolicValue": "أدخل القيمة الانبساطية",
"enterWeight": "أدخل الوزن",
"selectDuration": "اختر المدة",
"systolic": "الانقباضي",
"diastolic": "الانبساطي",
"sendReportByEmail": "إرسال التقرير عبر البريد الإلكتروني",
"enterYourEmailToReceiveReport": "أدخل عنوان بريدك الإلكتروني لاستلام التقرير",
"addNewRecord": "إضافة سجل جديد",
"healthTrackers": "متتبعات الصحة",
"monitorBloodPressureLevels": "راقب مستويات ضغط الدم لديك، وتتبع القراءات الانقباضية والانبساطية، وحافظ على صحة قلبك.",
"trackWeightProgress": "تتبع تقدم وزنك، وضع الأهداف، وحافظ على كتلة جسم صحية من أجل العافية الشاملة.",
"bookAppointment": "حجز\nموعد",
"completeCheckup": "الفحص الشامل",
"indoorNavigation": "الملاحة الداخلية",
"eReferralServices": "خدمات الإحالة الإلكترونية",
"bloodDonation": "التبرع بالدم",
"dailyWaterMonitor": "مراقب الماء اليومي",
"fetchingYourWaterIntakeDetails": "جاري جلب تفاصيل استهلاك الماء الخاص بك.",
"healthCalculatorsServices": "حاسبات\nالصحة",
"healthConvertersServices": "محولات\nالصحة",
"smartWatchesServices": "الساعات\nالذكية",
"exploreServices": "استكشف الخدمات",
"medicalAndCareServices": "الخدمات الطبية والرعاية",
"hmgServices": "خدمات مجموعة الحبيب الطبية",
"personalServices": "الخدمات الشخصية",
"habibWallet": "محفظة الحبيب",
"loginToViewWalletBalance": "سجل الدخول لعرض رصيد محفظتك",
"recharge": "إعادة الشحن",
"loginToViewMedicalFile": "سجل الدخول لعرض ملفك الطبي",
"addMember": "إضافة عضو",
"addFamilyMember": "إضافة فرد من العائلة",
"pleaseFillBelowFieldToAddNewFamilyMember": "يرجى ملء الحقل أدناه لإضافة فرد جديد من العائلة إلى ملفك الشخصي",
"healthTools": "أدوات الصحة",
"supportServices": "خدمات الدعم",
"virtualTour": "جولة افتراضية",
"carParking": "موقف السيارات",
"latestNews": "آخر الأخبار",
"hmgContact": "اتصل بمجموعة الحبيب الطبية"
} }

@ -689,11 +689,7 @@
"bikini": "Bikini", "bikini": "Bikini",
"totalMinutes": "Total Minutes", "totalMinutes": "Total Minutes",
"feedback": "Feedback", "feedback": "Feedback",
"send": "أرسل",
"status": "الحالة",
"likeToHear": "We would love to hear the feedback, concerns on healthcare services and eServices experience. Please use the below form", "likeToHear": "We would love to hear the feedback, concerns on healthcare services and eServices experience. Please use the below form",
"subject": "الموضوع",
"message": "رسالة",
"emptySubject": "Please enter the subject", "emptySubject": "Please enter the subject",
"emptyMessage": "Please enter message", "emptyMessage": "Please enter message",
"selectAttachment": "Select Attachment", "selectAttachment": "Select Attachment",
@ -864,7 +860,7 @@
"endDate": "End Date", "endDate": "End Date",
"hmgHospitals": "HMG Hospitals", "hmgHospitals": "HMG Hospitals",
"hmcMedicalClinic": "HMC Medical Centers", "hmcMedicalClinic": "HMC Medical Centers",
"applyFilter": "AppLy Filter", "applyFilter": "Apply Filter",
"facilityAndLocation": "Facility and Location", "facilityAndLocation": "Facility and Location",
"regionAndLocation": "Region And Locations", "regionAndLocation": "Region And Locations",
"clearAllFilters": "Clear all filters", "clearAllFilters": "Clear all filters",
@ -873,5 +869,343 @@
"walkin": "Walk In", "walkin": "Walk In",
"continueString": "Continue", "continueString": "Continue",
"laserClinic": "Laser Clinic", "laserClinic": "Laser Clinic",
"covid_info" :"Dr. Sulaiman Al Habib hospitals are conducting a test for the emerging corona virus and issuing travel certificates 24/7 in a short time and with high accuracy. Those wishing to benefit from this service can visit one of Dr. Sulaiman Al Habib branches to conduct a corona test within few minutes, and obtain the result within several hours. Corona Virus Covid 19 testing service with PCR technology to detect the virus according to the highest international standards and with the latest high-precision RT-PCR devices (American GeneXpert and others), That is approved by the Food and Drug Authority as well as by the Saudi Center for Infectious Diseases Prevention." "covid_info" :"Dr. Sulaiman Al Habib hospitals are conducting a test for the emerging corona virus and issuing travel certificates 24/7 in a short time and with high accuracy. Those wishing to benefit from this service can visit one of Dr. Sulaiman Al Habib branches to conduct a corona test within few minutes, and obtain the result within several hours. Corona Virus Covid 19 testing service with PCR technology to detect the virus according to the highest international standards and with the latest high-precision RT-PCR devices (American GeneXpert and others), That is approved by the Food and Drug Authority as well as by the Saudi Center for Infectious Diseases Prevention.",
"appointmentDetails": "Appointment Details",
"checkingDoctorAvailability": "Checking doctor availability...",
"cancellingAppointmentPleaseWait": "Cancelling Appointment, Please Wait...",
"appointmentCancelledSuccessfully": "Appointment Cancelled Successfully",
"notConfirmed": "Not Confirmed",
"appointmentStatus": "Appointment Status",
"doctorWillCallYou": "The doctor will call you once the appointment time approaches.",
"getDirections": "Get Directions",
"notifyMeBeforeAppointment": "Notify me before the appointment",
"fetchingLabResults": "Fetching Lab Results...",
"fetchingRadiologyResults": "Fetching Radiology Results...",
"fetchingAppointmentPrescriptions": "Fetching Appointment Prescriptions...",
"noPrescriptionsForAppointment": "You don't have any prescriptions for this appointment.",
"amountBeforeTax": "Amount before tax",
"rebookAppointment": "Re-book Appointment",
"fetchingDoctorSchedulePleaseWait": "Fetching Doctor Schedule, Please Wait...",
"pickADate": "Pick a Date",
"confirmingAppointmentPleaseWait": "Confirming Appointment, Please Wait...",
"appointmentConfirmedSuccessfully": "Appointment Confirmed Successfully",
"appointmentPayment": "Appointment Payment",
"checkingPaymentStatusPleaseWait": "Checking payment status, Please wait...",
"paymentFailedPleaseTryAgain": "Payment Failed! Please try again.",
"appointmentCheckIn": "Appointment check in",
"insuranceExpiredOrInactive": "Insurance expired or inactive",
"totalAmountToPay": "Total amount to pay",
"vat15": "VAT 15%",
"general": "General",
"liveCare": "LiveCare",
"recentVisits": "Recent Visits",
"searchByClinic": "Search By Clinic",
"tapToSelectClinic": "Tap to select clinic",
"searchByDoctor": "Search By Doctor",
"tapToSelect": "Tap to select",
"searchByRegion": "Search By Region",
"centralRegion": "Central Region",
"immediateConsultation": "Immediate Consultation",
"scheduledConsultation": "Scheduled Consultation",
"pharmaLiveCare": "Pharma LiveCare",
"notSureHelpMeChooseClinic": "Not sure? help me choose a clinic!",
"mentionYourSymptomsAndFindDoctors": "Mention your symptoms and find the list of doctors accordingly",
"immediateService": "Immediate service",
"noNeedToWaitGetMedicalConsultation": "No need to wait, you will get medical consultation immediately via video call",
"noVisitRequired": "No visit required",
"doctorWillContact": "Doctor will contact",
"specialisedDoctorWillContactYou": "A specialised doctor will contact you and will be able to view your medical history",
"freeMedicineDelivery": "Free medicine delivery",
"offersFreeMedicineDelivery": "Offers free medicine delivery for the LiveCare appointment",
"dentalChiefComplaints": "Dental Chief Complaints",
"viewAvailableAppointments": "View available appointments",
"doctorProfile": "Doctor Profile",
"waitingAppointment": "Waiting Appointment",
"hospitalInformation": "Hospital Information",
"fetchingAppointmentShare": "Fetching Appointment Share...",
"bookingYourAppointment": "Booking your appointment...",
"selectLiveCareClinic": "Select LiveCare Clinic",
"checkingForExistingDentalPlan": "Checking for an existing dental plan, Please wait...",
"dentalTreatmentPlan": "Dental treatment plan",
"youHaveExistingTreatmentPlan": "You have an existing treatment plan: ",
"mins": "Mins",
"totalTimeRequired": "Total time required",
"wouldYouLikeToContinue": "Would you like to continue it?",
"chooseDoctor": "Choose Doctor",
"viewNearestAppos": "View nearest available appointments",
"noDoctorFound": "No Doctor found for selected criteria...",
"yesPleasImInAHurry": "Yes please, I am in a hurry",
"fetchingFeesPleaseWait": "Fetching fees, Please wait...",
"noThanksPhysicalVisit": "No, Thanks. I would like a physical visit",
"offline": "Offline",
"videoCall": "Video Call",
"liveVideoCallWithHMGDoctors": "Live Video Call with HMG Doctors",
"audioCall": "Audio Call",
"phoneCall": "Phone Call",
"livePhoneCallWithHMGDoctors": "Live Phone Call with HMG Doctors",
"reviewLiveCareRequest": "Review LiveCare Request",
"selectedLiveCareType": "Selected LiveCare Type",
"selectLiveCareCallType": "Select LiveCare call type",
"confirmingLiveCareRequest": "Confirming LiveCare request, Please wait...",
"unknownErrorOccurred": "Unknown error occurred...",
"liveCarePermissionsMessage": "LiveCare requires Camera, Microphone, Location & Notifications permissions to enable virtual consultation between patient & doctor, Please allow these to proceed.",
"liveCarePayment": "LiveCare Payment",
"mada": "Mada",
"visaOrMastercard": "Visa or Mastercard",
"tamara": "Tamara",
"fetchingApplePayDetails": "Fetching Apple Pay details, Please wait...",
"liveCarePendingRequest": "LiveCare Pending Request",
"callLiveCareSupport": "Call LiveCare Support",
"whatIsWaitingAppointment": "What is Waiting Appointment?",
"waitingAppointmentsFeature": "The waiting appointments feature allows you to book an appointment while you are inside the hospital building, and in case there is no available slot in the doctor's schedule.",
"appointmentWithDoctorConfirmed": "The appointment with the doctor is confirmed, but the time of entry is uncertain.",
"paymentWithinTenMinutes": "Note: You must have to pay within 10 minutes of booking, otherwise your appointment will be cancelled automatically",
"liveLocation": "Live Location",
"verifyYourLocationAtHospital": "Verify your location to be at hospital to check in",
"error": "Error",
"ensureWithinHospitalLocation": "Please ensure you're within the hospital location to perform online check-in.",
"nfcNearFieldCommunication": "NFC (Near Field Communication)",
"scanPhoneViaNFC": "Scan your phone via NFC board to check in",
"qrCode": "QR Code",
"scanQRCodeToCheckIn": "Scan QR code with your camera to check in",
"processingCheckIn": "Processing Check-In...",
"bookingWaitingAppointment": "Booking Waiting Appointment, Please wait...",
"enterValidIDorIqama": "Please enter a valid national ID or file number",
"selectAppointment": "Select Appointment",
"rebookSameDoctor": "Rebook with same doctor",
"queueing": "Queueing",
"inQueue": "In Queue",
"yourTurn": "Your Turn",
"halaFirstName": "Hala {firstName}!!!",
"thankYouForPatience": "Thank you for your patience, here is your queue number.",
"servingNow": "Serving Now",
"callForVitalSigns": "Call for vital signs",
"callForDoctor": "Call for Doctor",
"thingsToAskDoctor": "Things to ask your doctor today",
"improveOverallHealth": "What can I do to improve my overall health?",
"routineScreenings": "Are there any routine screenings I should get?",
"whatIsThisMedicationFor": "What is this medication for?",
"sideEffectsToKnow": "Are there any side effects I should know about?",
"whenFollowUp": "When should I come back for a follow-up?",
"goToHomepage": "Go to homepage",
"appointmentsList": "Appointments List",
"allAppt": "All Appt.",
"upcoming": "Upcoming",
"completed": "Completed",
"noAppointmentsYet": "You don't have any appointments yet.",
"viewProfile": "View Profile",
"choosePreferredHospitalForService": "Choose your preferred hospital for the service",
"noHospitalsFound": "No hospitals Found",
"cancelOrderConfirmation": "Are you sure you want to cancel this order?",
"orderCancelledSuccessfully": "Order has been cancelled successfully",
"requestID": "Request ID:",
"noCMCOrdersYet": "You don't have any CMC orders yet.",
"cmcOrders": "CMC Orders",
"summary": "Summary",
"selectedService": "Selected Service",
"requestSubmittedSuccessfully": "Your request has been successfully submitted.",
"hereIsYourRequestNumber": "Here is your request #: ",
"pleaseSelectHospitalToContinue": "Please select a hospital to continue",
"confirmSubmitRequest": "Are you sure you want to submit this request?",
"pendingOrderWait": "You have a pending order. Please wait for it to be processed.",
"noServicesAvailable": "No services available",
"selectAService": "Select a Service",
"comprehensiveCheckup": "Comprehensive Checkup",
"viewNearestHMGLocations": "View your nearest HMG locations",
"provideFeedbackOnServices": "Provide your feedback on our services",
"liveChatWithHMG": "Live chat option with HMG",
"send": "Send",
"status": "Status",
"sendingFeedback": "Sending Feedback...",
"selectFeedbackType": "Select Feedback Type",
"loadingAppointmentsList": "Loading appointments list...",
"noAppointmentsForFeedback": "You do not have any appointments to submit a feedback.",
"selectedAppointment": "Selected Appointment:",
"subject": "Subject",
"enterSubjectHere": "Enter subject here",
"message": "Message",
"enterMessageHere": "Enter message here",
"filesSelected": "{count} file(s) selected",
"otherDetails": "Other Details",
"medicalReport": "Medical Report",
"medicalReportNumber": "Medical Report {number}",
"patientIsInsured": "Patient is Insured",
"insuranceDocument": "Insurance Document",
"selectBranch": "Select Branch",
"patientInformation": "Patient information",
"patientLocation": "Where the patient located",
"identificationNumber": "Identification Number",
"enterIdentificationNumber": "Enter Identification Number*",
"patientName": "Patient Name*",
"referralRequesterInformation": "Referral requester information",
"enterReferralRequesterName": "Enter Referral Requester Name*",
"requesterName": "Requester Name",
"relationship": "Relationship",
"selectRelation": "Select Relation",
"otherName": "Other Name",
"otherNameHint": "Other Name*",
"requesterNameRequired": "Referral requester name is required",
"selectRelationshipRequired": "Please select a relationship",
"otherRelationshipNameRequired": "Other relationship name is required",
"identificationNumberRequired": "Identification number is required",
"patientNameRequired": "Patient name is required",
"enterPatientPhoneRequired": "Please Enter patient phone number",
"selectPatientCityRequired": "Please select patient city",
"medicalReportRequired": "At least one medical report is required",
"selectBranchRequired": "Please select a branch",
"insuranceDocumentRequired": "Insurance document is required for insured patients",
"searchResult": "Search Result",
"referralNo": "Referral No {number}",
"eReferral": "E Referral",
"referralCreatedSuccessfully": "Your Referral has been created Successfully.",
"hereIsYourReferralNumber": "Here is your Referral #: ",
"searchEReferral": "Search E-Referral",
"enterRequiredInfoToSearch": "Please enter the required information to search for an e-referral",
"selectPickupDirection": "Select Pickup Direction",
"selectDirection": "Select Direction",
"toHospital": "To Hospital",
"fromHospital": "From Hospital",
"selectWay": "Select Way",
"oneWay": "One Way",
"twoWay": "Two Way",
"selectPickupDetails": "Select Pickup Details",
"pleaseSelectDetailsOfPickup": " Please select the details of pickup",
"selectDetails": "Select Details",
"work": "Work",
"pick": "Pick",
"insideTheHome": "Inside the home",
"haveAnyAppointment": "Have any appointment",
"amountPaidAtHospital": "Amount will be paid at the hospital",
"submitRequest": "Submit Request",
"enterPickupLocationManually": "Enter Pickup Location Manually",
"enterPickupLocation": "Enter Pickup Location",
"trackingDetails": "Tracking Details",
"cancelRequest": "Cancel Request",
"shareLocationWhatsapp": "Share Your Live Location on Whatsapp",
"pleaseWaitForCall": "Please wait for the call",
"toHospitalLower": "to hospital",
"contact": "Contact",
"failed": "Failed",
"confirmationCall": "Confirmation Call",
"pickupFromHome": "Pickup Up from Home",
"onTheWayToHospital": " On The Way To Hospital",
"arrivedAtHospital": "Arrived at Hospital",
"orderCancel": "Order Cancel",
"emergencyCheckIn": "Emergency Check-In",
"erOnlineCheckInDescription": "This service lets patients register their ER appointment prior to arrival.",
"erOnlineCheckInSuccess": "Your ER Online Check-In has been successfully done. Please proceed to the waiting area.",
"erOnlineCheckInError": "Unexpected error occurred during check-in. Please contact support.",
"fetchingHospitalsList": "Fetching hospitals list...",
"fetchingPaymentInformation": "Fetching payment information...",
"erVisitDetails": "ER Visit Details",
"erClinic": "ER Clinic",
"vatWithAmount": "VAT 15% ({amount})",
"erAppointmentBookedSuccess": "Your appointment has been booked successfully. Please perform Check-In once you arrive at the hospital.",
"underProcessing": "Under processing",
"canceledByPatient": "Cancelled by patient",
"rapidResponseTeam": "Rapid Response Team",
"allFacilities": "All Facilities",
"selectLocation": "Select Location",
"pleaseSelectTheLocation": "Please select the location",
"viewLocationGoogleMaps": "View Location on Google Maps",
"callAmbulance": "Call Ambulance",
"requestAmbulanceInEmergency": "Request an ambulance in emergency from home or hospital",
"confirmation": "Confirmation",
"areYouSureYouWantToCallAmbulance": "Are you sure you want to call an ambulance?",
"getDetailsOfNearestBranch": "Get the details of nearest branch including directions",
"areYouSureYouWantToCallRRT": "Are you sure you want to call Rapid Response Team (RRT)?",
"priorERCheckInToSkipLine": "Prior ER Check-In to skip the line & payment at the reception.",
"areYouSureYouWantToMakeERCheckIn": "Are you sure you want to make ER Check-In?",
"checkingYourERAppointmentStatus": "Checking your ER Appointment status...",
"transportOptions": "Transport Options",
"selectHospitalForAdvancePayment": "Please select the hospital you want to make an advance payment for.",
"recharge": "Recharge",
"activityLevel": "Activity Level",
"selectActivityLevel": "Select Activity Level",
"caloriesPerDay": "Calories Per Day",
"dietType": "Diet Type",
"selectDietType": "Select Diet Type",
"bodyFrameSize": "Body Frame Size",
"selectBodyFrameSize": "Select Body Frame Size",
"averageCycleLength": "Average Cycle Length (Usually 28 days)",
"averageLutealPhase": "Average Luteal Phase Length(Usually 14 days)",
"convert": "Convert",
"calculate": "Calculate",
"healthCalculators": "Health Calculators",
"healthConverters": "Health Converters",
"generalHealth": "General Health",
"relatedToBMICalories": "Related To BMI, calories, body fat, etc to stay updated with your health.",
"selectCalculator": "Select Calculator",
"womensHealth": "Women's Health",
"relatedToPeriodsOvulation": "Related To periods, ovulation, pregnancy, and other topics.",
"bloodSugar": "Blood Sugar",
"trackYourGlucoseLevels": "Track your glucose levels, understand trends, and get personalized insights for better health.",
"bloodCholesterol": "Blood Cholesterol",
"monitorCholesterolLevels": "Monitor cholesterol levels, assess heart health risks, and take proactive steps for well-being.",
"triglyceridesFatBlood": "Triglycerides Fat Blood",
"understandTriglyceridesImpact": "Understand triglycerides' impact on heart health with personalized insights and expert recommendations.",
"bmiCalculator": "BMI\nCalculator",
"caloriesCalculator": "Calories\nCalculator",
"bmrCalculator": "BMR\nCalculator",
"idealBodyWeight": "Ideal Body\nWeight",
"bodyFatCalculator": "Body Fat\nCalculator",
"carbsProteinFat": "Carbs\nProtein & Fat",
"ovulationPeriod": "Ovulation\nPeriod",
"deliveryDueDate": "Delivery\nDue Date",
"low": "Low",
"preDiabetic": "Pre-diabetic",
"high": "High",
"elevated": "Elevated",
"recorded": "Recorded",
"noRecordsYet": "No records yet",
"lastRecord": "Last Record",
"addBloodSugar": "Add Blood Sugar",
"addBloodPressure": "Add Blood Pressure",
"addWeight": "Add Weight",
"bloodSugarDataSavedSuccessfully": "Blood Sugar Data saved successfully",
"bloodPressureDataSavedSuccessfully": "Blood Pressure Data saved successfully",
"weightDataSavedSuccessfully": "Weight Data saved successfully",
"pleaseWait": "Please wait",
"selectUnit": "Select Unit",
"selectMeasureTime": "Select Measure Time",
"selectArm": "Select Arm",
"enterBloodSugar": "Enter Blood Sugar",
"enterSystolicValue": "Enter Systolic Value",
"enterDiastolicValue": "Enter Diastolic Value",
"enterWeight": "Enter Weight",
"selectDuration": "Select Duration",
"systolic": "Systolic",
"diastolic": "Diastolic",
"sendReportByEmail": "Send Report by Email",
"enterYourEmailToReceiveReport": "Enter your email address to receive the report",
"addNewRecord": "Add new Record",
"healthTrackers": "Health Trackers",
"monitorBloodPressureLevels": "Monitor your blood pressure levels, track systolic and diastolic readings, and maintain a healthy heart.",
"trackWeightProgress": "Track your weight progress, set goals, and maintain a healthy body mass for overall wellness.",
"bookAppointment": "Book\nAppointment",
"completeCheckup": "Complete Checkup",
"indoorNavigation": "Indoor Navigation",
"eReferralServices": "E-Referral Services",
"dailyWaterMonitor": "Daily Water Monitor",
"fetchingYourWaterIntakeDetails": "Fetching your water intake details.",
"healthCalculatorsServices": "Health\nCalculators",
"healthConvertersServices": "Health\nConverters",
"smartWatchesServices": "Smart\nWatches",
"exploreServices": "Explore Services",
"medicalAndCareServices": "Medical & Care Services",
"hmgServices": "HMG Services",
"personalServices": "Personal Services",
"habibWallet": "Habib Wallet",
"loginToViewWalletBalance": "Login to view your wallet balance",
"loginToViewMedicalFile": "Login to view your medical file",
"addMember": "Add Member",
"addFamilyMember": "Add Family Member",
"pleaseFillBelowFieldToAddNewFamilyMember": "Please fill the below field to add a new family member to your profile",
"healthTools": "Health Tools",
"supportServices": "Support Services",
"virtualTour": "Virtual Tour",
"carParking": "Car Parking",
"latestNews": "Latest News",
"hmgContact": "HMG Contact"
} }

@ -14,7 +14,7 @@ class PenguinNavigator {
} }
func navigateToPOI( referenceId:String,completion: @escaping (Bool, String?) -> Void) { func navigateToPOI( referenceId:String,completion: @escaping (Bool, String?) -> Void) {
PenNavUIManager.shared.getToken(clientID: config.clientID, clientKey: config.clientKey, showProgress: true) { [weak self] token, error in PenNavUIManager.shared.getToken(clientID: config.clientID, clientKey: config.clientKey, showProgress: false) { [weak self] token, error in
if let error = error { if let error = error {
let errorMessage = "Token error while getting the for Navigate to method" let errorMessage = "Token error while getting the for Navigate to method"

@ -312,6 +312,8 @@ class PenguinView: NSObject, FlutterPlatformView, PIEventsDelegate, PenNavInitia
print("====== after eventsDelegate onPenNavSuccess =========") print("====== after eventsDelegate onPenNavSuccess =========")
PenNavUIManager.shared.navigate(to: "108")
@ -385,21 +387,21 @@ class PenguinView: NSObject, FlutterPlatformView, PIEventsDelegate, PenNavInitia
self?.handleNavigation(clinicID: clinicID, token: token) { success, errorMessage in // self?.handleNavigation(clinicID: clinicID, token: token) { success, errorMessage in
//
if success { // if success {
//
print("Navigation successful") // print("Navigation successful")
//
} else { // } else {
//
print("Navigation failed: \(errorMessage ?? "Unknown error")") // print("Navigation failed: \(errorMessage ?? "Unknown error")")
//
} // }
//
//
//
} // }

@ -19,7 +19,7 @@ abstract class ApiClient {
Future<void> post( Future<void> post(
String endPoint, { String endPoint, {
required dynamic body, required Map<String, dynamic> body,
required Function(dynamic response, int statusCode, {int? messageStatus, String? errorMessage}) onSuccess, required Function(dynamic response, int statusCode, {int? messageStatus, String? errorMessage}) onSuccess,
required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure, required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure,
bool isAllowAny, bool isAllowAny,

@ -151,6 +151,7 @@ var GET_FINDUS_REQUEST = 'Services/Lists.svc/REST/Get_HMG_Locations';
///LiveChat ///LiveChat
var GET_LIVECHAT_REQUEST = 'Services/Patients.svc/REST/GetPatientICProjects'; var GET_LIVECHAT_REQUEST = 'Services/Patients.svc/REST/GetPatientICProjects';
var GET_LIVECHAT_REQUEST_ID = 'Services/Patients.svc/REST/Patient_ICChatRequest_Insert';
///babyInformation ///babyInformation
var GET_BABYINFORMATION_REQUEST = 'Services/Community.svc/REST/GetBabyByUserID'; var GET_BABYINFORMATION_REQUEST = 'Services/Community.svc/REST/GetBabyByUserID';
@ -207,7 +208,7 @@ var GET_APPOINTMENT_DETAILS_BY_NO = 'Services/MobileNotifications.svc/REST/GetAp
var NEW_RATE_APPOINTMENT_URL = "Services/Doctors.svc/REST/AppointmentsRating_InsertAppointmentRate"; var NEW_RATE_APPOINTMENT_URL = "Services/Doctors.svc/REST/AppointmentsRating_InsertAppointmentRate";
var NEW_RATE_DOCTOR_URL = "Services/Doctors.svc/REST/DoctorsRating_InsertDoctorRate"; var NEW_RATE_DOCTOR_URL = "Services/Doctors.svc/REST/DoctorsRating_InsertDoctorRate";
var GET_QR_PARKING = 'Services/SWP.svc/REST/GetQRParkingByID'; //var GET_QR_PARKING = 'Services/SWP.svc/REST/GetQRParkingByID';
//URL to get clinic list //URL to get clinic list
var GET_CLINICS_LIST_URL = "Services/lists.svc/REST/GetClinicCentralized"; var GET_CLINICS_LIST_URL = "Services/lists.svc/REST/GetClinicCentralized";
@ -398,6 +399,22 @@ var GET_COVID_DRIVETHRU_PROCEDURES_LIST = 'Services/Doctors.svc/REST/COVID19_Get
var GET_PATIENT_LAST_RECORD = 'Services/Patients.svc/REST/Med_GetPatientLastRecord'; var GET_PATIENT_LAST_RECORD = 'Services/Patients.svc/REST/Med_GetPatientLastRecord';
var INSERT_PATIENT_HEALTH_DATA = 'Services/Patients.svc/REST/Med_InsertTransactions'; var INSERT_PATIENT_HEALTH_DATA = 'Services/Patients.svc/REST/Med_InsertTransactions';
///Push Notifications
var GET_ALL_NOTIFICATIONS = 'Services/MobileNotifications.svc/REST/PushNotification_GetAllNotifications';
///My Trackers
var GET_DIABETIC_RESULT_AVERAGE = 'Services/Patients.svc/REST/Patient_GetDiabeticResultAverage';
var GET_DIABTEC_RESULT = 'Services/Patients.svc/REST/Patient_GetDiabtecResults';
var ADD_DIABTEC_RESULT = 'Services/Patients.svc/REST/Patient_AddDiabtecResult';
var GET_BLOOD_PRESSURE_RESULT_AVERAGE = 'Services/Patients.svc/REST/Patient_GetBloodPressureResultAverage';
var GET_BLOOD_PRESSURE_RESULT = 'Services/Patients.svc/REST/Patient_GetBloodPressureResult';
var ADD_BLOOD_PRESSURE_RESULT = 'Services/Patients.svc/REST/Patient_AddBloodPressureResult';
var GET_WEIGHT_PRESSURE_RESULT_AVERAGE = 'Services/Patients.svc/REST/Patient_GetWeightMeasurementResultAverage';
var GET_WEIGHT_PRESSURE_RESULT = 'Services/Patients.svc/REST/Patient_GetWeightMeasurementResult';
var ADD_WEIGHT_PRESSURE_RESULT = 'Services/Patients.svc/REST/Patient_AddWeightMeasurementResult';
var ADD_ACTIVE_PRESCRIPTIONS_REPORT_BY_PATIENT_ID = 'Services/Patients.svc/Rest/GetActivePrescriptionReportByPatientID'; var ADD_ACTIVE_PRESCRIPTIONS_REPORT_BY_PATIENT_ID = 'Services/Patients.svc/Rest/GetActivePrescriptionReportByPatientID';
var GET_CALL_INFO_HOURS_RESULT = 'Services/Doctors.svc/REST/GetCallInfoHoursResult'; var GET_CALL_INFO_HOURS_RESULT = 'Services/Doctors.svc/REST/GetCallInfoHoursResult';
@ -658,6 +675,8 @@ const FAMILY_FILES = 'Services/Authentication.svc/REST/GetAllSharedRecordsByStat
var GET_PRESCRIPTION_INSTRUCTIONS_PDF = 'Services/ChatBot_Service.svc/REST/Chatbot_SendMedicationInstructionByWhatsApp'; var GET_PRESCRIPTION_INSTRUCTIONS_PDF = 'Services/ChatBot_Service.svc/REST/Chatbot_SendMedicationInstructionByWhatsApp';
const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard';
class ApiConsts { class ApiConsts {
static const maxSmallScreen = 660; static const maxSmallScreen = 660;
@ -785,6 +804,11 @@ class ApiConsts {
static final String getAllSharedRecordsByStatus = 'Services/Authentication.svc/REST/GetAllSharedRecordsByStatus'; static final String getAllSharedRecordsByStatus = 'Services/Authentication.svc/REST/GetAllSharedRecordsByStatus';
static final String removeFileFromFamilyMembers = 'Services/Authentication.svc/REST/ActiveDeactive_PatientFile'; static final String removeFileFromFamilyMembers = 'Services/Authentication.svc/REST/ActiveDeactive_PatientFile';
static final String acceptAndRejectFamilyFile = 'Services/Authentication.svc/REST/Update_FileStatus'; static final String acceptAndRejectFamilyFile = 'Services/Authentication.svc/REST/Update_FileStatus';
static final String getActivePrescriptionsDetails = 'Services/Patients.svc/Rest/GetActivePrescriptionReportByPatientID';
static final String getTermsConditions = 'Services/Patients.svc/Rest/GetUserTermsAndConditions';
static final String getMonthlyReports = 'Services/Patients.svc/Rest/UpdatePateintHealthSummaryReport';
static final String updatePatientEmail = 'Services/Patients.svc/Rest/UpdatePateintEmail';
static final String getQrParkingDetails = 'Services/SWP.svc/REST/GetQRParkingByID';
// Ancillary Order Apis // Ancillary Order Apis
static final String getOnlineAncillaryOrderList = 'Services/Doctors.svc/REST/GetOnlineAncillaryOrderList'; static final String getOnlineAncillaryOrderList = 'Services/Doctors.svc/REST/GetOnlineAncillaryOrderList';

@ -225,6 +225,9 @@ class AppAssets {
static const String trade_down_red = '$svgBasePath/trade_down_red.svg'; static const String trade_down_red = '$svgBasePath/trade_down_red.svg';
static const String pharmacy_icon = '$svgBasePath/phramacy_icon.svg'; static const String pharmacy_icon = '$svgBasePath/phramacy_icon.svg';
static const String forward_top_nav_icon = '$svgBasePath/forward_top_nav_icon.svg';
static const String back_top_nav_icon = '$svgBasePath/back_top_nav_icon.svg';
//bottom navigation// //bottom navigation//
static const String homeBottom = '$svgBasePath/home_bottom.svg'; static const String homeBottom = '$svgBasePath/home_bottom.svg';
static const String bookAppoBottom = '$svgBasePath/book_appo_bottom.svg'; static const String bookAppoBottom = '$svgBasePath/book_appo_bottom.svg';
@ -349,3 +352,4 @@ class AppAnimations {
static const String ambulanceAlert = '$lottieBasePath/ambulance_alert.json'; static const String ambulanceAlert = '$lottieBasePath/ambulance_alert.json';
static const String rrtAmbulance = '$lottieBasePath/rrt_ambulance.json'; static const String rrtAmbulance = '$lottieBasePath/rrt_ambulance.json';
} }

@ -10,6 +10,8 @@ import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_repo.
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart'; import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.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/active_prescriptions/active_prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/models/active_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/common/common_repo.dart'; import 'package:hmg_patient_app_new/features/common/common_repo.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_repo.dart'; import 'package:hmg_patient_app_new/features/contact_us/contact_us_repo.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';
@ -33,17 +35,21 @@ import 'package:hmg_patient_app_new/features/medical_file/medical_file_repo.dart
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/monthly_report/monthly_report_repo.dart'; import 'package:hmg_patient_app_new/features/monthly_report/monthly_report_repo.dart';
import 'package:hmg_patient_app_new/features/monthly_report/monthly_report_view_model.dart'; import 'package:hmg_patient_app_new/features/monthly_report/monthly_report_view_model.dart';
import 'package:hmg_patient_app_new/features/monthly_reports/monthly_reports_repo.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart'; import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.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';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_repo.dart'; import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_repo.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart'; import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
import 'package:hmg_patient_app_new/features/notifications/notifications_repo.dart';
import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_repo.dart'; import 'package:hmg_patient_app_new/features/payfort/payfort_repo.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart'; import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart'; import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/features/qr_parking/qr_parking_repo.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart'; import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart'; import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_provider.dart'; import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_provider.dart';
@ -55,6 +61,7 @@ import 'package:hmg_patient_app_new/features/water_monitor/water_monitor_repo.da
import 'package:hmg_patient_app_new/features/water_monitor/water_monitor_view_model.dart'; import 'package:hmg_patient_app_new/features/water_monitor/water_monitor_view_model.dart';
import 'package:hmg_patient_app_new/presentation/health_trackers/health_trackers_view_model.dart'; import 'package:hmg_patient_app_new/presentation/health_trackers/health_trackers_view_model.dart';
import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart';
import 'package:hmg_patient_app_new/presentation/monthly_reports/monthly_reports_page.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart'; import 'package:hmg_patient_app_new/services/cache_service.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/services/error_handler_service.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart';
@ -68,8 +75,14 @@ import 'package:local_auth/local_auth.dart';
import 'package:logger/web.dart'; import 'package:logger/web.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import '../features/monthly_reports/monthly_reports_repo.dart';
import '../features/qr_parking/qr_parking_view_model.dart';
import '../presentation/health_calculators_and_converts/health_calculator_view_model.dart'; import '../presentation/health_calculators_and_converts/health_calculator_view_model.dart';
import '../features/active_prescriptions/active_prescriptions_repo.dart';
import '../features/monthly_reports/terms_conditions_repo.dart';
import '../features/monthly_reports/terms_conditions_view_model.dart';
GetIt getIt = GetIt.instance; GetIt getIt = GetIt.instance;
class AppDependencies { class AppDependencies {
@ -147,6 +160,13 @@ class AppDependencies {
getIt.registerLazySingleton<MyInvoicesRepo>(() => MyInvoicesRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt())); getIt.registerLazySingleton<MyInvoicesRepo>(() => MyInvoicesRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<HealthTrackersRepo>(() => HealthTrackersRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt())); getIt.registerLazySingleton<HealthTrackersRepo>(() => HealthTrackersRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<MonthlyReportRepo>(() => MonthlyReportRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt())); getIt.registerLazySingleton<MonthlyReportRepo>(() => MonthlyReportRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<ActivePrescriptionsRepo>(() => ActivePrescriptionsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<TermsConditionsRepo>(() => TermsConditionsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerFactory<TermsConditionsViewModel>(() => TermsConditionsViewModel(termsConditionsRepo: getIt<TermsConditionsRepo>(), errorHandlerService: getIt<ErrorHandlerService>(),
),);
getIt.registerLazySingleton<MonthlyReportsRepo>(() => MonthlyReportsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<QrParkingRepo>(() => QrParkingRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<NotificationsRepo>(() => NotificationsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels // ViewModels
// Global/shared VMs LazySingleton // Global/shared VMs LazySingleton
@ -265,14 +285,27 @@ class AppDependencies {
getIt.registerLazySingleton<WaterMonitorViewModel>(() => WaterMonitorViewModel(waterMonitorRepo: getIt(), errorHandlerService: getIt())); getIt.registerLazySingleton<WaterMonitorViewModel>(() => WaterMonitorViewModel(waterMonitorRepo: getIt(), errorHandlerService: getIt()));
//commenting this because its already define there was on run time error because of this.
getIt.registerLazySingleton<MyInvoicesViewModel>(() => MyInvoicesViewModel(myInvoicesRepo: getIt(), errorHandlerService: getIt(), navServices: getIt())); getIt.registerLazySingleton<MyInvoicesViewModel>(() => MyInvoicesViewModel(myInvoicesRepo: getIt(), errorHandlerService: getIt(), navServices: getIt()));
getIt.registerLazySingleton<MonthlyReportViewModel>(() => MonthlyReportViewModel(errorHandlerService: getIt(), monthlyReportRepo: getIt())); getIt.registerLazySingleton<MonthlyReportViewModel>(() => MonthlyReportViewModel(errorHandlerService: getIt(), monthlyReportRepo: getIt()));
getIt.registerLazySingleton<MyInvoicesViewModel>(() => MyInvoicesViewModel(
myInvoicesRepo: getIt(), getIt.registerLazySingleton<NotificationsViewModel>(() => NotificationsViewModel(notificationsRepo: getIt(), errorHandlerService: getIt()));
errorHandlerService: getIt(),
navServices: getIt(),
));
getIt.registerLazySingleton<HealthTrackersViewModel>(() => HealthTrackersViewModel(healthTrackersRepo: getIt(), errorHandlerService: getIt())); getIt.registerLazySingleton<HealthTrackersViewModel>(() => HealthTrackersViewModel(healthTrackersRepo: getIt(), errorHandlerService: getIt()));
getIt.registerLazySingleton<ActivePrescriptionsViewModel>(
() => ActivePrescriptionsViewModel(
errorHandlerService: getIt(),
activePrescriptionsRepo: getIt()
),
);
// getIt.registerFactory<QrParkingViewModel>(
// () => QrParkingViewModel(
// qrParkingRepo: getIt<QrParkingRepo>(),
// errorHandlerService: getIt<ErrorHandlerService>(),
// cacheService: getIt<CacheService>(),
// ),
// );
} }
} }

@ -0,0 +1,316 @@
import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:io';
import 'dart:ui';
import 'package:device_calendar/device_calendar.dart';
import 'package:flutter/widgets.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_reminder_view.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/permission_service.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:jiffy/jiffy.dart';
import 'package:manage_calendar_events/manage_calendar_events.dart' as ios;
import 'package:permission_handler/permission_handler.dart';
import 'package:timezone/data/latest.dart' as tzl;
final DeviceCalendarPlugin deviceCalendarPlugin = DeviceCalendarPlugin();
final ios.CalendarPlugin _myPlugin = ios.CalendarPlugin();
class CalendarUtils {
static Completer<CalendarUtils>? _completer;
dynamic get writableCalendars => calendars.firstWhere((c) => !c.isReadOnly!);
dynamic calendars;
CalendarUtils._(this.calendars);
// static Future<CalendarUtils> getInstance() async {
// if (_completer == null) {
// _completer = Completer<CalendarUtils>();
// print(_completer!.isCompleted);
// try {
// final dynamic calendarsResult;
// if (Platform.isIOS) {
// calendarsResult = await _myPlugin.getCalendars();
// if (!_completer!.isCompleted) {
// _completer?.complete(CalendarUtils._(await calendarsResult!));
// }
// } else {
// calendarsResult = await deviceCalendarPlugin.retrieveCalendars();
// if (!_completer!.isCompleted) {
// _completer?.complete(CalendarUtils._(await calendarsResult.data!));
// }
// }
// } on Exception catch (e) {
// if (!_completer!.isCompleted) {
// _completer!.completeError(e);
// }
// }
// }
// return _completer!.future;
// }
static Future<CalendarUtils> getInstance() async {
tzl.initializeTimeZones();
if (_completer != null) {
return _completer!.future;
}
_completer = Completer<CalendarUtils>();
try {
final dynamic calendarsResult;
if (Platform.isIOS) {
calendarsResult = await _myPlugin.getCalendars();
_completer!.complete(CalendarUtils._(calendarsResult));
} else {
calendarsResult = await deviceCalendarPlugin.retrieveCalendars();
_completer!.complete(CalendarUtils._(calendarsResult.data));
}
} catch (e) {
_completer!.completeError(e);
}
return _completer!.future;
}
Future createOrUpdateEvents({List<DateTime>? scheduleList, String? title, String? description, List<DateTime>? scheduleDateTime, List<DayOfWeek>? daysOfWeek}) async {
tzl.initializeTimeZones();
List<Event> events = [];
Location _currentLocation;
if (DateTime.now().timeZoneName == "+04")
_currentLocation = getLocation('Asia/Dubai');
else
_currentLocation = getLocation('Asia/Riyadh');
scheduleDateTime!.forEach((element) {
RecurrenceRule recurrenceRule = RecurrenceRule(
// RecurrenceFrequency.Daily,
// daysOfWeek: daysOfWeek,
// endDate: element,
until: element, frequency: Frequency.daily,
);
//added byAamir Tz Time
Event event = Event(writableCalendars!.id,
recurrenceRule: recurrenceRule,
start: TZDateTime.from(element, _currentLocation),
end: TZDateTime.from(element.add(Duration(minutes: 30)), _currentLocation),
title: title,
description: description);
events.add(event);
});
events.forEach((element) {
deviceCalendarPlugin.createOrUpdateEvent(element);
});
}
Future createOrUpdateEvent({required String title, required String description, required String location, DateTime? scheduleDateTime, String? eventId}) async {
RecurrenceRule recurrenceRule = RecurrenceRule(
// RecurrenceFrequency.Daily,
// daysOfWeek: daysOfWeek,
// endDate: scheduleDateTime,
until: scheduleDateTime, frequency: Frequency.daily,
);
Location _currentLocation;
// if (DateTime.now().timeZoneName == "+04")
// _currentLocation = getLocation('Asia/Dubai');
// else
_currentLocation = getLocation('Asia/Riyadh');
TZDateTime scheduleDateTimeUTZ = TZDateTime.from(scheduleDateTime!, _currentLocation);
print("writableCalendars-name: " + writableCalendars.name);
print("writableCalendars-Id: " + writableCalendars.id);
print("writableCalendarsToString: " + writableCalendars.toString());
print("writableCalendarsToString: " + writableCalendars!.id!);
Event event = Event(
writableCalendars!.id,
start: scheduleDateTimeUTZ,
end: scheduleDateTimeUTZ.add(Duration(minutes: 30)),
title: title,
description: description,
);
ios.CalendarEvent iosCalEvent =
ios.CalendarEvent(location: location, startDate: scheduleDateTimeUTZ, endDate: scheduleDateTimeUTZ.add(Duration(minutes: 30)), title: title, description: description, isAllDay: false);
if (Platform.isAndroid) {
Result<bool> result = await deviceCalendarPlugin.hasPermissions();
print(result);
await deviceCalendarPlugin.createOrUpdateEvent(event).catchError((e) {
print("catchError " + e.toString());
}).whenComplete(() {
print("whenComplete Calender ID " + eventId!);
});
} else {
await _myPlugin.createEvent(calendarId: writableCalendars.id!, event: iosCalEvent).catchError((e) {
print("catchError " + e.toString());
}).whenComplete(() {
print("whenComplete Calender ID iOS " + eventId!);
});
}
}
deleteEvent(String _calendarId, String _eventId) async {
if (Platform.isIOS) {
await _myPlugin.deleteEvent(calendarId: _calendarId, eventId: _eventId);
} else {
await deviceCalendarPlugin.deleteEvent(_calendarId, _eventId);
}
}
Future retrieveEvents(
String calendarId,
RetrieveEventsParams retrieveEventsParams,
) async {
if (Platform.isIOS) {
return await _myPlugin.getEvents(calendarId: calendarId);
} else {
return await deviceCalendarPlugin.retrieveEvents(calendarId, retrieveEventsParams);
}
}
Future createCalendar(
String calendarName, {
Color? calendarColor,
String? localAccountName,
}) async {
return await deviceCalendarPlugin.createCalendar(calendarName, calendarColor: calendarColor, localAccountName: localAccountName);
}
}
Future<Map<Permission, PermissionStatus>> requestPermissions() async {
var permissionResults = [Permission.calendarFullAccess].request();
return permissionResults;
}
showReminderBottomSheet(BuildContext context, DateTime dateTime, String doctorName, String eventId, String appoDateFormatted, String appoTimeFormatted,
{required Function() onSuccess, String? title, String? description, Function(int)? onMultiDateSuccess, bool isMultiAllowed = false}) async {
if (Platform.isAndroid) {
if (await PermissionService.isCalendarPermissionEnabled()) {
_showReminderBottomSheet(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted,
onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed);
} else {
// Utils.showPermissionConsentDialog(context, TranslationBase.of(context).calendarPermission, () async {
// if (await Permission.calendarFullAccess.request().isGranted) {
// _showReminderDialog(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted,
// onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed);
// }
// });
}
} else {
if (await Permission.calendarWriteOnly.request().isGranted) {
if (await Permission.calendarFullAccess.request().isGranted) {
_showReminderBottomSheet(context, dateTime, doctorName, eventId, appoDateFormatted, appoTimeFormatted,
onSuccess: onSuccess, title: title, description: description, onMultiDateSuccess: onMultiDateSuccess, isMultiAllowed: isMultiAllowed);
}
}
}
}
Future<void> _showReminderBottomSheet(BuildContext providedContext, DateTime dateTime, String doctorName, String eventId, String appoDateFormatted, String appoTimeFormatted,
{required Function onSuccess, String? title, String? description, Function(int)? onMultiDateSuccess, bool? isMultiAllowed}) async {
showCommonBottomSheetWithoutHeight(providedContext, title: "Set the timer of reminder".needTranslation, child: PrescriptionReminderView(
setReminder: (int value) async {
if (!isMultiAllowed!) {
if (onMultiDateSuccess == null) {
CalendarUtils calendarUtils = await CalendarUtils.getInstance();
await calendarUtils.createOrUpdateEvent(
title: title ?? "You have appointment with Dr. ".needTranslation + doctorName,
description: description ?? "At " + appoDateFormatted + " " + appoTimeFormatted,
scheduleDateTime: dateTime,
eventId: eventId,
location: '');
onSuccess();
}
} else {
onMultiDateSuccess!(value);
}
},
), callBackFunc: () {}, isFullScreen: false);
}
setCalender(BuildContext context,
{required String eventId, required int selectedMinutes, int? frequencyNumber, required int days, required String orderDate, required String itemDescriptionN, required String route}) async {
DateTime actualDate = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 8, 0);
frequencyNumber ??= 2; //Some time frequency number is null so by default will be 2
int remainingDays = days - (Jiffy.parseFromDateTime(DateTime.now()).diff(Jiffy.parseFromDateTime(DateUtil.convertStringToDate(orderDate)), unit: Unit.day) as int);
if (remainingDays.isNegative) {
getIt.get<DialogService>().showErrorBottomSheet(message: "Prescription date has been already passed you can not add a reminder for this prescription.");
return;
}
CalendarUtils calendarUtils = await CalendarUtils.getInstance();
try {
for (int i = 0; i < remainingDays; i++) {
//event for number of days.
for (int j = 0; j < frequencyNumber; j++) {
// event for number of times per day.
if (j != 0) {
actualDate.add(new Duration(hours: 8)); // 8 hours addition for daily dose.
}
//Time subtraction from actual reminder time. like before 30, or 1 hour.
actualDate = Jiffy.parseFromDateTime(actualDate).subtract(minutes: selectedMinutes).dateTime;
calendarUtils.createOrUpdateEvent(
title: "$itemDescriptionN} Prescription Reminder",
description: "$itemDescriptionN $frequencyNumber $route ",
scheduleDateTime: actualDate,
eventId: eventId + (i.toString() + j.toString()),
location: '', //event id with varitions
);
print("Creating event #$j for day $i$actualDate");
actualDate = DateTime(actualDate.year, actualDate.month, actualDate.day, 8, 0);
}
actualDate = Jiffy.parseFromDateTime(actualDate).add(days: 1).dateTime;
}
} catch (ex) {
getIt.get<DialogService>().showErrorBottomSheet(message: "catch:$ex");
}
}
Future<void> checkAndRemove(hasReminder, {bool delete = false, String itemDescriptionN = ""}) async {
final ios.CalendarPlugin _myPlugin = ios.CalendarPlugin();
CalendarUtils calendarUtils = await CalendarUtils.getInstance();
DateTime startEventsDate = Jiffy.parseFromDateTime(DateTime.now()).subtract(days: 30).dateTime;
DateTime endEventsDate = Jiffy.parseFromDateTime(DateTime.now()).add(days: 120).dateTime;
RetrieveEventsParams params = RetrieveEventsParams(startDate: startEventsDate, endDate: endEventsDate);
if (calendarUtils.calendars != null) {
if (Platform.isAndroid) {
await processEvents(calendarUtils.calendars, calendarUtils, params, delete, itemDescriptionN, hasReminder);
} else {
List<ios.Calendar>? iosCalendars = await _myPlugin.getCalendars();
if (iosCalendars != null) {
await processEvents(iosCalendars.map((cal) => Calendar(id: cal.id, name: cal.name, accountName: cal.accountName)).toList(), calendarUtils, params, delete, itemDescriptionN, hasReminder);
}
}
}
}
Future<void> processEvents(List<Calendar> calendars, calendarUtils, params, delete, String itemDescriptionN, hasReminder) async {
for (var calendar in calendars) {
Result<UnmodifiableListView<Event>> events = await calendarUtils.retrieveEvents(calendar.id!, params);
for (var event in events.data!) {
if (event.title!.contains(itemDescriptionN)) {
if (delete) {
await calendarUtils.deleteEvent(calendar, event);
// AppToast.showSuccessToast(message: TranslationBase.of(context).reminderCancelSuccess);
hasReminder = false;
} else {
hasReminder = false;
// setState(() {
// hasReminder = true;
// });
}
}
}
}
}

@ -3,6 +3,7 @@ import 'dart:async';
import 'package:device_calendar_plus/device_calendar_plus.dart'; import 'package:device_calendar_plus/device_calendar_plus.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:jiffy/jiffy.dart' show Jiffy; import 'package:jiffy/jiffy.dart' show Jiffy;
import 'package:manage_calendar_events/manage_calendar_events.dart' hide Calendar;
class CalenderUtilsNew { class CalenderUtilsNew {
final DeviceCalendar calender = DeviceCalendar.instance; final DeviceCalendar calender = DeviceCalendar.instance;

@ -43,7 +43,7 @@ class Utils {
{ {
"Desciption": "Sahafa Hospital", "Desciption": "Sahafa Hospital",
"DesciptionN": "مستشفى الصحافة", "DesciptionN": "مستشفى الصحافة",
"ID": 1, "ID": 1, // Campus ID
"LegalName": "Sahafa Hospital", "LegalName": "Sahafa Hospital",
"LegalNameN": "مستشفى الصحافة", "LegalNameN": "مستشفى الصحافة",
"Name": "Sahafa Hospital", "Name": "Sahafa Hospital",
@ -55,19 +55,20 @@ class Utils {
"IsActive": true, "IsActive": true,
"IsHmg": true, "IsHmg": true,
"IsVidaPlus": false, "IsVidaPlus": false,
"Latitude": "24.8113774", "Latitude": "24.8111548",
"Longitude": "46.6239813", "Longitude": "46.6217912",
"MainProjectID": 130, "MainProjectID": 130,
"ProjectOutSA": false, "ProjectOutSA": false,
"UsingInDoctorApp": false "UsingInDoctorApp": false,
"IsHMC": false
},{ },{
"Desciption": "Jeddah Hospital", "Desciption": "Jeddah Fayhaa Hospital",
"DesciptionN": "مستشفى الصحافة", "DesciptionN": "مستشفى جدة الفيحاء",
"ID": 3, "ID": 3, // Campus ID
"LegalName": "Jeddah Hospital", "LegalName": "Jeddah Fayhaa Hospital",
"LegalNameN": "مستشفى الصحافة", "LegalNameN": "مستشفى جدة الفيحاء",
"Name": "Jeddah Hospital", "Name": "Jeddah Fayhaa Hospital",
"NameN": "مستشفى الصحافة", "NameN": "مستشفى جدة الفيحاء",
"PhoneNumber": "+966115222222", "PhoneNumber": "+966115222222",
"SetupID": "013311", "SetupID": "013311",
"DistanceInKilometers": 0, "DistanceInKilometers": 0,
@ -75,11 +76,12 @@ class Utils {
"IsActive": true, "IsActive": true,
"IsHmg": true, "IsHmg": true,
"IsVidaPlus": false, "IsVidaPlus": false,
"Latitude": "24.8113774", "Latitude": "21.5086703",
"Longitude": "46.6239813", "Longitude": "39.2121855",
"MainProjectID": 130, "MainProjectID": 130,
"ProjectOutSA": false, "ProjectOutSA": false,
"UsingInDoctorApp": false "UsingInDoctorApp": false,
"IsHMC": false
} }
]; ];

@ -0,0 +1,65 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/models/active_prescriptions_response_model.dart';
import '../../core/api/api_client.dart';
import '../../core/api_consts.dart';
import '../../core/common_models/generic_api_model.dart';
import '../../core/exceptions/api_failure.dart';
import '../../services/logger_service.dart';
abstract class ActivePrescriptionsRepo {
Future<Either<Failure, GenericApiModel<List<ActivePrescriptionsResponseModel>>>> getActivePrescriptionsDetails();
}
class ActivePrescriptionsRepoImp implements ActivePrescriptionsRepo {
final ApiClient apiClient;
final LoggerService loggerService;
ActivePrescriptionsRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<ActivePrescriptionsResponseModel>>>> getActivePrescriptionsDetails() async
{
try {
GenericApiModel<List<ActivePrescriptionsResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getActivePrescriptionsDetails,
body: {},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
var list = response['List_ActiveGetPrescriptionReportByPatientID'];
var res = list
.map<ActivePrescriptionsResponseModel>(
(item) => ActivePrescriptionsResponseModel.fromJson(item))
.toList();
apiResponse = GenericApiModel<List<ActivePrescriptionsResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
// data: response,
data: res
);
return 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()));
}
}
}

@ -0,0 +1,101 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/models/active_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/active_prescriptions_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class ActivePrescriptionsViewModel extends ChangeNotifier {
late ActivePrescriptionsRepo activePrescriptionsRepo;
late ErrorHandlerService errorHandlerService;
List<ActivePrescriptionsResponseModel> activePrescriptionsDetailsList = [];
ActivePrescriptionsViewModel({
required this.activePrescriptionsRepo,
required this.errorHandlerService,
});
Future<void> getActiveMedications({
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
final result =
await activePrescriptionsRepo.getActivePrescriptionsDetails();
result.fold(
(failure) async =>
await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 1) {
activePrescriptionsDetailsList = apiResponse.data ?? [];
notifyListeners();
if (onSuccess != null) onSuccess(apiResponse.data);
}
},
);
}
DateTime parseDate(String? date) {
if (date == null) return DateTime.now();
final regex = RegExp(r"\/Date\((\d+)([+-]\d+)?\)\/");
final match = regex.firstMatch(date);
if (match != null) {
final millis = int.parse(match.group(1)!);
return DateTime.fromMillisecondsSinceEpoch(millis);
}
return DateTime.tryParse(date) ?? DateTime.now();
}
List<DateTime> generateMedicationDays(ActivePrescriptionsResponseModel med) {
final start = parseDate(med.startDate);
final duration = med.days ?? 0;
if (duration <= 0) return [];
final f = (med.frequency ?? "").toLowerCase().trim();
int intervalDays = 1;
if (f.contains("every six hours") ||
f.contains("every 6 hours") ||
f.contains("every four hours") ||
f.contains("every 4 hours") ||
f.contains("every eight hours") ||
f.contains("every 8 hours") ||
f.contains("every 12 hours") ||
f.contains("every twelve hours") ||
f.contains("every 24 hours") ||
f.contains("3 times a day") ||
f.contains("once a day")) {
intervalDays = 1;
}
else if (f.contains("once a week")) {
intervalDays = 7;
}
else if (f.contains("every 3 days")) {
intervalDays = 3;
}
else if (f.contains("every other day")) {
intervalDays = 2;
}
List<DateTime> result = [];
for (int offset = 0; offset < duration; offset += intervalDays) {
result.add(start.add(Duration(days: offset)));
}
return result;
}
bool sameYMD(DateTime a, DateTime b) =>
a.year == b.year && a.month == b.month && a.day == b.day;
List<ActivePrescriptionsResponseModel> getMedsForSelectedDay(
DateTime selectedDate) {
final clean = DateTime(selectedDate.year, selectedDate.month, selectedDate.day);
return activePrescriptionsDetailsList.where((med) {
final days = generateMedicationDays(med);
return days.any((d) => sameYMD(d, clean));
}).toList();
}
}

@ -0,0 +1,78 @@
class ActivePrescriptionsResponseModel {
String? itemId;
String? itemDescription;
String? route;
String? frequency;
int? frequencyNumber;
int? doseDailyQuantity;
int? days;
String? startDate;
String? endDate;
String? orderDate;
String? productImageString;
bool isReminderOn;
List<String?> selectedDoseTimes = [];
ActivePrescriptionsResponseModel({
this.itemId,
this.itemDescription,
this.route,
this.frequency,
this.frequencyNumber,
this.doseDailyQuantity,
this.days,
this.startDate,
this.endDate,
this.orderDate,
this.productImageString,
this.isReminderOn = false,
List<String?>? selectedDoseTimes,
}) {
this.selectedDoseTimes = selectedDoseTimes ?? [];
}
/// ========== JSON FROM ==========
factory ActivePrescriptionsResponseModel.fromJson(Map<String, dynamic> json) {
return ActivePrescriptionsResponseModel(
itemId: json["ItemID"]?.toString() ?? "",
itemDescription: json["ItemDescription"] ?? "",
route: json["Route"] ?? "",
frequency: json["Frequency"] ?? "",
frequencyNumber: json["FrequencyNumber"],
doseDailyQuantity: json["DoseDailyQuantity"] ?? 1,
days: json["Days"] ?? 0,
startDate: json["StartDate"] ?? "",
endDate: json["EndDate"] ?? "",
orderDate: json["OrderDate"] ?? "",
productImageString: json["ProductImageString"] ?? "",
isReminderOn: json["IsReminderOn"] == true,
selectedDoseTimes:
(json["SelectedDoseTimes"] as List<dynamic>?)
?.map((e) => e?.toString())
.toList() ??
[],
);
}
/// ========== JSON TO ==========
Map<String, dynamic> toJson() {
return {
"ItemID": itemId,
"ItemDescription": itemDescription,
"Route": route,
"Frequency": frequency,
"FrequencyNumber": frequencyNumber,
"DoseDailyQuantity": doseDailyQuantity,
"Days": days,
"StartDate": startDate,
"EndDate": endDate,
"OrderDate": orderDate,
"ProductImageString": productImageString,
"IsReminderOn": isReminderOn,
"SelectedDoseTimes": selectedDoseTimes,
};
}
}

@ -246,7 +246,6 @@ class AuthenticationViewModel extends ChangeNotifier {
} }
Future<void> _handleNewImeiRegistration() async { Future<void> _handleNewImeiRegistration() async {
await selectDeviceImei(onSuccess: (dynamic respData) async { await selectDeviceImei(onSuccess: (dynamic respData) async {
try { try {
if (respData != null) { if (respData != null) {
@ -461,6 +460,12 @@ class AuthenticationViewModel extends ChangeNotifier {
bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true || _appState.getUserRegistrationPayload.patientOutSa == 1); bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true || _appState.getUserRegistrationPayload.patientOutSa == 1);
MyAppointmentsViewModel myAppointmentsVM = getIt<MyAppointmentsViewModel>(); MyAppointmentsViewModel myAppointmentsVM = getIt<MyAppointmentsViewModel>();
if (isSwitchUser && _appState.getSuperUserID == null) {
nationalIdController.text = responseID.toString();
}else if( isSwitchUser && _appState.getSuperUserID != null){
nationalIdController.text = _appState.getSuperUserID.toString();
}
final request = RequestUtils.getCommonRequestWelcome( final request = RequestUtils.getCommonRequestWelcome(
phoneNumber: phoneNumberController.text, phoneNumber: phoneNumberController.text,
otpTypeEnum: otpTypeEnum, otpTypeEnum: otpTypeEnum,
@ -761,14 +766,14 @@ class AuthenticationViewModel extends ChangeNotifier {
phoneNumberController.text = (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0") phoneNumberController.text = (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0")
? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "") ? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "")
: _appState.getAuthenticatedUser()!.mobileNumber)!; : _appState.getAuthenticatedUser()!.mobileNumber)!;
nationalIdController.text = _appState.getAuthenticatedUser()!.nationalityId!; nationalIdController.text = _appState.getAuthenticatedUser()!.patientIdentificationNo!;
onSuccess(); onSuccess();
} else if ((loginTypeEnum == LoginTypeEnum.sms || loginTypeEnum == LoginTypeEnum.whatsapp && _appState.getSelectDeviceByImeiRespModelElement == null) && } else if ((loginTypeEnum == LoginTypeEnum.sms || loginTypeEnum == LoginTypeEnum.whatsapp && _appState.getSelectDeviceByImeiRespModelElement == null) &&
_appState.getAuthenticatedUser() != null) { _appState.getAuthenticatedUser() != null) {
phoneNumberController.text = (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0") phoneNumberController.text = (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0")
? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "") ? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "")
: _appState.getAuthenticatedUser()!.mobileNumber)!; : _appState.getAuthenticatedUser()!.mobileNumber)!;
nationalIdController.text = _appState.getAuthenticatedUser()!.nationalityId!; nationalIdController.text = _appState.getAuthenticatedUser()!.patientIdentificationNo!;
onSuccess(); onSuccess();
} }
} }

@ -53,6 +53,9 @@ class BookAppointmentsViewModel extends ChangeNotifier {
int? calculationID = 0; int? calculationID = 0;
bool isSortByClinic = true; bool isSortByClinic = true;
// Accordion expansion state
int? expandedGroupIndex;
int initialSlotDuration = 0; int initialSlotDuration = 0;
bool isNearestAppointmentSelected = false; bool isNearestAppointmentSelected = false;
@ -158,13 +161,65 @@ class BookAppointmentsViewModel extends ChangeNotifier {
bool isBodyPartsLoading = false; bool isBodyPartsLoading = false;
int duration = 0; int duration = 0;
setIsSortByClinic(bool value) { setIsSortByClinic(bool value) {
isSortByClinic = value; isSortByClinic = value;
doctorsListGrouped = isSortByClinic ? doctorsListByClinic : doctorsListByHospital; doctorsListGrouped = isSortByClinic ? doctorsListByClinic : doctorsListByHospital;
notifyListeners(); notifyListeners();
} }
// Toggle accordion expansion
void toggleGroupExpansion(int index) {
if (expandedGroupIndex == index) {
expandedGroupIndex = null;
} else {
expandedGroupIndex = index;
}
notifyListeners();
}
// Reset accordion expansion
void resetGroupExpansion() {
expandedGroupIndex = null;
notifyListeners();
}
// Sort filtered doctor list by clinic or hospital
void sortFilteredDoctorList(bool sortByClinic) {
isSortByClinic = sortByClinic;
if (sortByClinic) {
// Sort by clinic name
filteredDoctorList.sort((a, b) {
final clinicA = (a.clinicName ?? 'Unknown').toLowerCase();
final clinicB = (b.clinicName ?? 'Unknown').toLowerCase();
return clinicA.compareTo(clinicB);
});
} else {
// Sort by hospital/project name
filteredDoctorList.sort((a, b) {
final hospitalA = (a.projectName ?? 'Unknown').toLowerCase();
final hospitalB = (b.projectName ?? 'Unknown').toLowerCase();
return hospitalA.compareTo(hospitalB);
});
}
notifyListeners();
}
// Group filtered doctors list for accordion display
List<List<DoctorsListResponseModel>> getGroupedFilteredDoctorsList() {
final clinicMap = <String, List<DoctorsListResponseModel>>{};
final hospitalMap = <String, List<DoctorsListResponseModel>>{};
for (var doctor in filteredDoctorList) {
final clinicKey = (doctor.clinicName ?? 'Unknown').trim();
clinicMap.putIfAbsent(clinicKey, () => []).add(doctor);
final hospitalKey = (doctor.projectName ?? 'Unknown').trim();
hospitalMap.putIfAbsent(hospitalKey, () => []).add(doctor);
}
return isSortByClinic ? clinicMap.values.toList() : hospitalMap.values.toList();
}
// Group doctors by clinic and hospital // Group doctors by clinic and hospital
void _groupDoctorsList() { void _groupDoctorsList() {
final clinicMap = <String, List<DoctorsListResponseModel>>{}; final clinicMap = <String, List<DoctorsListResponseModel>>{};
@ -216,6 +271,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
isDoctorProfileLoading = true; isDoctorProfileLoading = true;
isLiveCareSchedule = false; isLiveCareSchedule = false;
currentlySelectedHospitalFromRegionFlow = null; currentlySelectedHospitalFromRegionFlow = null;
expandedGroupIndex = null; // Reset accordion state
clinicsList.clear(); clinicsList.clear();
doctorsList.clear(); doctorsList.clear();
liveCareClinicsList.clear(); liveCareClinicsList.clear();
@ -233,9 +289,24 @@ class BookAppointmentsViewModel extends ChangeNotifier {
this.isNearestAppointmentSelected = isNearestAppointmentSelected; this.isNearestAppointmentSelected = isNearestAppointmentSelected;
if (isNearestAppointmentSelected) { if (isNearestAppointmentSelected) {
doctorsList.sort((a, b) => DateUtil.convertStringToDate(a.nearestFreeSlot!).compareTo(DateUtil.convertStringToDate(b.nearestFreeSlot!))); for (var group in doctorsListGrouped) {
group.sort((a, b) {
var aSlot = a.nearestFreeSlot;
var bSlot = b.nearestFreeSlot;
if (aSlot == null || bSlot == null) return 0;
return DateUtil.convertStringToDate(aSlot).compareTo(DateUtil.convertStringToDate(bSlot));
});
}
} else { } else {
doctorsList.sort((a, b) => b.decimalDoctorRate!.compareTo(a.decimalDoctorRate!)); for (var group in doctorsListGrouped) {
group.sort((a, b) {
var aSlot = a.decimalDoctorRate;
var bSlot = b.decimalDoctorRate;
if (aSlot == null || bSlot == null) return 0;
return bSlot.compareTo(aSlot);
});
}
// doctorsList.sort((a, b) => b.decimalDoctorRate!.compareTo(a.decimalDoctorRate!));
} }
notifyListeners(); notifyListeners();

@ -14,6 +14,8 @@ abstract class ContactUsRepo {
Future<Either<Failure, GenericApiModel<List<GetPatientICProjectsModel>>>> getLiveChatProjectsList(); Future<Either<Failure, GenericApiModel<List<GetPatientICProjectsModel>>>> getLiveChatProjectsList();
Future<Either<Failure, GenericApiModel<String>>> getChatRequestID({required String name, required String mobileNo, required String workGroup});
Future<Either<Failure, GenericApiModel<dynamic>>> insertCOCItem({required RequestInsertCOCItem requestInsertCOCItem, PatientAppointmentHistoryResponseModel? patientSelectedAppointment}); Future<Either<Failure, GenericApiModel<dynamic>>> insertCOCItem({required RequestInsertCOCItem requestInsertCOCItem, PatientAppointmentHistoryResponseModel? patientSelectedAppointment});
} }
@ -97,6 +99,45 @@ class ContactUsRepoImp implements ContactUsRepo {
} }
} }
@override
Future<Either<Failure, GenericApiModel<String>>> getChatRequestID({required String name, required String mobileNo, required String workGroup}) async {
Map<String, dynamic> body = {};
body['Name'] = name;
body['MobileNo'] = mobileNo;
body['WorkGroup'] = workGroup;
try {
GenericApiModel<String>? apiResponse;
Failure? failure;
await apiClient.post(
GET_LIVECHAT_REQUEST_ID,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final requestId = response['RequestId'] as String;
apiResponse = GenericApiModel<String>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: requestId,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override @override
Future<Either<Failure, GenericApiModel<dynamic>>> insertCOCItem({required RequestInsertCOCItem requestInsertCOCItem, PatientAppointmentHistoryResponseModel? patientSelectedAppointment}) async { Future<Either<Failure, GenericApiModel<dynamic>>> insertCOCItem({required RequestInsertCOCItem requestInsertCOCItem, PatientAppointmentHistoryResponseModel? patientSelectedAppointment}) async {
final Map<String, dynamic> body = requestInsertCOCItem.toJson(); final Map<String, dynamic> body = requestInsertCOCItem.toJson();

@ -29,6 +29,8 @@ class ContactUsViewModel extends ChangeNotifier {
int selectedLiveChatProjectIndex = -1; int selectedLiveChatProjectIndex = -1;
String? chatRequestID;
List<String> feedbackAttachmentList = []; List<String> feedbackAttachmentList = [];
PatientAppointmentHistoryResponseModel? patientFeedbackSelectedAppointment; PatientAppointmentHistoryResponseModel? patientFeedbackSelectedAppointment;
@ -153,6 +155,32 @@ class ContactUsViewModel extends ChangeNotifier {
); );
} }
Future<void> getChatRequestID({required String name, required String mobileNo, required String workGroup, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await contactUsRepo.getChatRequestID(name: name, mobileNo: mobileNo, workGroup: workGroup);
result.fold(
(failure) async {
await errorHandlerService.handleError(failure: failure);
if (onError != null) {
onError(failure.toString());
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
if (onError != null) {
onError(apiResponse.errorMessage ?? 'Unknown error');
}
} else if (apiResponse.messageStatus == 1) {
chatRequestID = apiResponse.data;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> insertCOCItem({required String subject, required String message, Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> insertCOCItem({required String subject, required String message, Function(dynamic)? onSuccess, Function(String)? onError}) async {
RequestInsertCOCItem requestInsertCOCItem = RequestInsertCOCItem(); RequestInsertCOCItem requestInsertCOCItem = RequestInsertCOCItem();
requestInsertCOCItem.attachment = feedbackAttachmentList.isNotEmpty ? feedbackAttachmentList.first : ""; requestInsertCOCItem.attachment = feedbackAttachmentList.isNotEmpty ? feedbackAttachmentList.first : "";

@ -940,7 +940,16 @@ class HmgServicesRepoImp implements HmgServicesRepo {
for (var vitalSignJson in vitalSignsList) { for (var vitalSignJson in vitalSignsList) {
if (vitalSignJson is Map<String, dynamic>) { if (vitalSignJson is Map<String, dynamic>) {
vitalSignList.add(VitalSignResModel.fromJson(vitalSignJson)); final vitalSign = VitalSignResModel.fromJson(vitalSignJson);
// Only add records where BOTH height AND weight are greater than 0
final hasValidWeight = _isValidValue(vitalSign.weightKg);
final hasValidHeight = _isValidValue(vitalSign.heightCm);
// Only add if both height and weight are valid (> 0)
if (hasValidWeight && hasValidHeight) {
vitalSignList.add(vitalSign);
}
} }
} }
} }
@ -967,5 +976,22 @@ class HmgServicesRepoImp implements HmgServicesRepo {
} }
} }
/// Helper method to check if a value is valid (greater than 0)
bool _isValidValue(dynamic value) {
if (value == null) return false;
if (value is num) {
return value > 0;
}
if (value is String) {
if (value.trim().isEmpty) return false;
final parsed = double.tryParse(value);
return parsed != null && parsed > 0;
}
return false;
}
} }

@ -40,6 +40,8 @@ class HmgServicesViewModel extends ChangeNotifier {
bool isHospitalListLoading = false; bool isHospitalListLoading = false;
bool isVitalSignLoading = false; bool isVitalSignLoading = false;
bool hasVitalSignDataLoaded = false;
// HHC specific loading states // HHC specific loading states
bool isHhcOrdersLoading = false; bool isHhcOrdersLoading = false;
bool isHhcServicesLoading = false; bool isHhcServicesLoading = false;
@ -878,6 +880,7 @@ class HmgServicesViewModel extends ChangeNotifier {
Function(dynamic)? onSuccess, Function(dynamic)? onSuccess,
Function(String)? onError, Function(String)? onError,
}) async { }) async {
if (hasVitalSignDataLoaded) return;
isVitalSignLoading = true; isVitalSignLoading = true;
notifyListeners(); notifyListeners();
@ -896,6 +899,7 @@ class HmgServicesViewModel extends ChangeNotifier {
isVitalSignLoading = false; isVitalSignLoading = false;
if (apiResponse.messageStatus == 1) { if (apiResponse.messageStatus == 1) {
vitalSignList = apiResponse.data ?? []; vitalSignList = apiResponse.data ?? [];
hasVitalSignDataLoaded = true;
notifyListeners(); notifyListeners();
if (onSuccess != null) { if (onSuccess != null) {
onSuccess(apiResponse); onSuccess(apiResponse);

@ -8,8 +8,10 @@ class HmgServicesComponentModel {
Color? iconColor; Color? iconColor;
bool isLogin; bool isLogin;
bool isLocked; bool isLocked;
Color textColor;
Color bgColor; Color bgColor;
String? route; String? route;
bool isExternalLink;
Function? onTap; Function? onTap;
HmgServicesComponentModel( HmgServicesComponentModel(
@ -23,6 +25,8 @@ class HmgServicesComponentModel {
this.bgColor = Colors.white, this.bgColor = Colors.white,
this.iconColor = Colors.white, this.iconColor = Colors.white,
this.route, this.route,
this.onTap this.onTap,
this.textColor = Colors.black,
this.isExternalLink = false,
}); });
} }

@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.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/location_util.dart';
import 'package:hmg_patient_app_new/core/utils/penguin_method_channel.dart'; import 'package:hmg_patient_app_new/core/utils/penguin_method_channel.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/features/hospital/AppPermission.dart'; import 'package:hmg_patient_app_new/features/hospital/AppPermission.dart';
@ -17,20 +19,32 @@ class HospitalSelectionBottomSheetViewModel extends ChangeNotifier {
int hmgCount = 0; int hmgCount = 0;
TextEditingController searchController = TextEditingController(); TextEditingController searchController = TextEditingController();
final AppState appState; final AppState appState;
LocationUtils locationUtils = getIt.get<LocationUtils>();
HospitalSelectionBottomSheetViewModel(this.appState) { HospitalSelectionBottomSheetViewModel(this.appState) {
Utils.navigationProjectsList.forEach((element) { locationUtils.getCurrentLocation(onSuccess: (value) {
HospitalsModel model = HospitalsModel.fromJson(element); Utils.navigationProjectsList.forEach((element) {
if (model.isHMC == true) { HospitalsModel model = HospitalsModel.fromJson(element);
hmcHospitalList.add(model);
} else { double dist = Utils.distance(value.latitude, value.longitude, double.parse(model.latitude!), double.parse(model.longitude!)).ceilToDouble();
hmgHospitalList.add(model); print(dist);
} model.distanceInKilometers = dist;
listOfData.add(model);
if (model.isHMC == true) {
hmcHospitalList.add(model);
} else {
hmgHospitalList.add(model);
}
listOfData.add(model);
});
hmgCount = hmgHospitalList.length;
hmcCount = hmcHospitalList.length;
listOfData.sort((a, b) => a.distanceInKilometers.compareTo(b.distanceInKilometers));
hmgHospitalList.sort((a, b) => a.distanceInKilometers.compareTo(b.distanceInKilometers));
getDisplayList();
}); });
hmgCount = hmgHospitalList.length;
hmcCount = hmcHospitalList.length;
getDisplayList();
} }
getDisplayList() { getDisplayList() {
@ -79,13 +93,14 @@ class HospitalSelectionBottomSheetViewModel extends ChangeNotifier {
} }
void openPenguin(HospitalsModel hospital) { void openPenguin(HospitalsModel hospital, {String clinicID = ""}) {
initPenguinSDK(hospital.iD); initPenguinSDK(hospital.iD, clinicID: clinicID);
} }
initPenguinSDK(int projectID) async { initPenguinSDK(int projectID, {String clinicID = ""}) async {
NavigationClinicDetails data = NavigationClinicDetails(); NavigationClinicDetails data = NavigationClinicDetails();
data.projectId = projectID.toString(); data.projectId = projectID.toString();
data.clinicId = clinicID;
final bool permited = await AppPermission.askPenguinPermissions(); final bool permited = await AppPermission.askPenguinPermissions();
if (!permited) { if (!permited) {
Map<Permission, PermissionStatus> statuses = await [ Map<Permission, PermissionStatus> statuses = await [

@ -0,0 +1,96 @@
import 'package:dartz/dartz.dart';
import '../../core/api/api_client.dart';
import '../../core/api_consts.dart';
import '../../core/common_models/generic_api_model.dart';
import '../../core/exceptions/api_failure.dart';
import '../../services/logger_service.dart';
abstract class MonthlyReportsRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> saveMonthlyReport({
String? email,
});
}
class MonthlyReportsRepoImp implements MonthlyReportsRepo {
final ApiClient apiClient;
final LoggerService loggerService;
MonthlyReportsRepoImp({
required this.loggerService,
required this.apiClient,
});
@override
Future<Either<Failure, GenericApiModel<dynamic>>> saveMonthlyReport({
String? email,
}) async {
try {
Failure? failure;
GenericApiModel<dynamic>? reportApiResponse;
await apiClient.post(
ApiConsts.getMonthlyReports,
body: <String, dynamic>{},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
reportApiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (reportApiResponse == null) return Left(ServerFailure("Unknown error"));
if ((reportApiResponse!.messageStatus ?? 0) != 1) {
return Right(reportApiResponse!);
}
GenericApiModel<dynamic>? emailApiResponse;
final Map<String, dynamic> emailRequest = <String, dynamic>{};
if (email != null && email.trim().isNotEmpty) {
emailRequest["Email"] = email.trim();
}
await apiClient.post(
ApiConsts.updatePatientEmail,
body: emailRequest,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
emailApiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (emailApiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(emailApiResponse!);
} catch (e) {
loggerService.logError("MonthlyReportsRepo.saveMonthlyReport error: $e");
return Left(UnknownFailure(e.toString()));
}
}
}

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'monthly_reports_repo.dart';
class MonthlyReportsViewModel extends ChangeNotifier {
final MonthlyReportsRepo monthlyReportsRepo;
final ErrorHandlerService errorHandlerService;
bool isLoading = false;
MonthlyReportsViewModel({
required this.monthlyReportsRepo,
required this.errorHandlerService,
});
Future<bool> saveMonthlyReport({String? email}) async {
isLoading = true;
notifyListeners();
final result = await monthlyReportsRepo.saveMonthlyReport(email: email);
final success = result.fold(
(failure) {
errorHandlerService.handleError(failure: failure);
return false;
},
(apiResponse) => (apiResponse.messageStatus ?? 0) == 1,
);
isLoading = false;
notifyListeners();
return success;
}
}

@ -0,0 +1,60 @@
import 'package:dartz/dartz.dart';
import '../../core/api/api_client.dart';
import '../../core/api_consts.dart';
import '../../core/exceptions/api_failure.dart';
import '../../services/logger_service.dart';
abstract class TermsConditionsRepo {
Future<Either<Failure, String>> getTermsConditions();
}
class TermsConditionsRepoImp implements TermsConditionsRepo {
final ApiClient apiClient;
final LoggerService loggerService;
TermsConditionsRepoImp({
required this.loggerService,
required this.apiClient,
});
@override
Future<Either<Failure, String>> getTermsConditions() async {
Failure? failure;
String? html;
try {
await apiClient.post(
ApiConsts.getTermsConditions,
body: <String, dynamic>{},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType ?? ServerFailure(error.toString());
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final content = response['UserAgreementContent'];
if (content is String && content.isNotEmpty) {
html = content;
} else {
failure = DataParsingFailure(
'UserAgreementContent is null or not String');
}
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
} catch (e) {
failure = UnknownFailure(e.toString());
}
if (failure != null) return Left(failure!);
if (html == null || html!.isEmpty) {
return Left(ServerFailure('No terms and conditions returned'));
}
return Right(html!);
}
}

@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/features/monthly_reports/terms_conditions_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class TermsConditionsViewModel extends ChangeNotifier {
final TermsConditionsRepo termsConditionsRepo;
final ErrorHandlerService errorHandlerService;
String? termsConditionsHtml;
bool isLoading = false;
TermsConditionsViewModel({
required this.termsConditionsRepo,
required this.errorHandlerService,
});
Future<void> getTermsConditions({
Function()? onSuccess,
Function(String)? onError,
}) async {
isLoading = true;
notifyListeners();
final result = await termsConditionsRepo.getTermsConditions();
result.fold(
(failure) async {
await errorHandlerService.handleError(failure: failure);
isLoading = false;
notifyListeners();
if (onError != null) {
onError(failure.message ?? 'Something went wrong');
}
},
(html) {
termsConditionsHtml = html;
isLoading = false;
notifyListeners();
if (onSuccess != null) onSuccess();
},
);
}
}

@ -281,9 +281,9 @@ class MyAppointmentsViewModel extends ChangeNotifier {
} }
} }
print('Upcoming Appointments: ${patientUpcomingAppointmentsHistoryList.length}'); debugPrint('Upcoming Appointments: ${patientUpcomingAppointmentsHistoryList.length}');
print('Arrived Appointments: ${patientArrivedAppointmentsHistoryList.length}'); debugPrint('Arrived Appointments: ${patientArrivedAppointmentsHistoryList.length}');
print('All Appointments: ${patientAppointmentsHistoryList.length}'); debugPrint('All Appointments: ${patientAppointmentsHistoryList.length}');
getFiltersForSelectedAppointmentList(filteredAppointmentList); getFiltersForSelectedAppointmentList(filteredAppointmentList);
notifyListeners(); notifyListeners();
} }
@ -726,6 +726,7 @@ class MyAppointmentsViewModel extends ChangeNotifier {
} }
Future<void> getPatientAppointmentQueueDetails({Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getPatientAppointmentQueueDetails({Function(dynamic)? onSuccess, Function(String)? onError}) async {
//TODO: Discuss With Haroon, Is the User Has no data it return No Element Bad State;
isAppointmentQueueDetailsLoading = true; isAppointmentQueueDetailsLoading = true;
notifyListeners(); notifyListeners();
final result = await myAppointmentsRepo.getPatientAppointmentQueueDetails( final result = await myAppointmentsRepo.getPatientAppointmentQueueDetails(

@ -0,0 +1,96 @@
class NotificationResponseModel {
int? id;
int? recordId;
int? patientID;
bool? projectOutSA;
String? deviceType;
String? deviceToken;
String? message;
String? messageType;
String? messageTypeData;
String? videoURL;
bool? isQueue;
String? isQueueOn;
String? createdOn;
dynamic createdBy;
String? notificationType;
bool? isSent;
String? isSentOn;
bool? isRead;
dynamic isReadOn;
int? channelID;
int? projectID;
NotificationResponseModel(
{this.id,
this.recordId,
this.patientID,
this.projectOutSA,
this.deviceType,
this.deviceToken,
this.message,
this.messageType,
this.messageTypeData,
this.videoURL,
this.isQueue,
this.isQueueOn,
this.createdOn,
this.createdBy,
this.notificationType,
this.isSent,
this.isSentOn,
this.isRead,
this.isReadOn,
this.channelID,
this.projectID});
NotificationResponseModel.fromJson(Map<String, dynamic> json) {
id = json['Id'];
recordId = json['RecordId'];
patientID = json['PatientID'];
projectOutSA = json['ProjectOutSA'];
deviceType = json['DeviceType'];
deviceToken = json['DeviceToken'];
message = json['Message'];
messageType = json['MessageType'];
messageTypeData = json['MessageTypeData'];
videoURL = json['VideoURL'];
isQueue = json['IsQueue'];
isQueueOn = json['IsQueueOn'];
createdOn = json['CreatedOn'];
createdBy = json['CreatedBy'];
notificationType = json['NotificationType'];
isSent = json['IsSent'];
isSentOn = json['IsSentOn'];
isRead = json['IsRead'];
isReadOn = json['IsReadOn'];
channelID = json['ChannelID'];
projectID = json['ProjectID'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['Id'] = this.id;
data['RecordId'] = this.recordId;
data['PatientID'] = this.patientID;
data['ProjectOutSA'] = this.projectOutSA;
data['DeviceType'] = this.deviceType;
data['DeviceToken'] = this.deviceToken;
data['Message'] = this.message;
data['MessageType'] = this.messageType;
data['MessageTypeData'] = this.messageTypeData;
data['VideoURL'] = this.videoURL;
data['IsQueue'] = this.isQueue;
data['IsQueueOn'] = this.isQueueOn;
data['CreatedOn'] = this.createdOn;
data['CreatedBy'] = this.createdBy;
data['NotificationType'] = this.notificationType;
data['IsSent'] = this.isSent;
data['IsSentOn'] = this.isSentOn;
data['IsRead'] = this.isRead;
data['IsReadOn'] = this.isReadOn;
data['ChannelID'] = this.channelID;
data['ProjectID'] = this.projectID;
return data;
}
}

@ -0,0 +1,78 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/notifications/models/resp_models/notification_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class NotificationsRepo {
Future<Either<Failure, GenericApiModel<List<NotificationResponseModel>>>> getAllNotifications({
required int notificationStatusID,
required int pagingSize,
required int currentPage,
});
}
class NotificationsRepoImp implements NotificationsRepo {
final ApiClient apiClient;
final LoggerService loggerService;
NotificationsRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<NotificationResponseModel>>>> getAllNotifications({
required int notificationStatusID,
required int pagingSize,
required int currentPage,
}) async {
Map<String, dynamic> mapDevice = {
"NotificationStatusID": notificationStatusID,
"pagingSize": pagingSize,
"currentPage": currentPage,
};
try {
GenericApiModel<List<NotificationResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_ALL_NOTIFICATIONS,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['List_GetAllNotificationsFromPool'];
if (list == null || list.isEmpty) {
// Return empty list if no notifications
apiResponse = GenericApiModel<List<NotificationResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: [],
);
return;
}
final notifications = list.map((item) => NotificationResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<NotificationResponseModel>();
apiResponse = GenericApiModel<List<NotificationResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: notifications,
);
} 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()));
}
}
}

@ -0,0 +1,113 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/features/notifications/models/resp_models/notification_response_model.dart';
import 'package:hmg_patient_app_new/features/notifications/notifications_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class NotificationsViewModel extends ChangeNotifier {
bool isNotificationsLoading = false;
bool hasMoreNotifications = true;
NotificationsRepo notificationsRepo;
ErrorHandlerService errorHandlerService;
List<NotificationResponseModel> notificationsList = [];
int currentPage = 0;
int pagingSize = 14;
int notificationStatusID = 2; // Default to status 2 (e.g., unread)
NotificationsViewModel({
required this.notificationsRepo,
required this.errorHandlerService,
});
initNotificationsViewModel({int? statusID}) {
notificationsList.clear();
currentPage = 0;
hasMoreNotifications = true;
isNotificationsLoading = true;
// if (statusID != null) {
// notificationStatusID = statusID;
// }
// getAllNotifications();
notifyListeners();
}
setNotificationStatusID(int statusID) {
notificationStatusID = statusID;
notificationsList.clear();
currentPage = 0;
hasMoreNotifications = true;
notifyListeners();
}
Future<void> getAllNotifications({
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
isNotificationsLoading = true;
notifyListeners();
final result = await notificationsRepo.getAllNotifications(
notificationStatusID: notificationStatusID,
pagingSize: pagingSize,
currentPage: currentPage,
);
result.fold(
(failure) async {
isNotificationsLoading = false;
notifyListeners();
await errorHandlerService.handleError(failure: failure);
if (onError != null) {
onError(failure.toString());
}
},
(apiResponse) {
isNotificationsLoading = false;
if (apiResponse.messageStatus == 2) {
notifyListeners();
if (onError != null) {
onError(apiResponse.errorMessage ?? "Unknown error");
}
} else if (apiResponse.messageStatus == 1) {
final newNotifications = apiResponse.data ?? [];
if (newNotifications.isEmpty || newNotifications.length < pagingSize) {
hasMoreNotifications = false;
}
notificationsList.addAll(newNotifications);
currentPage++;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> refreshNotifications({
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
notificationsList.clear();
currentPage = 0;
hasMoreNotifications = true;
await getAllNotifications(onSuccess: onSuccess, onError: onError);
}
Future<void> loadMoreNotifications({
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
await getAllNotifications(onSuccess: onSuccess, onError: onError);
}
@override
void dispose() {
super.dispose();
}
}

@ -0,0 +1,183 @@
class QrParkingResponseModel {
dynamic totalRecords;
dynamic nRowID;
int? qRParkingID;
String? description;
String? descriptionN;
dynamic qRCompare;
dynamic qRValue;
String? imagePath;
bool? isActive;
int? parkingID;
int? branchID;
int? companyID;
int? buildingID;
int? rowID;
int? gateID;
int? floorID;
dynamic imagePath1;
int? createdBy;
String? createdOn;
dynamic editedBy;
dynamic editedOn;
String? parkingDescription;
String? parkingDescriptionN;
String? gateDescription;
String? gateDescriptionN;
String? branchDescription;
String? branchDescriptionN;
String? companyDescription;
String? companyDescriptionN;
String? rowDescription;
String? rowDescriptionN;
String? floorDescription;
String? floorDescriptionN;
String? buildingDescription;
String? buildingDescriptionN;
String? qRParkingCode;
String? parkingCode;
double? latitude;
double? longitude;
String? qRImageStr;
QrParkingResponseModel({
this.totalRecords,
this.nRowID,
this.qRParkingID,
this.description,
this.descriptionN,
this.qRCompare,
this.qRValue,
this.imagePath,
this.isActive,
this.parkingID,
this.branchID,
this.companyID,
this.buildingID,
this.rowID,
this.gateID,
this.floorID,
this.imagePath1,
this.createdBy,
this.createdOn,
this.editedBy,
this.editedOn,
this.parkingDescription,
this.parkingDescriptionN,
this.gateDescription,
this.gateDescriptionN,
this.branchDescription,
this.branchDescriptionN,
this.companyDescription,
this.companyDescriptionN,
this.rowDescription,
this.rowDescriptionN,
this.floorDescription,
this.floorDescriptionN,
this.buildingDescription,
this.buildingDescriptionN,
this.qRParkingCode,
this.parkingCode,
this.latitude,
this.longitude,
this.qRImageStr,
});
QrParkingResponseModel.fromJson(Map<String, dynamic> json) {
totalRecords = json['TotalRecords'];
nRowID = json['nRowID'];
qRParkingID = json['QRParkingID'];
description = json['Description'];
descriptionN = json['DescriptionN'];
qRCompare = json['QRCompare'];
qRValue = json['QRValue'];
imagePath = json['ImagePath'];
isActive = json['IsActive'];
parkingID = json['ParkingID'];
branchID = json['BranchID'];
companyID = json['CompanyID'];
buildingID = json['BuildingID'];
rowID = json['RowID'];
gateID = json['GateID'];
floorID = json['FloorID'];
imagePath1 = json['ImagePath1'];
createdBy = json['CreatedBy'];
createdOn = json['CreatedOn'];
editedBy = json['EditedBy'];
editedOn = json['EditedOn'];
parkingDescription = json['ParkingDescription'];
parkingDescriptionN = json['ParkingDescriptionN'];
gateDescription = json['GateDescription'];
gateDescriptionN = json['GateDescriptionN'];
branchDescription = json['BranchDescription'];
branchDescriptionN = json['BranchDescriptionN'];
companyDescription = json['CompanyDescription'];
companyDescriptionN = json['CompanyDescriptionN'];
rowDescription = json['RowDescription'];
rowDescriptionN = json['RowDescriptionN'];
floorDescription = json['FloorDescription'];
floorDescriptionN = json['FloorDescriptionN'];
buildingDescription = json['BuildingDescription'];
buildingDescriptionN = json['BuildingDescriptionN'];
qRParkingCode = json['QRParkingCode'];
parkingCode = json['ParkingCode'];
latitude = _toDouble(json['Latitude']);
longitude = _toDouble(json['Longitude']);
qRImageStr = json['QRImageStr'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['TotalRecords'] = totalRecords;
data['nRowID'] = nRowID;
data['QRParkingID'] = qRParkingID;
data['Description'] = description;
data['DescriptionN'] = descriptionN;
data['QRCompare'] = qRCompare;
data['QRValue'] = qRValue;
data['ImagePath'] = imagePath;
data['IsActive'] = isActive;
data['ParkingID'] = parkingID;
data['BranchID'] = branchID;
data['CompanyID'] = companyID;
data['BuildingID'] = buildingID;
data['RowID'] = rowID;
data['GateID'] = gateID;
data['FloorID'] = floorID;
data['ImagePath1'] = imagePath1;
data['CreatedBy'] = createdBy;
data['CreatedOn'] = createdOn;
data['EditedBy'] = editedBy;
data['EditedOn'] = editedOn;
data['ParkingDescription'] = parkingDescription;
data['ParkingDescriptionN'] = parkingDescriptionN;
data['GateDescription'] = gateDescription;
data['GateDescriptionN'] = gateDescriptionN;
data['BranchDescription'] = branchDescription;
data['BranchDescriptionN'] = branchDescriptionN;
data['CompanyDescription'] = companyDescription;
data['CompanyDescriptionN'] = companyDescriptionN;
data['RowDescription'] = rowDescription;
data['RowDescriptionN'] = rowDescriptionN;
data['FloorDescription'] = floorDescription;
data['FloorDescriptionN'] = floorDescriptionN;
data['BuildingDescription'] = buildingDescription;
data['BuildingDescriptionN'] = buildingDescriptionN;
data['QRParkingCode'] = qRParkingCode;
data['ParkingCode'] = parkingCode;
data['Latitude'] = latitude;
data['Longitude'] = longitude;
data['QRImageStr'] = qRImageStr;
return data;
}
static double? _toDouble(dynamic v) {
if (v == null) return null;
if (v is double) return v;
if (v is int) return v.toDouble();
return double.tryParse(v.toString());
}
}

@ -0,0 +1,74 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/features/qr_parking/models/qr_parking_response_model.dart';
import '../../core/api/api_client.dart';
import '../../core/api_consts.dart';
import '../../core/common_models/generic_api_model.dart';
import '../../core/exceptions/api_failure.dart';
import '../../services/logger_service.dart';
abstract class QrParkingRepo {
Future<Either<Failure, GenericApiModel<List<QrParkingResponseModel>>>>
getQrParking({
required int qrParkingId,
});
}
class QrParkingRepoImp implements QrParkingRepo {
final ApiClient apiClient;
final LoggerService loggerService;
QrParkingRepoImp({
required this.loggerService,
required this.apiClient,
});
@override
Future<Either<Failure, GenericApiModel<List<QrParkingResponseModel>>>>
getQrParking({required int qrParkingId}) async {
try {
GenericApiModel<List<QrParkingResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getQrParkingDetails, // GetQRParkingByID
body: {'QRParkingID': qrParkingId},
onFailure: (error, statusCode,
{messageStatus, failureType}) {
failure = failureType ??
StatusCodeFailure("$error ($statusCode)");
},
onSuccess: (response, statusCode,
{messageStatus, errorMessage}) {
final list =
(response['List_SWP_QRParkingModel'] as List?) ?? [];
final res = list
.map((e) => QrParkingResponseModel.fromJson(
Map<String, dynamic>.from(e),
))
.toList();
apiResponse = GenericApiModel<List<QrParkingResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: res,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) {
return Left(ServerFailure("Unknown error"));
}
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -0,0 +1,144 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:hmg_patient_app_new/features/qr_parking/qr_parking_repo.dart';
import '../../services/cache_service.dart';
import '../../services/error_handler_service.dart';
import 'models/qr_parking_response_model.dart';
class QrParkingViewModel extends ChangeNotifier {
final QrParkingRepo qrParkingRepo;
final ErrorHandlerService errorHandlerService;
final CacheService cacheService;
String IS_GO_TO_PARKING = 'IS_GO_TO_PARKING';
bool isLoading = false;
String? error;
bool isSavePark = false;
QrParkingResponseModel? qrParkingModel;
List<QrParkingResponseModel> qrParkingList = [];
QrParkingViewModel({
required this.qrParkingRepo,
required this.errorHandlerService,
required this.cacheService,
});
Future<QrParkingResponseModel?> scanAndGetParking() async {
try {
error = null;
isLoading = true;
notifyListeners();
final result = await BarcodeScanner.scan();
if (result.type != ResultType.Barcode) {
isLoading = false;
notifyListeners();
return null;
}
final raw = result.rawContent.trim();
if (raw.isEmpty) {
error = "Invalid QR Code";
isLoading = false;
notifyListeners();
return null;
}
final qrParkingId = _extractQrParkingId(raw);
if (qrParkingId == null) {
error = "Invalid QR Code";
isLoading = false;
notifyListeners();
return null;
}
final apiResult =
await qrParkingRepo.getQrParking(qrParkingId: qrParkingId);
final model = apiResult.fold(
(failure) {
errorHandlerService.handleError(failure: failure);
error = failure.toString();
return null;
},
(apiResponse) {
qrParkingList = apiResponse.data ?? [];
if (qrParkingList.isNotEmpty) {
return qrParkingList.first;
}
error = "Invalid Qr Code";
return null;
},
);
if (model != null) {
qrParkingModel = model;
isSavePark = true;
await cacheService.saveObject(
key: IS_GO_TO_PARKING,
value: model.toJson(),
);
}
isLoading = false;
notifyListeners();
return model;
} catch (e) {
error = "Scan error";
isLoading = false;
notifyListeners();
return null;
}
}
/// Load saved parking
Future<void> getIsSaveParking() async {
isLoading = true;
notifyListeners();
final parking =
await cacheService.getObject(key: IS_GO_TO_PARKING);
if (parking != null) {
isSavePark = true;
qrParkingModel = QrParkingResponseModel.fromJson(
Map<String, dynamic>.from(parking),
);
} else {
isSavePark = false;
qrParkingModel = null;
}
isLoading = false;
notifyListeners();
}
/// Reset parking
Future<void> clearParking() async {
await cacheService.remove(key: IS_GO_TO_PARKING);
isSavePark = false;
qrParkingModel = null;
notifyListeners();
}
int? _extractQrParkingId(String raw) {
try {
if (raw.startsWith("{")) {
final data = jsonDecode(raw);
return int.tryParse(data['QRParkingID'].toString());
}
return int.tryParse(raw);
} catch (_) {
return null;
}
}
}

@ -48,6 +48,8 @@ abstract class TodoSectionRepo {
}); });
Future<Either<Failure, dynamic>> applePayInsertRequest({required dynamic applePayInsertRequest}); Future<Either<Failure, dynamic>> applePayInsertRequest({required dynamic applePayInsertRequest});
Future<Either<Failure, dynamic>> getPatientDashboard();
} }
class TodoSectionRepoImp implements TodoSectionRepo { class TodoSectionRepoImp implements TodoSectionRepo {
@ -376,4 +378,29 @@ class TodoSectionRepoImp implements TodoSectionRepo {
return Left(UnknownFailure(e.toString())); return Left(UnknownFailure(e.toString()));
} }
} }
@override
Future<Either<Failure, dynamic>> getPatientDashboard() async {
Map<String, dynamic> mapDevice = {};
try {
dynamic apiResponse;
Failure? failure;
await apiClient.post(
DASHBOARD,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = response;
},
);
if (failure != null) return Left(failure!);
return Right(apiResponse);
} catch (e) {
loggerService.logError("Unknown error in applePayInsertRequest: ${e.toString()}");
return Left(UnknownFailure(e.toString()));
}
}
} }

@ -10,11 +10,15 @@ class TodoSectionViewModel extends ChangeNotifier {
TodoSectionViewModel({required this.todoSectionRepo, required this.errorHandlerService}); TodoSectionViewModel({required this.todoSectionRepo, required this.errorHandlerService});
String? notificationsCount = "0";
initializeTodoSectionViewModel() async { initializeTodoSectionViewModel() async {
patientAncillaryOrdersList.clear(); patientAncillaryOrdersList.clear();
isAncillaryOrdersLoading = true; isAncillaryOrdersLoading = true;
isAncillaryDetailsProceduresLoading = true; isAncillaryDetailsProceduresLoading = true;
await getPatientOnlineAncillaryOrderList(); notificationsCount = "0";
getPatientOnlineAncillaryOrderList();
getPatientDashboard();
} }
bool isAncillaryOrdersLoading = false; bool isAncillaryOrdersLoading = false;
@ -28,6 +32,28 @@ class TodoSectionViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
Future<void> getPatientDashboard({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await todoSectionRepo.getPatientDashboard();
result.fold(
(failure) async {
await errorHandlerService.handleError(failure: failure);
},
(apiResponse) {
// if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
// } else if (apiResponse.messageStatus == 1) {
notificationsCount =
apiResponse['List_PatientDashboard'][0]['UnreadPatientNotificationCount'] > 99 ? '99+' : apiResponse['List_PatientDashboard'][0]['UnreadPatientNotificationCount'].toString();
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
// }
},
);
}
Future<void> getPatientOnlineAncillaryOrderList({Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getPatientOnlineAncillaryOrderList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
patientAncillaryOrdersList.clear(); patientAncillaryOrdersList.clear();
isAncillaryOrdersLoading = true; isAncillaryOrdersLoading = true;

@ -693,11 +693,7 @@ abstract class LocaleKeys {
static const bikini = 'bikini'; static const bikini = 'bikini';
static const totalMinutes = 'totalMinutes'; static const totalMinutes = 'totalMinutes';
static const feedback = 'feedback'; static const feedback = 'feedback';
static const send = 'send';
static const status = 'status';
static const likeToHear = 'likeToHear'; static const likeToHear = 'likeToHear';
static const subject = 'subject';
static const message = 'message';
static const emptySubject = 'emptySubject'; static const emptySubject = 'emptySubject';
static const emptyMessage = 'emptyMessage'; static const emptyMessage = 'emptyMessage';
static const selectAttachment = 'selectAttachment'; static const selectAttachment = 'selectAttachment';
@ -876,5 +872,341 @@ abstract class LocaleKeys {
static const laserClinic = 'laserClinic'; static const laserClinic = 'laserClinic';
static const continueString = 'continueString'; static const continueString = 'continueString';
static const covid_info = 'covid_info'; static const covid_info = 'covid_info';
static const appointmentDetails = 'appointmentDetails';
static const checkingDoctorAvailability = 'checkingDoctorAvailability';
static const cancellingAppointmentPleaseWait = 'cancellingAppointmentPleaseWait';
static const appointmentCancelledSuccessfully = 'appointmentCancelledSuccessfully';
static const notConfirmed = 'notConfirmed';
static const appointmentStatus = 'appointmentStatus';
static const doctorWillCallYou = 'doctorWillCallYou';
static const getDirections = 'getDirections';
static const notifyMeBeforeAppointment = 'notifyMeBeforeAppointment';
static const fetchingLabResults = 'fetchingLabResults';
static const fetchingRadiologyResults = 'fetchingRadiologyResults';
static const fetchingAppointmentPrescriptions = 'fetchingAppointmentPrescriptions';
static const noPrescriptionsForAppointment = 'noPrescriptionsForAppointment';
static const amountBeforeTax = 'amountBeforeTax';
static const rebookAppointment = 'rebookAppointment';
static const fetchingDoctorSchedulePleaseWait = 'fetchingDoctorSchedulePleaseWait';
static const pickADate = 'pickADate';
static const confirmingAppointmentPleaseWait = 'confirmingAppointmentPleaseWait';
static const appointmentConfirmedSuccessfully = 'appointmentConfirmedSuccessfully';
static const appointmentPayment = 'appointmentPayment';
static const checkingPaymentStatusPleaseWait = 'checkingPaymentStatusPleaseWait';
static const paymentFailedPleaseTryAgain = 'paymentFailedPleaseTryAgain';
static const appointmentCheckIn = 'appointmentCheckIn';
static const insuranceExpiredOrInactive = 'insuranceExpiredOrInactive';
static const totalAmountToPay = 'totalAmountToPay';
static const vat15 = 'vat15';
static const liveCare = 'liveCare';
static const recentVisits = 'recentVisits';
static const searchByClinic = 'searchByClinic';
static const tapToSelectClinic = 'tapToSelectClinic';
static const searchByDoctor = 'searchByDoctor';
static const tapToSelect = 'tapToSelect';
static const searchByRegion = 'searchByRegion';
static const centralRegion = 'centralRegion';
static const immediateConsultation = 'immediateConsultation';
static const scheduledConsultation = 'scheduledConsultation';
static const pharmaLiveCare = 'pharmaLiveCare';
static const notSureHelpMeChooseClinic = 'notSureHelpMeChooseClinic';
static const mentionYourSymptomsAndFindDoctors = 'mentionYourSymptomsAndFindDoctors';
static const immediateService = 'immediateService';
static const noNeedToWaitGetMedicalConsultation = 'noNeedToWaitGetMedicalConsultation';
static const noVisitRequired = 'noVisitRequired';
static const doctorWillContact = 'doctorWillContact';
static const specialisedDoctorWillContactYou = 'specialisedDoctorWillContactYou';
static const freeMedicineDelivery = 'freeMedicineDelivery';
static const offersFreeMedicineDelivery = 'offersFreeMedicineDelivery';
static const dentalChiefComplaints = 'dentalChiefComplaints';
static const viewAvailableAppointments = 'viewAvailableAppointments';
static const doctorProfile = 'doctorProfile';
static const waitingAppointment = 'waitingAppointment';
static const hospitalInformation = 'hospitalInformation';
static const fetchingAppointmentShare = 'fetchingAppointmentShare';
static const bookingYourAppointment = 'bookingYourAppointment';
static const selectLiveCareClinic = 'selectLiveCareClinic';
static const checkingForExistingDentalPlan = 'checkingForExistingDentalPlan';
static const dentalTreatmentPlan = 'dentalTreatmentPlan';
static const youHaveExistingTreatmentPlan = 'youHaveExistingTreatmentPlan';
static const mins = 'mins';
static const totalTimeRequired = 'totalTimeRequired';
static const wouldYouLikeToContinue = 'wouldYouLikeToContinue';
static const chooseDoctor = 'chooseDoctor';
static const viewNearestAppos = 'viewNearestAppos';
static const noDoctorFound = 'noDoctorFound';
static const yesPleasImInAHurry = 'yesPleasImInAHurry';
static const fetchingFeesPleaseWait = 'fetchingFeesPleaseWait';
static const noThanksPhysicalVisit = 'noThanksPhysicalVisit';
static const offline = 'offline';
static const videoCall = 'videoCall';
static const liveVideoCallWithHMGDoctors = 'liveVideoCallWithHMGDoctors';
static const audioCall = 'audioCall';
static const phoneCall = 'phoneCall';
static const livePhoneCallWithHMGDoctors = 'livePhoneCallWithHMGDoctors';
static const reviewLiveCareRequest = 'reviewLiveCareRequest';
static const selectedLiveCareType = 'selectedLiveCareType';
static const selectLiveCareCallType = 'selectLiveCareCallType';
static const confirmingLiveCareRequest = 'confirmingLiveCareRequest';
static const unknownErrorOccurred = 'unknownErrorOccurred';
static const liveCarePermissionsMessage = 'liveCarePermissionsMessage';
static const liveCarePayment = 'liveCarePayment';
static const mada = 'mada';
static const visaOrMastercard = 'visaOrMastercard';
static const tamara = 'tamara';
static const fetchingApplePayDetails = 'fetchingApplePayDetails';
static const liveCarePendingRequest = 'liveCarePendingRequest';
static const callLiveCareSupport = 'callLiveCareSupport';
static const whatIsWaitingAppointment = 'whatIsWaitingAppointment';
static const waitingAppointmentsFeature = 'waitingAppointmentsFeature';
static const appointmentWithDoctorConfirmed = 'appointmentWithDoctorConfirmed';
static const paymentWithinTenMinutes = 'paymentWithinTenMinutes';
static const liveLocation = 'liveLocation';
static const verifyYourLocationAtHospital = 'verifyYourLocationAtHospital';
static const error = 'error';
static const ensureWithinHospitalLocation = 'ensureWithinHospitalLocation';
static const nfcNearFieldCommunication = 'nfcNearFieldCommunication';
static const scanPhoneViaNFC = 'scanPhoneViaNFC';
static const qrCode = 'qrCode';
static const scanQRCodeToCheckIn = 'scanQRCodeToCheckIn';
static const processingCheckIn = 'processingCheckIn';
static const bookingWaitingAppointment = 'bookingWaitingAppointment';
static const enterValidIDorIqama = 'enterValidIDorIqama';
static const selectAppointment = 'selectAppointment';
static const rebookSameDoctor = 'rebookSameDoctor';
static const queueing = 'queueing';
static const inQueue = 'inQueue';
static const yourTurn = 'yourTurn';
static const halaFirstName = 'halaFirstName';
static const thankYouForPatience = 'thankYouForPatience';
static const servingNow = 'servingNow';
static const callForVitalSigns = 'callForVitalSigns';
static const callForDoctor = 'callForDoctor';
static const thingsToAskDoctor = 'thingsToAskDoctor';
static const improveOverallHealth = 'improveOverallHealth';
static const routineScreenings = 'routineScreenings';
static const whatIsThisMedicationFor = 'whatIsThisMedicationFor';
static const sideEffectsToKnow = 'sideEffectsToKnow';
static const whenFollowUp = 'whenFollowUp';
static const goToHomepage = 'goToHomepage';
static const appointmentsList = 'appointmentsList';
static const allAppt = 'allAppt';
static const upcoming = 'upcoming';
static const completed = 'completed';
static const noAppointmentsYet = 'noAppointmentsYet';
static const viewProfile = 'viewProfile';
static const choosePreferredHospitalForService = 'choosePreferredHospitalForService';
static const noHospitalsFound = 'noHospitalsFound';
static const cancelOrderConfirmation = 'cancelOrderConfirmation';
static const orderCancelledSuccessfully = 'orderCancelledSuccessfully';
static const requestID = 'requestID';
static const noCMCOrdersYet = 'noCMCOrdersYet';
static const cmcOrders = 'cmcOrders';
static const summary = 'summary';
static const selectedService = 'selectedService';
static const requestSubmittedSuccessfully = 'requestSubmittedSuccessfully';
static const hereIsYourRequestNumber = 'hereIsYourRequestNumber';
static const pleaseSelectHospitalToContinue = 'pleaseSelectHospitalToContinue';
static const confirmSubmitRequest = 'confirmSubmitRequest';
static const pendingOrderWait = 'pendingOrderWait';
static const noServicesAvailable = 'noServicesAvailable';
static const selectAService = 'selectAService';
static const comprehensiveCheckup = 'comprehensiveCheckup';
static const viewNearestHMGLocations = 'viewNearestHMGLocations';
static const provideFeedbackOnServices = 'provideFeedbackOnServices';
static const liveChatWithHMG = 'liveChatWithHMG';
static const send = 'send';
static const status = 'status';
static const sendingFeedback = 'sendingFeedback';
static const selectFeedbackType = 'selectFeedbackType';
static const loadingAppointmentsList = 'loadingAppointmentsList';
static const noAppointmentsForFeedback = 'noAppointmentsForFeedback';
static const selectedAppointment = 'selectedAppointment';
static const subject = 'subject';
static const enterSubjectHere = 'enterSubjectHere';
static const message = 'message';
static const enterMessageHere = 'enterMessageHere';
static const filesSelected = 'filesSelected';
static const otherDetails = 'otherDetails';
static const medicalReport = 'medicalReport';
static const medicalReportNumber = 'medicalReportNumber';
static const patientIsInsured = 'patientIsInsured';
static const insuranceDocument = 'insuranceDocument';
static const selectBranch = 'selectBranch';
static const patientInformation = 'patientInformation';
static const patientLocation = 'patientLocation';
static const identificationNumber = 'identificationNumber';
static const enterIdentificationNumber = 'enterIdentificationNumber';
static const patientName = 'patientName';
static const referralRequesterInformation = 'referralRequesterInformation';
static const enterReferralRequesterName = 'enterReferralRequesterName';
static const requesterName = 'requesterName';
static const relationship = 'relationship';
static const selectRelation = 'selectRelation';
static const otherName = 'otherName';
static const otherNameHint = 'otherNameHint';
static const requesterNameRequired = 'requesterNameRequired';
static const selectRelationshipRequired = 'selectRelationshipRequired';
static const otherRelationshipNameRequired = 'otherRelationshipNameRequired';
static const identificationNumberRequired = 'identificationNumberRequired';
static const patientNameRequired = 'patientNameRequired';
static const enterPatientPhoneRequired = 'enterPatientPhoneRequired';
static const selectPatientCityRequired = 'selectPatientCityRequired';
static const medicalReportRequired = 'medicalReportRequired';
static const selectBranchRequired = 'selectBranchRequired';
static const insuranceDocumentRequired = 'insuranceDocumentRequired';
static const searchResult = 'searchResult';
static const referralNo = 'referralNo';
static const eReferral = 'eReferral';
static const referralCreatedSuccessfully = 'referralCreatedSuccessfully';
static const hereIsYourReferralNumber = 'hereIsYourReferralNumber';
static const searchEReferral = 'searchEReferral';
static const enterRequiredInfoToSearch = 'enterRequiredInfoToSearch';
static const selectPickupDirection = 'selectPickupDirection';
static const selectDirection = 'selectDirection';
static const toHospital = 'toHospital';
static const fromHospital = 'fromHospital';
static const selectWay = 'selectWay';
static const oneWay = 'oneWay';
static const twoWay = 'twoWay';
static const selectPickupDetails = 'selectPickupDetails';
static const pleaseSelectDetailsOfPickup = 'pleaseSelectDetailsOfPickup';
static const selectDetails = 'selectDetails';
static const work = 'work';
static const pick = 'pick';
static const insideTheHome = 'insideTheHome';
static const haveAnyAppointment = 'haveAnyAppointment';
static const amountPaidAtHospital = 'amountPaidAtHospital';
static const submitRequest = 'submitRequest';
static const enterPickupLocationManually = 'enterPickupLocationManually';
static const enterPickupLocation = 'enterPickupLocation';
static const trackingDetails = 'trackingDetails';
static const cancelRequest = 'cancelRequest';
static const shareLocationWhatsapp = 'shareLocationWhatsapp';
static const pleaseWaitForCall = 'pleaseWaitForCall';
static const toHospitalLower = 'toHospitalLower';
static const contact = 'contact';
static const failed = 'failed';
static const confirmationCall = 'confirmationCall';
static const pickupFromHome = 'pickupFromHome';
static const onTheWayToHospital = 'onTheWayToHospital';
static const arrivedAtHospital = 'arrivedAtHospital';
static const orderCancel = 'orderCancel';
static const emergencyCheckIn = 'emergencyCheckIn';
static const erOnlineCheckInDescription = 'erOnlineCheckInDescription';
static const erOnlineCheckInSuccess = 'erOnlineCheckInSuccess';
static const erOnlineCheckInError = 'erOnlineCheckInError';
static const fetchingHospitalsList = 'fetchingHospitalsList';
static const fetchingPaymentInformation = 'fetchingPaymentInformation';
static const erVisitDetails = 'erVisitDetails';
static const erClinic = 'erClinic';
static const vatWithAmount = 'vatWithAmount';
static const erAppointmentBookedSuccess = 'erAppointmentBookedSuccess';
static const underProcessing = 'underProcessing';
static const canceledByPatient = 'canceledByPatient';
static const rapidResponseTeam = 'rapidResponseTeam';
static const allFacilities = 'allFacilities';
static const selectLocation = 'selectLocation';
static const pleaseSelectTheLocation = 'pleaseSelectTheLocation';
static const viewLocationGoogleMaps = 'viewLocationGoogleMaps';
static const callAmbulance = 'callAmbulance';
static const requestAmbulanceInEmergency = 'requestAmbulanceInEmergency';
static const confirmation = 'confirmation';
static const areYouSureYouWantToCallAmbulance = 'areYouSureYouWantToCallAmbulance';
static const getDetailsOfNearestBranch = 'getDetailsOfNearestBranch';
static const areYouSureYouWantToCallRRT = 'areYouSureYouWantToCallRRT';
static const priorERCheckInToSkipLine = 'priorERCheckInToSkipLine';
static const areYouSureYouWantToMakeERCheckIn = 'areYouSureYouWantToMakeERCheckIn';
static const checkingYourERAppointmentStatus = 'checkingYourERAppointmentStatus';
static const transportOptions = 'transportOptions';
static const selectHospitalForAdvancePayment = 'selectHospitalForAdvancePayment';
static const recharge = 'recharge';
static const activityLevel = 'activityLevel';
static const selectActivityLevel = 'selectActivityLevel';
static const caloriesPerDay = 'caloriesPerDay';
static const dietType = 'dietType';
static const selectDietType = 'selectDietType';
static const bodyFrameSize = 'bodyFrameSize';
static const selectBodyFrameSize = 'selectBodyFrameSize';
static const averageCycleLength = 'averageCycleLength';
static const averageLutealPhase = 'averageLutealPhase';
static const convert = 'convert';
static const calculate = 'calculate';
static const healthCalculators = 'healthCalculators';
static const healthConverters = 'healthConverters';
static const generalHealth = 'generalHealth';
static const relatedToBMICalories = 'relatedToBMICalories';
static const selectCalculator = 'selectCalculator';
static const womensHealth = 'womensHealth';
static const relatedToPeriodsOvulation = 'relatedToPeriodsOvulation';
static const bloodSugar = 'bloodSugar';
static const trackYourGlucoseLevels = 'trackYourGlucoseLevels';
static const bloodCholesterol = 'bloodCholesterol';
static const monitorCholesterolLevels = 'monitorCholesterolLevels';
static const triglyceridesFatBlood = 'triglyceridesFatBlood';
static const understandTriglyceridesImpact = 'understandTriglyceridesImpact';
static const bmiCalculator = 'bmiCalculator';
static const caloriesCalculator = 'caloriesCalculator';
static const bmrCalculator = 'bmrCalculator';
static const idealBodyWeight = 'idealBodyWeight';
static const bodyFatCalculator = 'bodyFatCalculator';
static const carbsProteinFat = 'carbsProteinFat';
static const ovulationPeriod = 'ovulationPeriod';
static const deliveryDueDate = 'deliveryDueDate';
static const low = 'low';
static const preDiabetic = 'preDiabetic';
static const high = 'high';
static const elevated = 'elevated';
static const recorded = 'recorded';
static const noRecordsYet = 'noRecordsYet';
static const lastRecord = 'lastRecord';
static const addBloodSugar = 'addBloodSugar';
static const addBloodPressure = 'addBloodPressure';
static const addWeight = 'addWeight';
static const bloodSugarDataSavedSuccessfully = 'bloodSugarDataSavedSuccessfully';
static const bloodPressureDataSavedSuccessfully = 'bloodPressureDataSavedSuccessfully';
static const weightDataSavedSuccessfully = 'weightDataSavedSuccessfully';
static const pleaseWait = 'pleaseWait';
static const selectUnit = 'selectUnit';
static const selectMeasureTime = 'selectMeasureTime';
static const selectArm = 'selectArm';
static const enterBloodSugar = 'enterBloodSugar';
static const enterSystolicValue = 'enterSystolicValue';
static const enterDiastolicValue = 'enterDiastolicValue';
static const enterWeight = 'enterWeight';
static const selectDuration = 'selectDuration';
static const systolic = 'systolic';
static const diastolic = 'diastolic';
static const sendReportByEmail = 'sendReportByEmail';
static const enterYourEmailToReceiveReport = 'enterYourEmailToReceiveReport';
static const addNewRecord = 'addNewRecord';
static const healthTrackers = 'healthTrackers';
static const monitorBloodPressureLevels = 'monitorBloodPressureLevels';
static const trackWeightProgress = 'trackWeightProgress';
static const bookAppointment = 'bookAppointment';
static const completeCheckup = 'completeCheckup';
static const indoorNavigation = 'indoorNavigation';
static const eReferralServices = 'eReferralServices';
static const dailyWaterMonitor = 'dailyWaterMonitor';
static const fetchingYourWaterIntakeDetails = 'fetchingYourWaterIntakeDetails';
static const healthCalculatorsServices = 'healthCalculatorsServices';
static const healthConvertersServices = 'healthConvertersServices';
static const smartWatchesServices = 'smartWatchesServices';
static const exploreServices = 'exploreServices';
static const medicalAndCareServices = 'medicalAndCareServices';
static const hmgServices = 'hmgServices';
static const personalServices = 'personalServices';
static const habibWallet = 'habibWallet';
static const loginToViewWalletBalance = 'loginToViewWalletBalance';
static const loginToViewMedicalFile = 'loginToViewMedicalFile';
static const addMember = 'addMember';
static const addFamilyMember = 'addFamilyMember';
static const pleaseFillBelowFieldToAddNewFamilyMember = 'pleaseFillBelowFieldToAddNewFamilyMember';
static const healthTools = 'healthTools';
static const supportServices = 'supportServices';
static const virtualTour = 'virtualTour';
static const carParking = 'carParking';
static const latestNews = 'latestNews';
static const hmgContact = 'hmgContact';
} }

@ -10,6 +10,7 @@ import 'package:hmg_patient_app_new/core/dependencies.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/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart'; import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/active_prescriptions_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/book_appointments_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/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart'; import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart';
@ -27,6 +28,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart'; import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.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';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart'; import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart'; import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart'; import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
@ -46,6 +48,7 @@ import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart'; import 'package:provider/single_child_widget.dart';
import 'core/utils/size_utils.dart'; import 'core/utils/size_utils.dart';
import 'features/monthly_reports/terms_conditions_view_model.dart';
import 'firebase_options.dart'; import 'firebase_options.dart';
@pragma('vm:entry-point') @pragma('vm:entry-point')
@ -181,6 +184,15 @@ void main() async {
), ),
ChangeNotifierProvider<MonthlyReportViewModel>( ChangeNotifierProvider<MonthlyReportViewModel>(
create: (_) => getIt.get<MonthlyReportViewModel>(), create: (_) => getIt.get<MonthlyReportViewModel>(),
),
ChangeNotifierProvider<NotificationsViewModel>(
create: (_) => getIt.get<NotificationsViewModel>(),
),
ChangeNotifierProvider<ActivePrescriptionsViewModel>(
create: (_) => getIt.get<ActivePrescriptionsViewModel>(),
),
ChangeNotifierProvider<TermsConditionsViewModel>(
create: (_) => getIt.get<TermsConditionsViewModel>(),
) )
], child: MyApp()), ], child: MyApp()),
), ),

@ -87,7 +87,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
children: [ children: [
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: "Appointment Details".needTranslation, title: LocaleKeys.appointmentDetails.tr(),
report: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) report: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)
? () { ? () {
contactUsViewModel.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel); contactUsViewModel.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel);
@ -105,14 +105,13 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
AppointmentDoctorCard( AppointmentDoctorCard(
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onAskDoctorTap: () async { onAskDoctorTap: () async {
LoaderBottomSheet.showLoader(loadingText: "Checking doctor availability...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr());
await myAppointmentsViewModel.isDoctorAvailable( await myAppointmentsViewModel.isDoctorAvailable(
projectID: widget.patientAppointmentHistoryResponseModel.projectID, projectID: widget.patientAppointmentHistoryResponseModel.projectID,
doctorId: widget.patientAppointmentHistoryResponseModel.doctorID, doctorId: widget.patientAppointmentHistoryResponseModel.doctorID,
clinicId: widget.patientAppointmentHistoryResponseModel.clinicID, clinicId: widget.patientAppointmentHistoryResponseModel.clinicID,
onSuccess: (value) async { onSuccess: (value) async {
if (value) { if (value) {
print("Doctor is available");
await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) { await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
@ -129,14 +128,14 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
); );
}); });
} else { } else {
print("Doctor is not available"); debugPrint("Doctor is not available");
} }
}); });
}, },
onCancelTap: () async { onCancelTap: () async {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
LoaderBottomSheet.showLoader(loadingText: "Cancelling Appointment, Please Wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.cancellingAppointmentPleaseWait.tr());
await myAppointmentsViewModel.cancelAppointment( await myAppointmentsViewModel.cancelAppointment(
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onSuccess: (apiResponse) { onSuccess: (apiResponse) {
@ -145,7 +144,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
myAppointmentsViewModel.getPatientAppointments(true, false); myAppointmentsViewModel.getPatientAppointments(true, false);
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getSuccessWidget(loadingText: "Appointment Cancelled Successfully".needTranslation), child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentCancelledSuccessfully.tr()),
callBackFunc: () { callBackFunc: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
@ -182,13 +181,13 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
children: [ children: [
Row( Row(
children: [ children: [
"Appointment Status".needTranslation.toText16(isBold: true), LocaleKeys.appointmentStatus.tr().toText16(isBold: true),
], ],
), ),
SizedBox(height: 4.h), SizedBox(height: 4.h),
(!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel) (!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel)
? "Not Confirmed".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500) ? LocaleKeys.notConfirmed.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500)
: "Confirmed".needTranslation.toText12(color: AppColors.successColor, fontWeight: FontWeight.w500)), : LocaleKeys.confirmed.tr().toText12(color: AppColors.successColor, fontWeight: FontWeight.w500)),
SizedBox(height: 16.h), SizedBox(height: 16.h),
//TODO Add countdown timer in case of LiveCare Appointment //TODO Add countdown timer in case of LiveCare Appointment
widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false
@ -200,9 +199,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"The doctor will call you once the appointment time approaches." LocaleKeys.doctorWillCallYou.tr().toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
.needTranslation
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
], ],
), ),
), ),
@ -224,11 +221,11 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
child: SizedBox( child: SizedBox(
width: MediaQuery.of(context).size.width * 0.785, width: MediaQuery.of(context).size.width * 0.785,
child: CustomButton( child: CustomButton(
text: "Get Directions".needTranslation,
onPressed: () { onPressed: () {
MapsLauncher.launchCoordinates(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!), MapsLauncher.launchCoordinates(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!),
double.parse(widget.patientAppointmentHistoryResponseModel.longitude!), widget.patientAppointmentHistoryResponseModel.projectName); double.parse(widget.patientAppointmentHistoryResponseModel.longitude!), widget.patientAppointmentHistoryResponseModel.projectName);
}, },
text: LocaleKeys.getDirections.tr(),
backgroundColor: AppColors.textColor.withValues(alpha: 0.8), backgroundColor: AppColors.textColor.withValues(alpha: 0.8),
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01),
textColor: AppColors.whiteColor, textColor: AppColors.whiteColor,
@ -283,9 +280,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.setReminder.tr(context: context).toText13(isBold: true), LocaleKeys.setReminder.tr(context: context).toText13(isBold: true),
"Notify me before the appointment" LocaleKeys.notifyMeBeforeAppointment.tr().toText11(color: AppColors.textColorLight, weight: FontWeight.w500),
.needTranslation
.toText11(color: AppColors.textColorLight, weight: FontWeight.w500),
], ],
), ),
const Spacer(), const Spacer(),
@ -307,8 +302,9 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
"${widget.patientAppointmentHistoryResponseModel.appointmentNo}"??"", "${widget.patientAppointmentHistoryResponseModel.appointmentNo}"??"",
"", "",
"", "",
title: "Appointment with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}".needTranslation, title: "Appointment with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}",
description:"${widget.patientAppointmentHistoryResponseModel.doctorNameObj} will be having an appointment on ${widget.patientAppointmentHistoryResponseModel.appointmentDate}".needTranslation, description:
"${widget.patientAppointmentHistoryResponseModel.doctorNameObj} will be having an appointment on ${widget.patientAppointmentHistoryResponseModel.appointmentDate}",
onSuccess: () { onSuccess: () {
setState(() { setState(() {
myAppointmentsViewModel.setAppointmentReminder(newValue, widget.patientAppointmentHistoryResponseModel); myAppointmentsViewModel.setAppointmentReminder(newValue, widget.patientAppointmentHistoryResponseModel);
@ -318,10 +314,10 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
onMultiDateSuccess: (int selectedIndex) async { onMultiDateSuccess: (int selectedIndex) async {
isEventAddedOrRemoved = await calender.createOrUpdateEvent( isEventAddedOrRemoved = await calender.createOrUpdateEvent(
title: "Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} on ${DateUtil.convertStringToDate(widget title:
.patientAppointmentHistoryResponseModel.appointmentDate)}, Appointment #${widget.patientAppointmentHistoryResponseModel.appointmentNo}".needTranslation, "Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} on ${DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate)}, Appointment #${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
description: "Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} in ${widget description:
.patientAppointmentHistoryResponseModel.projectName}", "Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} in ${widget.patientAppointmentHistoryResponseModel.projectName}",
scheduleDateTime: DateUtil.convertStringToDate(widget scheduleDateTime: DateUtil.convertStringToDate(widget
.patientAppointmentHistoryResponseModel.appointmentDate), .patientAppointmentHistoryResponseModel.appointmentDate),
eventId: "${widget.patientAppointmentHistoryResponseModel.appointmentNo}", eventId: "${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
@ -369,7 +365,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
isLargeText: true, isLargeText: true,
iconSize: 36.w, iconSize: 36.w,
).onPress(() async { ).onPress(() async {
LoaderBottomSheet.showLoader(loadingText: "Fetching Lab Results...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingLabResults.tr());
await labViewModel.getLabResultsByAppointmentNo( await labViewModel.getLabResultsByAppointmentNo(
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo, appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo,
projectID: widget.patientAppointmentHistoryResponseModel.projectID, projectID: widget.patientAppointmentHistoryResponseModel.projectID,
@ -402,7 +398,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
isLargeText: true, isLargeText: true,
iconSize: 36.w, iconSize: 36.w,
).onPress(() async { ).onPress(() async {
LoaderBottomSheet.showLoader(loadingText: "Fetching Radiology Results...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingRadiologyResults.tr());
await radiologyViewModel.getPatientRadiologyOrdersByAppointment( await radiologyViewModel.getPatientRadiologyOrdersByAppointment(
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo, appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo,
projectID: widget.patientAppointmentHistoryResponseModel.projectID, projectID: widget.patientAppointmentHistoryResponseModel.projectID,
@ -429,7 +425,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
isLargeText: true, isLargeText: true,
iconSize: 36.w, iconSize: 36.w,
).onPress(() async { ).onPress(() async {
LoaderBottomSheet.showLoader(loadingText: "Fetching Appointment Prescriptions...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingAppointmentPrescriptions.tr());
await prescriptionsViewModel.getPrescriptionDetails( await prescriptionsViewModel.getPrescriptionDetails(
getPrescriptionRequestModel(), getPrescriptionRequestModel(),
onSuccess: (val) { onSuccess: (val) {
@ -457,8 +453,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
} else { } else {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget( child: Utils.getErrorWidget(loadingText: LocaleKeys.noPrescriptionsForAppointment.tr()),
loadingText: "You don't have any prescriptions for this appointment.".needTranslation),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -713,7 +708,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Amount before tax".needTranslation.toText18(isBold: true), LocaleKeys.amountBeforeTax.tr().toText18(isBold: true),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true), widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true),
AppColors.blackColor, AppColors.blackColor,
@ -730,7 +725,6 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
.tr(context: context) .tr(context: context)
.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor)), .toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor)),
"VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})" "VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})"
.needTranslation
.toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -2), .toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -2),
], ],
), ),
@ -758,7 +752,7 @@ 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( ? CustomButton(
text: "Re-book Appointment".needTranslation, text: LocaleKeys.rebookAppointment.tr(),
onPressed: () { onPressed: () {
openDoctorScheduleCalendar(); openDoctorScheduleCalendar();
}, },
@ -816,13 +810,13 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
projectName: widget.patientAppointmentHistoryResponseModel.projectName, projectName: widget.patientAppointmentHistoryResponseModel.projectName,
); );
bookAppointmentsViewModel.setSelectedDoctor(doctor); bookAppointmentsViewModel.setSelectedDoctor(doctor);
LoaderBottomSheet.showLoader(loadingText: "Fetching Doctor Schedule, Please Wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingDoctorSchedulePleaseWait.tr());
await bookAppointmentsViewModel.getDoctorFreeSlots( await bookAppointmentsViewModel.getDoctorFreeSlots(
isBookingForLiveCare: false, isBookingForLiveCare: false,
onSuccess: (dynamic respData) async { onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: "Pick a Date".needTranslation, title: LocaleKeys.pickADate.tr(),
context, context,
child: AppointmentCalendar(), child: AppointmentCalendar(),
isFullScreen: false, isFullScreen: false,
@ -847,15 +841,14 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
case 0: case 0:
break; break;
case 10: case 10:
LoaderBottomSheet.showLoader(loadingText: "Confirming Appointment, Please Wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingAppointmentPleaseWait.tr());
await myAppointmentsViewModel.confirmAppointment( await myAppointmentsViewModel.confirmAppointment(
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onSuccess: (apiResponse) { onSuccess: (apiResponse) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.getPatientAppointments(true, false); myAppointmentsViewModel.getPatientAppointments(true, false);
showCommonBottomSheet(context, child: Utils.getSuccessWidget(loadingText: "Appointment Confirmed Successfully".needTranslation), showCommonBottomSheet(context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentConfirmedSuccessfully.tr()), callBackFunc: (str) {
callBackFunc: (str) {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
title: "", title: "",

@ -90,7 +90,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
children: [ children: [
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: "Appointment Payment".needTranslation, title: LocaleKeys.appointmentPayment.tr(),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -111,7 +111,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
Image.asset(AppAssets.mada, width: 72.h, height: 25.h) Image.asset(AppAssets.mada, width: 72.h, height: 25.h)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), .toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Mada".needTranslation.toText16(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), "Mada".toText16(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
], ],
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
@ -154,7 +154,6 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Visa or Mastercard" "Visa or Mastercard"
.needTranslation
.toText16(isBold: true) .toText16(isBold: true)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), .toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
], ],
@ -195,7 +194,6 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
.toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), .toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Tamara" "Tamara"
.needTranslation
.toText16(isBold: true) .toText16(isBold: true)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), .toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
], ],
@ -250,8 +248,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Insurance expired or inactive" LocaleKeys.insuranceExpiredOrInactive.tr()
.needTranslation
.toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500) .toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500)
.paddingSymmetrical(24.h, 0.h), .paddingSymmetrical(24.h, 0.h),
CustomButton( CustomButton(
@ -277,12 +274,12 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
) )
: const SizedBox(), : const SizedBox(),
SizedBox(height: 24.h), SizedBox(height: 24.h),
"Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h), LocaleKeys.totalAmountToPay.tr().toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h), SizedBox(height: 17.h),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Amount before tax".needTranslation.toText14(isBold: true), LocaleKeys.amountBeforeTax.tr().toText14(isBold: true),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
myAppointmentsVM.patientAppointmentShareResponseModel!.patientShare!.toString().toText16(isBold: true), myAppointmentsVM.patientAppointmentShareResponseModel!.patientShare!.toString().toText16(isBold: true),
AppColors.blackColor, AppColors.blackColor,
@ -293,7 +290,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor), "VAT 15%".toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
myAppointmentsVM.patientAppointmentShareResponseModel!.patientTaxAmount! myAppointmentsVM.patientAppointmentShareResponseModel!.patientTaxAmount!
.toString() .toString()
@ -307,7 +304,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"".needTranslation.toText14(isBold: true), "".toText14(isBold: true),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
myAppointmentsVM.patientAppointmentShareResponseModel!.patientShareWithTax!.toString().toText24(isBold: true), myAppointmentsVM.patientAppointmentShareResponseModel!.patientShareWithTax!.toString().toText24(isBold: true),
AppColors.blackColor, AppColors.blackColor,
@ -383,7 +380,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
} }
void checkPaymentStatus() async { void checkPaymentStatus() async {
LoaderBottomSheet.showLoader(loadingText: "Checking payment status, Please wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr());
if (selectedPaymentMethod == "TAMARA") { if (selectedPaymentMethod == "TAMARA") {
await payfortViewModel.checkTamaraPaymentStatus( await payfortViewModel.checkTamaraPaymentStatus(
transactionID: transID, transactionID: transID,
@ -441,7 +438,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation), child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr()),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -522,7 +519,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
} else { } else {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation), child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr()),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,

@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.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/app_state.dart';
@ -7,6 +8,7 @@ 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/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart'; import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.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';
@ -30,7 +32,7 @@ class AppointmentQueuePage extends StatelessWidget {
children: [ children: [
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: "Queueing".needTranslation, title: LocaleKeys.queueing.tr(context: context),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: EdgeInsets.all(24.0), padding: EdgeInsets.all(24.0),
@ -57,7 +59,7 @@ class AppointmentQueuePage extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
labelText: myAppointmentsVM.currentQueueStatus == 0 ? "In Queue".needTranslation : "Your Turn".needTranslation, labelText: myAppointmentsVM.currentQueueStatus == 0 ? LocaleKeys.inQueue.tr(context: context) : LocaleKeys.yourTurn.tr(context: context),
backgroundColor: Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus).withValues(alpha: 0.20), backgroundColor: Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus).withValues(alpha: 0.20),
textColor: Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus), textColor: Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus),
), ),
@ -66,12 +68,10 @@ class AppointmentQueuePage extends StatelessWidget {
).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading), ).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 10.h), SizedBox(height: 10.h),
"Hala ${appState!.getAuthenticatedUser()!.firstName}!!!" "Hala ${appState!.getAuthenticatedUser()!.firstName}!!!"
.needTranslation
.toText16(isBold: true) .toText16(isBold: true)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading), .toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 8.h), SizedBox(height: 8.h),
"Thank you for your patience, here is your queue number." LocaleKeys.thankYouForPatience.tr(context: context)
.needTranslation
.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight) .toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading), .toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 8.h), SizedBox(height: 8.h),
@ -111,8 +111,7 @@ class AppointmentQueuePage extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Serving Now" LocaleKeys.servingNow.tr(context: context)
.needTranslation
.toText16(isBold: true) .toText16(isBold: true)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading), .toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 18.h), SizedBox(height: 18.h),
@ -138,8 +137,8 @@ class AppointmentQueuePage extends StatelessWidget {
? AppAssets.call_for_vitals ? AppAssets.call_for_vitals
: AppAssets.call_for_doctor, : AppAssets.call_for_doctor,
labelText: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 labelText: myAppointmentsVM.patientQueueDetailsList[index].callType == 1
? "Call for vital signs".needTranslation ? LocaleKeys.callForVitalSigns.tr(context: context)
: "Call for Doctor".needTranslation, : LocaleKeys.callForDoctor.tr(context: context),
iconColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 iconColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1
? AppColors.primaryRedColor ? AppColors.primaryRedColor
: AppColors.successColor, : AppColors.successColor,
@ -180,35 +179,23 @@ class AppointmentQueuePage extends StatelessWidget {
children: [ children: [
Utils.buildSvgWithAssets(icon: AppAssets.bulb_icon, width: 24.w, height: 24.h), Utils.buildSvgWithAssets(icon: AppAssets.bulb_icon, width: 24.w, height: 24.h),
SizedBox(width: 8.w), SizedBox(width: 8.w),
"Things to ask your doctor today".needTranslation.toText16(isBold: true), LocaleKeys.thingsToAskDoctor.tr(context: context).toText16(isBold: true),
], ],
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
"${LocaleKeys.improveOverallHealth.tr(context: context)}"
// What can I do to improve my overall health?
// Are there any routine screenings I should get?
// What is this medication for?
// Are there any side effects I should know about?
// When should I come back for a follow-up?
"${"What can I do to improve my overall health?"}"
.needTranslation
.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), .toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"${"Are there any routine screenings I should get?"}" "${LocaleKeys.routineScreenings.tr(context: context)}"
.needTranslation
.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), .toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"${"What is this medication for?"}" "${LocaleKeys.whatIsThisMedicationFor.tr(context: context)}"
.needTranslation
.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), .toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"${"Are there any side effects I should know about?"}" "${LocaleKeys.sideEffectsToKnow.tr(context: context)}"
.needTranslation
.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), .toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"${"When should I come back for a follow-up?"}" "${LocaleKeys.whenFollowUp.tr(context: context)}"
.needTranslation
.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight), .toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 16.h), SizedBox(height: 16.h),
@ -229,7 +216,7 @@ class AppointmentQueuePage extends StatelessWidget {
hasShadow: true, hasShadow: true,
), ),
child: CustomButton( child: CustomButton(
text: "Go to homepage".needTranslation, text: LocaleKeys.goToHomepage.tr(context: context),
onPressed: () { onPressed: () {
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
context, context,
@ -249,11 +236,10 @@ class AppointmentQueuePage extends StatelessWidget {
icon: AppAssets.homeBottom, icon: AppAssets.homeBottom,
iconColor: AppColors.whiteColor, iconColor: AppColors.whiteColor,
iconSize: 18.h, iconSize: 18.h,
).paddingSymmetrical(16.h, 24.h), ).paddingSymmetrical(24.h, 24.h),
) ),
], ],
); );
}), }));
);
} }
} }

@ -56,7 +56,7 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
return Scaffold( return Scaffold(
backgroundColor: AppColors.bgScaffoldColor, backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView( body: CollapsingListView(
title: "Appointments List".needTranslation, title: LocaleKeys.appointmentsList.tr(context: context),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
@ -65,9 +65,9 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
activeTextColor: Color(0xffED1C2B), activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
tabs: [ tabs: [
CustomTabBarModel(null, "All Appt.".needTranslation), CustomTabBarModel(null, LocaleKeys.allAppt.tr(context: context)),
CustomTabBarModel(null, "Upcoming".needTranslation), CustomTabBarModel(null, LocaleKeys.upcoming.tr(context: context)),
CustomTabBarModel(null, "Completed".needTranslation), CustomTabBarModel(null, LocaleKeys.completed.tr(context: context)),
], ],
onTabChange: (index) { onTabChange: (index) {
setState(() { setState(() {
@ -248,7 +248,7 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
) )
: Utils.getNoDataWidget( : Utils.getNoDataWidget(
context, context,
noDataText: "You don't have any appointments yet.".needTranslation, noDataText: LocaleKeys.noAppointmentsYet.tr(context: context),
callToActionButton: CustomButton( callToActionButton: CustomButton(
text: LocaleKeys.bookAppo.tr(context: context), text: LocaleKeys.bookAppo.tr(context: context),
onPressed: () { onPressed: () {
@ -296,7 +296,7 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
onClicked: () { onClicked: () {
if (myAppointmentsVM.availableFilters[index] == AppointmentListingFilters.DATESELECTION) { if (myAppointmentsVM.availableFilters[index] == AppointmentListingFilters.DATESELECTION) {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: "Set The Date Range".needTranslation, title: LocaleKeys.setTheDateRange.tr(context: context),
context, context,
child: DateRangeSelector( child: DateRangeSelector(
onRangeSelected: (start, end) { onRangeSelected: (start, end) {

@ -211,7 +211,7 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
AppCustomChipWidget(labelText: "${group.length} ${'doctors'.needTranslation}"), AppCustomChipWidget(labelText: "${group.length} ${'doctors'}"),
Icon(isExpanded ? Icons.expand_less : Icons.expand_more), Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
], ],
), ),
@ -284,7 +284,7 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
icon: AppAssets.view_report_icon, icon: AppAssets.view_report_icon,
iconColor: AppColors.primaryRedColor, iconColor: AppColors.primaryRedColor,
iconSize: 16.h, iconSize: 16.h,
text: "View Profile".needTranslation.tr(context: context), text: LocaleKeys.viewProfile.tr(context: context),
onPressed: () async { onPressed: () async {
bookAppointmentsViewModel.setSelectedDoctor(DoctorsListResponseModel( bookAppointmentsViewModel.setSelectedDoctor(DoctorsListResponseModel(
clinicID: doctor?.clinicID ?? 0, clinicID: doctor?.clinicID ?? 0,

@ -96,13 +96,13 @@ class AppointmentCard extends StatelessWidget {
AppCustomChipWidget( AppCustomChipWidget(
icon: isLoading ? AppAssets.walkin_appointment_icon : (isLiveCare ? AppAssets.small_livecare_icon : AppAssets.walkin_appointment_icon), icon: isLoading ? AppAssets.walkin_appointment_icon : (isLiveCare ? AppAssets.small_livecare_icon : AppAssets.walkin_appointment_icon),
iconColor: isLoading ? AppColors.textColor : (isLiveCare ? AppColors.whiteColor : AppColors.textColor), iconColor: isLoading ? AppColors.textColor : (isLiveCare ? AppColors.whiteColor : AppColors.textColor),
labelText: isLoading ? 'Walk In'.needTranslation : (isLiveCare ? LocaleKeys.livecare.tr(context: context) : 'Walk In'.needTranslation), labelText: isLoading ? LocaleKeys.walkin.tr(context: context) : (isLiveCare ? LocaleKeys.livecare.tr(context: context) : LocaleKeys.walkin.tr(context: context)),
backgroundColor: isLoading ? AppColors.greyColor : (isLiveCare ? AppColors.successColor : AppColors.greyColor), backgroundColor: isLoading ? AppColors.greyColor : (isLiveCare ? AppColors.successColor : AppColors.greyColor),
textColor: isLoading ? AppColors.textColor : (isLiveCare ? AppColors.whiteColor : AppColors.textColor), textColor: isLoading ? AppColors.textColor : (isLiveCare ? AppColors.whiteColor : AppColors.textColor),
).toShimmer2(isShow: isLoading), ).toShimmer2(isShow: isLoading),
AppCustomChipWidget( AppCustomChipWidget(
labelText: isLoading labelText: isLoading
? 'OutPatient'.needTranslation ? 'OutPatient'
: (appState.isArabic() : (appState.isArabic()
? patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN! ? patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN!
: patientAppointmentHistoryResponseModel.isInOutPatientDescription!), : patientAppointmentHistoryResponseModel.isInOutPatientDescription!),
@ -111,7 +111,7 @@ class AppointmentCard extends StatelessWidget {
).toShimmer2(isShow: isLoading), ).toShimmer2(isShow: isLoading),
AppCustomChipWidget( AppCustomChipWidget(
labelText: isLoading labelText: isLoading
? 'Booked'.needTranslation ? 'Booked'
: AppointmentType.getAppointmentStatusType(patientAppointmentHistoryResponseModel.patientStatusType!), : AppointmentType.getAppointmentStatusType(patientAppointmentHistoryResponseModel.patientStatusType!),
backgroundColor: AppColors.successColor.withValues(alpha: 0.1), backgroundColor: AppColors.successColor.withValues(alpha: 0.1),
textColor: AppColors.successColor, textColor: AppColors.successColor,
@ -229,7 +229,7 @@ class AppointmentCard extends StatelessWidget {
return SizedBox.shrink(); return SizedBox.shrink();
} else { } else {
return CustomButton( return CustomButton(
text: 'Select appointment'.needTranslation, text: LocaleKeys.selectAppointment.tr(context: context),
onPressed: () { onPressed: () {
if (isForFeedback) { if (isForFeedback) {
contactUsViewModel!.setPatientFeedbackSelectedAppointment(patientAppointmentHistoryResponseModel); contactUsViewModel!.setPatientFeedbackSelectedAppointment(patientAppointmentHistoryResponseModel);
@ -310,7 +310,7 @@ class AppointmentCard extends StatelessWidget {
return CustomButton( return CustomButton(
text: LocaleKeys.askDoctor.tr(context: context), text: LocaleKeys.askDoctor.tr(context: context),
onPressed: () async { onPressed: () async {
LoaderBottomSheet.showLoader(loadingText: "Checking doctor availability...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context));
await myAppointmentsViewModel.isDoctorAvailable( await myAppointmentsViewModel.isDoctorAvailable(
projectID: patientAppointmentHistoryResponseModel.projectID, projectID: patientAppointmentHistoryResponseModel.projectID,
doctorId: patientAppointmentHistoryResponseModel.doctorID, doctorId: patientAppointmentHistoryResponseModel.doctorID,
@ -353,7 +353,7 @@ class AppointmentCard extends StatelessWidget {
} }
return CustomButton( return CustomButton(
text: 'Rebook with same doctor'.needTranslation, text: LocaleKeys.rebookSameDoctor.tr(context: context),
onPressed: () => openDoctorScheduleCalendar(context), onPressed: () => openDoctorScheduleCalendar(context),
backgroundColor: AppColors.greyColor, backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor, borderColor: AppColors.greyColor,
@ -417,7 +417,7 @@ class AppointmentCard extends StatelessWidget {
context, context,
child: AppointmentCalendar(), child: AppointmentCalendar(),
callBackFunc: () {}, callBackFunc: () {},
title: 'Pick a Date'.needTranslation, title: LocaleKeys.pickADate.tr(context: context),
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
); );

@ -45,8 +45,8 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
children: [ children: [
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_location_icon, AppAssets.checkin_location_icon,
"Live Location".needTranslation, LocaleKeys.liveLocation.tr(context: context),
"Verify your location to be at hospital to check in".needTranslation, LocaleKeys.verifyYourLocationAtHospital.tr(context: context),
).onPress(() { ).onPress(() {
// locationUtils = LocationUtils( // locationUtils = LocationUtils(
// isShowConfirmDialog: false, // isShowConfirmDialog: false,
@ -61,8 +61,10 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
sendCheckInRequest(projectDetailListModel.checkInQrCode!, 3, context); sendCheckInRequest(projectDetailListModel.checkInQrCode!, 3, context);
} else { } else {
showCommonBottomSheetWithoutHeight(context, showCommonBottomSheetWithoutHeight(context,
title: "Error".needTranslation, title: LocaleKeys.error.tr(context: context),
child: Utils.getErrorWidget(loadingText: "Please ensure you're within the hospital location to perform online check-in.".needTranslation), callBackFunc: () { child: Utils.getErrorWidget(
loadingText: LocaleKeys.ensureWithinHospitalLocation.tr(context: context),
), callBackFunc: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, isFullScreen: false); }, isFullScreen: false);
} }
@ -71,8 +73,8 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
SizedBox(height: 16.h), SizedBox(height: 16.h),
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_nfc_icon, AppAssets.checkin_nfc_icon,
"NFC (Near Field Communication)".needTranslation, LocaleKeys.nfcNearFieldCommunication.tr(context: context),
"Scan your phone via NFC board to check in".needTranslation, LocaleKeys.scanPhoneViaNFC.tr(context: context),
).onPress(() { ).onPress(() {
Future.delayed(const Duration(milliseconds: 500), () { Future.delayed(const Duration(milliseconds: 500), () {
showNfcReader(context, onNcfScan: (String nfcId) { showNfcReader(context, onNcfScan: (String nfcId) {
@ -85,8 +87,8 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
SizedBox(height: 16.h), SizedBox(height: 16.h),
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_qr_icon, AppAssets.checkin_qr_icon,
"QR Code".needTranslation, LocaleKeys.qrCode.tr(context: context),
"Scan QR code with your camera to check in".needTranslation, LocaleKeys.scanQRCodeToCheckIn.tr(context: context),
).onPress(() async { ).onPress(() async {
String onlineCheckInQRCode = (await BarcodeScanner.scan().then((value) => value.rawContent)); String onlineCheckInQRCode = (await BarcodeScanner.scan().then((value) => value.rawContent));
if (onlineCheckInQRCode != "") { if (onlineCheckInQRCode != "") {
@ -139,14 +141,16 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
} }
void sendCheckInRequest(String scannedCode, int checkInType, BuildContext context) async { void sendCheckInRequest(String scannedCode, int checkInType, BuildContext context) async {
LoaderBottomSheet.showLoader(loadingText: "Processing Check-In...".needTranslation); LoaderBottomSheet.showLoader(
loadingText: LocaleKeys.processingCheckIn.tr(context: context),
);
await myAppointmentsViewModel.sendCheckInNfcRequest( await myAppointmentsViewModel.sendCheckInNfcRequest(
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
scannedCode: scannedCode, scannedCode: scannedCode,
checkInType: checkInType, checkInType: checkInType,
onSuccess: (apiResponse) { onSuccess: (apiResponse) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: "Success".needTranslation, child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()), callBackFunc: () async { showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.success.tr(context: context), child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()), callBackFunc: () async {
await myAppointmentsViewModel.getPatientAppointmentQueueDetails(); await myAppointmentsViewModel.getPatientAppointmentQueueDetails();
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
@ -164,7 +168,7 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
}, },
onError: (error) { onError: (error) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: "Error".needTranslation, child: Utils.getErrorWidget(loadingText: error), callBackFunc: () { showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.error.tr(context: context), child: Utils.getErrorWidget(loadingText: error), callBackFunc: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, isFullScreen: false); }, isFullScreen: false);
}, },

@ -114,7 +114,7 @@ class AppointmentDoctorCard extends StatelessWidget {
iconColor: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.textColor : AppColors.whiteColor, iconColor: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.textColor : AppColors.whiteColor,
labelText: patientAppointmentHistoryResponseModel.isLiveCareAppointment! labelText: patientAppointmentHistoryResponseModel.isLiveCareAppointment!
? LocaleKeys.livecare.tr(context: context) ? LocaleKeys.livecare.tr(context: context)
: "Walk In".needTranslation, : LocaleKeys.walkin.tr(context: context),
backgroundColor: backgroundColor:
!patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.greyColor : AppColors.successColor, !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.greyColor : AppColors.successColor,
textColor: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.textColor : AppColors.whiteColor, textColor: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.textColor : AppColors.whiteColor,
@ -160,7 +160,7 @@ class AppointmentDoctorCard extends StatelessWidget {
iconColor: AppColors.primaryRedColor, iconColor: AppColors.primaryRedColor,
) )
: CustomButton( : CustomButton(
text: "Rebook with same doctor".needTranslation, text: LocaleKeys.rebookSameDoctor.tr(),
onPressed: () { onPressed: () {
onRescheduleTap(); onRescheduleTap();
}, },

@ -105,7 +105,7 @@ class AskDoctorRequestTypeSelect extends StatelessWidget {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getSuccessWidget(loadingText: "Request has been sent successfully, you will be contacted soon.".needTranslation), child: Utils.getSuccessWidget(loadingText: "Request has been sent successfully, you will be contacted soon."),
callBackFunc: () { callBackFunc: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },

@ -46,7 +46,7 @@ class FacilityTypeSelectionWidget extends StatelessWidget {
SizedBox(height: 24.h), SizedBox(height: 24.h),
FacilitySelectionItem( FacilitySelectionItem(
svgPath: AppAssets.hmg, svgPath: AppAssets.hmg,
title: "HMG".needTranslation, title: "HMG",
subTitle: LocaleKeys.hospitalsWithCount.tr(namedArgs: { subTitle: LocaleKeys.hospitalsWithCount.tr(namedArgs: {
'count': 'count':
"${bookAppointmentViewModel.hospitalList?.registeredDoctorMap?[selectedRegion]?.hmgSize ?? 0}" "${bookAppointmentViewModel.hospitalList?.registeredDoctorMap?[selectedRegion]?.hmgSize ?? 0}"
@ -63,7 +63,7 @@ class FacilityTypeSelectionWidget extends StatelessWidget {
SizedBox(height: 16.h), SizedBox(height: 16.h),
FacilitySelectionItem( FacilitySelectionItem(
svgPath: AppAssets.hmc, svgPath: AppAssets.hmc,
title: "HMC".needTranslation, title: "HMC",
subTitle: LocaleKeys.medicalCentersWithCount.tr(namedArgs: { subTitle: LocaleKeys.medicalCentersWithCount.tr(namedArgs: {
'count': 'count':
"${bookAppointmentViewModel.hospitalList?.registeredDoctorMap?[selectedRegion]?.hmcSize ?? 0}" "${bookAppointmentViewModel.hospitalList?.registeredDoctorMap?[selectedRegion]?.hmcSize ?? 0}"

@ -76,7 +76,7 @@ class HospitalListItem extends StatelessWidget {
Visibility( Visibility(
visible: (hospitalData?.distanceInKMs != "0"), visible: (hospitalData?.distanceInKMs != "0"),
child: AppCustomChipWidget( child: AppCustomChipWidget(
labelText: "${hospitalData?.distanceInKMs ?? ""} km".needTranslation, labelText: "${hospitalData?.distanceInKMs ?? ""} km",
deleteIcon: AppAssets.location_red, deleteIcon: AppAssets.location_red,
deleteIconSize: Size(9, 12), deleteIconSize: Size(9, 12),
backgroundColor: AppColors.secondaryLightRedColor, backgroundColor: AppColors.secondaryLightRedColor,
@ -88,7 +88,7 @@ class HospitalListItem extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
labelText: "Distance not available".needTranslation, labelText: "Distance not available",
textColor: AppColors.blackColor, textColor: AppColors.blackColor,
), ),
// SizedBox( // SizedBox(
@ -99,7 +99,7 @@ class HospitalListItem extends StatelessWidget {
Visibility( Visibility(
visible: !isLocationEnabled, visible: !isLocationEnabled,
child: AppCustomChipWidget( child: AppCustomChipWidget(
labelText: "Location turned off".needTranslation, labelText: "Location turned off",
deleteIcon: AppAssets.location_unavailable, deleteIcon: AppAssets.location_unavailable,
deleteIconSize: Size(9.w, 12.h), deleteIconSize: Size(9.w, 12.h),
textColor: AppColors.blackColor, textColor: AppColors.blackColor,

@ -23,7 +23,7 @@ class TypeSelectionWidget extends StatelessWidget {
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
labelText: "All Facilities".needTranslation, labelText: "All Facilities",
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
side: BorderSide( side: BorderSide(
color: data.currentlySelectedFacility == FacilitySelection.ALL color: data.currentlySelectedFacility == FacilitySelection.ALL
@ -45,7 +45,7 @@ class TypeSelectionWidget extends StatelessWidget {
AppCustomChipWidget( AppCustomChipWidget(
icon: AppAssets.hmg, icon: AppAssets.hmg,
iconHasColor: false, iconHasColor: false,
labelText: "Hospitals".needTranslation, labelText: "Hospitals",
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
side: BorderSide( side: BorderSide(
color: data.currentlySelectedFacility == FacilitySelection.HMG color: data.currentlySelectedFacility == FacilitySelection.HMG
@ -67,7 +67,7 @@ class TypeSelectionWidget extends StatelessWidget {
AppCustomChipWidget( AppCustomChipWidget(
icon: AppAssets.hmc, icon: AppAssets.hmc,
iconHasColor: false, iconHasColor: false,
labelText: "Medical Centers".needTranslation, labelText: "Medical Centers",
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
side: BorderSide( side: BorderSide(
color: data.currentlySelectedFacility == FacilitySelection.HMC color: data.currentlySelectedFacility == FacilitySelection.HMC

@ -87,7 +87,7 @@ class LoginScreenState extends State<LoginScreen> {
isAllowLeadingIcon: true, isAllowLeadingIcon: true,
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 10.h), padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 10.h),
leadingIcon: AppAssets.student_card, leadingIcon: AppAssets.student_card,
errorMessage: "Please enter a valid national ID or file number".needTranslation, errorMessage: LocaleKeys.enterValidIDorIqama.tr(),
hasError: false, hasError: false,
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),

@ -112,7 +112,7 @@ class _RegisterNew extends State<RegisterNew> {
Divider(height: 1), Divider(height: 1),
TextInputWidget( TextInputWidget(
labelText: LocaleKeys.dob.tr(), labelText: LocaleKeys.dob.tr(),
hintText: "11 July, 1994".needTranslation, hintText: "11 July, 1994",
controller: authVm.dobController, controller: authVm.dobController,
focusNode: _dobFocusNode, focusNode: _dobFocusNode,
isEnable: true, isEnable: true,

@ -89,8 +89,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
initialIndex: bookAppointmentsVM.selectedTabIndex, initialIndex: bookAppointmentsVM.selectedTabIndex,
tabs: [ tabs: [
CustomTabBarModel(null, "General".needTranslation), CustomTabBarModel(null, LocaleKeys.general.tr()),
CustomTabBarModel(null, "LiveCare".needTranslation), CustomTabBarModel(null, LocaleKeys.liveCare.tr()),
], ],
onTabChange: (index) { onTabChange: (index) {
bookAppointmentsVM.onTabChanged(index); bookAppointmentsVM.onTabChanged(index);
@ -121,7 +121,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (appState.isAuthenticated) ...[], if (appState.isAuthenticated) ...[],
"Recent Visits".needTranslation.toText18(isBold: true).paddingSymmetrical(24.w, 0.h), LocaleKeys.recentVisits.tr().toText18(isBold: true).paddingSymmetrical(24.w, 0.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
SizedBox( SizedBox(
height: 110.h, height: 110.h,
@ -232,8 +232,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Search By Clinic".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.searchByClinic.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), LocaleKeys.tapToSelectClinic.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
], ],
), ),
], ],
@ -264,8 +264,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Search By Doctor".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.searchByDoctor.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), LocaleKeys.tapToSelect.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
], ],
), ),
], ],
@ -294,8 +294,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Search By Region".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.searchByRegion.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Central Region".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), LocaleKeys.centralRegion.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
], ],
), ),
], ],
@ -340,8 +340,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Immediate Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.immediateConsultation.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), LocaleKeys.tapToSelectClinic.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
], ],
), ),
], ],
@ -382,8 +382,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Scheduled Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.scheduledConsultation.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), LocaleKeys.tapToSelectClinic.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
], ],
), ),
], ],
@ -412,8 +412,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Pharma LiveCare".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.pharmaLiveCare.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500),
"".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), "".toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
], ],
), ),
], ],
@ -447,9 +447,9 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Not sure? help me choose a clinic!".needTranslation.toText16(weight: FontWeight.w600, color: AppColors.textColor), LocaleKeys.notSureHelpMeChooseClinic.tr().toText16(weight: FontWeight.w600, color: AppColors.textColor),
SizedBox(height: 4.h), SizedBox(height: 8.h),
"Mention your symptoms and find the list of doctors accordingly".needTranslation.toText12( LocaleKeys.mentionYourSymptomsAndFindDoctors.tr().toText12(
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
), ),
@ -558,8 +558,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Immediate service".needTranslation.toText18(color: AppColors.textColor, isBold: true), LocaleKeys.immediateService.tr().toText18(color: AppColors.textColor, isBold: true),
"No need to wait, you will get medical consultation immediately via video call".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), LocaleKeys.noNeedToWaitGetMedicalConsultation.tr().toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
], ],
), ),
), ),
@ -574,7 +574,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"No visit required".needTranslation.toText18(color: AppColors.textColor, isBold: true), LocaleKeys.noVisitRequired.tr().toText18(color: AppColors.textColor, isBold: true),
LocaleKeys.livecarePoint5.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), LocaleKeys.livecarePoint5.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
], ],
), ),
@ -590,8 +590,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Doctor will contact".needTranslation.toText18(color: AppColors.textColor, isBold: true), LocaleKeys.doctorWillContact.tr().toText18(color: AppColors.textColor, isBold: true),
"A specialised doctor will contact you and will be able to view your medical history".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), LocaleKeys.specialisedDoctorWillContactYou.tr().toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
], ],
), ),
), ),
@ -606,8 +606,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Free medicine delivery".needTranslation.toText18(color: AppColors.textColor, isBold: true), LocaleKeys.freeMedicineDelivery.tr().toText18(color: AppColors.textColor, isBold: true),
"Offers free medicine delivery for the LiveCare appointment".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), LocaleKeys.offersFreeMedicineDelivery.tr().toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
], ],
), ),
), ),
@ -615,7 +615,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
), ),
SizedBox(height: 36.h), SizedBox(height: 36.h),
CustomButton( CustomButton(
text: "Login to use this service".needTranslation, text: "Login to use this service",
onPressed: () async { onPressed: () async {
await authVM.onLoginPressed(); await authVM.onLoginPressed();
}, },

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/app_state.dart';
@ -9,6 +10,7 @@ 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/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/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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/select_doctor_page.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/select_doctor_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/chief_complaint_card.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/chief_complaint_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
@ -40,7 +42,7 @@ class _DentalChiefComplaintsPageState extends State<DentalChiefComplaintsPage> {
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false); bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
appState = getIt.get<AppState>(); appState = getIt.get<AppState>();
return CollapsingListView( return CollapsingListView(
title: "Dental Chief Complaints".needTranslation, title: LocaleKeys.dentalChiefComplaints.tr(),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.h), padding: EdgeInsets.symmetric(horizontal: 24.h),

@ -128,7 +128,7 @@ class DoctorsFilters extends StatelessWidget{
TextInputWidget( TextInputWidget(
controller: TextEditingController()..text =context.watch<DoctorFilterViewModel>().selectedClinicForFilters ??'', controller: TextEditingController()..text =context.watch<DoctorFilterViewModel>().selectedClinicForFilters ??'',
labelText: LocaleKeys.clinicName.tr(context: context), labelText: LocaleKeys.clinicName.tr(context: context),
hintText: LocaleKeys.searchClinic.tr().needTranslation, hintText: LocaleKeys.searchClinic.tr(),
isEnable: false, isEnable: false,
prefix: null, prefix: null,
autoFocus: false, autoFocus: false,

@ -1,4 +1,5 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.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/app_state.dart';
@ -8,6 +9,7 @@ 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/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/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/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';
@ -33,7 +35,7 @@ class DoctorProfilePage extends StatelessWidget {
children: [ children: [
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: "Doctor Profile".needTranslation, title: LocaleKeys.doctorProfile.tr(),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -84,11 +86,11 @@ class DoctorProfilePage extends StatelessWidget {
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
iconColor: AppColors.ratingColorYellow, iconColor: AppColors.ratingColorYellow,
labelText: "Branch: ${bookAppointmentsViewModel.doctorsProfileResponseModel.projectName}".needTranslation, labelText: "${bookAppointmentsViewModel.doctorsProfileResponseModel.projectName}",
), ),
AppCustomChipWidget( AppCustomChipWidget(
iconColor: AppColors.ratingColorYellow, iconColor: AppColors.ratingColorYellow,
labelText: "Clinic: ${bookAppointmentsViewModel.doctorsProfileResponseModel.clinicDescription}".needTranslation, labelText: "${bookAppointmentsViewModel.doctorsProfileResponseModel.clinicDescription}",
), ),
], ],
), ),
@ -142,7 +144,7 @@ class DoctorProfilePage extends StatelessWidget {
hasShadow: true, hasShadow: true,
), ),
child: CustomButton( child: CustomButton(
text: "View available appointments".needTranslation, text: LocaleKeys.viewAvailableAppointments.tr(),
onPressed: () async { onPressed: () async {
LoaderBottomSheet.showLoader(); LoaderBottomSheet.showLoader();
bookAppointmentsViewModel.isLiveCareSchedule bookAppointmentsViewModel.isLiveCareSchedule
@ -151,7 +153,7 @@ class DoctorProfilePage extends StatelessWidget {
onSuccess: (dynamic respData) async { onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: "Pick a Date".needTranslation, title: LocaleKeys.pickADate.tr(),
context, context,
child: AppointmentCalendar(), child: AppointmentCalendar(),
isFullScreen: false, isFullScreen: false,
@ -174,7 +176,7 @@ class DoctorProfilePage extends StatelessWidget {
onSuccess: (dynamic respData) async { onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: "Pick a Date".needTranslation, title: LocaleKeys.pickADate.tr(),
context, context,
child: AppointmentCalendar(), child: AppointmentCalendar(),
isFullScreen: false, isFullScreen: false,

@ -83,8 +83,8 @@ class LaserAppointment extends StatelessWidget {
activeTextColor: Color(0xffED1C2B), activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
tabs: [ tabs: [
CustomTabBarModel(null,LocaleKeys.malE.tr()), CustomTabBarModel(null, LocaleKeys.malE.tr()),
CustomTabBarModel(null, "Female".needTranslation), CustomTabBarModel(null, "Female"),
], ],
onTabChange: (index) { onTabChange: (index) {
var viewmodel = context.read<BookAppointmentsViewModel>(); var viewmodel = context.read<BookAppointmentsViewModel>();

@ -45,7 +45,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
children: [ children: [
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: "Review LiveCare Request".needTranslation, title: LocaleKeys.reviewLiveCareRequest.tr(context: context),
child: SingleChildScrollView( child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 24.h), padding: EdgeInsets.symmetric(horizontal: 24.h),
child: Column( child: Column(
@ -80,7 +80,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
spacing: 3.h, spacing: 3.h,
runSpacing: 4.h, runSpacing: 4.h,
children: [ children: [
AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} Years Old".needTranslation), AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} ${LocaleKeys.yearsOld.tr(context: context)}"),
AppCustomChipWidget( AppCustomChipWidget(
labelText: labelText:
"${LocaleKeys.clinic.tr()}: ${(appState.isArabic() ? immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceNameN : immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceName)!}"), "${LocaleKeys.clinic.tr()}: ${(appState.isArabic() ? immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceNameN : immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceName)!}"),
@ -93,7 +93,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
), ),
), ),
SizedBox(height: 24.h), SizedBox(height: 24.h),
"Selected LiveCare Type".needTranslation.toText16(isBold: true), LocaleKeys.selectedLiveCareType.tr(context: context).toText16(isBold: true),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) { Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
return Container( return Container(
@ -111,7 +111,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
children: [ children: [
Utils.buildSvgWithAssets(icon: AppAssets.livecare_clinic_icon, width: 32.h, height: 32.h, fit: BoxFit.contain), Utils.buildSvgWithAssets(icon: AppAssets.livecare_clinic_icon, width: 32.h, height: 32.h, fit: BoxFit.contain),
SizedBox(width: 8.h), SizedBox(width: 8.h),
getLiveCareType(immediateLiveCareViewModel.liveCareSelectedCallType).toText16(isBold: true), getLiveCareType(context, immediateLiveCareViewModel.liveCareSelectedCallType).toText16(isBold: true),
], ],
), ),
Utils.buildSvgWithAssets(icon: AppAssets.edit_icon, width: 24.h, height: 24.h, fit: BoxFit.contain), Utils.buildSvgWithAssets(icon: AppAssets.edit_icon, width: 24.h, height: 24.h, fit: BoxFit.contain),
@ -121,7 +121,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
).onPress(() { ).onPress(() {
showCommonBottomSheetWithoutHeight(context, child: SelectLiveCareCallType(immediateLiveCareViewModel: immediateLiveCareViewModel), callBackFunc: () async { showCommonBottomSheetWithoutHeight(context, child: SelectLiveCareCallType(immediateLiveCareViewModel: immediateLiveCareViewModel), callBackFunc: () async {
debugPrint("Selected Call Type: ${immediateLiveCareViewModel.liveCareSelectedCallType}"); debugPrint("Selected Call Type: ${immediateLiveCareViewModel.liveCareSelectedCallType}");
}, title: "Select LiveCare call type".needTranslation, isCloseButtonVisible: true, isFullScreen: false); }, title: LocaleKeys.selectLiveCareCallType.tr(context: context), isCloseButtonVisible: true, isFullScreen: false);
}); });
}), }),
SizedBox(height: 24.h) SizedBox(height: 24.h)
@ -152,7 +152,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Insurance expired or inactive".needTranslation.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: () {
@ -176,12 +176,12 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
) )
: const SizedBox(), : const SizedBox(),
SizedBox(height: 24.h), SizedBox(height: 24.h),
"Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h), LocaleKeys.totalAmountToPay.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h), SizedBox(height: 17.h),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Amount before tax".needTranslation.toText14(isBold: true), LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.amount!.toText16(isBold: true), AppColors.blackColor, 13, Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.amount!.toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"), isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
], ],
@ -189,7 +189,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor), LocaleKeys.vat15.tr(context: context).toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.tax!.toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13, immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.tax!.toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13,
isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"), isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
@ -210,7 +210,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
onPressed: () async { onPressed: () async {
await askVideoCallPermission().then((val) async { await askVideoCallPermission().then((val) async {
if (val) { if (val) {
LoaderBottomSheet.showLoader(loadingText: "Confirming LiveCare request, Please wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingLiveCareRequest.tr(context: context));
await immediateLiveCareViewModel.addNewCallRequestForImmediateLiveCare("${appState.getAuthenticatedUser()!.patientId}${DateTime.now().millisecondsSinceEpoch}"); await immediateLiveCareViewModel.addNewCallRequestForImmediateLiveCare("${appState.getAuthenticatedUser()!.patientId}${DateTime.now().millisecondsSinceEpoch}");
await immediateLiveCareViewModel.getPatientLiveCareHistory(); await immediateLiveCareViewModel.getPatientLiveCareHistory();
@ -230,7 +230,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
} else { } else {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "Unknown error occurred...".needTranslation), child: Utils.getErrorWidget(loadingText: LocaleKeys.unknownErrorOccurred.tr(context: context)),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -241,9 +241,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
title: LocaleKeys.notice.tr(context: context), title: LocaleKeys.notice.tr(context: context),
context, context,
child: Utils.getWarningWidget( child: Utils.getWarningWidget(
loadingText: loadingText: LocaleKeys.liveCarePermissionsMessage.tr(context: context),
"LiveCare requires Camera, Microphone, Location & Notifications permissions to enable virtual consultation between patient & doctor, Please allow these to proceed."
.needTranslation,
isShowActionButtons: true, isShowActionButtons: true,
onCancelTap: () { onCancelTap: () {
Navigator.pop(context); Navigator.pop(context);
@ -285,9 +283,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
title: LocaleKeys.notice.tr(context: context), title: LocaleKeys.notice.tr(context: context),
context, context,
child: Utils.getWarningWidget( child: Utils.getWarningWidget(
loadingText: loadingText: LocaleKeys.liveCarePermissionsMessage.tr(context: context),
"LiveCare requires Camera, Microphone, Location & Notifications permissions to enable virtual consultation between patient & doctor, Please allow these to proceed."
.needTranslation,
isShowActionButtons: true, isShowActionButtons: true,
onCancelTap: () { onCancelTap: () {
Navigator.pop(context); Navigator.pop(context);
@ -351,16 +347,16 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
// } // }
} }
String getLiveCareType(int callType) { String getLiveCareType(BuildContext context, int callType) {
switch (callType) { switch (callType) {
case 1: case 1:
return "Video Call".needTranslation; return LocaleKeys.videoCall.tr(context: context);
case 2: case 2:
return "Audio Call".needTranslation; return LocaleKeys.audioCall.tr(context: context);
case 3: case 3:
return "Phone Call".needTranslation; return LocaleKeys.phoneCall.tr(context: context);
default: default:
return "Video Call".needTranslation; return LocaleKeys.videoCall.tr(context: context);
} }
} }
} }

@ -84,7 +84,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
children: [ children: [
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: "LiveCare Payment".needTranslation, title: LocaleKeys.liveCarePayment.tr(context: context),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -104,7 +104,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
children: [ children: [
Image.asset(AppAssets.mada, width: 72.h, height: 25.h), Image.asset(AppAssets.mada, width: 72.h, height: 25.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Mada".needTranslation.toText16(isBold: true), LocaleKeys.mada.tr(context: context).toText16(isBold: true),
], ],
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
@ -146,7 +146,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
], ],
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Visa or Mastercard".needTranslation.toText16(isBold: true), LocaleKeys.visaOrMastercard.tr(context: context).toText16(isBold: true),
], ],
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
@ -183,7 +183,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
children: [ children: [
Image.asset(AppAssets.tamaraEng, width: 72.h, height: 25.h), Image.asset(AppAssets.tamaraEng, width: 72.h, height: 25.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Tamara".needTranslation.toText16(isBold: true), LocaleKeys.tamara.tr(context: context).toText16(isBold: true),
], ],
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
@ -234,7 +234,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Insurance expired or inactive".needTranslation.toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h), LocaleKeys.insuranceExpiredOrInactive.tr().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: () {
@ -258,12 +258,12 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
) )
: const SizedBox(), : const SizedBox(),
SizedBox(height: 24.h), SizedBox(height: 24.h),
"Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h), LocaleKeys.totalAmountToPay.tr().toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h), SizedBox(height: 17.h),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Amount before tax".needTranslation.toText14(isBold: true), LocaleKeys.amountBeforeTax.tr().toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.amount!.toString().toText16(isBold: true), AppColors.blackColor, 13, Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.amount!.toString().toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: true), isSaudiCurrency: true),
], ],
@ -271,7 +271,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor), LocaleKeys.vat15.tr().toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.tax!.toString().toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13, immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.tax!.toString().toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13,
isSaudiCurrency: true), isSaudiCurrency: true),
@ -281,7 +281,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"".needTranslation.toText14(isBold: true), "".toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total!.toString().toText24(isBold: true), AppColors.blackColor, 17, Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total!.toString().toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: true), isSaudiCurrency: true),
], ],
@ -355,7 +355,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
} }
void checkPaymentStatus() async { void checkPaymentStatus() async {
LoaderBottomSheet.showLoader(loadingText: "Checking payment status, Please wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr());
if (selectedPaymentMethod == "TAMARA") { if (selectedPaymentMethod == "TAMARA") {
await payfortViewModel.checkTamaraPaymentStatus( await payfortViewModel.checkTamaraPaymentStatus(
@ -382,7 +382,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
} else { } else {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "Unknown error occurred...".needTranslation), child: Utils.getErrorWidget(loadingText: "Unknown error occurred..."),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -393,7 +393,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation), child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr()),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -434,7 +434,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
} else { } else {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "Unknown error occurred...".needTranslation), child: Utils.getErrorWidget(loadingText: "Unknown error occurred..."),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -443,7 +443,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
} else { } else {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation), child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr()),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -482,7 +482,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
} }
startApplePay() async { startApplePay() async {
LoaderBottomSheet.showLoader(loadingText: "Fetching Apple Pay details, Please wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingApplePayDetails.tr());
transID = Utils.getAppointmentTransID( transID = Utils.getAppointmentTransID(
immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceID!, immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceID!,
ApiConsts.appEnvironmentType == AppEnvironmentTypeEnum.uat ? 15 : 12, ApiConsts.appEnvironmentType == AppEnvironmentTypeEnum.uat ? 15 : 12,

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.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/app_state.dart';
@ -10,6 +11,7 @@ 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/immediate_livecare/immediate_livecare_view_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.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/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -62,7 +64,7 @@ class _ImmediateLiveCarePendingRequestPageState extends State<ImmediateLiveCareP
children: [ children: [
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: "LiveCare Pending Request".needTranslation, title: LocaleKeys.liveCarePendingRequest.tr(),
child: Padding( child: Padding(
padding: EdgeInsets.all(24.0), padding: EdgeInsets.all(24.0),
child: Column( child: Column(
@ -124,7 +126,7 @@ class _ImmediateLiveCarePendingRequestPageState extends State<ImmediateLiveCareP
], ],
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
"Hala ${appState.getAuthenticatedUser()!.firstName}!!!".needTranslation.toText16(isBold: true), "Hala ${appState.getAuthenticatedUser()!.firstName}!!!".toText16(isBold: true),
SizedBox(height: 8.h), SizedBox(height: 8.h),
AppCustomChipWidget( AppCustomChipWidget(
icon: AppAssets.appointment_calendar_icon, icon: AppAssets.appointment_calendar_icon,
@ -148,7 +150,7 @@ class _ImmediateLiveCarePendingRequestPageState extends State<ImmediateLiveCareP
hasShadow: true, hasShadow: true,
), ),
child: CustomButton( child: CustomButton(
text: "Call LiveCare Support".needTranslation, text: LocaleKeys.callLiveCareSupport.tr(),
onPressed: () async { onPressed: () async {
launchUrl(Uri.parse("tel://" + "011 525 9553")); launchUrl(Uri.parse("tel://" + "011 525 9553"));
}, },

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/app_state.dart';
@ -13,6 +14,7 @@ import 'package:hmg_patient_app_new/features/book_appointments/models/resp_model
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_livecare_clinics_response_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_livecare_clinics_response_model.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_immediate_clinics_response_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_immediate_clinics_response_model.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/widgets/select_livecare_call_type.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/widgets/select_livecare_call_type.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/clinic_card.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/clinic_card.dart';
@ -59,7 +61,7 @@ class _SelectImmediateLiveCareClinicPageState extends State<SelectImmediateLiveC
return Scaffold( return Scaffold(
backgroundColor: AppColors.bgScaffoldColor, backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView( body: CollapsingListView(
title: "Select LiveCare Clinic".needTranslation, title: LocaleKeys.selectLiveCareClinic.tr(),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: EdgeInsets.all(24.h), padding: EdgeInsets.all(24.h),
@ -118,7 +120,7 @@ class _SelectImmediateLiveCareClinicPageState extends State<SelectImmediateLiveC
showCommonBottomSheetWithoutHeight(context, child: SelectLiveCareCallType(immediateLiveCareViewModel: immediateLiveCareViewModel), callBackFunc: () async { showCommonBottomSheetWithoutHeight(context, child: SelectLiveCareCallType(immediateLiveCareViewModel: immediateLiveCareViewModel), callBackFunc: () async {
if (immediateLiveCareViewModel.liveCareSelectedCallType != 0) { if (immediateLiveCareViewModel.liveCareSelectedCallType != 0) {
immediateLiveCareViewModel.setImmediateLiveCareSelectedClinic(liveCareClinic); immediateLiveCareViewModel.setImmediateLiveCareSelectedClinic(liveCareClinic);
LoaderBottomSheet.showLoader(loadingText: "Fetching fees, Please wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingFeesPleaseWait.tr());
await immediateLiveCareViewModel.getLiveCareImmediateAppointmentFees(onSuccess: (val) { await immediateLiveCareViewModel.getLiveCareImmediateAppointmentFees(onSuccess: (val) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(context).push( Navigator.of(context).push(
@ -130,11 +132,11 @@ class _SelectImmediateLiveCareClinicPageState extends State<SelectImmediateLiveC
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
}); });
} }
}, title: "Select LiveCare call type".needTranslation, isCloseButtonVisible: true, isFullScreen: false); }, title: LocaleKeys.selectLiveCareCallType.tr(), isCloseButtonVisible: true, isFullScreen: false);
} else { } else {
showCommonBottomSheetWithoutHeight(context, showCommonBottomSheetWithoutHeight(context,
child: Utils.getErrorWidget( child: Utils.getErrorWidget(
loadingText: "The selected clinic is only available between ${liveCareClinic.shiftTimings!.first.startTime} & ${liveCareClinic.shiftTimings!.first.endTime} hours.".needTranslation), loadingText: "The selected clinic is only available between ${liveCareClinic.shiftTimings!.first.startTime} & ${liveCareClinic.shiftTimings!.first.endTime} hours."),
callBackFunc: () {}, callBackFunc: () {},
title: "", title: "",
isCloseButtonVisible: true, isCloseButtonVisible: true,

@ -37,7 +37,7 @@ class LiveCareClinicCard extends StatelessWidget {
AppCustomChipWidget( AppCustomChipWidget(
icon: AppAssets.livecare_online_icon, icon: AppAssets.livecare_online_icon,
iconColor: AppColors.whiteColor, iconColor: AppColors.whiteColor,
richText: (liveCareClinicListResponseModel.isOnline == 1 ? LocaleKeys.online.tr(context: context) : "Offline".needTranslation).toText10(isBold: true, color: AppColors.whiteColor), richText: (liveCareClinicListResponseModel.isOnline == 1 ? LocaleKeys.online.tr(context: context) : LocaleKeys.offline.tr()).toText10(isBold: true, color: AppColors.whiteColor),
backgroundColor: liveCareClinicListResponseModel.isOnline == 1 ? AppColors.successColor : AppColors.primaryRedColor, backgroundColor: liveCareClinicListResponseModel.isOnline == 1 ? AppColors.successColor : AppColors.primaryRedColor,
textColor: AppColors.whiteColor, textColor: AppColors.whiteColor,
), ),

@ -1,3 +1,4 @@
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/app_state.dart';
@ -7,6 +8,7 @@ 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/immediate_livecare/immediate_livecare_view_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
class SelectLiveCareCallType extends StatelessWidget { class SelectLiveCareCallType extends StatelessWidget {
@ -21,8 +23,8 @@ class SelectLiveCareCallType extends StatelessWidget {
children: [ children: [
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_location_icon, AppAssets.checkin_location_icon,
"Video Call".needTranslation, LocaleKeys.videoCall.tr(context: context),
"View your nearest HMG locations".needTranslation, LocaleKeys.liveVideoCallWithHMGDoctors.tr(context: context),
).onPress(() { ).onPress(() {
Navigator.of(context).pop(); Navigator.of(context).pop();
immediateLiveCareViewModel.setLiveCareSelectedCallType(1); immediateLiveCareViewModel.setLiveCareSelectedCallType(1);
@ -30,8 +32,8 @@ class SelectLiveCareCallType extends StatelessWidget {
SizedBox(height: 16.h), SizedBox(height: 16.h),
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_location_icon, AppAssets.checkin_location_icon,
"Audio Call".needTranslation, LocaleKeys.audioCall.tr(context: context),
"Provide your feedback on our services".needTranslation, LocaleKeys.liveVideoCallWithHMGDoctors.tr(context: context),
).onPress(() { ).onPress(() {
Navigator.of(context).pop(); Navigator.of(context).pop();
immediateLiveCareViewModel.setLiveCareSelectedCallType(2); immediateLiveCareViewModel.setLiveCareSelectedCallType(2);
@ -39,8 +41,8 @@ class SelectLiveCareCallType extends StatelessWidget {
SizedBox(height: 16.h), SizedBox(height: 16.h),
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_location_icon, AppAssets.checkin_location_icon,
"Phone Call".needTranslation, LocaleKeys.phoneCall.tr(context: context),
"Live chat option with HMG".needTranslation, LocaleKeys.livePhoneCallWithHMGDoctors.tr(context: context),
).onPress(() { ).onPress(() {
Navigator.of(context).pop(); Navigator.of(context).pop();
immediateLiveCareViewModel.setLiveCareSelectedCallType(3); immediateLiveCareViewModel.setLiveCareSelectedCallType(3);

@ -113,20 +113,18 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
runSpacing: 8.h, runSpacing: 8.h,
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
labelText: "${LocaleKeys.clinic.tr(context: context)}: ${bookAppointmentsViewModel.selectedDoctor.clinicName}".needTranslation, labelText: "${LocaleKeys.clinic.tr(context: context)}: ${bookAppointmentsViewModel.selectedDoctor.clinicName}",
), ),
AppCustomChipWidget( AppCustomChipWidget(
labelText: "${LocaleKeys.branch.tr(context: context)} ${bookAppointmentsViewModel.selectedDoctor.projectName}".needTranslation, labelText: "${LocaleKeys.branch.tr(context: context)} ${bookAppointmentsViewModel.selectedDoctor.projectName}",
), ),
AppCustomChipWidget( AppCustomChipWidget(
labelText: labelText:
"${LocaleKeys.date.tr(context: context)}: ${bookAppointmentsViewModel.isWaitingAppointmentSelected ? DateUtil.formatDateToDate(DateTime.now(), false) : bookAppointmentsViewModel.selectedAppointmentDate}" "${LocaleKeys.date.tr(context: context)}: ${bookAppointmentsViewModel.isWaitingAppointmentSelected ? DateUtil.formatDateToDate(DateTime.now(), false) : bookAppointmentsViewModel.selectedAppointmentDate}",
.needTranslation,
), ),
AppCustomChipWidget( AppCustomChipWidget(
labelText: labelText:
"${LocaleKeys.time.tr(context: context)}: ${bookAppointmentsViewModel.isWaitingAppointmentSelected ? "Waiting Appointment".needTranslation : bookAppointmentsViewModel.selectedAppointmentTime}" "${LocaleKeys.time.tr(context: context)}: ${bookAppointmentsViewModel.isWaitingAppointmentSelected ? LocaleKeys.waitingAppointment.tr(context: context) : bookAppointmentsViewModel.selectedAppointmentTime}",
.needTranslation,
), ),
], ],
), ),
@ -166,7 +164,7 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
), ),
), ),
SizedBox(height: 24.h), SizedBox(height: 24.h),
"Hospital Information".needTranslation.toText16(isBold: true), LocaleKeys.hospitalInformation.tr(context: context).toText16(isBold: true),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Container( Container(
width: double.infinity, width: double.infinity,
@ -241,7 +239,7 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
} }
void getWalkInAppointmentPatientShare() async { void getWalkInAppointmentPatientShare() async {
LoaderBottomSheet.showLoader(loadingText: "Fetching Appointment Share...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingAppointmentShare.tr(context: context));
await bookAppointmentsViewModel.getWalkInPatientShareAppointment(onSuccess: (val) { await bookAppointmentsViewModel.getWalkInPatientShareAppointment(onSuccess: (val) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(context).push( Navigator.of(context).push(
@ -262,7 +260,7 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
} }
void initiateBookAppointment() async { void initiateBookAppointment() async {
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: "Booking your appointment...".needTranslation); LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: LocaleKeys.bookingYourAppointment.tr(context: context));
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
if (bookAppointmentsViewModel.isLiveCareSchedule) { if (bookAppointmentsViewModel.isLiveCareSchedule) {

@ -34,6 +34,14 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
TextEditingController searchEditingController = TextEditingController(); TextEditingController searchEditingController = TextEditingController();
FocusNode textFocusNode = FocusNode(); FocusNode textFocusNode = FocusNode();
late BookAppointmentsViewModel bookAppointmentsViewModel; late BookAppointmentsViewModel bookAppointmentsViewModel;
late ScrollController _scrollController;
final Map<int, GlobalKey> _itemKeys = {};
@override
void initState() {
_scrollController = ScrollController();
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -43,8 +51,8 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
body: Column( body: Column(
children: [ children: [
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: "Choose Doctor".needTranslation, title: LocaleKeys.chooseDoctor.tr(),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.h), padding: EdgeInsets.symmetric(horizontal: 24.h),
@ -76,7 +84,7 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
) )
: null, : null,
onChange: (value) { onChange: (value) {
// bookAppointmentsViewModel.filterClinics(value!); // bookAppointmentsViewModel.filterClinics(value!);
}, },
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
vertical: ResponsiveExtension(10).h, vertical: ResponsiveExtension(10).h,
@ -89,43 +97,41 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
child: SizedBox( child: SizedBox(
height: 56.h, height: 56.h,
width: 56.h, width: 56.h,
child: DecoratedBox(decoration: RoundedRectangleBorder().toSmoothCornerDecoration( child: DecoratedBox(
color: AppColors.whiteColor, decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
borderRadius: 10.h, color: AppColors.whiteColor,
hasShadow: false, borderRadius: 10.h,
), hasShadow: false,
child: Utils.buildSvgWithAssets(icon: AppAssets.ic_filters, ),
height: 24.h, child: Utils.buildSvgWithAssets(
width: 24.h, ).paddingAll(16.h).onPress((){ icon: AppAssets.ic_filters,
context.read<DoctorFilterViewModel>() height: 24.h,
width: 24.h,
).paddingAll(16.h).onPress(() {
context.read<DoctorFilterViewModel>()
..clearSelection() ..clearSelection()
..clearSearchFilters() ..clearSearchFilters()
..getFiltersFromDoctorList( ..getFiltersFromDoctorList(bookAppointmentsViewModel.doctorsList)
bookAppointmentsViewModel.doctorsList ..setSelections(bookAppointmentsViewModel.selectedFacilityForFilters?.toList(), bookAppointmentsViewModel.selectedRegionForFilters?.toList(),
)..setSelections( bookAppointmentsViewModel.selectedClinicForFilters, bookAppointmentsViewModel.selectedHospitalForFilters, bookAppointmentsViewModel.applyFilters);
bookAppointmentsViewModel.selectedFacilityForFilters?.toList(), Navigator.of(context).push(
bookAppointmentsViewModel.selectedRegionForFilters?.toList(), PageRouteBuilder(
bookAppointmentsViewModel.selectedClinicForFilters, pageBuilder: (context, animation, secondaryAnimation) => DoctorsFilters(), // Replace YourNewPage with your actual page widget
bookAppointmentsViewModel.selectedHospitalForFilters, transitionsBuilder: (context, animation, secondaryAnimation, child) {
bookAppointmentsViewModel.applyFilters) ; const begin = Offset(0.0, 1.0); // Start from the bottom (y=1.0)
Navigator.of(context).push( const end = Offset.zero; // End at the original position (y=0.0)
PageRouteBuilder( final tween = Tween(begin: begin, end: end);
pageBuilder: (context, animation, secondaryAnimation) => DoctorsFilters(), // Replace YourNewPage with your actual page widget final offsetAnimation = animation.drive(tween);
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 1.0); // Start from the bottom (y=1.0)
const end = Offset.zero; // End at the original position (y=0.0)
final tween = Tween(begin: begin, end: end);
final offsetAnimation = animation.drive(tween);
return SlideTransition( return SlideTransition(
position: offsetAnimation, position: offsetAnimation,
child: child, child: child,
); );
}, },
transitionDuration: Duration(milliseconds: 200), // Adjust duration as needed transitionDuration: Duration(milliseconds: 200), // Adjust duration as needed
), ),
); );
}), }),
), ),
), ),
) )
@ -136,13 +142,50 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (bookAppointmentsVM.isDoctorSearchByNameStarted)
Row(
children: [
CustomButton(
text: LocaleKeys.byClinic.tr(context: context),
onPressed: () {
bookAppointmentsVM.sortFilteredDoctorList(true);
},
backgroundColor: bookAppointmentsVM.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: bookAppointmentsVM.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
textColor: bookAppointmentsVM.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
SizedBox(width: 8.h),
CustomButton(
text: LocaleKeys.byHospital.tr(context: context),
onPressed: () {
bookAppointmentsVM.sortFilteredDoctorList(false);
},
backgroundColor: bookAppointmentsVM.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor,
borderColor: bookAppointmentsVM.isSortByClinic ? AppColors.textColor.withOpacity(0.2) : AppColors.primaryRedColor,
textColor: bookAppointmentsVM.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor,
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
],
).paddingSymmetrical(0.h, 0.h),
bookAppointmentsVM.isDoctorSearchByNameStarted bookAppointmentsVM.isDoctorSearchByNameStarted
? ListView.separated( ? ListView.separated(
padding: EdgeInsets.only(top: 24.h), padding: EdgeInsets.only(top: 20.h),
shrinkWrap: true, shrinkWrap: true,
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
itemCount: bookAppointmentsVM.isDoctorsListLoading ? 5 : bookAppointmentsVM.filteredDoctorList.length, itemCount: bookAppointmentsVM.isDoctorsListLoading ? 5 : bookAppointmentsVM.getGroupedFilteredDoctorsList().length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final isExpanded = bookAppointmentsVM.expandedGroupIndex == index;
final groupedDoctors = bookAppointmentsVM.getGroupedFilteredDoctorsList();
return bookAppointmentsVM.isDoctorsListLoading return bookAppointmentsVM.isDoctorsListLoading
? DoctorCard( ? DoctorCard(
doctorsListResponseModel: DoctorsListResponseModel(), doctorsListResponseModel: DoctorsListResponseModel(),
@ -156,35 +199,112 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
verticalOffset: 100.0, verticalOffset: 100.0,
child: FadeInAnimation( child: FadeInAnimation(
child: AnimatedContainer( child: AnimatedContainer(
key: _itemKeys.putIfAbsent(index, () => GlobalKey()),
duration: Duration(milliseconds: 300), duration: Duration(milliseconds: 300),
curve: Curves.easeInOut, curve: Curves.easeInOut,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: DoctorCard( child: InkWell(
doctorsListResponseModel: bookAppointmentsVM.filteredDoctorList[index], onTap: () {
isLoading: false, bookAppointmentsVM.toggleGroupExpansion(index);
bookAppointmentsViewModel: bookAppointmentsViewModel, // After rebuild, ensure the expanded item is visible
).onPress(() async { WidgetsBinding.instance.addPostFrameCallback((_) {
bookAppointmentsVM.setSelectedDoctor(bookAppointmentsVM.filteredDoctorList[index]); final key = _itemKeys[index];
// bookAppointmentsVM.setSelectedDoctor(DoctorsListResponseModel()); if (key != null && key.currentContext != null && bookAppointmentsVM.expandedGroupIndex == index) {
LoaderBottomSheet.showLoader(); Scrollable.ensureVisible(
await bookAppointmentsVM.getDoctorProfile(onSuccess: (dynamic respData) { key.currentContext!,
LoaderBottomSheet.hideLoader(); duration: Duration(milliseconds: 350),
Navigator.of(context).push( curve: Curves.easeInOut,
CustomPageRoute( alignment: 0.1,
page: DoctorProfilePage(), );
), }
); });
}, onError: (err) { },
LoaderBottomSheet.hideLoader(); child: Padding(
showCommonBottomSheetWithoutHeight( padding: EdgeInsets.all(16.h),
context, child: Column(
child: Utils.getErrorWidget(loadingText: err), crossAxisAlignment: CrossAxisAlignment.start,
callBackFunc: () {}, children: [
isFullScreen: false, Row(
isCloseButtonVisible: true, mainAxisAlignment: MainAxisAlignment.spaceBetween,
); children: [
}); CustomButton(
}), text: "${groupedDoctors[index].length} ${'doctors'}",
onPressed: () {},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,
fontSize: 10,
fontWeight: FontWeight.w500,
borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 30.h),
Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
],
),
SizedBox(height: 8.h),
// Clinic/Hospital name as group title
Text(
bookAppointmentsVM.isSortByClinic
? (groupedDoctors[index].first.clinicName ?? 'Unknown')
: (groupedDoctors[index].first.projectName ?? 'Unknown'),
style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600),
overflow: TextOverflow.ellipsis,
),
// Expanded content - list of doctors in this group
AnimatedSwitcher(
duration: Duration(milliseconds: 400),
child: isExpanded
? Container(
key: ValueKey<int>(index),
padding: EdgeInsets.only(top: 12.h),
child: Column(
children: groupedDoctors[index].asMap().entries.map<Widget>((entry) {
final doctorIndex = entry.key;
final doctor = entry.value;
final isLastDoctor = doctorIndex == groupedDoctors[index].length - 1;
return Column(
children: [
DoctorCard(
doctorsListResponseModel: doctor,
isLoading: false,
bookAppointmentsViewModel: bookAppointmentsViewModel,
).onPress(() async {
bookAppointmentsVM.setSelectedDoctor(doctor);
LoaderBottomSheet.showLoader();
await bookAppointmentsVM.getDoctorProfile(
onSuccess: (dynamic respData) {
LoaderBottomSheet.hideLoader();
Navigator.of(context).push(
CustomPageRoute(
page: DoctorProfilePage(),
),
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
);
}),
if (!isLastDoctor)
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
],
);
}).toList(),
),
)
: SizedBox.shrink(),
),
],
),
),
),
), ),
), ),
), ),
@ -261,8 +381,10 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
), ),
); );
} }
@override @override
void dispose() { void dispose() {
_scrollController.dispose();
bookAppointmentsViewModel.doctorsList.clear(); bookAppointmentsViewModel.doctorsList.clear();
super.dispose(); super.dispose();
} }

@ -103,7 +103,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
return Scaffold( return Scaffold(
backgroundColor: AppColors.bgScaffoldColor, backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView( body: CollapsingListView(
title: bookAppointmentsViewModel.isLiveCareSchedule ? "Select LiveCare Clinic".needTranslation : LocaleKeys.selectClinic.tr(context: context), title: bookAppointmentsViewModel.isLiveCareSchedule ? LocaleKeys.selectLiveCareClinic.tr(context: context) : LocaleKeys.selectClinic.tr(context: context),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.h), padding: EdgeInsets.symmetric(horizontal: 24.h),
@ -1114,18 +1114,18 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
void initDentalAppointmentBookingFlow(int projectID) async { void initDentalAppointmentBookingFlow(int projectID) async {
bookAppointmentsViewModel.setProjectID(projectID.toString()); bookAppointmentsViewModel.setProjectID(projectID.toString());
LoaderBottomSheet.showLoader(loadingText: "Checking for an existing dental plan, Please wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingForExistingDentalPlan.tr(context: context));
await bookAppointmentsViewModel.getPatientDentalEstimation(projectID: projectID).then((value) { await bookAppointmentsViewModel.getPatientDentalEstimation(projectID: projectID).then((value) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
if (bookAppointmentsViewModel.patientDentalPlanEstimationList.isNotEmpty) { if (bookAppointmentsViewModel.patientDentalPlanEstimationList.isNotEmpty) {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
// title: LocaleKeys.notice.tr(context: context), // title: LocaleKeys.notice.tr(context: context),
title: "Dental treatment plan".needTranslation, title: LocaleKeys.dentalTreatmentPlan.tr(context: context),
context, context,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"You have an existing treatment plan: ".needTranslation.toText14(weight: FontWeight.w500), LocaleKeys.youHaveExistingTreatmentPlan.tr(context: context).toText14(weight: FontWeight.w500),
SizedBox(height: 8.h), SizedBox(height: 8.h),
Container( Container(
width: double.infinity, width: double.infinity,
@ -1156,7 +1156,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
bookAppointmentsViewModel.patientDentalPlanEstimationList[index].procedureName!.toText12(isBold: true), bookAppointmentsViewModel.patientDentalPlanEstimationList[index].procedureName!.toText12(isBold: true),
AppCustomChipWidget(icon: AppAssets.appointment_time_icon, labelText: "${bookAppointmentsViewModel.totalTimeNeededForDentalProcedure} Mins".needTranslation), AppCustomChipWidget(icon: AppAssets.appointment_time_icon, labelText: "${bookAppointmentsViewModel.totalTimeNeededForDentalProcedure} ${LocaleKeys.mins.tr(context: context)}"),
], ],
); );
}, },
@ -1171,15 +1171,15 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Total time required".needTranslation.toText14(isBold: true), LocaleKeys.totalTimeRequired.tr(context: context).toText14(isBold: true),
AppCustomChipWidget(icon: AppAssets.appointment_time_icon, labelText: "30 Mins".needTranslation), AppCustomChipWidget(icon: AppAssets.appointment_time_icon, labelText: "30 ${LocaleKeys.mins.tr(context: context)}"),
], ],
) )
], ],
), ),
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Would you like to continue it?".needTranslation.toText14(weight: FontWeight.w500), LocaleKeys.wouldYouLikeToContinue.tr(context: context).toText14(weight: FontWeight.w500),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Row( Row(
children: [ children: [

@ -33,7 +33,6 @@ class SelectDoctorPage extends StatefulWidget {
class _SelectDoctorPageState extends State<SelectDoctorPage> { class _SelectDoctorPageState extends State<SelectDoctorPage> {
TextEditingController searchEditingController = TextEditingController(); TextEditingController searchEditingController = TextEditingController();
int? expandedIndex;
FocusNode textFocusNode = FocusNode(); FocusNode textFocusNode = FocusNode();
@ -76,7 +75,7 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
return Scaffold( return Scaffold(
backgroundColor: AppColors.bgScaffoldColor, backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView( body: CollapsingListView(
title: "Choose Doctor".needTranslation, title: LocaleKeys.chooseDoctor.tr(),
// bottomChild: Container( // bottomChild: Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.only(topLeft: Radius.circular(24.r), topRight: Radius.circular(24.r))), // decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.only(topLeft: Radius.circular(24.r), topRight: Radius.circular(24.r))),
// padding: EdgeInsets.symmetric(vertical: 20.h, horizontal: 20.h), // padding: EdgeInsets.symmetric(vertical: 20.h, horizontal: 20.h),
@ -170,8 +169,7 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
), ),
], ],
).paddingSymmetrical(0.h, 0.h), ).paddingSymmetrical(0.h, 0.h),
if (bookAppointmentsViewModel.isGetDocForHealthCal && bookAppointmentsVM.showSortFilterButtons) if (bookAppointmentsViewModel.isGetDocForHealthCal && bookAppointmentsVM.showSortFilterButtons) SizedBox(height: 16.h),
SizedBox(height: 16.h),
Row( Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
@ -180,7 +178,7 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
children: [ children: [
LocaleKeys.nearestAppo.tr(context: context).toText13(isBold: true), LocaleKeys.nearestAppo.tr(context: context).toText13(isBold: true),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"View nearest available appointments".needTranslation.toText11(color: AppColors.textColorLight, weight: FontWeight.w500), LocaleKeys.viewNearestAppos.toText11(color: AppColors.textColorLight, weight: FontWeight.w500),
], ],
), ),
const Spacer(), const Spacer(),
@ -190,7 +188,6 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
value: bookAppointmentsVM.isNearestAppointmentSelected, value: bookAppointmentsVM.isNearestAppointmentSelected,
onChanged: (newValue) async { onChanged: (newValue) async {
bookAppointmentsVM.setIsNearestAppointmentSelected(newValue); bookAppointmentsVM.setIsNearestAppointmentSelected(newValue);
}, },
), ),
], ],
@ -199,11 +196,10 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
padding: EdgeInsets.only(top: 16.h), padding: EdgeInsets.only(top: 16.h),
shrinkWrap: true, shrinkWrap: true,
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
itemCount: bookAppointmentsVM.isDoctorsListLoading itemCount: bookAppointmentsVM.isDoctorsListLoading ? 5 : (bookAppointmentsVM.doctorsListGrouped.isNotEmpty ? bookAppointmentsVM.doctorsListGrouped.length : 1),
? 5
: (bookAppointmentsVM.doctorsListGrouped.isNotEmpty ? bookAppointmentsVM.doctorsListGrouped.length : 1),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final isExpanded = expandedIndex == index; // final isExpanded = bookAppointmentsVM.expandedGroupIndex == index;
final isExpanded = true;
return bookAppointmentsVM.isDoctorsListLoading return bookAppointmentsVM.isDoctorsListLoading
? DoctorCard( ? DoctorCard(
doctorsListResponseModel: DoctorsListResponseModel(), doctorsListResponseModel: DoctorsListResponseModel(),
@ -211,7 +207,7 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
bookAppointmentsViewModel: bookAppointmentsViewModel, bookAppointmentsViewModel: bookAppointmentsViewModel,
) )
: bookAppointmentsVM.doctorsListGrouped.isEmpty : bookAppointmentsVM.doctorsListGrouped.isEmpty
? Utils.getNoDataWidget(context, noDataText: "No Doctor found for selected criteria...".needTranslation) ? Utils.getNoDataWidget(context, noDataText: LocaleKeys.noDoctorFound.tr())
: AnimationConfiguration.staggeredList( : AnimationConfiguration.staggeredList(
position: index, position: index,
duration: const Duration(milliseconds: 500), duration: const Duration(milliseconds: 500),
@ -225,13 +221,11 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: InkWell( child: InkWell(
onTap: () { onTap: () {
setState(() { bookAppointmentsVM.toggleGroupExpansion(index);
expandedIndex = isExpanded ? null : index;
});
// After rebuild, ensure the expanded item is visible // After rebuild, ensure the expanded item is visible
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
final key = _itemKeys[index]; final key = _itemKeys[index];
if (key != null && key.currentContext != null && expandedIndex == index) { if (key != null && key.currentContext != null && bookAppointmentsVM.expandedGroupIndex == index) {
Scrollable.ensureVisible( Scrollable.ensureVisible(
key.currentContext!, key.currentContext!,
duration: Duration(milliseconds: 350), duration: Duration(milliseconds: 350),
@ -251,7 +245,7 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
CustomButton( CustomButton(
text: "${bookAppointmentsVM.doctorsListGrouped[index].length} ${'doctors'.needTranslation}", text: "${bookAppointmentsVM.doctorsListGrouped[index].length} ${'doctors'}",
onPressed: () {}, onPressed: () {},
backgroundColor: AppColors.greyColor, backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor, borderColor: AppColors.greyColor,
@ -282,34 +276,41 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
key: ValueKey<int>(index), key: ValueKey<int>(index),
padding: EdgeInsets.only(top: 12.h), padding: EdgeInsets.only(top: 12.h),
child: Column( child: Column(
children: bookAppointmentsVM.doctorsListGrouped[index].map<Widget>((doctor) { children: bookAppointmentsVM.doctorsListGrouped[index].asMap().entries.map<Widget>((entry) {
return Container( final doctorIndex = entry.key;
margin: EdgeInsets.only(bottom: 12.h), final doctor = entry.value;
child: DoctorCard( final isLastDoctor = doctorIndex == bookAppointmentsVM.doctorsListGrouped[index].length - 1;
doctorsListResponseModel: doctor,
isLoading: false, return Column(
bookAppointmentsViewModel: bookAppointmentsViewModel, children: [
).onPress(() async { DoctorCard(
bookAppointmentsVM.setSelectedDoctor(doctor); doctorsListResponseModel: doctor,
LoaderBottomSheet.showLoader(); isLoading: false,
await bookAppointmentsVM.getDoctorProfile(onSuccess: (dynamic respData) { bookAppointmentsViewModel: bookAppointmentsViewModel,
LoaderBottomSheet.hideLoader(); ).onPress(() async {
Navigator.of(context).push( bookAppointmentsVM.setSelectedDoctor(doctor);
CustomPageRoute( LoaderBottomSheet.showLoader();
page: DoctorProfilePage(), await bookAppointmentsVM.getDoctorProfile(onSuccess: (dynamic respData) {
), LoaderBottomSheet.hideLoader();
); Navigator.of(context).push(
}, onError: (err) { CustomPageRoute(
LoaderBottomSheet.hideLoader(); page: DoctorProfilePage(),
showCommonBottomSheetWithoutHeight( ),
context, );
child: Utils.getErrorWidget(loadingText: err), }, onError: (err) {
callBackFunc: () {}, LoaderBottomSheet.hideLoader();
isFullScreen: false, showCommonBottomSheetWithoutHeight(
isCloseButtonVisible: true, context,
); child: Utils.getErrorWidget(loadingText: err),
}); callBackFunc: () {},
}), isFullScreen: false,
isCloseButtonVisible: true,
);
});
}),
if (!isLastDoctor)
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
],
); );
}).toList(), }).toList(),
), ),

@ -54,8 +54,8 @@ class SelectLivecareClinicPage extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Immediate service".needTranslation.toText18(color: AppColors.textColor, isBold: true), LocaleKeys.immediateService.tr(context: context).toText18(color: AppColors.textColor, isBold: true),
"No need to wait, you will get medical consultation immediately via video call".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), LocaleKeys.noNeedToWaitGetMedicalConsultation.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
], ],
), ),
), ),
@ -70,7 +70,7 @@ class SelectLivecareClinicPage extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"No visit required".needTranslation.toText18(color: AppColors.textColor, isBold: true), LocaleKeys.noVisitRequired.tr(context: context).toText18(color: AppColors.textColor, isBold: true),
LocaleKeys.livecarePoint5.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), LocaleKeys.livecarePoint5.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
], ],
), ),
@ -86,8 +86,8 @@ class SelectLivecareClinicPage extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Doctor will contact".needTranslation.toText18(color: AppColors.textColor, isBold: true), LocaleKeys.doctorWillContact.tr(context: context).toText18(color: AppColors.textColor, isBold: true),
"A specialised doctor will contact you and will be able to view your medical history".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), LocaleKeys.specialisedDoctorWillContactYou.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
], ],
), ),
), ),
@ -102,8 +102,8 @@ class SelectLivecareClinicPage extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Free medicine delivery".needTranslation.toText18(color: AppColors.textColor, isBold: true), LocaleKeys.freeMedicineDelivery.tr(context: context).toText18(color: AppColors.textColor, isBold: true),
"Offers free medicine delivery for the LiveCare appointment".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), LocaleKeys.offersFreeMedicineDelivery.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
], ],
), ),
), ),
@ -117,7 +117,7 @@ class SelectLivecareClinicPage extends StatelessWidget {
Column( Column(
children: [ children: [
CustomButton( CustomButton(
text: "Yes please, I am in a hurry".needTranslation, text: LocaleKeys.yesPleasImInAHurry.tr(context: context),
onPressed: () async { onPressed: () async {
Navigator.pop(context); Navigator.pop(context);
GetLiveCareClinicListResponseModel liveCareClinic = GetLiveCareClinicListResponseModel( GetLiveCareClinicListResponseModel liveCareClinic = GetLiveCareClinicListResponseModel(
@ -129,7 +129,7 @@ class SelectLivecareClinicPage extends StatelessWidget {
immediateLiveCareViewModel.setLiveCareSelectedCallType(1); immediateLiveCareViewModel.setLiveCareSelectedCallType(1);
immediateLiveCareViewModel.setImmediateLiveCareSelectedClinic(liveCareClinic); immediateLiveCareViewModel.setImmediateLiveCareSelectedClinic(liveCareClinic);
LoaderBottomSheet.showLoader(loadingText: "Fetching fees, Please wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingFeesPleaseWait.tr(context: context));
await immediateLiveCareViewModel.getLiveCareImmediateAppointmentFees(onSuccess: (val) { await immediateLiveCareViewModel.getLiveCareImmediateAppointmentFees(onSuccess: (val) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).push( Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).push(
@ -162,7 +162,7 @@ class SelectLivecareClinicPage extends StatelessWidget {
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
CustomButton( CustomButton(
text: "No, Thanks. I would like a physical visit".needTranslation, text: LocaleKeys.noThanksPhysicalVisit.tr(context: context),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
onNegativeClicked?.call(); onNegativeClicked?.call();

@ -28,7 +28,7 @@ class WaitingAppointmentInfo extends StatelessWidget {
children: [ children: [
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: "Waiting Appointment".needTranslation, title: LocaleKeys.waitingAppointment.tr(),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -47,13 +47,11 @@ class WaitingAppointmentInfo extends StatelessWidget {
children: [ children: [
Utils.buildSvgWithAssets(icon: AppAssets.waiting_appointment_icon, width: 48.h, height: 48.h, fit: BoxFit.contain), Utils.buildSvgWithAssets(icon: AppAssets.waiting_appointment_icon, width: 48.h, height: 48.h, fit: BoxFit.contain),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"What is Waiting Appointment?".needTranslation.toText16(isBold: true), LocaleKeys.whatIsWaitingAppointment.tr(context: context).toText16(isBold: true),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"The waiting appointments feature allows you to book an appointment while you are inside the hospital building, and in case there is no available slot in the doctors schedule." LocaleKeys.waitingAppointmentsFeature.tr(context: context).toText14(isBold: false),
.needTranslation
.toText14(isBold: false),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"The appointment with the doctor is confirmed, but the time of entry is uncertain.".needTranslation.toText14(isBold: false), LocaleKeys.appointmentWithDoctorConfirmed.tr(context: context).toText14(isBold: false),
SizedBox(height: 24.h), SizedBox(height: 24.h),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -66,9 +64,7 @@ class WaitingAppointmentInfo extends StatelessWidget {
SizedBox(width: 10.w), SizedBox(width: 10.w),
SizedBox( SizedBox(
width: MediaQuery.of(context).size.width * 0.7, width: MediaQuery.of(context).size.width * 0.7,
child: "Note: You must have to pay within 10 minutes of booking, otherwise your appointment will be cancelled automatically" child: LocaleKeys.paymentWithinTenMinutes.tr(context: context).toText14(isBold: true, color: AppColors.warningColorYellow),
.needTranslation
.toText14(isBold: true, color: AppColors.warningColorYellow),
), ),
], ],
), ),
@ -88,7 +84,7 @@ class WaitingAppointmentInfo extends StatelessWidget {
hasShadow: true, hasShadow: true,
), ),
child: CustomButton( child: CustomButton(
text: "Continue".needTranslation, text: LocaleKeys.continueString.tr(),
onPressed: () async { onPressed: () async {
showCommonBottomSheetWithoutHeight(context, showCommonBottomSheetWithoutHeight(context,
title: LocaleKeys.onlineCheckIn.tr(), title: LocaleKeys.onlineCheckIn.tr(),

@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_nfc_kit/flutter_nfc_kit.dart'; import 'package:flutter_nfc_kit/flutter_nfc_kit.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -10,6 +11,7 @@ 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/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/presentation/book_appointment/review_appointment_page.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/review_appointment_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:barcode_scan2/barcode_scan2.dart'; import 'package:barcode_scan2/barcode_scan2.dart';
@ -42,14 +44,9 @@ class WaitingAppointmentOnlineCheckinSheet extends StatelessWidget {
children: [ children: [
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_location_icon, AppAssets.checkin_location_icon,
"Live Location".needTranslation, LocaleKeys.liveLocation.tr(),
"Verify your location to be at hospital to check in".needTranslation, LocaleKeys.verifyYourLocationAtHospital.tr(),
).onPress(() { ).onPress(() {
// locationUtils = LocationUtils(
// isShowConfirmDialog: false,
// navigationService: myAppointmentsViewModel.navigationService,
// appState: myAppointmentsViewModel.appState,
// );
locationUtils.getCurrentLocation(onSuccess: (value) { locationUtils.getCurrentLocation(onSuccess: (value) {
projectDetailListModel = Utils.getProjectDetailObj(appState, bookAppointmentsViewModel.waitingAppointmentProjectID); projectDetailListModel = Utils.getProjectDetailObj(appState, bookAppointmentsViewModel.waitingAppointmentProjectID);
double dist = Utils.distance(value.latitude, value.longitude, double.parse(projectDetailListModel.latitude!), double.parse(projectDetailListModel.longitude!)).ceilToDouble() * 1000; double dist = Utils.distance(value.latitude, value.longitude, double.parse(projectDetailListModel.latitude!), double.parse(projectDetailListModel.longitude!)).ceilToDouble() * 1000;
@ -58,8 +55,8 @@ class WaitingAppointmentOnlineCheckinSheet extends StatelessWidget {
checkScannedNFCAndQRCode(projectDetailListModel.checkInQrCode!, context); checkScannedNFCAndQRCode(projectDetailListModel.checkInQrCode!, context);
} else { } else {
showCommonBottomSheetWithoutHeight(context, showCommonBottomSheetWithoutHeight(context,
title: "Error".needTranslation, title: LocaleKeys.error.tr(),
child: Utils.getErrorWidget(loadingText: "Please ensure you're within the hospital location to perform online check-in.".needTranslation), callBackFunc: () { child: Utils.getErrorWidget(loadingText: LocaleKeys.ensureWithinHospitalLocation.tr()), callBackFunc: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, isFullScreen: false); }, isFullScreen: false);
} }
@ -68,8 +65,8 @@ class WaitingAppointmentOnlineCheckinSheet extends StatelessWidget {
SizedBox(height: 16.h), SizedBox(height: 16.h),
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_nfc_icon, AppAssets.checkin_nfc_icon,
"NFC (Near Field Communication)".needTranslation, LocaleKeys.nfcNearFieldCommunication.tr(),
"Scan your phone via NFC board to check in".needTranslation, LocaleKeys.scanPhoneViaNFC.tr(),
).onPress(() { ).onPress(() {
Future.delayed(const Duration(milliseconds: 500), () { Future.delayed(const Duration(milliseconds: 500), () {
showNfcReader(context, onNcfScan: (String nfcId) { showNfcReader(context, onNcfScan: (String nfcId) {
@ -82,8 +79,8 @@ class WaitingAppointmentOnlineCheckinSheet extends StatelessWidget {
SizedBox(height: 16.h), SizedBox(height: 16.h),
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_qr_icon, AppAssets.checkin_qr_icon,
"QR Code".needTranslation, LocaleKeys.qrCode.tr(),
"Scan QR code with your camera to check in".needTranslation, LocaleKeys.scanQRCodeToCheckIn.tr()
).onPress(() async { ).onPress(() async {
String onlineCheckInQRCode = (await BarcodeScanner.scan().then((value) => value.rawContent)); String onlineCheckInQRCode = (await BarcodeScanner.scan().then((value) => value.rawContent));
if (onlineCheckInQRCode != "") { if (onlineCheckInQRCode != "") {
@ -136,7 +133,7 @@ class WaitingAppointmentOnlineCheckinSheet extends StatelessWidget {
} }
void checkScannedNFCAndQRCode(String scannedCode, BuildContext context) async { void checkScannedNFCAndQRCode(String scannedCode, BuildContext context) async {
LoaderBottomSheet.showLoader(loadingText: "Processing Check-In...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.processingCheckIn.tr());
bookAppointmentsViewModel.checkScannedNFCAndQRCode( bookAppointmentsViewModel.checkScannedNFCAndQRCode(
scannedCode, scannedCode,
bookAppointmentsViewModel.waitingAppointmentProjectID, bookAppointmentsViewModel.waitingAppointmentProjectID,
@ -152,7 +149,7 @@ class WaitingAppointmentOnlineCheckinSheet extends StatelessWidget {
}, },
onError: (err) { onError: (err) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: "Error".needTranslation, child: Utils.getErrorWidget(loadingText: err), callBackFunc: () { showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.error.tr(), child: Utils.getErrorWidget(loadingText: err), callBackFunc: () {
// Navigator.of(context).pop(); // Navigator.of(context).pop();
}, isFullScreen: false); }, isFullScreen: false);
}, },

@ -94,7 +94,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
children: [ children: [
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: "Appointment Payment".needTranslation, title: LocaleKeys.appointmentPayment.tr(context: context),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -114,7 +114,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
children: [ children: [
Image.asset(AppAssets.mada, width: 72.h, height: 25.h), Image.asset(AppAssets.mada, width: 72.h, height: 25.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Mada".needTranslation.toText16(isBold: true), LocaleKeys.mada.tr(context: context).toText16(isBold: true),
], ],
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
@ -156,7 +156,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
], ],
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Visa or Mastercard".needTranslation.toText16(isBold: true), LocaleKeys.visaOrMastercard.tr(context: context).toText16(isBold: true),
], ],
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
@ -193,7 +193,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
children: [ children: [
Image.asset(AppAssets.tamaraEng, width: 72.h, height: 25.h), Image.asset(AppAssets.tamaraEng, width: 72.h, height: 25.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Tamara".needTranslation.toText16(isBold: true), LocaleKeys.tamara.tr(context: context).toText16(isBold: true),
], ],
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
@ -244,9 +244,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Insurance expired or inactive" LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500)
.needTranslation
.toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500)
.paddingSymmetrical(24.h, 0.h), .paddingSymmetrical(24.h, 0.h),
CustomButton( CustomButton(
text: LocaleKeys.updateInsurance.tr(context: context), text: LocaleKeys.updateInsurance.tr(context: context),
@ -271,12 +269,12 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
) )
: const SizedBox(), : const SizedBox(),
SizedBox(height: 24.h), SizedBox(height: 24.h),
"Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h), LocaleKeys.totalAmountToPay.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h), SizedBox(height: 17.h),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Amount before tax".needTranslation.toText14(isBold: true), LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
bookAppointmentsVM.patientWalkInAppointmentShareResponseModel!.patientShare!.toString().toText16(isBold: true), bookAppointmentsVM.patientWalkInAppointmentShareResponseModel!.patientShare!.toString().toText16(isBold: true),
AppColors.blackColor, AppColors.blackColor,
@ -287,7 +285,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor), LocaleKeys.vat15.tr(context: context).toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
bookAppointmentsVM.patientWalkInAppointmentShareResponseModel!.patientTaxAmount! bookAppointmentsVM.patientWalkInAppointmentShareResponseModel!.patientTaxAmount!
.toString() .toString()
@ -301,7 +299,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"".needTranslation.toText14(isBold: true), "".toText14(isBold: true),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
bookAppointmentsVM.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!.toString().toText24(isBold: true), bookAppointmentsVM.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!.toString().toText24(isBold: true),
AppColors.blackColor, AppColors.blackColor,
@ -377,7 +375,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
} }
void checkPaymentStatus() async { void checkPaymentStatus() async {
LoaderBottomSheet.showLoader(loadingText: "Checking payment status, Please wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr(context: context));
if (selectedPaymentMethod == "TAMARA") { if (selectedPaymentMethod == "TAMARA") {
await payfortViewModel.checkTamaraPaymentStatus( await payfortViewModel.checkTamaraPaymentStatus(
transactionID: transID, transactionID: transID,
@ -435,7 +433,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation), child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr(context: context)),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -459,7 +457,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
print(apiResponse.data); print(apiResponse.data);
if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") { if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
LoaderBottomSheet.showLoader(loadingText: "Booking Waiting Appointment, Please wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingWaitingAppointment.tr(context: context));
await bookAppointmentsViewModel.insertSpecificAppointmentForWalkIn(onSuccess: (val) async { await bookAppointmentsViewModel.insertSpecificAppointmentForWalkIn(onSuccess: (val) async {
String appointmentNo = val.data['AppointmentNo'].toString(); String appointmentNo = val.data['AppointmentNo'].toString();
await myAppointmentsViewModel.createAdvancePayment( await myAppointmentsViewModel.createAdvancePayment(
@ -488,7 +486,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
} else { } else {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation), child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr(context: context)),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -630,7 +628,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
} }
void sendCheckInRequest(String scannedCode, String appointmentNo, BuildContext context) async { void sendCheckInRequest(String scannedCode, String appointmentNo, BuildContext context) async {
LoaderBottomSheet.showLoader(loadingText: "Processing Check-In...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.processingCheckIn.tr(context: context));
PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel = PatientAppointmentHistoryResponseModel( PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel = PatientAppointmentHistoryResponseModel(
appointmentNo: appointmentNo, appointmentNo: appointmentNo,
clinicID: bookAppointmentsViewModel.selectedDoctor.clinicID, clinicID: bookAppointmentsViewModel.selectedDoctor.clinicID,
@ -642,8 +640,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
checkInType: 2, checkInType: 2,
onSuccess: (apiResponse) { onSuccess: (apiResponse) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.success.tr(context: context), child: Utils.getSuccessWidget(loadingText: apiResponse.data["SuccessMsg"]), callBackFunc: () {
title: "Success".needTranslation, child: Utils.getSuccessWidget(loadingText: apiResponse.data["SuccessMsg"]), callBackFunc: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
context, context,
@ -655,8 +652,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
}, },
onError: (error) { onError: (error) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context, title: "Error".needTranslation, child: Utils.getErrorWidget(loadingText: error), showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.error.tr(context: context), child: Utils.getErrorWidget(loadingText: error), callBackFunc: () {
callBackFunc: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, isFullScreen: false); }, isFullScreen: false);
}, },

@ -171,10 +171,10 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
CustomButton( CustomButton(
text: "Select".needTranslation, text: LocaleKeys.select.tr(context: context),
onPressed: () async { onPressed: () async {
if (appState.isAuthenticated) { if (appState.isAuthenticated) {
if(selectedTime == "Waiting Appointment".needTranslation){ if(selectedTime == LocaleKeys.waitingAppointment.tr(context: context)){
bookAppointmentsViewModel.setWaitingAppointmentProjectID(bookAppointmentsViewModel.selectedDoctor.projectID!); bookAppointmentsViewModel.setWaitingAppointmentProjectID(bookAppointmentsViewModel.selectedDoctor.projectID!);
bookAppointmentsViewModel.setWaitingAppointmentDoctor(bookAppointmentsViewModel.selectedDoctor); bookAppointmentsViewModel.setWaitingAppointmentDoctor(bookAppointmentsViewModel.selectedDoctor);
@ -293,7 +293,7 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
dayEvents.clear(); dayEvents.clear();
DateTime dateStartObj = new DateTime(dateStart.year, dateStart.month, dateStart.day, 0, 0, 0, 0, 0); DateTime dateStartObj = new DateTime(dateStart.year, dateStart.month, dateStart.day, 0, 0, 0, 0, 0);
if (bookAppointmentsViewModel.isWaitingAppointmentAvailable && DateUtils.isSameDay(dateStart, DateTime.now())) { if (bookAppointmentsViewModel.isWaitingAppointmentAvailable && DateUtils.isSameDay(dateStart, DateTime.now())) {
dayEvents.add(TimeSlot(isoTime: "Waiting Appointment".needTranslation, start: DateTime.now(), end: DateTime.now(), vidaDate: "")); dayEvents.add(TimeSlot(isoTime: LocaleKeys.waitingAppointment.tr(context: context), start: DateTime.now(), end: DateTime.now(), vidaDate: ""));
} }
freeSlots.forEach((v) { freeSlots.forEach((v) {
if (v.start == dateStartObj) dayEvents.add(v); if (v.start == dateStartObj) dayEvents.add(v);
@ -332,7 +332,7 @@ class TimeSlotChip extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: onTap, onTap: onTap,
child: label == "Waiting Appointment".needTranslation child: label == LocaleKeys.waitingAppointment.tr(context: context)
? Container( ? Container(
padding: EdgeInsets.symmetric(horizontal: 14.h, vertical: 8.h), padding: EdgeInsets.symmetric(horizontal: 14.h, vertical: 8.h),
decoration: ShapeDecoration( decoration: ShapeDecoration(

@ -38,20 +38,49 @@ class DoctorCard extends StatelessWidget {
hasShadow: false, hasShadow: false,
), ),
child: Padding( child: Padding(
padding: EdgeInsets.all(14.h), padding: EdgeInsets.only(top: 14.h,bottom: 20.h),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Image.network( Column(
isLoading crossAxisAlignment: CrossAxisAlignment.center,
? "https://hmgwebservices.com/Images/MobileImages/OALAY/1439.png" children: [
: doctorsListResponseModel.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/OALAY/1439.png", Image.network(
width: 63.h, isLoading
height: 63.h, ? "https://hmgwebservices.com/Images/MobileImages/OALAY/1439.png"
fit: BoxFit.cover, : doctorsListResponseModel.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/OALAY/1439.png",
).circle(100).toShimmer2(isShow: isLoading), width: 63.h,
height: 63.h,
fit: BoxFit.cover,
).circle(100).toShimmer2(isShow: isLoading),
Transform.translate(
offset: Offset(0.0, -20.h),
child: Container(
width: 40.w,
height: 40.h,
decoration: BoxDecoration(
color: AppColors.whiteColor,
shape: BoxShape.circle, // Makes the container circular
border: Border.all(
color: AppColors.scaffoldBgColor, // Color of the border
width: 1.5.w, // Width of the border
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h),
SizedBox(height: 2.h),
"${isLoading ? 4.78 : doctorsListResponseModel.decimalDoctorRate}".toText11(isBold: true, color: AppColors.textColor),
],
),
).circle(100).toShimmer2(isShow: isLoading),
),
],
),
SizedBox(width: 8.h), SizedBox(width: 8.h),
Expanded( Expanded(
flex: 9, flex: 9,
@ -70,15 +99,19 @@ class DoctorCard extends StatelessWidget {
), ),
SizedBox(height: 2.h), SizedBox(height: 2.h),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
(isLoading SizedBox(
? "Consultant Cardiologist" width: MediaQuery.of(context).size.width * 0.45,
: doctorsListResponseModel.speciality!.isNotEmpty child: (isLoading
? doctorsListResponseModel.speciality!.first ? "Consultant Cardiologist"
: "") : doctorsListResponseModel.speciality!.isNotEmpty
.toString() ? doctorsListResponseModel.speciality!.first
.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor, maxLine: 1) : "")
.toShimmer2(isShow: isLoading), .toString()
.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor, maxLine: 2)
.toShimmer2(isShow: isLoading),
),
SizedBox(width: 6.w), SizedBox(width: 6.w),
Image.network( Image.network(
isLoading ? "https://hmgwebservices.com/Images/flag/SYR.png" : doctorsListResponseModel.nationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SYR.png", isLoading ? "https://hmgwebservices.com/Images/flag/SYR.png" : doctorsListResponseModel.nationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SYR.png",
@ -98,27 +131,21 @@ class DoctorCard extends StatelessWidget {
), ),
], ],
), ),
SizedBox(height: 12.h),
Wrap( Wrap(
direction: Axis.horizontal, direction: Axis.horizontal,
spacing: 3.h, spacing: 3.h,
runSpacing: 4.h, runSpacing: 4.h,
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
labelText: "Clinic: ${isLoading ? "Cardiologist" : doctorsListResponseModel.clinicName}".needTranslation, labelText: "${isLoading ? "Cardiologist" : doctorsListResponseModel.clinicName}",
).toShimmer2(isShow: isLoading), ).toShimmer2(isShow: isLoading),
AppCustomChipWidget( AppCustomChipWidget(
labelText: "Branch: ${isLoading ? "Olaya Hospital" : doctorsListResponseModel.projectName}".needTranslation, labelText: "${isLoading ? "Olaya Hospital" : doctorsListResponseModel.projectName}",
).toShimmer2(isShow: isLoading), ).toShimmer2(isShow: isLoading),
doctorsListResponseModel.decimalDoctorRate != null ? AppCustomChipWidget(
icon: AppAssets.rating_icon,
iconColor: AppColors.ratingColorYellow,
labelText: "Rating: ${isLoading ? 4.78 : doctorsListResponseModel.decimalDoctorRate}".needTranslation,
).toShimmer2(isShow: isLoading) : SizedBox(),
bookAppointmentsViewModel.isNearestAppointmentSelected bookAppointmentsViewModel.isNearestAppointmentSelected
? doctorsListResponseModel.nearestFreeSlot != null ? doctorsListResponseModel.nearestFreeSlot != null
? AppCustomChipWidget( ? AppCustomChipWidget(
labelText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot)).needTranslation, labelText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot)),
backgroundColor: AppColors.successColor, backgroundColor: AppColors.successColor,
textColor: AppColors.whiteColor, textColor: AppColors.whiteColor,
).toShimmer2(isShow: isLoading) ).toShimmer2(isShow: isLoading)
@ -138,7 +165,7 @@ class DoctorCard extends StatelessWidget {
onSuccess: (dynamic respData) async { onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: "Pick a Date".needTranslation, title: LocaleKeys.pickADate.tr(context: context),
context, context,
child: AppointmentCalendar(), child: AppointmentCalendar(),
isFullScreen: false, isFullScreen: false,
@ -161,7 +188,7 @@ class DoctorCard extends StatelessWidget {
onSuccess: (dynamic respData) async { onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: "Pick a Date".needTranslation, title: LocaleKeys.pickADate.tr(context: context),
context, context,
child: AppointmentCalendar(), child: AppointmentCalendar(),
isFullScreen: false, isFullScreen: false,

@ -10,6 +10,7 @@ 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/hmg_services/hmg_services_view_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/widgets/cmc_ui_selection_helper.dart'; import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/widgets/cmc_ui_selection_helper.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/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
@ -124,7 +125,7 @@ class _CmcOrderDetailPageState extends State<CmcOrderDetailPage> {
Row( Row(
children: [ children: [
if (!isLoading) ...[ if (!isLoading) ...[
"Request ID:".needTranslation.toText14( LocaleKeys.requestID.tr(context: context).toText14(
color: AppColors.textColorLight, color: AppColors.textColorLight,
weight: FontWeight.w500, weight: FontWeight.w500,
), ),
@ -164,7 +165,7 @@ class _CmcOrderDetailPageState extends State<CmcOrderDetailPage> {
children: [ children: [
Expanded( Expanded(
child: CustomButton( child: CustomButton(
text: "Cancel Order".needTranslation, text: LocaleKeys.cancelOrder.tr(context: context),
onPressed: isLoading ? () {} : () => CmcUiSelectionHelper.showCancelConfirmationDialog(context: context, order: order), onPressed: isLoading ? () {} : () => CmcUiSelectionHelper.showCancelConfirmationDialog(context: context, order: order),
backgroundColor: AppColors.primaryRedColor, backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
@ -196,7 +197,7 @@ class _CmcOrderDetailPageState extends State<CmcOrderDetailPage> {
), ),
child: Utils.getNoDataWidget( child: Utils.getNoDataWidget(
context, context,
noDataText: "You don't have any CMC orders yet.".needTranslation, noDataText: LocaleKeys.noCMCOrdersYet.tr(context: context),
isSmallWidget: true, isSmallWidget: true,
width: 62.w, width: 62.w,
height: 62.h, height: 62.h,
@ -209,7 +210,7 @@ class _CmcOrderDetailPageState extends State<CmcOrderDetailPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CollapsingListView( return CollapsingListView(
title: "CMC Orders".needTranslation, title: LocaleKeys.cmcOrders.tr(context: context),
isLeading: true, isLeading: true,
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(

@ -55,7 +55,7 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
final isArabic = appState.isArabic(); final isArabic = appState.isArabic();
return CollapsingListView( return CollapsingListView(
title: "Summary".needTranslation, title: LocaleKeys.summary.tr(context: context),
bottomChild: _buildBottomButton(), bottomChild: _buildBottomButton(),
child: SingleChildScrollView( child: SingleChildScrollView(
padding: EdgeInsets.all(16.w), padding: EdgeInsets.all(16.w),
@ -89,7 +89,7 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Select Hospital".needTranslation, LocaleKeys.selectHospital.tr(context: context),
style: TextStyle( style: TextStyle(
fontSize: 16.f, fontSize: 16.f,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
@ -132,7 +132,7 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
Text( Text(
isLocationSelected && selectedHospital != null isLocationSelected && selectedHospital != null
? (isArabic ? (selectedHospital.nameN ?? selectedHospital.name ?? '') : (selectedHospital.name ?? '')) ? (isArabic ? (selectedHospital.nameN ?? selectedHospital.name ?? '') : (selectedHospital.name ?? ''))
: "Select Hospital".needTranslation, : LocaleKeys.selectHospital.tr(context: context),
style: TextStyle( style: TextStyle(
fontSize: 14.f, fontSize: 14.f,
fontWeight: isLocationSelected ? FontWeight.w600 : FontWeight.w400, fontWeight: isLocationSelected ? FontWeight.w600 : FontWeight.w400,
@ -189,7 +189,7 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Selected Service".needTranslation.toText14( LocaleKeys.selectedService.tr(context: context).toText14(
weight: FontWeight.w600, weight: FontWeight.w600,
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
letterSpacing: -0.4, letterSpacing: -0.4,
@ -226,14 +226,14 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 24.h), SizedBox(height: 24.h),
"Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h), LocaleKeys.totalAmountToPay.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h), SizedBox(height: 17.h),
// Amount before tax // Amount before tax
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Amount before tax".needTranslation.toText14(isBold: true), LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
amountBeforeTax.toString().toText16(isBold: true), amountBeforeTax.toString().toText16(isBold: true),
AppColors.blackColor, AppColors.blackColor,
@ -247,7 +247,7 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor), LocaleKeys.vat15.tr(context: context).toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
taxAmount.toString().toText14(isBold: true, color: AppColors.greyTextColor), taxAmount.toString().toText14(isBold: true, color: AppColors.greyTextColor),
AppColors.greyTextColor, AppColors.greyTextColor,
@ -261,7 +261,7 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"".needTranslation.toText14(isBold: true), "".toText14(isBold: true),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
totalAmount.toString().toText24(isBold: true), totalAmount.toString().toText24(isBold: true),
AppColors.blackColor, AppColors.blackColor,
@ -298,7 +298,7 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
], ],
), ),
child: CustomButton( child: CustomButton(
text: "Confirm".needTranslation, text: LocaleKeys.confirm.tr(context: context),
onPressed: () { onPressed: () {
isLocationSelected ? _handleConfirm() : null; isLocationSelected ? _handleConfirm() : null;
}, },
@ -339,10 +339,10 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
padding: EdgeInsets.all(16.w), padding: EdgeInsets.all(16.w),
child: Column( child: Column(
children: [ children: [
Utils.getSuccessWidget(loadingText: "Your request has been successfully submitted.".needTranslation), Utils.getSuccessWidget(loadingText: LocaleKeys.requestSubmittedSuccessfully.tr(context: context)),
Row( Row(
children: [ children: [
"Here is your request #: ".needTranslation.toText14( LocaleKeys.hereIsYourRequestNumber.tr(context: context).toText14(
color: AppColors.textColorLight, color: AppColors.textColorLight,
weight: FontWeight.w500, weight: FontWeight.w500,
), ),
@ -383,7 +383,7 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
if (selectedHospital == null) { if (selectedHospital == null) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text("Please select a hospital to continue".needTranslation), content: Text(LocaleKeys.pleaseSelectHospitalToContinue.tr(context: context)),
backgroundColor: AppColors.errorColor, backgroundColor: AppColors.errorColor,
), ),
); );
@ -395,7 +395,7 @@ class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
title: LocaleKeys.notice.tr(context: context), title: LocaleKeys.notice.tr(context: context),
context, context,
child: Utils.getWarningWidget( child: Utils.getWarningWidget(
loadingText: "Are you sure you want to submit this request?".needTranslation, loadingText: LocaleKeys.confirmSubmitRequest.tr(context: context),
isShowActionButtons: true, isShowActionButtons: true,
onCancelTap: () { onCancelTap: () {
Navigator.pop(context); Navigator.pop(context);

@ -12,6 +12,7 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/cmc_order_detail_page.dart'; import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/cmc_order_detail_page.dart';
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/cmc_selection_review_page.dart'; import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/cmc_selection_review_page.dart';
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/widgets/cmc_ui_selection_helper.dart'; import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/widgets/cmc_ui_selection_helper.dart';
@ -128,7 +129,7 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
// Request ID // Request ID
Row( Row(
children: [ children: [
"Request ID:".needTranslation.toText14(color: AppColors.textColorLight, weight: FontWeight.w500), LocaleKeys.requestID.tr(context: context).toText14(color: AppColors.textColorLight, weight: FontWeight.w500),
SizedBox(width: 4.w), SizedBox(width: 4.w),
"${order.iD ?? '-'}".toText16(isBold: true), "${order.iD ?? '-'}".toText16(isBold: true),
], ],
@ -179,7 +180,7 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
), ),
SizedBox(width: 8.w), SizedBox(width: 8.w),
Expanded( Expanded(
child: "You have a pending order. Please wait for it to be processed.".needTranslation.toText12( child: LocaleKeys.pendingOrderWait.tr(context: context).toText12(
color: AppColors.infoBannerTextColor, color: AppColors.infoBannerTextColor,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
@ -193,7 +194,7 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
children: [ children: [
Expanded( Expanded(
child: CustomButton( child: CustomButton(
text: "Cancel Order".needTranslation, text: LocaleKeys.cancelOrder.tr(context: context),
onPressed: () => CmcUiSelectionHelper.showCancelConfirmationDialog(context: context, order: order), onPressed: () => CmcUiSelectionHelper.showCancelConfirmationDialog(context: context, order: order),
backgroundColor: AppColors.primaryRedColor, backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
@ -219,7 +220,7 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
child: Padding( child: Padding(
padding: EdgeInsets.all(24.h), padding: EdgeInsets.all(24.h),
child: Text( child: Text(
'No services available'.needTranslation, LocaleKeys.noServicesAvailable.tr(context: context),
style: TextStyle( style: TextStyle(
fontSize: 16.h, fontSize: 16.h,
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
@ -234,7 +235,7 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
children: [ children: [
SizedBox(height: 16.h), SizedBox(height: 16.h),
Text( Text(
'Select a Service'.needTranslation, LocaleKeys.selectAService.tr(context: context),
style: TextStyle( style: TextStyle(
fontSize: 20.h, fontSize: 20.h,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
@ -357,7 +358,7 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CollapsingListView( return CollapsingListView(
title: "Comprehensive Checkup".needTranslation, title: LocaleKeys.comprehensiveCheckup.tr(context: context),
history: () => Navigator.of(context).push(CustomPageRoute(page: CmcOrderDetailPage(), direction: AxisDirection.up)), history: () => Navigator.of(context).push(CustomPageRoute(page: CmcOrderDetailPage(), direction: AxisDirection.up)),
bottomChild: Consumer<HmgServicesViewModel>( bottomChild: Consumer<HmgServicesViewModel>(
builder: (context, hmgServicesViewModel, child) { builder: (context, hmgServicesViewModel, child) {
@ -375,7 +376,7 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 12.h), padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 12.h),
child: CustomButton( child: CustomButton(
borderWidth: 0, borderWidth: 0,
text: "Next".needTranslation, text: LocaleKeys.next.tr(context: context),
onPressed: _proceedWithSelectedService, onPressed: _proceedWithSelectedService,
textColor: AppColors.whiteColor, textColor: AppColors.whiteColor,
borderRadius: 12.r, borderRadius: 12.r,

@ -55,7 +55,7 @@ class CmcHospitalBottomSheetBody extends StatelessWidget {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Choose your preferred hospital for the service".needTranslation.toText14( LocaleKeys.choosePreferredHospitalForService.tr(context: context).toText14(
weight: FontWeight.w400, weight: FontWeight.w400,
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
letterSpacing: -0.4, letterSpacing: -0.4,
@ -85,7 +85,7 @@ class CmcHospitalBottomSheetBody extends StatelessWidget {
? _buildLoadingShimmer() ? _buildLoadingShimmer()
: hmgServicesViewModel.filteredHospitalsList.isEmpty : hmgServicesViewModel.filteredHospitalsList.isEmpty
? Center( ? Center(
child: "No hospitals Found".needTranslation.toText16(weight: FontWeight.w500, color: AppColors.greyTextColor), child: LocaleKeys.noHospitalsFound.tr(context: context).toText16(weight: FontWeight.w500, color: AppColors.greyTextColor),
) )
: ListView.separated( : ListView.separated(
itemCount: hmgServicesViewModel.filteredHospitalsList.length, itemCount: hmgServicesViewModel.filteredHospitalsList.length,

@ -97,7 +97,7 @@ class CmcHospitalListItem extends StatelessWidget {
Visibility( Visibility(
visible: (hospital.distanceInKilometers != null && hospital.distanceInKilometers! > 0), visible: (hospital.distanceInKilometers != null && hospital.distanceInKilometers! > 0),
child: AppCustomChipWidget( child: AppCustomChipWidget(
labelText: "$distanceText km".needTranslation, labelText: "$distanceText km",
icon: AppAssets.location_red, icon: AppAssets.location_red,
iconColor: AppColors.errorColor, iconColor: AppColors.errorColor,
backgroundColor: AppColors.secondaryLightRedColor, backgroundColor: AppColors.secondaryLightRedColor,
@ -107,7 +107,7 @@ class CmcHospitalListItem extends StatelessWidget {
Visibility( Visibility(
visible: (hospital.distanceInKilometers == null || hospital.distanceInKilometers == 0), visible: (hospital.distanceInKilometers == null || hospital.distanceInKilometers == 0),
child: AppCustomChipWidget( child: AppCustomChipWidget(
labelText: " Distance not available".needTranslation, labelText: " Distance not available",
textColor: AppColors.blackColor, textColor: AppColors.blackColor,
), ),
), ),

@ -24,7 +24,7 @@ class CmcUiSelectionHelper {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
title: "Select Hospital".needTranslation, title: LocaleKeys.selectHospital.tr(context: context),
child: CmcHospitalBottomSheetBody( child: CmcHospitalBottomSheetBody(
onHospitalSelected: (hospital) { onHospitalSelected: (hospital) {
hmgServicesViewModel.setSelectedHospitalForOrder(hospital); hmgServicesViewModel.setSelectedHospitalForOrder(hospital);
@ -44,7 +44,7 @@ class CmcUiSelectionHelper {
title: LocaleKeys.notice.tr(context: context), title: LocaleKeys.notice.tr(context: context),
context, context,
child: Utils.getWarningWidget( child: Utils.getWarningWidget(
loadingText: "Are you sure you want to cancel this order?".needTranslation, loadingText: LocaleKeys.cancelOrderConfirmation.tr(context: context),
isShowActionButtons: true, isShowActionButtons: true,
onCancelTap: () { onCancelTap: () {
Navigator.pop(context); Navigator.pop(context);
@ -70,7 +70,7 @@ class CmcUiSelectionHelper {
padding: EdgeInsets.all(16.w), padding: EdgeInsets.all(16.w),
child: Column( child: Column(
children: [ children: [
Utils.getSuccessWidget(loadingText: "Order has been cancelled successfully".needTranslation), Utils.getSuccessWidget(loadingText: LocaleKeys.orderCancelledSuccessfully.tr(context: context)),
SizedBox(height: 24.h), SizedBox(height: 24.h),
Row( Row(
children: [ children: [

@ -36,7 +36,7 @@ class ContactUs extends StatelessWidget {
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_location_icon, AppAssets.checkin_location_icon,
LocaleKeys.findUs.tr(), LocaleKeys.findUs.tr(),
"View your nearest HMG locations".needTranslation, LocaleKeys.viewNearestHMGLocations.tr(),
).onPress(() { ).onPress(() {
locationUtils.getCurrentLocation(onSuccess: (value) { locationUtils.getCurrentLocation(onSuccess: (value) {
contactUsViewModel.initContactUsViewModel(); contactUsViewModel.initContactUsViewModel();
@ -52,7 +52,7 @@ class ContactUs extends StatelessWidget {
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_location_icon, AppAssets.checkin_location_icon,
LocaleKeys.feedback.tr(), LocaleKeys.feedback.tr(),
"Provide your feedback on our services".needTranslation, LocaleKeys.provideFeedbackOnServices.tr(),
).onPress(() { ).onPress(() {
contactUsViewModel.setSelectedFeedbackType( contactUsViewModel.setSelectedFeedbackType(
FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد'), FeedbackType(id: 5, nameEN: "Not classified", nameAR: 'غير محدد'),
@ -68,7 +68,7 @@ class ContactUs extends StatelessWidget {
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_location_icon, AppAssets.checkin_location_icon,
LocaleKeys.liveChat.tr(), LocaleKeys.liveChat.tr(),
"Live chat option with HMG".needTranslation, LocaleKeys.liveChatWithHMG.tr(),
).onPress(() { ).onPress(() {
locationUtils.getCurrentLocation(onSuccess: (value) { locationUtils.getCurrentLocation(onSuccess: (value) {
contactUsViewModel.getLiveChatProjectsList(); contactUsViewModel.getLiveChatProjectsList();

@ -55,8 +55,8 @@ class FeedbackPage extends StatelessWidget {
activeTextColor: AppColors.primaryRedColor, activeTextColor: AppColors.primaryRedColor,
activeBackgroundColor: AppColors.primaryRedColor.withValues(alpha: .1), activeBackgroundColor: AppColors.primaryRedColor.withValues(alpha: .1),
tabs: [ tabs: [
CustomTabBarModel(null, "Send".needTranslation), CustomTabBarModel(null, LocaleKeys.send.tr(context: context)),
CustomTabBarModel(null, "Status".needTranslation), CustomTabBarModel(null, LocaleKeys.status.tr(context: context)),
], ],
onTabChange: (index) { onTabChange: (index) {
contactUsViewModel.setIsSendFeedbackTabSelected(index == 0); contactUsViewModel.setIsSendFeedbackTabSelected(index == 0);
@ -93,7 +93,7 @@ class FeedbackPage extends StatelessWidget {
); );
return; return;
} }
LoaderBottomSheet.showLoader(loadingText: "Sending Feedback...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.sendingFeedback.tr(context: context));
contactUsViewModel.insertCOCItem( contactUsViewModel.insertCOCItem(
subject: subjectTextController.text, subject: subjectTextController.text,
message: messageTextController.text, message: messageTextController.text,
@ -172,7 +172,7 @@ class FeedbackPage extends StatelessWidget {
], ],
).onPress(() { ).onPress(() {
showCommonBottomSheetWithoutHeight(context, showCommonBottomSheetWithoutHeight(context,
title: "Select Feedback Type".needTranslation, title: LocaleKeys.selectFeedbackType.tr(context: context),
child: Container( child: Container(
width: double.infinity, width: double.infinity,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24),
@ -207,7 +207,7 @@ class FeedbackPage extends StatelessWidget {
Navigator.pop(context); Navigator.pop(context);
contactUsViewModel.setSelectedFeedbackType(newValue!); contactUsViewModel.setSelectedFeedbackType(newValue!);
if (contactUsViewModel.selectedFeedbackType.id == 1) { if (contactUsViewModel.selectedFeedbackType.id == 1) {
LoaderBottomSheet.showLoader(loadingText: "Loading appointments list...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.loadingAppointmentsList.tr(context: context));
await medicalFileViewModel.getPatientMedicalReportAppointmentsList(onSuccess: (val) async { await medicalFileViewModel.getPatientMedicalReportAppointmentsList(onSuccess: (val) async {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
bool? value = await Navigator.of(context).push( bool? value = await Navigator.of(context).push(
@ -224,7 +224,7 @@ class FeedbackPage extends StatelessWidget {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "You do not have any appointments to submit a feedback.".needTranslation), child: Utils.getErrorWidget(loadingText: LocaleKeys.noAppointmentsForFeedback.tr(context: context)),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -248,7 +248,7 @@ class FeedbackPage extends StatelessWidget {
), ),
if (contactUsViewModel.patientFeedbackSelectedAppointment != null) ...[ if (contactUsViewModel.patientFeedbackSelectedAppointment != null) ...[
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Selected Appointment:".needTranslation.toText16(isBold: true), LocaleKeys.selectedAppointment.tr(context: context).toText16(isBold: true),
SizedBox(height: 8.h), SizedBox(height: 8.h),
Container( Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
@ -295,8 +295,8 @@ class FeedbackPage extends StatelessWidget {
], ],
SizedBox(height: 16.h), SizedBox(height: 16.h),
TextInputWidget( TextInputWidget(
labelText: "Subject".needTranslation, labelText: LocaleKeys.subject.tr(context: context),
hintText: "Enter subject here".needTranslation, hintText: LocaleKeys.enterSubjectHere.tr(context: context),
controller: subjectTextController, controller: subjectTextController,
isEnable: true, isEnable: true,
prefix: null, prefix: null,
@ -310,8 +310,8 @@ class FeedbackPage extends StatelessWidget {
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
TextInputWidget( TextInputWidget(
labelText: "Message".needTranslation, labelText: LocaleKeys.message.tr(context: context),
hintText: "Enter message here".needTranslation, hintText: LocaleKeys.enterMessageHere.tr(context: context),
controller: messageTextController, controller: messageTextController,
isEnable: true, isEnable: true,
prefix: null, prefix: null,

@ -114,7 +114,6 @@ class LiveChatPage extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
("${appState.isArabic() ? contactUsVM.liveChatProjectsList[index].projectNameN! : contactUsVM.liveChatProjectsList[index].projectName!}\n${contactUsVM.liveChatProjectsList[index].distanceInKilometers!} KM") ("${appState.isArabic() ? contactUsVM.liveChatProjectsList[index].projectNameN! : contactUsVM.liveChatProjectsList[index].projectName!}\n${contactUsVM.liveChatProjectsList[index].distanceInKilometers!} KM")
.needTranslation
.toText14(isBold: true, color: contactUsVM.selectedLiveChatProjectIndex == index ? AppColors.whiteColor : AppColors.textColor), .toText14(isBold: true, color: contactUsVM.selectedLiveChatProjectIndex == index ? AppColors.whiteColor : AppColors.textColor),
Transform.flip( Transform.flip(
flipX: getIt.get<AppState>().isArabic(), flipX: getIt.get<AppState>().isArabic(),
@ -130,9 +129,13 @@ class LiveChatPage extends StatelessWidget {
).paddingSymmetrical(16.h, 16.h), ).paddingSymmetrical(16.h, 16.h),
).onPress(() { ).onPress(() {
contactUsVM.setSelectedLiveChatProjectIndex(index); contactUsVM.setSelectedLiveChatProjectIndex(index);
chatURL = _getChatRequestID(
"https://chat.hmg.com/Index.aspx?Name=${appState.getAuthenticatedUser()!.firstName}&PatientID=${appState.getAuthenticatedUser()!.patientId}&MobileNo=${appState.getAuthenticatedUser()!.mobileNumber}&Language=${appState.isArabic() ? 'ar' : 'en'}&WorkGroup=${contactUsVM.liveChatProjectsList[index].value}"; context,
debugPrint("Chat URL: $chatURL"); contactUsVM,
name: appState.getAuthenticatedUser()!.firstName ?? '',
mobileNo: appState.getAuthenticatedUser()!.mobileNumber ?? '',
workGroup: contactUsVM.liveChatProjectsList[index].value ?? '',
);
}), }),
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
), ),
@ -155,8 +158,14 @@ class LiveChatPage extends StatelessWidget {
child: CustomButton( child: CustomButton(
text: LocaleKeys.liveChat.tr(context: context), text: LocaleKeys.liveChat.tr(context: context),
onPressed: () async { onPressed: () async {
Uri uri = Uri.parse(chatURL); if (contactUsVM.chatRequestID != null) {
launchUrl(uri, mode: LaunchMode.platformDefault, webOnlyWindowName: ""); chatURL = "https://chat.hmg.com/Index.aspx?RequestedId=${contactUsVM.chatRequestID}";
debugPrint("Chat URL: $chatURL");
Uri uri = Uri.parse(chatURL);
launchUrl(uri, mode: LaunchMode.platformDefault, webOnlyWindowName: "");
} else {
debugPrint("Chat Request ID is null");
}
}, },
backgroundColor: contactUsVM.selectedLiveChatProjectIndex == -1 ? AppColors.greyColor : AppColors.primaryRedColor, backgroundColor: contactUsVM.selectedLiveChatProjectIndex == -1 ? AppColors.greyColor : AppColors.primaryRedColor,
borderColor: contactUsVM.selectedLiveChatProjectIndex == -1 ? AppColors.greyColor : AppColors.primaryRedColor, borderColor: contactUsVM.selectedLiveChatProjectIndex == -1 ? AppColors.greyColor : AppColors.primaryRedColor,
@ -173,4 +182,20 @@ class LiveChatPage extends StatelessWidget {
}), }),
); );
} }
void _getChatRequestID(BuildContext context, ContactUsViewModel contactUsVM, {required String name, required String mobileNo, required String workGroup}) {
contactUsVM.getChatRequestID(
name: name,
mobileNo: mobileNo,
workGroup: workGroup,
onSuccess: (response) {
debugPrint("Chat Request ID received: ${contactUsVM.chatRequestID}");
chatURL = "https://chat.hmg.com/Index.aspx?RequestedId=${contactUsVM.chatRequestID}";
debugPrint("Chat URL: $chatURL");
},
onError: (error) {
debugPrint("Error getting chat request ID: $error");
},
);
}
} }

@ -68,7 +68,7 @@ class FindUsItemCard extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
labelText: "${getHMGLocationsModel.distanceInKilometers ?? ""} km".needTranslation, labelText: "${getHMGLocationsModel.distanceInKilometers ?? ""} km",
icon: AppAssets.location_red, icon: AppAssets.location_red,
iconColor: AppColors.primaryRedColor, iconColor: AppColors.primaryRedColor,
backgroundColor: AppColors.secondaryLightRedColor, backgroundColor: AppColors.secondaryLightRedColor,
@ -77,7 +77,7 @@ class FindUsItemCard extends StatelessWidget {
Row( Row(
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
labelText: "Get Directions".needTranslation, labelText: LocaleKeys.getDirections.tr(),
icon: AppAssets.directions_icon, icon: AppAssets.directions_icon,
iconColor: AppColors.whiteColor, iconColor: AppColors.whiteColor,
backgroundColor: AppColors.textColor.withValues(alpha: 0.8), backgroundColor: AppColors.textColor.withValues(alpha: 0.8),

@ -94,7 +94,7 @@ class _Covid19LandingPageState extends State<Covid19LandingPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
CustomButton( CustomButton(
text: "SelectLocation".needTranslation, text: "Select Location",
onPressed: () { onPressed: () {
_showBranchBottomSheet(context); _showBranchBottomSheet(context);
}, },
@ -124,7 +124,7 @@ class _Covid19LandingPageState extends State<Covid19LandingPage> {
showCommonBottomSheet( showCommonBottomSheet(
context, context,
title: "Select Branch".needTranslation, title: "Select Branch",
height: ResponsiveExtension.screenHeight * 0.651, height: ResponsiveExtension.screenHeight * 0.651,
child: StatefulBuilder( child: StatefulBuilder(
builder: (context, setBottomSheetState) { builder: (context, setBottomSheetState) {
@ -240,7 +240,7 @@ class _Covid19LandingPageState extends State<Covid19LandingPage> {
child: SafeArea( child: SafeArea(
top: false, top: false,
child: CustomButton( child: CustomButton(
text: "Next".needTranslation, text: LocaleKeys.next.tr(context: context),
onPressed: (){ onPressed: (){
Navigator.of(context) Navigator.of(context)

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.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/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@ -7,6 +8,7 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/ui_models/covid_questionnare_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/ui_models/covid_questionnare_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/covid19test/covid_review_screen.dart'; import 'package:hmg_patient_app_new/presentation/covid19test/covid_review_screen.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/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
@ -61,7 +63,7 @@ class _Covid19QuestionnaireState extends State<Covid19Questionnaire> {
topRight: Radius.circular(24.r), topRight: Radius.circular(24.r),
), ),
),child: CustomButton( ),child: CustomButton(
text: "Next".needTranslation, text: LocaleKeys.next.tr(context: context),
onPressed: () { onPressed: () {
moveToNextPage(context); moveToNextPage(context);
}, },

@ -89,7 +89,7 @@ class _CovidPaymentScreenState extends State<CovidPaymentScreen> {
return Scaffold( return Scaffold(
backgroundColor: AppColors.bgScaffoldColor, backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView( body: CollapsingListView(
title: widget.title.needTranslation, title: widget.title,
bottomChild: Container( bottomChild: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, color: AppColors.whiteColor,
@ -100,19 +100,19 @@ class _CovidPaymentScreenState extends State<CovidPaymentScreen> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 24.h), SizedBox(height: 24.h),
"Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h), LocaleKeys.totalAmountToPay.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h), SizedBox(height: 17.h),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Amount before tax".needTranslation.toText14(isBold: true), LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(( (widget.amount - widget.taxAmount).toString()).toText16(isBold: true), AppColors.blackColor, 13, isSaudiCurrency: true), Utils.getPaymentAmountWithSymbol(( (widget.amount - widget.taxAmount).toString()).toText16(isBold: true), AppColors.blackColor, 13, isSaudiCurrency: true),
], ],
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor), LocaleKeys.vat15.tr(context: context).toText14(isBold: true, color: AppColors.greyTextColor),
// Show VAT amount passed from review screen // Show VAT amount passed from review screen
Utils.getPaymentAmountWithSymbol((widget.taxAmount.toString()).toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13, isSaudiCurrency: true), Utils.getPaymentAmountWithSymbol((widget.taxAmount.toString()).toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13, isSaudiCurrency: true),
], ],
@ -121,7 +121,7 @@ class _CovidPaymentScreenState extends State<CovidPaymentScreen> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"".needTranslation.toText14(isBold: true), "".toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(widget.amount.toString().toText24(isBold: true), AppColors.blackColor, 17, isSaudiCurrency: true), Utils.getPaymentAmountWithSymbol(widget.amount.toString().toText24(isBold: true), AppColors.blackColor, 17, isSaudiCurrency: true),
], ],
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
@ -212,7 +212,7 @@ class _CovidPaymentScreenState extends State<CovidPaymentScreen> {
children: [ children: [
Image.asset(AppAssets.mada, width: 72.h, height: 25.h), Image.asset(AppAssets.mada, width: 72.h, height: 25.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Mada".needTranslation.toText16(isBold: true), LocaleKeys.mada.tr(context: context).toText16(isBold: true),
], ],
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
@ -257,7 +257,7 @@ class _CovidPaymentScreenState extends State<CovidPaymentScreen> {
], ],
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Visa or Mastercard".needTranslation.toText16(isBold: true), LocaleKeys.visaOrMastercard.tr(context: context).toText16(isBold: true),
], ],
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
@ -312,7 +312,7 @@ class _CovidPaymentScreenState extends State<CovidPaymentScreen> {
}, },
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Tamara".needTranslation.toText16(isBold: true), LocaleKeys.tamara.tr(context: context).toText16(isBold: true),
], ],
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
@ -387,7 +387,7 @@ class _CovidPaymentScreenState extends State<CovidPaymentScreen> {
} }
Future<void> checkPaymentStatus() async { Future<void> checkPaymentStatus() async {
LoaderBottomSheet.showLoader(loadingText: "Checking payment status, Please wait...".needTranslation); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingPaymentStatusPleaseWait.tr(context: context));
try { try {
await payfortViewModel.checkPaymentStatus(transactionID: transID, onSuccess: (apiResponse) async { await payfortViewModel.checkPaymentStatus(transactionID: transID, onSuccess: (apiResponse) async {
// treat any successful responseMessage as success; otherwise show generic error // treat any successful responseMessage as success; otherwise show generic error
@ -396,7 +396,7 @@ class _CovidPaymentScreenState extends State<CovidPaymentScreen> {
if (success) { if (success) {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getSuccessWidget(loadingText: "Payment successful".needTranslation), child: Utils.getSuccessWidget(loadingText: "Payment successful"),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -404,7 +404,7 @@ class _CovidPaymentScreenState extends State<CovidPaymentScreen> {
} else { } else {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation), child: Utils.getErrorWidget(loadingText: LocaleKeys.paymentFailedPleaseTryAgain.tr(context: context)),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,

@ -75,7 +75,7 @@ class _CovidReviewScreenState extends State<CovidReviewScreen> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Amount before tax".needTranslation.toText18(isBold: true), LocaleKeys.amountBeforeTax.tr(context: context).toText18(isBold: true),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
(info.patientShareField ?? 0).toString().toText16(isBold: true), (info.patientShareField ?? 0).toString().toText16(isBold: true),
AppColors.blackColor, AppColors.blackColor,
@ -87,7 +87,7 @@ class _CovidReviewScreenState extends State<CovidReviewScreen> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Tax Amount".needTranslation.toText14(isBold: true), LocaleKeys.vat15.tr(context: context).toText14(isBold: true),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
(info.patientTaxAmountField ?? 0).toString().toText16(isBold: true), (info.patientTaxAmountField ?? 0).toString().toText16(isBold: true),
AppColors.blackColor, AppColors.blackColor,
@ -208,13 +208,13 @@ class _CovidReviewScreenState extends State<CovidReviewScreen> {
Expanded( Expanded(
child: CustomButton( child: CustomButton(
height: 56.h, height: 56.h,
text: "Next".needTranslation, text: LocaleKeys.next.tr(context: context),
onPressed: () async { onPressed: () async {
// Validate selection and payment info // Validate selection and payment info
if (_selectedProcedure == null) { if (_selectedProcedure == null) {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "Please select a procedure".needTranslation), child: Utils.getErrorWidget(loadingText: "Please select a procedure"),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
@ -236,7 +236,7 @@ class _CovidReviewScreenState extends State<CovidReviewScreen> {
if (hmgServicesViewModel.covidPaymentInfo == null) { if (hmgServicesViewModel.covidPaymentInfo == null) {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
child: Utils.getErrorWidget(loadingText: "Payment information not available".needTranslation), child: Utils.getErrorWidget(loadingText: "Payment information not available"),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,

@ -1,64 +1,65 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.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/features/hmg_services/models/ui_models/e_referral_form_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/ui_models/e_referral_form_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
class ReferralValidator { class ReferralValidator {
static FormValidationErrors validateStep1(ReferralFormData formData) { static FormValidationErrors validateStep1(ReferralFormData formData, BuildContext context) {
final errors = FormValidationErrors(); final errors = FormValidationErrors();
if (formData.requesterName.trim().isEmpty) { if (formData.requesterName.trim().isEmpty) {
errors.requesterName = 'Referral requester name is required'.needTranslation; errors.requesterName = LocaleKeys.requesterNameRequired.tr(context: context);
} }
if (formData.relationship == null) { if (formData.relationship == null) {
errors.relationship = 'Please select a relationship'.needTranslation; errors.relationship = LocaleKeys.selectRelationshipRequired.tr(context: context);
} }
if (formData.relationship != null && if (formData.relationship != null &&
formData.relationship?.iD == 5 && formData.relationship?.iD == 5 &&
formData.otherRelationshipName.trim().isEmpty) { formData.otherRelationshipName.trim().isEmpty) {
errors.otherRelationshipName = 'Other relationship name is required'.needTranslation; errors.otherRelationshipName = LocaleKeys.otherRelationshipNameRequired.tr(context: context);
} }
return errors; return errors;
} }
static FormValidationErrors validateStep2(ReferralFormData formData) { static FormValidationErrors validateStep2(ReferralFormData formData, BuildContext context) {
final errors = FormValidationErrors(); final errors = FormValidationErrors();
if (formData.patientIdentification.trim().isEmpty) { if (formData.patientIdentification.trim().isEmpty) {
errors.patientIdentification = 'Identification number is required'.needTranslation; errors.patientIdentification = LocaleKeys.identificationNumberRequired.tr(context: context);
} }
if (formData.patientName.trim().isEmpty) { if (formData.patientName.trim().isEmpty) {
errors.patientName = 'Patient name is required'.needTranslation; errors.patientName = LocaleKeys.patientNameRequired.tr(context: context);
} }
if (formData.patientPhone == null) { if (formData.patientPhone == null) {
errors.patientPhone = 'Please Enter patient phone number'.needTranslation; errors.patientPhone = LocaleKeys.enterPatientPhoneRequired.tr(context: context);
} }
if (formData.patientCity == null) { if (formData.patientCity == null) {
errors.patientCity = 'Please select patient city'.needTranslation; errors.patientCity = LocaleKeys.selectPatientCityRequired.tr(context: context);
} }
return errors; return errors;
} }
static FormValidationErrors validateStep3(ReferralFormData formData) { static FormValidationErrors validateStep3(ReferralFormData formData, BuildContext context) {
final errors = FormValidationErrors(); final errors = FormValidationErrors();
if (formData.medicalReportImages.isEmpty) { if (formData.medicalReportImages.isEmpty) {
errors.medicalReport = 'At least one medical report is required'.needTranslation; errors.medicalReport = LocaleKeys.medicalReportRequired.tr(context: context);
} }
if (formData.branch == null) { if (formData.branch == null) {
errors.branch = 'Please select a branch'.needTranslation; errors.branch = LocaleKeys.selectBranchRequired.tr(context: context);
} }
if (formData.isPatientInsured && formData.insuredPatientImages.isEmpty) { if (formData.isPatientInsured && formData.insuredPatientImages.isEmpty) {
errors.insuredDocument = 'Insurance document is required for insured patients'.needTranslation; errors.insuredDocument = LocaleKeys.insuranceDocumentRequired.tr(context: context);
} }
return errors; return errors;

@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart';
@ -5,6 +6,7 @@ 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/features/hmg_services/hmg_services_view_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/search_e_referral_resp_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/search_e_referral_resp_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.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:provider/provider.dart'; import 'package:provider/provider.dart';
@ -31,7 +33,7 @@ class _SearchResultPageState extends State<SearchResultPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CollapsingListView( return CollapsingListView(
title: "Search Result".needTranslation, title: LocaleKeys.searchResult.tr(context: context),
child: Column( child: Column(
children: [ children: [
// List of referrals // List of referrals
@ -61,10 +63,7 @@ class _SearchResultPageState extends State<SearchResultPage> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
LocaleKeys.referralNo.tr(context: context, namedArgs: {'number': '${referral.referralNumber}'}).toText18(isBold: true, color: AppColors.textColor),
'Referral No ${referral.referralNumber}'.needTranslation.toText18(isBold: true, color: AppColors.textColor),
Container( Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6), padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration( decoration: BoxDecoration(

@ -81,13 +81,13 @@ class _NewReferralPageState extends State<NewReferralPage> {
switch (_currentStep) { switch (_currentStep) {
case 0: case 0:
stepErrors = ReferralValidator.validateStep1(_formManager.formData); stepErrors = ReferralValidator.validateStep1(_formManager.formData, context);
break; break;
case 1: case 1:
stepErrors = ReferralValidator.validateStep2(_formManager.formData); stepErrors = ReferralValidator.validateStep2(_formManager.formData, context);
break; break;
case 2: case 2:
stepErrors = ReferralValidator.validateStep3(_formManager.formData); stepErrors = ReferralValidator.validateStep3(_formManager.formData, context);
break; break;
default: default:
stepErrors = FormValidationErrors(); stepErrors = FormValidationErrors();
@ -159,7 +159,7 @@ class _NewReferralPageState extends State<NewReferralPage> {
return Scaffold( return Scaffold(
backgroundColor: AppColors.bgScaffoldColor, backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView( body: CollapsingListView(
title: "E Referral".needTranslation, title: LocaleKeys.eReferral.tr(context: context),
isClose: false, isClose: false,
search: () async { search: () async {
await Navigator.of(context).push( await Navigator.of(context).push(
@ -222,10 +222,10 @@ class _NewReferralPageState extends State<NewReferralPage> {
padding: EdgeInsets.all(16.w), padding: EdgeInsets.all(16.w),
child: Column( child: Column(
children: [ children: [
Utils.getSuccessWidget(loadingText: "Your Referral has been created Successfully.".needTranslation), Utils.getSuccessWidget(loadingText: LocaleKeys.referralCreatedSuccessfully.tr(context: context)),
Row( Row(
children: [ children: [
"Here is your Referral #: ".needTranslation.toText14( LocaleKeys.hereIsYourReferralNumber.tr(context: context).toText14(
color: AppColors.textColorLight, color: AppColors.textColorLight,
weight: FontWeight.w500, weight: FontWeight.w500,
), ),

@ -80,7 +80,7 @@ class _SearchEReferralPageState extends State<SearchEReferralPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CollapsingListView( return CollapsingListView(
title: "Search E-Referral".needTranslation, title: LocaleKeys.searchEReferral.tr(context: context),
isClose: true, isClose: true,
bottomChild: Container( bottomChild: Container(
color: Colors.white, color: Colors.white,
@ -111,7 +111,7 @@ class _SearchEReferralPageState extends State<SearchEReferralPage> {
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [SizedBox(height: 8), 'Please enter the required information to search for an e-referral'.needTranslation.toText12()], children: [SizedBox(height: 8), LocaleKeys.enterRequiredInfoToSearch.tr(context: context).toText12()],
), ),
); );
} }

@ -1,10 +1,12 @@
import 'dart:io'; import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/utils/validation_utils.dart'; import 'package:hmg_patient_app_new/core/utils/validation_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/hmg_services/models/req_models/create_e_referral_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/create_e_referral_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/e_referral_form_manager.dart'; import 'package:hmg_patient_app_new/presentation/e_referral/e_referral_form_manager.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -46,14 +48,14 @@ class _OtherDetailsStepState extends State<OtherDetailsStep> {
void _updateMedicalReportText() { void _updateMedicalReportText() {
final hasMedicalReports = _formManager.formData.medicalReportImages.isNotEmpty; final hasMedicalReports = _formManager.formData.medicalReportImages.isNotEmpty;
_medicalReportController.text = hasMedicalReports _medicalReportController.text = hasMedicalReports
? '${_formManager.formData.medicalReportImages.length} file(s) selected'.needTranslation ? '${_formManager.formData.medicalReportImages.length} file(s) selected'
: ''; : '';
} }
void _updateInsuranceText() { void _updateInsuranceText() {
final hasInsuranceDocs = _formManager.formData.insuredPatientImages.isNotEmpty; final hasInsuranceDocs = _formManager.formData.insuredPatientImages.isNotEmpty;
_insuranceController.text = hasInsuranceDocs _insuranceController.text = hasInsuranceDocs
? '${_formManager.formData.insuredPatientImages.length} file(s) selected'.needTranslation ? '${_formManager.formData.insuredPatientImages.length} file(s) selected'
: ''; : '';
} }
@ -68,7 +70,7 @@ class _OtherDetailsStepState extends State<OtherDetailsStep> {
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
children: [ children: [
const SizedBox(height: 12), const SizedBox(height: 12),
_buildSectionTitle('Other Details'.needTranslation), _buildSectionTitle(LocaleKeys.otherDetails.tr(context: context)),
const SizedBox(height: 12), const SizedBox(height: 12),
_buildMedicalReportField(formManager), _buildMedicalReportField(formManager),
_buildBranchField(context, formManager), _buildBranchField(context, formManager),
@ -96,8 +98,8 @@ class _OtherDetailsStepState extends State<OtherDetailsStep> {
child: TextInputWidget( child: TextInputWidget(
controller: _medicalReportController, controller: _medicalReportController,
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0),
hintText: 'Medical Report'.needTranslation, hintText: LocaleKeys.medicalReport.tr(context: context),
labelText: 'Select Attachment'.needTranslation, labelText: LocaleKeys.selectAttachment.tr(context: context),
suffix: const Icon(Icons.attachment), suffix: const Icon(Icons.attachment),
isReadOnly: true, isReadOnly: true,
errorMessage: formManager.errors.medicalReport, errorMessage: formManager.errors.medicalReport,
@ -121,7 +123,7 @@ class _OtherDetailsStepState extends State<OtherDetailsStep> {
children: formManager.formData.medicalReportImages.asMap().entries.map((entry) { children: formManager.formData.medicalReportImages.asMap().entries.map((entry) {
final index = entry.key; final index = entry.key;
return Chip( return Chip(
label: Text('Medical Report ${index + 1}'.needTranslation), label: Text(LocaleKeys.medicalReportNumber.tr(context: context, namedArgs: {'number': '${index + 1}'})),
deleteIcon: const Icon(Icons.close, size: 16), deleteIcon: const Icon(Icons.close, size: 16),
onDeleted: () { onDeleted: () {
_removeMedicalReport(index, formManager); _removeMedicalReport(index, formManager);
@ -172,7 +174,7 @@ class _OtherDetailsStepState extends State<OtherDetailsStep> {
Padding( Padding(
padding: EdgeInsets.all(5.0), padding: EdgeInsets.all(5.0),
child: child:
"Patient is Insured".needTranslation.toText14( LocaleKeys.patientIsInsured.tr(context: context).toText14(
color: Colors.black, color: Colors.black,
weight: FontWeight.w600, weight: FontWeight.w600,
), ),
@ -193,8 +195,8 @@ class _OtherDetailsStepState extends State<OtherDetailsStep> {
child: TextInputWidget( child: TextInputWidget(
controller: _insuranceController, controller: _insuranceController,
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0),
hintText: 'Insurance Document'.needTranslation, hintText: LocaleKeys.insuranceDocument.tr(context: context),
labelText: 'Select Attachment'.needTranslation, labelText: LocaleKeys.selectAttachment.tr(context: context),
suffix: const Icon(Icons.attachment), suffix: const Icon(Icons.attachment),
isReadOnly: true, isReadOnly: true,
errorMessage: formManager.errors.insuredDocument, errorMessage: formManager.errors.insuredDocument,
@ -235,7 +237,7 @@ class _OtherDetailsStepState extends State<OtherDetailsStep> {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
title: "Select Branch".needTranslation, title: LocaleKeys.selectBranch.tr(context: context),
child: Consumer<HabibWalletViewModel>( child: Consumer<HabibWalletViewModel>(
builder: (context, habibWalletVM, child) { builder: (context, habibWalletVM, child) {
final hospitals = habibWalletVM.advancePaymentHospitals; final hospitals = habibWalletVM.advancePaymentHospitals;

@ -1,8 +1,10 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/utils/validation_utils.dart'; import 'package:hmg_patient_app_new/core/utils/validation_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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/e_referral_form_manager.dart'; import 'package:hmg_patient_app_new/presentation/e_referral/e_referral_form_manager.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -65,14 +67,14 @@ class PatientInformationStepState extends State<PatientInformationStep> {
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
children: [ children: [
const SizedBox(height: 12), const SizedBox(height: 12),
_buildSectionTitle('Patient information'.needTranslation), _buildSectionTitle(LocaleKeys.patientInfo.tr(context: context)),
const SizedBox(height: 12), const SizedBox(height: 12),
_buildIdentificationField(formManager), _buildIdentificationField(formManager),
_buildPatientNameField(formManager), _buildPatientNameField(formManager),
// _buildPatientCountryField(context, formManager), // _buildPatientCountryField(context, formManager),
_buildPatientPhoneField(formManager), _buildPatientPhoneField(formManager),
const SizedBox(height: 20), const SizedBox(height: 20),
_buildSectionTitle('Where the patient located'.needTranslation), _buildSectionTitle(LocaleKeys.patientLocation.tr(context: context)),
_buildPatientCityField(context, formManager), _buildPatientCityField(context, formManager),
], ],
), ),
@ -94,8 +96,8 @@ class PatientInformationStepState extends State<PatientInformationStep> {
child: TextInputWidget( child: TextInputWidget(
controller: _identificationController, controller: _identificationController,
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0),
hintText: 'Enter Identification Number*'.needTranslation, hintText: LocaleKeys.enterIdentificationNumber.tr(context: context),
labelText: 'Identification Number'.needTranslation, labelText: LocaleKeys.identificationNumber.tr(context: context),
errorMessage: formManager.errors.patientIdentification, errorMessage: formManager.errors.patientIdentification,
hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.patientIdentification), hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.patientIdentification),
onChange: (value) { onChange: (value) {
@ -114,8 +116,8 @@ class PatientInformationStepState extends State<PatientInformationStep> {
child: TextInputWidget( child: TextInputWidget(
controller: _nameController, controller: _nameController,
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0),
hintText: 'Patient Name*'.needTranslation, hintText: LocaleKeys.patientName.tr(context: context),
labelText: 'Name'.needTranslation, labelText: LocaleKeys.name.tr(context: context),
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
errorMessage: formManager.errors.patientName, errorMessage: formManager.errors.patientName,
hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.patientName), hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.patientName),
@ -133,7 +135,7 @@ class PatientInformationStepState extends State<PatientInformationStep> {
return Focus( return Focus(
focusNode: _phoneFocusNode, focusNode: _phoneFocusNode,
child: TextInputWidget( child: TextInputWidget(
labelText: 'Phone Number'.needTranslation, labelText: LocaleKeys.phoneNumber.tr(context: context),
hintText: "5xxxxxxxx", hintText: "5xxxxxxxx",
controller: _phoneController, controller: _phoneController,
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
@ -159,7 +161,7 @@ class PatientInformationStepState extends State<PatientInformationStep> {
Widget _buildPatientCityField(BuildContext context, ReferralFormManager formManager) { Widget _buildPatientCityField(BuildContext context, ReferralFormManager formManager) {
return DropdownWidget( return DropdownWidget(
labelText: 'City', labelText: 'City',
hintText: formManager.formData.patientCity?.description ?? "Select City".needTranslation, hintText: formManager.formData.patientCity?.description ?? LocaleKeys.selectCity.tr(context: context),
isEnable: false, isEnable: false,
hasSelectionCustomIcon: true, hasSelectionCustomIcon: true,
labelColor: Colors.black, labelColor: Colors.black,
@ -179,7 +181,7 @@ class PatientInformationStepState extends State<PatientInformationStep> {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
title: "Select City".needTranslation, title: LocaleKeys.selectCity.tr(context: context),
child: Consumer<HmgServicesViewModel>( child: Consumer<HmgServicesViewModel>(
builder: (context, hmgServicesVM, child) { builder: (context, hmgServicesVM, child) {
final cities = hmgServicesVM.getAllCitiesList; final cities = hmgServicesVM.getAllCitiesList;

@ -1,8 +1,10 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/utils/validation_utils.dart'; import 'package:hmg_patient_app_new/core/utils/validation_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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/e_referral_form_manager.dart'; import 'package:hmg_patient_app_new/presentation/e_referral/e_referral_form_manager.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -67,8 +69,8 @@ class RequesterFormStepState extends State<RequesterFormStep> {
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
children: [ children: [
// const SizedBox(height: 12), // const SizedBox(height: 12),
_buildSectionTitle('Referral requester information'.needTranslation), _buildSectionTitle(LocaleKeys.referralRequesterInformation.tr(context: context)),
const SizedBox(height: 12), const SizedBox(height: 12),
_buildNameField(formManager), _buildNameField(formManager),
// _buildPhoneField(formManager), // _buildPhoneField(formManager),
_buildRelationshipField(context, formManager), _buildRelationshipField(context, formManager),
@ -93,8 +95,8 @@ class RequesterFormStepState extends State<RequesterFormStep> {
child: TextInputWidget( child: TextInputWidget(
controller: _nameController, controller: _nameController,
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0),
hintText: 'Enter Referral Requester Name*'.needTranslation, hintText: LocaleKeys.enterReferralRequesterName.tr(context: context),
labelText: 'Requester Name'.needTranslation, labelText: LocaleKeys.requesterName.tr(context: context),
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
errorMessage: formManager.errors.requesterName, errorMessage: formManager.errors.requesterName,
isAllowLeadingIcon: true, isAllowLeadingIcon: true,
@ -109,10 +111,10 @@ class RequesterFormStepState extends State<RequesterFormStep> {
} }
Widget _buildRelationshipField(BuildContext context, ReferralFormManager formManager) { Widget _buildRelationshipField(BuildContext context, ReferralFormManager formManager) {
return DropdownWidget( return DropdownWidget(
labelText: "Relationship".needTranslation, labelText: LocaleKeys.relationship.tr(context: context),
hintText: formManager.formData.relationship?.textEn ?? "Select Relation".needTranslation, hintText: formManager.formData.relationship?.textEn ?? LocaleKeys.selectRelation.tr(context: context),
isEnable: false, isEnable: false,
selectedValue: formManager.formData.relationship?.textEn ?? "Select Relation".needTranslation, selectedValue: formManager.formData.relationship?.textEn ?? LocaleKeys.selectRelation.tr(context: context),
errorMessage: formManager.errors.relationship, errorMessage: formManager.errors.relationship,
hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.relationship), hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.relationship),
hasSelectionCustomIcon: false, hasSelectionCustomIcon: false,
@ -132,8 +134,8 @@ class RequesterFormStepState extends State<RequesterFormStep> {
controller: _otherNameController, controller: _otherNameController,
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0),
hintText: 'Other Name*'.needTranslation, hintText: LocaleKeys.otherNameHint.tr(context: context),
labelText: 'Other Name'.needTranslation, labelText: LocaleKeys.otherName.tr(context: context),
errorMessage: formManager.errors.otherRelationshipName, errorMessage: formManager.errors.otherRelationshipName,
onChange: (value) { onChange: (value) {
formManager.updateOtherRelationshipName(value ?? ''); formManager.updateOtherRelationshipName(value ?? '');
@ -152,7 +154,7 @@ class RequesterFormStepState extends State<RequesterFormStep> {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
context, context,
title: "Select Relation".needTranslation, title: LocaleKeys.selectRelation.tr(context: context),
child: Consumer<HmgServicesViewModel>( child: Consumer<HmgServicesViewModel>(
builder: (context, hmgServicesVM, child) { builder: (context, hmgServicesVM, child) {
if (hmgServicesVM.relationTypes.isEmpty) { if (hmgServicesVM.relationTypes.isEmpty) {
@ -164,8 +166,8 @@ class RequesterFormStepState extends State<RequesterFormStep> {
); );
} }
return DecoratedBox( return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: Colors.white, color: Colors.white,
customBorder: BorderRadius.all(Radius.circular(24.h)) , customBorder: BorderRadius.all(Radius.circular(24.h)) ,

@ -1,4 +1,3 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -135,19 +134,19 @@ class RrtMapScreen extends StatelessWidget {
Column( Column(
spacing: 4.h, spacing: 4.h,
children: [ children: [
"Select Location".needTranslation.toText21( LocaleKeys.selectLocation.tr().toText21(
weight: FontWeight.w600, weight: FontWeight.w600,
color: AppColors.textColor, color: AppColors.textColor,
), ),
"Please select the location".needTranslation.toText12( LocaleKeys.pleaseSelectTheLocation.tr().toText12(
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
) )
], ],
), ),
CustomButton( CustomButton(
text: "Submit Request".needTranslation, text: LocaleKeys.submitRequest.tr(),
onPressed: () { onPressed: () {
LocationViewModel locationViewModel = context.read<LocationViewModel>(); LocationViewModel locationViewModel = context.read<LocationViewModel>();
GeocodeResponse? response = locationViewModel.geocodeResponse; GeocodeResponse? response = locationViewModel.geocodeResponse;
PlaceDetails? placeDetails = locationViewModel.placeDetails; PlaceDetails? placeDetails = locationViewModel.placeDetails;
@ -235,7 +234,7 @@ class RrtMapScreen extends StatelessWidget {
height: 40.h, height: 40.h,
backgroundColor: AppColors.lightRedButtonColor, backgroundColor: AppColors.lightRedButtonColor,
borderColor: Colors.transparent, borderColor: Colors.transparent,
text: "Add new address".needTranslation, text: LocaleKeys.addNewAddress.tr(),
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
iconColor: AppColors.primaryRedColor, iconColor: AppColors.primaryRedColor,
onPressed: () {}, onPressed: () {},
@ -245,9 +244,7 @@ class RrtMapScreen extends StatelessWidget {
isSelected: index == 0, isSelected: index == 0,
address: address:
"Flat No 301, Building No 12, Palm Spring Apartment, Sector 45, Gurugram, Haryana 122003", "Flat No 301, Building No 12, Palm Spring Apartment, Sector 45, Gurugram, Haryana 122003",
title: index == 0 title: index == 0 ? LocaleKeys.home.tr() : LocaleKeys.work.tr(),
? "Home".needTranslation
: "Work".needTranslation,
onTap: () {}, onTap: () {},
); );
} }
@ -291,8 +288,8 @@ class RrtMapScreen extends StatelessWidget {
Row( Row(
children: [ children: [
hospitalAndPickUpItemContent( hospitalAndPickUpItemContent(
title: "Pick".needTranslation, title: LocaleKeys.pick.tr(),
subTitle: "Inside the home".needTranslation, subTitle: LocaleKeys.insideTheHome.tr(),
leadingIcon: AppAssets.pickup_bed, leadingIcon: AppAssets.pickup_bed,
), ),
CustomSwitch( CustomSwitch(
@ -312,7 +309,7 @@ class RrtMapScreen extends StatelessWidget {
children: [ children: [
hospitalAndPickUpItemContent( hospitalAndPickUpItemContent(
title: '', title: '',
subTitle: "Have any appointment".needTranslation, subTitle: LocaleKeys.haveAnyAppointment.tr(),
leadingIcon: AppAssets.appointment_checkin_icon, leadingIcon: AppAssets.appointment_checkin_icon,
), ),
CustomSwitch( CustomSwitch(
@ -416,8 +413,8 @@ class RrtMapScreen extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4.h, spacing: 4.h,
children: [ children: [
"Total amount to pay".needTranslation.toText18( LocaleKeys.totalAmountToPay.tr().toText18(
weight: FontWeight.w600, weight: FontWeight.w600,
color: AppColors.textColor, color: AppColors.textColor,
), ),
Row( Row(
@ -425,9 +422,7 @@ class RrtMapScreen extends StatelessWidget {
Utils.buildSvgWithAssets(icon: AppAssets.warning, Utils.buildSvgWithAssets(icon: AppAssets.warning,
height: 18.h, width: 18.h), height: 18.h, width: 18.h),
SizedBox(width: 4.h,), SizedBox(width: 4.h,),
"Amount will be paid at the hospital" LocaleKeys.amountPaidAtHospital.tr().toText12(
.needTranslation
.toText12(
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
), ),
@ -452,7 +447,7 @@ class RrtMapScreen extends StatelessWidget {
], ],
), ),
CustomButton( CustomButton(
text: "Submit Request".needTranslation, text: LocaleKeys.submitRequest.tr(),
onPressed: () { onPressed: () {
LocationViewModel locationViewModel = context.read<LocationViewModel>(); LocationViewModel locationViewModel = context.read<LocationViewModel>();
GeocodeResponse? response = locationViewModel.geocodeResponse; GeocodeResponse? response = locationViewModel.geocodeResponse;
@ -530,8 +525,8 @@ class RrtMapScreen extends StatelessWidget {
return SizedBox( return SizedBox(
width: MediaQuery.sizeOf(context).width, width: MediaQuery.sizeOf(context).width,
child: TextInputWidget( child: TextInputWidget(
labelText: "Enter Pickup Location Manually".needTranslation, labelText: LocaleKeys.enterPickupLocationManually.tr(),
hintText: "Enter Pickup Location".needTranslation, hintText: LocaleKeys.enterPickupLocation.tr(),
controller: TextEditingController( controller: TextEditingController(
text: vm.geocodeResponse?.results.first.formattedAddress ?? text: vm.geocodeResponse?.results.first.formattedAddress ??
vm.selectedPrediction?.description, vm.selectedPrediction?.description,
@ -562,7 +557,7 @@ class RrtMapScreen extends StatelessWidget {
openLocationInputBottomSheet(BuildContext context) { openLocationInputBottomSheet(BuildContext context) {
context.read<LocationViewModel>().flushSearchPredictions(); context.read<LocationViewModel>().flushSearchPredictions();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: "".needTranslation, title: "",
context, context,
child: SizedBox( child: SizedBox(
height: MediaQuery.sizeOf(context).height * .8, height: MediaQuery.sizeOf(context).height * .8,
@ -583,11 +578,10 @@ class RrtMapScreen extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
hospitalAndPickUpItemContent( hospitalAndPickUpItemContent(
title: "Select Hospital".needTranslation, title: "Select Hospital".tr(),
subTitle: context subTitle: context
.read<EmergencyServicesViewModel>() .read<EmergencyServicesViewModel>()
.getSelectedHospitalName() ?? .getSelectedHospitalName() ?? "Select Hospital".tr(),
"Select Hospital".needTranslation,
leadingIcon: AppAssets.hospital, leadingIcon: AppAssets.hospital,
), ),
Utils.buildSvgWithAssets( Utils.buildSvgWithAssets(
@ -606,7 +600,7 @@ class RrtMapScreen extends StatelessWidget {
void openAppointmentList(BuildContext context) { void openAppointmentList(BuildContext context) {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: "Select Appointment".needTranslation, title: LocaleKeys.selectAppointment.tr(),
context, context,
child: SizedBox( child: SizedBox(
height: MediaQuery.sizeOf(context).height * .5, height: MediaQuery.sizeOf(context).height * .5,

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save