* 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New: (41 commits)
  pull down to refresh in appointment queue implemented
  Pull to refresh implemented
  Updates & fixes
  updates
  Updates
  Updates
  WD:map issues resolved: 1. map type added to the screen along with the translation 2. null shown for the arabic name of the fixed to show the actual name. 3. if the user opens the locationBottomsheet and close it without input of the area the screen freezes with no action on the location. 4. Gms And Hms Maps handled. 5. theme handled inside the maps screen.
  Updates
  Font changes, Updates & fixes
  map type is added to the maps already present
  family switch parent child and child 2
  translation service changes
  Updates
  updates
  print statement removed
  graph reference low nd high value address. * if the referenncehigh is 0 then it will be neglected * if the referencelow is 0 then it will be neglected.
  family switch parent child and child 2
  updates
  remote localization files added
  Updates
  ...

# Conflicts:
#	android/app/build.gradle.kts
#	lib/presentation/rate_appointment/rate_appointment_doctor.dart
pull/219/head
Sultan khan 1 week ago
commit 18331f077e

@ -50,6 +50,8 @@
android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
tools:node="remove" /> <!-- <uses-permission android:name="android.permission.INTERNET" /> --> tools:node="remove" /> <!-- <uses-permission android:name="android.permission.INTERNET" /> -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" tools:node="remove" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" tools:node="remove" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
@ -92,7 +94,6 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" /> <uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.VIDEO_CAPTURE" /> <uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" /> <uses-permission android:name="android.permission.AUDIO_CAPTURE" />

@ -45,6 +45,7 @@
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" tools:node="remove" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" tools:node="remove" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" tools:node="remove" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" tools:node="remove" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" tools:node="remove" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" tools:node="remove" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" tools:node="remove" />
<uses-permission <uses-permission
android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
@ -93,7 +94,6 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" /> <uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.VIDEO_CAPTURE" /> <uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" /> <uses-permission android:name="android.permission.AUDIO_CAPTURE" />

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 KiB

After

Width:  |  Height:  |  Size: 468 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

@ -0,0 +1,6 @@
<svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="56" height="56" rx="28" fill="white"/>
<rect width="56" height="56" rx="28" fill="white"/>
<rect x="0.5" y="0.5" width="55" height="55" rx="27.5" stroke="#2E3039" stroke-opacity="0.13" stroke-dasharray="2 2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M28 18.25C28.4142 18.25 28.75 18.5858 28.75 19V26.25H36C36.4142 26.25 36.75 26.5858 36.75 27C36.75 27.4142 36.4142 27.75 36 27.75H28.75V35C28.75 35.4142 28.4142 35.75 28 35.75C27.5858 35.75 27.25 35.4142 27.25 35V27.75H20C19.5858 27.75 19.25 27.4142 19.25 27C19.25 26.5858 19.5858 26.25 20 26.25H27.25V19C27.25 18.5858 27.5858 18.25 28 18.25Z" fill="#161616" stroke="#2E3039" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 835 B

@ -0,0 +1,6 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="40" height="40" rx="10" fill="#EFEFF0"/>
<path d="M18.9994 9.25C16.0999 9.25 13.7494 11.6005 13.7494 14.5C13.7494 17.3995 16.0999 19.75 18.9994 19.75C21.8989 19.75 24.2494 17.3995 24.2494 14.5C24.2494 11.6005 21.8989 9.25 18.9994 9.25Z" fill="#8F9AA3"/>
<path d="M22.4393 22.3825L22.4269 22.3899C22.3982 22.4063 22.3715 22.4164 22.3391 22.4232L22.3222 22.4264C21.5275 22.5747 20.3099 23.081 19.8772 24.4469C19.436 25.84 20.178 26.9751 20.7397 27.5414L20.9312 27.7346C21.045 27.8493 21.1019 27.9066 21.1231 27.9808C21.1442 28.055 21.1262 28.1337 21.09 28.2912L21.0601 28.4219C20.9887 28.7329 20.9096 29.2541 20.9862 29.8241C21.0509 30.3047 21.0832 30.545 20.9935 30.6475C20.9039 30.75 20.7005 30.75 20.2937 30.75L14.5901 30.75C12.7718 30.75 11.366 29.8556 10.1945 28.7396C9.51551 28.0927 9.17705 27.3646 9.26185 26.5888C9.3416 25.8592 9.78025 25.2637 10.2419 24.8118C10.9801 24.0893 12.0577 23.4813 12.7705 23.0792C12.9331 22.9875 13.0768 22.9064 13.1931 22.8372C14.4979 22.0602 15.93 21.5691 17.3945 21.3625C18.4583 21.2125 19.5401 21.2125 20.6039 21.3625C21.0835 21.4302 21.8204 21.628 22.365 21.7855C22.4184 21.801 22.4451 21.8087 22.4641 21.8172C22.6658 21.9073 22.7022 22.1856 22.5303 22.3244C22.5142 22.3375 22.4892 22.3525 22.4393 22.3825Z" fill="#8F9AA3"/>
<path d="M27.3627 22.245C27.12 21.7533 26.67 21.25 25.9982 21.25C25.3273 21.25 24.8762 21.7522 24.6315 22.2431L23.9345 23.6487L23.9282 23.6547C23.9233 23.6592 23.9176 23.6639 23.9113 23.6687C23.9049 23.6734 23.8987 23.6775 23.893 23.681L23.8859 23.6851L22.6351 23.8946C22.0941 23.9855 21.5068 24.2757 21.3091 24.8998C21.1123 25.5211 21.4213 26.0967 21.8065 26.4851L22.7841 27.4708C22.7875 27.4778 22.792 27.4888 22.7959 27.5027C22.8003 27.5181 22.8024 27.5314 22.8031 27.5401L22.524 28.7572C22.397 29.3106 22.3883 30.0742 22.9815 30.5106C23.5783 30.9496 24.3047 30.7069 24.7916 30.4156L25.9668 29.7142C26.0142 29.6859 26.0283 29.702 26.0294 29.7135L27.2061 30.4159C27.6913 30.7048 28.4194 30.9516 29.0171 30.5123C29.6116 30.0753 29.5995 29.3093 29.4735 28.7579L29.1942 27.5401C29.1949 27.5314 29.197 27.5181 29.2014 27.5027C29.2053 27.4888 29.2098 27.4778 29.2132 27.4708L30.1889 26.487L30.1899 26.486C30.5775 26.0974 30.8877 25.521 30.6893 24.8985C30.4905 24.275 29.9028 23.9855 29.3626 23.8947L28.1075 23.6844L28.0992 23.6798C28.0935 23.6763 28.0874 23.6722 28.0811 23.6676C28.0789 23.6659 28.0766 23.6642 28.0745 23.6625C28.0709 23.6596 28.0675 23.6567 28.0645 23.654L28.0587 23.6484L27.3632 22.2459L27.3627 22.245Z" fill="#8F9AA3"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -0,0 +1,9 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="40" height="40" rx="10" fill="#2E3039"/>
<path d="M16 20C15.4477 20 15 20.4477 15 21C15 21.5523 15.4477 22 16 22H16.009C16.5613 22 17.009 21.5523 17.009 21C17.009 20.4477 16.5613 20 16.009 20H16Z" fill="white"/>
<path d="M19.9955 20C19.4432 20 18.9955 20.4477 18.9955 21C18.9955 21.5523 19.4432 22 19.9955 22H20.0045C20.5568 22 21.0045 21.5523 21.0045 21C21.0045 20.4477 20.5568 20 20.0045 20H19.9955Z" fill="white"/>
<path d="M23.991 20C23.4387 20 22.991 20.4477 22.991 21C22.991 21.5523 23.4387 22 23.991 22H24C24.5523 22 25 21.5523 25 21C25 20.4477 24.5523 20 24 20H23.991Z" fill="white"/>
<path d="M16 24C15.4477 24 15 24.4477 15 25C15 25.5523 15.4477 26 16 26H16.009C16.5613 26 17.009 25.5523 17.009 25C17.009 24.4477 16.5613 24 16.009 24H16Z" fill="white"/>
<path d="M19.9955 24C19.4432 24 18.9955 24.4477 18.9955 25C18.9955 25.5523 19.4432 26 19.9955 26H20.0045C20.5568 26 21.0045 25.5523 21.0045 25C21.0045 24.4477 20.5568 24 20.0045 24H19.9955Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.75 10C14.75 9.58579 14.4142 9.25 14 9.25C13.5858 9.25 13.25 9.58579 13.25 10V10.6348C12.4452 10.8629 11.7665 11.2336 11.2015 11.8444C10.4236 12.6853 10.0778 13.7479 9.91225 15.0795C9.74998 16.3843 9.74999 18.0565 9.75 20.19V20.81C9.74999 22.9435 9.74998 24.6157 9.91225 25.9205C10.0778 27.2521 10.4236 28.3147 11.2015 29.1556C11.9871 30.0049 12.9928 30.3901 14.2513 30.573C15.4693 30.75 17.0255 30.75 18.9892 30.75H21.0108C22.9745 30.75 24.5307 30.75 25.7487 30.573C27.0072 30.3901 28.0129 30.0049 28.7985 29.1556C29.5764 28.3147 29.9222 27.2521 30.0878 25.9205C30.25 24.6157 30.25 22.9435 30.25 20.8099V20.1901C30.25 18.0565 30.25 16.3843 30.0878 15.0795C29.9222 13.7479 29.5764 12.6853 28.7985 11.8444C28.2335 11.2336 27.5548 10.8629 26.75 10.6348V10C26.75 9.58579 26.4142 9.25 26 9.25C25.5858 9.25 25.25 9.58579 25.25 10V10.3659C24.1139 10.25 22.716 10.25 21.0108 10.25L18.9892 10.25C17.284 10.25 15.8861 10.25 14.75 10.3659V10ZM13.2786 12.2058C13.3681 12.52 13.6572 12.75 14 12.75C14.4142 12.75 14.75 12.4142 14.75 12V11.8746C15.811 11.7516 17.1824 11.75 19.05 11.75L20.95 11.75C22.8176 11.75 24.189 11.7516 25.25 11.8746V12C25.25 12.4142 25.5858 12.75 26 12.75C26.3428 12.75 26.6319 12.52 26.7214 12.2058C27.1287 12.3679 27.438 12.5826 27.6973 12.8629C28.1704 13.3744 28.4505 14.0759 28.5982 15.2564C28.5661 15.2522 28.5333 15.25 28.5 15.25L11.5 15.25C11.4667 15.25 11.4339 15.2522 11.4018 15.2564C11.5495 14.0759 11.8296 13.3744 12.3027 12.8629C12.562 12.5826 12.8713 12.3679 13.2786 12.2058ZM11.2901 16.7202C11.2506 17.6832 11.25 18.8363 11.25 20.2432V20.7568C11.25 22.9551 11.2514 24.5339 11.4008 25.7354C11.5482 26.9208 11.8285 27.6244 12.3027 28.1371C12.7692 28.6414 13.3973 28.9331 14.467 29.0886C15.5648 29.2481 17.0119 29.25 19.05 29.25H20.95C22.9881 29.25 24.4352 29.2481 25.533 29.0886C26.6027 28.9331 27.2308 28.6414 27.6973 28.1371C28.1715 27.6244 28.4518 26.9208 28.5992 25.7354C28.7486 24.5339 28.75 22.9551 28.75 20.7568V20.2432C28.75 18.8363 28.7494 17.6832 28.7099 16.7202C28.6433 16.7396 28.5728 16.75 28.5 16.75L11.5 16.75C11.4272 16.75 11.3567 16.7396 11.2901 16.7202Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

@ -3,6 +3,8 @@
"arabic": "العربية", "arabic": "العربية",
"login": "تسجيل الدخول", "login": "تسجيل الدخول",
"noDataAvailable": "لا توجد بيانات متاحة", "noDataAvailable": "لا توجد بيانات متاحة",
"noRatingAvailable": "لا يوجد تقييم متاح",
"doctorDoesNotHaveRating": "لم يحصل هذا الطبيب على أي تقييمات بعد.",
"confirm": "تأكيد", "confirm": "تأكيد",
"loadingText": "جاري التحميل، يرجى الانتظار...", "loadingText": "جاري التحميل، يرجى الانتظار...",
"kilometerUnit": "كم", "kilometerUnit": "كم",
@ -301,7 +303,7 @@
"vitalSignsSubTitle": "التقارير", "vitalSignsSubTitle": "التقارير",
"myMedical": "نشط", "myMedical": "نشط",
"myMedicalSubtitle": "الأدوية", "myMedicalSubtitle": "الأدوية",
"myDoctor": "طبيبي", "myDoctor": "أطبائي",
"myDoctorSubtitle": "القائمة", "myDoctorSubtitle": "القائمة",
"eye": "العين", "eye": "العين",
"eyeSubtitle": "القياس", "eyeSubtitle": "القياس",
@ -363,7 +365,7 @@
"paymentOnline": "الخدمة", "paymentOnline": "الخدمة",
"onlineCheckIn": "تسجيل الوصول عبر الإنترنت", "onlineCheckIn": "تسجيل الوصول عبر الإنترنت",
"myBalances": "رصيدي", "myBalances": "رصيدي",
"myWallet": "محف<EFBFBD><EFBFBD>تي", "myWallet": "محفظتي",
"balanceAmount": "مبلغ المحفظة", "balanceAmount": "مبلغ المحفظة",
"totalBalance": "إجمالي الرصيد", "totalBalance": "إجمالي الرصيد",
"createAdvancedPayment": "إعادة شحن المحفظة", "createAdvancedPayment": "إعادة شحن المحفظة",
@ -487,7 +489,7 @@
"services2": "الخدمات", "services2": "الخدمات",
"cantSeeProfile": "لرؤية ملفك الطبي، يرجى تسجيل الدخول أو التسجيل الآن", "cantSeeProfile": "لرؤية ملفك الطبي، يرجى تسجيل الدخول أو التسجيل الآن",
"loginRegisterNow": "تسجيل الدخول أو التسجيل الآن", "loginRegisterNow": "تسجيل الدخول أو التسجيل الآن",
"hmgPharmacy": "صيدلية مجموعة الحبيب الطبية", "hmgPharmacy": "صيدلية الحبيب",
"ecommerceSolution": "حلول التجارة الإلكترونية", "ecommerceSolution": "حلول التجارة الإلكترونية",
"comprehensive": "شامل", "comprehensive": "شامل",
"onlineConsulting": "استشارات عبر الإنترنت", "onlineConsulting": "استشارات عبر الإنترنت",
@ -858,7 +860,7 @@
"onboardingBody1": "ببضع نقرات فقط يمكنك استشارة الطبيب الذي تختاره.", "onboardingBody1": "ببضع نقرات فقط يمكنك استشارة الطبيب الذي تختاره.",
"onboardingHeading2": "الوصول إلى السجل الطبي بين يديك", "onboardingHeading2": "الوصول إلى السجل الطبي بين يديك",
"onboardingBody2": "تتبع تاريخك الطبي بما في ذلك الفحوصات المخبرية، الوصفات الطبية، التأمين، وغيرها.", "onboardingBody2": "تتبع تاريخك الطبي بما في ذلك الفحوصات المخبرية، الوصفات الطبية، التأمين، وغيرها.",
"hmgHospitals": "مستشفيات مجموعة الحبيب الطبية", "hmgHospitals": "مستشفيات الحبيب",
"hmcMedicalClinic": "مراكز مجموعة الحبيب الطبية", "hmcMedicalClinic": "مراكز مجموعة الحبيب الطبية",
"applyFilter": "تطبيق الفلتر", "applyFilter": "تطبيق الفلتر",
"facilityAndLocation": "المرفق والموقع", "facilityAndLocation": "المرفق والموقع",
@ -934,7 +936,7 @@
"hospitalInformation": "معلومات المستشفى", "hospitalInformation": "معلومات المستشفى",
"fetchingAppointmentShare": "جاري جلب تفاصيل الموعد...", "fetchingAppointmentShare": "جاري جلب تفاصيل الموعد...",
"bookingYourAppointment": "جاري حجز موعدك...", "bookingYourAppointment": "جاري حجز موعدك...",
"selectLiveCareClinic": "اختر عيادة لايف كير", "selectLiveCareClinic": "عيادة لايف كير",
"checkingForExistingDentalPlan": "جاري التحقق من وجود خطة أسنان حالية، يرجى الانتظار...", "checkingForExistingDentalPlan": "جاري التحقق من وجود خطة أسنان حالية، يرجى الانتظار...",
"dentalTreatmentPlan": "خطة علاج الأسنان", "dentalTreatmentPlan": "خطة علاج الأسنان",
"youHaveExistingTreatmentPlan": "لديك خطة علاج حالية: ", "youHaveExistingTreatmentPlan": "لديك خطة علاج حالية: ",
@ -1618,5 +1620,74 @@
"sortByLocation": "الترتيب حسب الموقع", "sortByLocation": "الترتيب حسب الموقع",
"timeForFirstReminder": "وقت التذكير الأول", "timeForFirstReminder": "وقت التذكير الأول",
"reminderRemovalNote": "يمكنك إزالتها من التقويم الخاص بك لاحقاً عن طريق إيقاف تشغيل التذكير", "reminderRemovalNote": "يمكنك إزالتها من التقويم الخاص بك لاحقاً عن طريق إيقاف تشغيل التذكير",
"communicationLanguage": "لغة التواصل" "communicationLanguage": "لغة التواصل",
"cmcServiceHeader": "فحص صحي شامل: تشخيص متقدم، معلومات صحية مفصلة",
"cmcServiceDescription": "احصل على معلومات تفصيلية عن صحتك من خلال خدمات التشخيص المتقدمة لدينا. افهم جسمك بشكل أفضل لمستقبل صحي.",
"eReferralServiceHeader": "نظام الإحالة الإلكترونية في مستشفى حبيب: تبسيط عملية إحالة المرضى",
"eReferralServiceDescription": "نُسهّل عملية نقل المرضى بسلاسة إلى مستشفى حبيب من خلال نظام الإحالة الإلكترونية الآمن لدينا. نضمن استمرارية الرعاية لكل مريض.",
"bloodDonationServiceHeader": "تبرع بالدم، أنقذ الأرواح. تبرعك يُحدث فرقاً.",
"bloodDonationServiceDescription": "تبرّع بالدم، وأنقذ الأرواح. تبرعك يبعث الأمل. انضم لحملة التبرع بالدم وكن شريان حياة للمحتاجين. كل قطرة تُحدث فرقًا!",
"healthTrackersServiceHeader": "تتبّع مؤشراتك الحيوية بسهولة ويسر",
"healthTrackersServiceDescription": "أدخل بياناتك لمراقبة معدل ضربات القلب وضغط الدم بشكل مستمر، بالإضافة إلى ملخصات دقيقة لأنشطتك اليومية. ابقَ على اطلاع وحسّن صحتك بسهولة.",
"waterConsumptionServiceHeader": "حافظ على رطوبتك، حافظ على صحتك. تتبع كمية الماء التي تشربها يومياً بكل سهولة.",
"waterConsumptionServiceDescription": "أروِ عطشك، وتابع صحتك. راقب كمية الماء التي تتناولها يومياً بكل سهولة باستخدام تطبيقنا سهل الاستخدام، مما يضمن لك الترطيب الأمثل والصحة الجيدة.",
"smartWatchServiceHeader": "قم بمزامنة ساعتك الذكية مع تطبيقات الصحة",
"smartWatchServiceDescription": "قم بتوصيل ساعتك الذكية بسلاسة بتطبيقنا الصحي لتتبع البيانات بسهولة والحصول على رؤى شخصية.",
"liveChatServiceHeader": "مساعدة الخبراء على مدار الساعة طوال أيام الأسبوع\n\nمساعدة",
"liveChatServiceDescription": "هل تحتاج إلى مساعدة؟ تتيح لك خدمة الدردشة المباشرة لدينا التواصل مع فريق دعم الخبراء للإجابة على أي أسئلة لديك حول الميزات أو الإعدادات أو استكشاف الأخطاء وإصلاحها.",
"emergencyServiceHeader": "تسجيل الوصول إلى قسم الطوارئ، أسرع من أي وقت مضى. اتصل بالإسعاف / فريق الاستجابة السريعة على الفور",
"emergencyServiceDescription": "هل تواجه حالة طبية طارئة؟ سيارات الإسعاف وفرق الاستجابة السريعة لدينا جاهزة على مدار الساعة. بالإضافة إلى ذلك، يمكنك تسجيل دخولك إلى قسم الطوارئ بسرعة لتلقي رعاية أسرع.",
"homeHealthCareServiceHeader": "صحتك، في أبهى صورها. رعاية فائقة الجودة، تصلك إلى عتبة دارك.",
"homeHealthCareServiceDescription": "نقدم لكم رعاية صحية عالية الجودة تصلكم إلى عتبة منزلكم. ممرضات ذوات خبرة يقدمون رعاية حانية في راحة منزلكم.",
"profileOnlyText": "الملف الشخصي",
"information": "معلومة",
"noFavouriteDoctors": "ليس لديك أي قائمة مفضلة حتى الآن",
"addDoctors": "إضافة الأطباء",
"favouriteList": "قائمة المفضلة",
"later": "لاحقاً",
"cancelAppointmentConfirmMessage": "هل أنت متأكد من رغبتك في إلغاء هذا الموعد؟",
"acknowledged": "معترف به",
"searchLabResults": "بحث نتائج المختبر",
"callForAssistance": "اتصل للحصول على المساعدة الفورية",
"oneWaySubtitle": "نقل من الموقع إلى المستشفى",
"twoWaySubtitle": "نقل من الموقع إلى المستشفى والعودة مرة أخرى",
"toHospitalSubtitle": "نقل من موقعك الحالي إلى المستشفى",
"fromHospitalSubtitle": "نقل من المستشفى إلى منزلك",
"clinicSchedule": "جدول العيادة",
"doctorAddedToFavourite": "تمت إضافة إلى قائمة المفضلة",
"doctorRemovedFromFavourite": "تمت إزالة من قائمة الأطباء المفضلين",
"addNewFavorite": "إضافة مفضلة جديدة",
"favourites": "المفضلة",
"pendingAncillaryOrders": "مدفوعات طلبات الاضافية",
"liveCarePermissions": "يتطلب لايف كير أذونات الكاميرا والميكروفون وإشعارات، يرجى السماح لها بالمتابعة.",
"containsImage": "يحتوي على صورة",
"servicesSelected": "الخدمة (الخدمات) المختارة",
"selectMedicalFileFromFamily": "اختر ملف طبي من عائلتك",
"anyFileFromHMG": "أي ملف طبي نشط من مجموعة حبيب الطبية",
"noDistance": "المسافة غير متوفرة",
"enterAmount": "يرجى إدخال المبلغ للمتابعة.",
"selectHospitalContinue": "يرجى اختيار المستشفى للمتابعة.",
"year": "سنة",
"notifyPrescription": "أبلغني قبل وقت الاستهلاك",
"doctorRatingAppointment": "طبيب\nتصنيف",
"ratingSubmitted": "تم إرسال التقييم",
"rateTheDoctor": "يرجى تقييم الطبيب",
"downloadInvoice": "تحميل الفاتورة",
"approvalDetails": "تفاصيل الموافقة",
"obese": "سمين",
"overWeight": "وزن زائد",
"underWeight": "وزن ناقص",
"nearestGate": "أقرب بوابة",
"RRTDDetails": "فريق الاستجابة السريعة يقوم بتقديم رعاية صحية متكاملة لجميع الحالات الطارئة و المستقرة، الخدمة تشمل جميع الأعمار بما في ذلك حالات الأطفال.",
"fromHospitalSubtitle": "نقل من المستشفى إلى منزلك",
"normalMapType": "افتراضي",
"satelliteMapType": "قمر صناعي",
"terrainMapType": "تضاريس",
"hybridMapType": "هجين",
"openCamera": "افتح الكاميرا",
"openGallery": "افتح المعرض",
"openFiles": "فتح الملفات",
"generateAiAnalysisRadResult": "بإنشاء تحليل الذكاء الاصطناعي لهذا التقرير",
"grantLocationPermission": "يرجى منح إذن الوصول إلى الموقع من إعدادات التطبيق للحصول على نتائج أفضل."
} }

@ -3,6 +3,8 @@
"arabic": "Arabic", "arabic": "Arabic",
"login": "Login", "login": "Login",
"noDataAvailable": "No Data Available", "noDataAvailable": "No Data Available",
"noRatingAvailable": "No Rating Available",
"doctorDoesNotHaveRating": "This doctor does not have any ratings yet.",
"confirm": "Confirm", "confirm": "Confirm",
"loadingText": "Loading, please wait...", "loadingText": "Loading, please wait...",
"kilometerUnit": "KM", "kilometerUnit": "KM",
@ -300,7 +302,7 @@
"vitalSignsSubTitle": "Reports", "vitalSignsSubTitle": "Reports",
"myMedical": "Active", "myMedical": "Active",
"myMedicalSubtitle": "Medications", "myMedicalSubtitle": "Medications",
"myDoctor": "My Doctor", "myDoctor": "My Doctors",
"myDoctorSubtitle": "List", "myDoctorSubtitle": "List",
"eye": "Eye", "eye": "Eye",
"eyeSubtitle": "Measurement", "eyeSubtitle": "Measurement",
@ -928,7 +930,7 @@
"hospitalInformation": "Hospital Information", "hospitalInformation": "Hospital Information",
"fetchingAppointmentShare": "Fetching Appointment Share...", "fetchingAppointmentShare": "Fetching Appointment Share...",
"bookingYourAppointment": "Booking your appointment...", "bookingYourAppointment": "Booking your appointment...",
"selectLiveCareClinic": "Select LiveCare Clinic", "selectLiveCareClinic": "LiveCare Clinic",
"checkingForExistingDentalPlan": "Checking for an existing dental plan, Please wait...", "checkingForExistingDentalPlan": "Checking for an existing dental plan, Please wait...",
"dentalTreatmentPlan": "Dental treatment plan", "dentalTreatmentPlan": "Dental treatment plan",
"youHaveExistingTreatmentPlan": "You have an existing treatment plan: ", "youHaveExistingTreatmentPlan": "You have an existing treatment plan: ",
@ -1239,7 +1241,7 @@
"quickLinks": "Quick Links", "quickLinks": "Quick Links",
"viewMedicalFileLandingPage": "View medical file", "viewMedicalFileLandingPage": "View medical file",
"immediateLiveCareRequest": "Immediate LiveCare Request", "immediateLiveCareRequest": "Immediate LiveCare Request",
"yourTurnIsAfterPatients": "Your turn is after {count} patients.", "yourTurnIsAfterPatients": "Your turn is after {count} patients. Please wait for your turn, The doctor will call you shortly.",
"dontHaveHHCOrders": "You don't have any Home Health Care orders yet.", "dontHaveHHCOrders": "You don't have any Home Health Care orders yet.",
"hhcOrders": "HHC Orders", "hhcOrders": "HHC Orders",
"requestedServices": "Requested Services", "requestedServices": "Requested Services",
@ -1307,7 +1309,7 @@
"rejectedYourFamilyMemberRequest": "{status} your family member request", "rejectedYourFamilyMemberRequest": "{status} your family member request",
"notAvailable": "N/A", "notAvailable": "N/A",
"selectAProfile": "Please select a profile", "selectAProfile": "Please select a profile",
"switchFamilyFile": "Switch from the below list of medical file", "switchFamilyFile": "Switch from the below list of medical files",
"medicalFiles": "Medical Files", "medicalFiles": "Medical Files",
"addANewFamilyMember": "Add a new family member", "addANewFamilyMember": "Add a new family member",
"viewInvoiceDetails": "View invoice details", "viewInvoiceDetails": "View invoice details",
@ -1611,5 +1613,73 @@
"sortByLocation": "Sort by location", "sortByLocation": "Sort by location",
"sortByNearestLocation": "Sort by nearest to your location", "sortByNearestLocation": "Sort by nearest to your location",
"giveLocationPermissionForNearestList": "Please grant location permission from app settings to see the nearest locations.", "giveLocationPermissionForNearestList": "Please grant location permission from app settings to see the nearest locations.",
"communicationLanguage": "Communication Language" "communicationLanguage": "Communication Language",
"cmcServiceHeader": "Complete Health Checkup: Advanced diagnostics, Detailed Health insights",
"cmcServiceDescription": "Get detailed insights into your health with our advanced diagnostics. Understand your body better for a healthier future.",
"eReferralServiceHeader": "HMG Hospital E-Referral: Streamlined patient referrals",
"eReferralServiceDescription": "Facilitate seamless patient transfers to HMG with our secure e-referral system. Ensure continuity of care for every patient.",
"bloodDonationServiceHeader": "Give Blood, Save Lives. Your donation makes a difference.",
"bloodDonationServiceDescription": "Donate blood, empower lives. Your contribution creates hope. Join our blood drive and be a lifeline for those in need. Every drop counts!",
"healthTrackersServiceHeader": "Track Your Vitals with Ease and effortlessly ",
"healthTrackersServiceDescription": "Input your metrics for continuous heart rate monitoring, blood pressure and precise daily activity summaries. Stay informed and optimize your well-being with ease.",
"waterConsumptionServiceHeader": "Stay Hydrated, Stay Healthy. Track your daily water intake with ease.",
"waterConsumptionServiceDescription": "Quench your thirst, track your health. Effortlessly monitor your daily water intake with our user-friendly app, ensuring optimal hydration and well-being.",
"smartWatchServiceHeader": "Sync Your Smartwatch with Health Apps",
"smartWatchServiceDescription": "Seamlessly connect your smartwatch to our health app for effortless data tracking and personalized insights.",
"liveChatServiceHeader": "24/7 Expert\nAssistance",
"liveChatServiceDescription": "Need help ? Our live chat connects you with expert support for any questions about features, settings, or troubleshooting.",
"emergencyServiceHeader": "ER Check-in, Faster Than Ever. Call ambulance / Rapid Response Team instantly",
"emergencyServiceDescription": "In a medical emergency? Our ambulances and rapid response teams are on standby 24/7. Plus, quick ER check-in for faster care.",
"homeHealthCareServiceHeader": "Your Health, Elevated. Premium care, delivered to your doorstep.",
"homeHealthCareServiceDescription": "We bring quality healthcare to your doorstep. Experienced nurses providing compassionate care in the comfort of your home.",
"profileOnlyText": "Profile",
"information": "Information",
"noFavouriteDoctors": "You don't have any favourite list yet",
"addDoctors": "Add Doctors",
"favouriteList": "Favourite List",
"later": "Later",
"cancelAppointmentConfirmMessage": "Are you sure you want to cancel this appointment?",
"acknowledged": "Acknowledged",
"searchLabResults": "Search lab results",
"callForAssistance": "Call for immediate assistance",
"oneWaySubtitle": "Pickup from location to hospital",
"twoWaySubtitle": "Round trip from location to hospital and back",
"toHospitalSubtitle": "Transfer from your current location to the hospital",
"fromHospitalSubtitle": "Transfer from the hospital back to your home",
"clinicSchedule": "Clinic Schedule",
"doctorAddedToFavourite": "Added to favorites list",
"doctorRemovedFromFavourite": "Removed from favorites list",
"favourites": "Favourites",
"addNewFavorite": "Add new favourite",
"pendingAncillaryOrders": "Pending ancillary orders",
"liveCarePermissions": "LiveCare requires Camera, Microphone & Notifications permissions to enable virtual consultation between patient & doctor, Open app settings to allow them.",
"containsImage": "Contains Image",
"servicesSelected": "Service(s) Selected",
"selectMedicalFileFromFamily": "Select a medical file from your family",
"anyFileFromHMG": "Any active medical file from HMG",
"noDistance": "Distance not available",
"enterAmount": "Please enter amount to continue.",
"selectHospitalContinue": "Please select hospital to continue.",
"year": "Year",
"notifyPrescription": "Notify me before the consumption time",
"doctorRatingAppointment": "Doctor\nRating",
"ratingSubmitted": "Rating Submitted",
"rateTheDoctor": "Please rate the doctor",
"downloadInvoice": "Download Invoice",
"approvalDetails": "Approval Details",
"obese": "Obese",
"overWeight": "OverWeight",
"underWeight": "UnderWeight",
"nearestGate": "Nearest Gate",
"RRTDDetails": "The Rapid response team provides a comprehensive medical service for all sorts of urgent and stable cases of all ages, including adult and paediatric patients.",
"fromHospitalSubtitle": "Transfer from the hospital back to your home",
"normalMapType": "Default",
"satelliteMapType": "Satellite",
"terrainMapType": "Terrain",
"hybridMapType": "Hybrid",
"openCamera": "Open Camera",
"openGallery": "Open Gallery",
"openFiles": "Open Files",
"generateAiAnalysisRadResult": "Generate AI analysis for this result",
"grantLocationPermission": "Please grant location permission from app settings to see better results."
} }

Binary file not shown.

@ -200,7 +200,7 @@ class ApiClientImp implements ApiClient {
} }
// body['TokenID'] = "@dm!n"; // body['TokenID'] = "@dm!n";
// body['PatientID'] = 1231755; // body['PatientID'] = 1018977;
// body['PatientTypeID'] = 1; // body['PatientTypeID'] = 1;
// body['PatientOutSA'] = 0; // body['PatientOutSA'] = 0;
// body['SessionID'] = "45786230487560q"; // body['SessionID'] = "45786230487560q";

@ -4,7 +4,7 @@ import 'package:hmg_patient_app_new/core/enums.dart';
class ApiConsts { class ApiConsts {
static const maxSmallScreen = 660; static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.preProd; static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
@ -233,6 +233,11 @@ class ApiConsts {
static String getAiOverViewLabOrders = "Services/Patients.svc/REST/HMGAI_Lab_Analyze_Orders_API"; static String getAiOverViewLabOrders = "Services/Patients.svc/REST/HMGAI_Lab_Analyze_Orders_API";
static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API"; static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API";
static String googleCloudStorageARTranslationFileURL = "https://storage.googleapis.com/hmg-patientapp-translations/ar-SA.json";
static String googleCloudStorageENTranslationFileURL = "https://storage.googleapis.com/hmg-patientapp-translations/en-US.json";
static String googleCloudStorageENTranslationFileBaseURL = "https://storage.googleapis.com/hmg-patientapp-translations";
// ************ static values for Api **************** // ************ static values for Api ****************
static final double appVersionID = 20.9; static final double appVersionID = 20.9;
@ -450,6 +455,7 @@ var IS_LAST_APPOITMENT_RATED = 'Services/Doctors.svc/REST/IsLastAppoitmentRated_
var GET_APPOINTMENT_DETAILS_BY_NO = 'Services/MobileNotifications.svc/REST/GetAppointmentDetailsByApptNo'; var GET_APPOINTMENT_DETAILS_BY_NO = 'Services/MobileNotifications.svc/REST/GetAppointmentDetailsByApptNo';
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_DOCTORS_RATING_CHECK = "Services/Doctors.svc/REST/GetDoctorsRatingCheck";
//var GET_QR_PARKING = 'Services/SWP.svc/REST/GetQRParkingByID'; //var GET_QR_PARKING = 'Services/SWP.svc/REST/GetQRParkingByID';
@ -934,6 +940,8 @@ const PROFILE_SETTING = 'Services/Patients.svc/REST/GetPateintInfoForUpdate';
const SAVE_SETTING = 'Services/Patients.svc/REST/UpdatePateintInfo'; const SAVE_SETTING = 'Services/Patients.svc/REST/UpdatePateintInfo';
const DOWNLOAD_INVOICE_PDF = 'Services/Notifications.svc/REST/DownloadInvoiceReport';
class ApiKeyConstants { class ApiKeyConstants {
static final String googleMapsApiKey = 'AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng'; static final String googleMapsApiKey = 'AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng';
} }

@ -174,7 +174,7 @@ class AppAssets {
static const String warning = '$svgBasePath/warning.svg'; static const String warning = '$svgBasePath/warning.svg';
static const String share_location = '$svgBasePath/share_location.svg'; static const String share_location = '$svgBasePath/share_location.svg';
static const String to_arrow = '$svgBasePath/to_arrow.svg'; static const String to_arrow = '$svgBasePath/to_arrow.svg';
static const String dual_arrow = '$svgBasePath/to_arrow.svg'; static const String dual_arrow = '$svgBasePath/dual_arrow.svg';
static const String forward_arrow_medium = '$svgBasePath/forward_arrow_medium.svg'; static const String forward_arrow_medium = '$svgBasePath/forward_arrow_medium.svg';
static const String eReferral = '$svgBasePath/e-referral.svg'; static const String eReferral = '$svgBasePath/e-referral.svg';
static const String comprehensiveCheckup = '$svgBasePath/comprehensive_checkup.svg'; static const String comprehensiveCheckup = '$svgBasePath/comprehensive_checkup.svg';
@ -220,6 +220,7 @@ class AppAssets {
static const String ibw = '$svgBasePath/ibw.svg'; static const String ibw = '$svgBasePath/ibw.svg';
static const String general_health = '$svgBasePath/general_health.svg'; static const String general_health = '$svgBasePath/general_health.svg';
static const String women_health = '$svgBasePath/women_health.svg'; static const String women_health = '$svgBasePath/women_health.svg';
static const String add_new_family_icon = '$svgBasePath/add_new_family_icon.svg';
static const String height = '$svgBasePath/height.svg'; static const String height = '$svgBasePath/height.svg';
static const String weight = '$svgBasePath/weight.svg'; static const String weight = '$svgBasePath/weight.svg';
@ -236,6 +237,7 @@ class AppAssets {
static const String forward_top_nav_icon = '$svgBasePath/forward_top_nav_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'; static const String back_top_nav_icon = '$svgBasePath/back_top_nav_icon.svg';
static const String bluetooth = '$svgBasePath/bluetooth.svg'; static const String bluetooth = '$svgBasePath/bluetooth.svg';
static const String calendar_filled_icon = '$svgBasePath/calendar_filled_icon.svg';
//smartwatch //smartwatch
static const String watchActivity = '$svgBasePath/watch_activity.svg'; static const String watchActivity = '$svgBasePath/watch_activity.svg';
@ -354,6 +356,7 @@ class AppAssets {
static const String darkModeIcon = '$svgBasePath/dark_mode_icon.svg'; static const String darkModeIcon = '$svgBasePath/dark_mode_icon.svg';
static const String biometricLockIcon = '$svgBasePath/biometric_lock_icon.svg'; static const String biometricLockIcon = '$svgBasePath/biometric_lock_icon.svg';
static const String imageIcon = '$svgBasePath/image_icon.svg'; static const String imageIcon = '$svgBasePath/image_icon.svg';
static const String appointmentRatingIcon = '$svgBasePath/appointment_rating_icon.svg';
// PNGS // // PNGS //
static const String hmgLogo = '$pngBasePath/hmg_logo.png'; static const String hmgLogo = '$pngBasePath/hmg_logo.png';
@ -366,6 +369,10 @@ class AppAssets {
static const String emergencyService = '$pngBasePath/emergency_services_image.png'; static const String emergencyService = '$pngBasePath/emergency_services_image.png';
static const String cmcService = '$pngBasePath/cmc_services_image.png'; static const String cmcService = '$pngBasePath/cmc_services_image.png';
static const String eReferralService = '$pngBasePath/ereferral_services_image.png'; static const String eReferralService = '$pngBasePath/ereferral_services_image.png';
static const String carParkingService = '$pngBasePath/Carparking_services_image.png';
static const String smartWatchService = '$pngBasePath/smartwatch_services_image.png';
static const String healthTrackersService = '$pngBasePath/healthtrackers_services_image.png';
static const String livechatService = '$pngBasePath/livechat_services_image.png';
static const String maleImg = '$pngBasePath/male_img.png'; static const String maleImg = '$pngBasePath/male_img.png';
static const String femaleImg = '$pngBasePath/female_img.png'; static const String femaleImg = '$pngBasePath/female_img.png';

@ -175,4 +175,78 @@ class AppState {
setRatedVisible(bool value) { setRatedVisible(bool value) {
isRatedVisible = value; isRatedVisible = value;
} }
Map<String, dynamic> _userSwitchPayloads = {};
int _childSwitchCounter = 0;
Map<String, dynamic> get getUserSwitchPayloads => _userSwitchPayloads;
void addUserSwitchPayload(dynamic payload, {bool isSuperUser = false}) {
var patientID = payload is Map ? payload['patientid'] : null;
if (patientID == null) {
if (isSuperUser) {
_userSwitchPayloads['superUser'] = payload;
_childSwitchCounter = 0;
} else {
_childSwitchCounter++;
if (_childSwitchCounter == 1) {
_userSwitchPayloads['child'] = payload;
} else {
_userSwitchPayloads['child$_childSwitchCounter'] = payload;
}
}
return;
}
String? existingKey;
for (var entry in _userSwitchPayloads.entries) {
if (entry.value is Map && entry.value['PatientID'] == patientID) {
existingKey = entry.key;
break;
}
}
if (isSuperUser) {
if (existingKey != null && existingKey != 'superUser') {
_userSwitchPayloads.remove(existingKey);
}
_userSwitchPayloads['superUser'] = payload;
_childSwitchCounter = 0;
} else {
if (existingKey != null) {
_userSwitchPayloads[existingKey] = payload;
} else {
_childSwitchCounter++;
if (_childSwitchCounter == 1) {
_userSwitchPayloads['child'] = payload;
} else {
_userSwitchPayloads['child$_childSwitchCounter'] = payload;
}
}
}
}
dynamic getUserSwitchPayload({required String userType}) {
return _userSwitchPayloads[userType];
}
dynamic getUserSwitchPayloadByIndex({bool isSuperUser = false, int? childIndex}) {
if (isSuperUser) {
return _userSwitchPayloads['superUser'];
} else if (childIndex != null) {
if (childIndex == 1) {
return _userSwitchPayloads['child'];
} else {
return _userSwitchPayloads['child$childIndex'];
}
}
return null;
}
void clearUserSwitchPayloads() {
_userSwitchPayloads.clear();
_childSwitchCounter = 0;
}
} }

@ -99,7 +99,7 @@ class LocationUtils {
title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!), title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!),
navigationService.navigatorKey.currentContext!, navigationService.navigatorKey.currentContext!,
child: Utils.getWarningWidget( child: Utils.getWarningWidget(
loadingText: "Please grant location permission from app settings to see better results", loadingText: LocaleKeys.grantLocationPermission.tr(),
isShowActionButtons: true, isShowActionButtons: true,
onCancelTap: () { onCancelTap: () {
navigationService.pop(); navigationService.pop();
@ -124,7 +124,7 @@ class LocationUtils {
title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!), title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!),
navigationService.navigatorKey.currentContext!, navigationService.navigatorKey.currentContext!,
child: Utils.getWarningWidget( child: Utils.getWarningWidget(
loadingText: "Please grant location permission from app settings to see better results", loadingText: LocaleKeys.grantLocationPermission.tr(),
isShowActionButtons: true, isShowActionButtons: true,
onCancelTap: () { onCancelTap: () {
navigationService.pop(); navigationService.pop();
@ -285,7 +285,7 @@ class LocationUtils {
title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!), title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!),
navigationService.navigatorKey.currentContext!, navigationService.navigatorKey.currentContext!,
child: Utils.getWarningWidget( child: Utils.getWarningWidget(
loadingText: "Please grant location permission from app settings to see better results", loadingText: LocaleKeys.grantLocationPermission.tr(),
isShowActionButtons: true, isShowActionButtons: true,
onCancelTap: () { onCancelTap: () {
navigationService.pop(); navigationService.pop();

@ -15,37 +15,37 @@ class LoadingUtils {
static bool get isLoading => _isLoadingVisible; static bool get isLoading => _isLoadingVisible;
static showFullScreenLoader({bool barrierDismissible = true, isSuccessDialog = false, String loadingText = "Loading, Please wait..."}) { // static showFullScreenLoader({bool barrierDismissible = true, isSuccessDialog = false, String loadingText = "Loading, Please wait..."}) {
if (!_isLoadingVisible) { // if (!_isLoadingVisible) {
_isLoadingVisible = true; // _isLoadingVisible = true;
final context = _navigationService.navigatorKey.currentContext; // final context = _navigationService.navigatorKey.currentContext;
log("got the context in showFullScreenLoading"); // log("got the context in showFullScreenLoading");
if (context == null) return; // if (context == null) return;
//
showDialog( // showDialog(
barrierDismissible: barrierDismissible, // barrierDismissible: barrierDismissible,
context: context, // context: context,
barrierColor: AppColors.blackColor.withOpacity(0.5), // barrierColor: AppColors.blackColor.withOpacity(0.5),
useRootNavigator: false, // useRootNavigator: false,
useSafeArea: false, // useSafeArea: false,
builder: (BuildContext context) { // builder: (BuildContext context) {
return Container( // return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( // decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, // color: AppColors.whiteColor,
borderRadius: 20.h, // borderRadius: 20.h,
hasShadow: false, // hasShadow: false,
), // ),
child: Material( // child: Material(
child: Center( // child: Center(
child: isSuccessDialog ? Utils.getSuccessWidget(loadingText: loadingText) : Utils.getLoadingWidget(loadingText: loadingText), // child: isSuccessDialog ? Utils.getSuccessWidget(loadingText: loadingText) : Utils.getLoadingWidget(loadingText: loadingText),
).paddingSymmetrical(24.w, 0), // ).paddingSymmetrical(24.w, 0),
), // ),
); // );
}).then((value) { // }).then((value) {
_isLoadingVisible = false; // _isLoadingVisible = false;
}); // });
} // }
} // }
static hideFullScreenLoader() { static hideFullScreenLoader() {
if (!_isLoadingVisible) return; if (!_isLoadingVisible) return;

@ -396,10 +396,10 @@ class PushNotificationHandler {
final deviceInfo = DeviceInfoPlugin(); final deviceInfo = DeviceInfoPlugin();
final androidInfo = await deviceInfo.androidInfo; final androidInfo = await deviceInfo.androidInfo;
int sdkInt = androidInfo.version.sdkInt ?? 0; // int sdkInt = androidInfo.version.sdkInt ?? 0;
if (sdkInt >= 33) { // if (sdkInt >= 33) {
await FlutterCallkitIncoming.requestFullIntentPermission(); // await FlutterCallkitIncoming.requestFullIntentPermission();
} // }
} }
} }

@ -152,9 +152,11 @@ class Utils {
static String getDayMonthYearDateFormatted(DateTime? dateTime) { static String getDayMonthYearDateFormatted(DateTime? dateTime) {
if (dateTime == null) return ""; if (dateTime == null) return "";
return appState.isArabic() return
? "${dateTime.day.toString()} ${getMonthArabic(dateTime.month)}, ${dateTime.year.toString()}" // appState.isArabic()
: "${dateTime.day.toString()} ${getMonth(dateTime.month)}, ${dateTime.year.toString()}"; // ? "${dateTime.day.toString()} ${getMonthArabic(dateTime.month)}, ${dateTime.year.toString()}"
// :
"${dateTime.day.toString()} ${getMonth(dateTime.month)}, ${dateTime.year.toString()}";
} }
/// get month by /// get month by
@ -353,7 +355,7 @@ class Utils {
repeat: false, reverse: false, frameRate: FrameRate(60), width: width.w, height: height.h, fit: BoxFit.fill), repeat: false, reverse: false, frameRate: FrameRate(60), width: width.w, height: height.h, fit: BoxFit.fill),
SizedBox(height: 16.h), SizedBox(height: 16.h),
(noDataText ?? LocaleKeys.noDataAvailable.tr()) (noDataText ?? LocaleKeys.noDataAvailable.tr())
.toText14(weight: FontWeight.w500, color: AppColors.greyTextColor, isCenter: true) .toText14(isBold: true, color: AppColors.greyTextColor, isCenter: true)
.paddingSymmetrical(64.w, 0.h), .paddingSymmetrical(64.w, 0.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
callToActionButton callToActionButton
@ -369,7 +371,7 @@ class Utils {
Lottie.asset(AppAnimations.loadingAnimation, Lottie.asset(AppAnimations.loadingAnimation,
repeat: true, reverse: false, frameRate: FrameRate(60), width: 80.h, height: 80.h, fit: BoxFit.fill), repeat: true, reverse: false, frameRate: FrameRate(60), width: 80.h, height: 80.h, fit: BoxFit.fill),
SizedBox(height: 8.h), SizedBox(height: 8.h),
(loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor, isCenter: true), (loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor, isCenter: true, isBold: true),
SizedBox(height: 8.h), SizedBox(height: 8.h),
], ],
).center; ).center;
@ -382,7 +384,7 @@ class Utils {
children: [ children: [
Lottie.asset(AppAnimations.checkmark, repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill), Lottie.asset(AppAnimations.checkmark, repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
SizedBox(height: 8.h), SizedBox(height: 8.h),
(loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor).paddingSymmetrical(24.h, 0.h), (loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor, isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 8.h), SizedBox(height: 8.h),
], ],
).center; ).center;
@ -768,6 +770,7 @@ class Utils {
return Row( return Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
spacing: 5.w,
children: [ children: [
Image.asset(AppAssets.mada, width: 35.h, height: 35.h), Image.asset(AppAssets.mada, width: 35.h, height: 35.h),
Image.asset( Image.asset(

@ -24,7 +24,7 @@ extension CapExtension on String {
extension EmailValidator on String { extension EmailValidator on String {
Widget get toWidget => Text(this); Widget get toWidget => Text(this);
Widget toText8({Color? color, FontWeight? fontWeight, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) => Text( Widget toText8({bool isEnglishOnly = false, Color? color, FontWeight? fontWeight, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) => Text(
this, this,
maxLines: maxlines, maxLines: maxlines,
overflow: textOverflow, overflow: textOverflow,
@ -34,6 +34,7 @@ extension EmailValidator on String {
fontWeight: fontWeight ?? (isBold ? FontWeight.bold : FontWeight.normal), fontWeight: fontWeight ?? (isBold ? FontWeight.bold : FontWeight.normal),
color: color ?? AppColors.blackColor, color: color ?? AppColors.blackColor,
letterSpacing: 0, letterSpacing: 0,
fontFamily: getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins',
), ),
); );
@ -60,7 +61,7 @@ extension EmailValidator on String {
color: color ?? AppColors.blackColor, color: color ?? AppColors.blackColor,
letterSpacing: letterSpacing, letterSpacing: letterSpacing,
decoration: isUnderLine ? TextDecoration.underline : null, decoration: isUnderLine ? TextDecoration.underline : null,
fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins', fontFamily: getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins',
decorationColor: color ?? AppColors.blackColor), decorationColor: color ?? AppColors.blackColor),
); );
@ -73,13 +74,14 @@ extension EmailValidator on String {
int? maxlines, int? maxlines,
FontStyle? fontStyle, FontStyle? fontStyle,
TextOverflow? textOverflow, TextOverflow? textOverflow,
double letterSpacing = 0}) => double letterSpacing = 0, bool isEnglishOnly = false}) =>
Text( Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
maxLines: maxlines, maxLines: maxlines,
overflow: textOverflow, overflow: textOverflow,
style: TextStyle( style: TextStyle(
fontFamily: getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins',
fontSize: 9.f, fontSize: 9.f,
fontStyle: fontStyle ?? FontStyle.normal, fontStyle: fontStyle ?? FontStyle.normal,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
@ -89,7 +91,7 @@ extension EmailValidator on String {
decorationColor: color ?? AppColors.blackColor), decorationColor: color ?? AppColors.blackColor),
); );
Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isCenter = false, bool isBold = false, int maxLine = 0, double letterSpacing = 0}) => Text( Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isCenter = false, bool isBold = false, int maxLine = 0, double letterSpacing = 0, bool isEnglishOnly = false,}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null, maxLines: (maxLine > 0) ? maxLine : null,
@ -100,6 +102,7 @@ extension EmailValidator on String {
color: color ?? AppColors.blackColor, color: color ?? AppColors.blackColor,
letterSpacing: letterSpacing, letterSpacing: letterSpacing,
decoration: isUnderLine ? TextDecoration.underline : null, decoration: isUnderLine ? TextDecoration.underline : null,
fontFamily: getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins',
), ),
); );
@ -125,7 +128,7 @@ extension EmailValidator on String {
height: height, height: height,
decorationColor: isUnderLine ? AppColors.blackColor : null, decorationColor: isUnderLine ? AppColors.blackColor : null,
decoration: isUnderLine ? TextDecoration.underline : null, decoration: isUnderLine ? TextDecoration.underline : null,
fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins', fontFamily: getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins',
), ),
); );
@ -208,7 +211,7 @@ extension EmailValidator on String {
height: height, height: height,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
decoration: isUnderLine ? TextDecoration.underline : null, decoration: isUnderLine ? TextDecoration.underline : null,
fontFamily: fontFamily ?? (isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'), fontFamily: fontFamily ?? (isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins'),
decorationColor: color ?? AppColors.blackColor), decorationColor: color ?? AppColors.blackColor),
); );
@ -249,14 +252,14 @@ extension EmailValidator on String {
overflow: textOverflow, overflow: textOverflow,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
decoration: isUnderLine ? TextDecoration.underline : null, decoration: isUnderLine ? TextDecoration.underline : null,
fontFamily: fontFamily ?? (isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'), fontFamily: fontFamily ?? (isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins'),
decorationColor: decorationColor ?? AppColors.errorColor), decorationColor: decorationColor ?? AppColors.errorColor),
); );
Widget toText17({bool isEnglishOnly = false, Color? color, bool isBold = false, bool isCenter = false}) => Text( Widget toText17({bool isEnglishOnly = false, Color? color, bool isBold = false, bool isCenter = false}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 17.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'), style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 17.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins'),
); );
Widget toText18({Color? color, FontWeight? weight, bool isBold = false, bool isCenter = false, int? maxlines, TextOverflow? textOverflow, bool isEnglishOnly = false,}) => Text( Widget toText18({Color? color, FontWeight? weight, bool isBold = false, bool isCenter = false, int? maxlines, TextOverflow? textOverflow, bool isEnglishOnly = false,}) => Text(
@ -264,7 +267,7 @@ extension EmailValidator on String {
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
this, this,
overflow: textOverflow, overflow: textOverflow,
style: TextStyle(fontSize: 18.f, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4, fontFamily: (isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'),), style: TextStyle(fontSize: 18.f, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4, fontFamily: (isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins'),),
); );
Widget toText19({Color? color, bool isBold = false}) => Text( Widget toText19({Color? color, bool isBold = false}) => Text(
@ -294,36 +297,38 @@ extension EmailValidator on String {
style: TextStyle(height: 1, color: color ?? AppColors.blackColor, fontSize: 22.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), style: TextStyle(height: 1, color: color ?? AppColors.blackColor, fontSize: 22.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
); );
Widget toText24({Color? color, bool isBold = false, bool isCenter = false, FontWeight? fontWeight, double? letterSpacing}) => Text( Widget toText24({Color? color, bool isBold = false, bool isCenter = false, FontWeight? fontWeight, double? letterSpacing, bool isEnglishOnly = false,}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
style: TextStyle( style: TextStyle(
fontFamily: (isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins'),
height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.f, letterSpacing: letterSpacing ?? -1, fontWeight: isBold ? FontWeight.bold : fontWeight ?? FontWeight.normal), height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.f, letterSpacing: letterSpacing ?? -1, fontWeight: isBold ? FontWeight.bold : fontWeight ?? FontWeight.normal),
); );
Widget toText26({Color? color, bool isBold = false, double? height, bool isCenter = false, FontWeight? weight, double? letterSpacing}) => Text( Widget toText26({Color? color, bool isBold = false, double? height, bool isCenter = false, FontWeight? weight, double? letterSpacing, bool isEnglishOnly = false,}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
style: TextStyle( style: TextStyle(
fontFamily: (isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins'),
height: height ?? 23 / 26, color: color ?? AppColors.blackColor, fontSize: 26.f, letterSpacing: letterSpacing ?? -1, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)), height: height ?? 23 / 26, color: color ?? AppColors.blackColor, fontSize: 26.f, letterSpacing: letterSpacing ?? -1, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
); );
Widget toText28({bool isEnglishOnly = false, Color? color, bool isBold = false, double? height, bool isCenter = false, double? letterSpacing}) => Text( Widget toText28({bool isEnglishOnly = false, Color? color, bool isBold = false, double? height, bool isCenter = false, double? letterSpacing}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(height: height ?? 23 / 28, color: color ?? AppColors.blackColor, fontSize: 28.f, letterSpacing: letterSpacing ?? -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'), style: TextStyle(height: height ?? 23 / 28, color: color ?? AppColors.blackColor, fontSize: 28.f, letterSpacing: letterSpacing ?? -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins'),
); );
Widget toText32({bool isEnglishOnly = false, FontWeight? weight, Color? color, bool isBold = false, bool isCenter = false}) => Text( Widget toText32({bool isEnglishOnly = false, FontWeight? weight, Color? color, bool isBold = false, bool isCenter = false}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
style: TextStyle( style: TextStyle(
height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.f, letterSpacing: -1, fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins', fontWeight: isBold ? FontWeight.bold : weight ?? FontWeight.normal), height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.f, letterSpacing: -1, fontFamily: getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins', fontWeight: isBold ? FontWeight.bold : weight ?? FontWeight.normal),
); );
Widget toText44({Color? color, bool isBold = false, bool isEnglishOnly = false,}) => Text( Widget toText44({Color? color, bool isBold = false, bool isEnglishOnly = false,}) => Text(
this, this,
style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: (isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'),), style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: (isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins'),),
); );
Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) { Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) {
@ -429,7 +434,7 @@ extension DynamicTextStyleExtension on BuildContext {
String? fontFamily, String? fontFamily,
bool isLanguageSwitcher = false}) { bool isLanguageSwitcher = false}) {
AppState appState = getIt.get<AppState>(); AppState appState = getIt.get<AppState>();
final family = appState.getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'; final family = appState.getLanguageCode() == "ar" ? 'CairoArabic' : 'Poppins';
return TextStyle( return TextStyle(
fontFamily: fontFamily ?? family, fontFamily: fontFamily ?? family,
fontSize: fontSize, fontSize: fontSize,
@ -460,7 +465,7 @@ class FontUtils {
/// Get the appropriate font family for a specific language /// Get the appropriate font family for a specific language
static String getFontFamilyForLanguage(bool isArabic) { static String getFontFamilyForLanguage(bool isArabic) {
return isArabic ? 'GESSTwo' : 'Poppins'; return isArabic ? 'CairoArabic' : 'Poppins';
} }
} }

@ -6,6 +6,7 @@ import 'package:hmg_patient_app_new/core/api_consts.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/common_models/generic_api_model.dart'; import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/select_device_by_imei.dart'; import 'package:hmg_patient_app_new/features/authentication/models/resp_models/select_device_by_imei.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart';
@ -214,56 +215,6 @@ class AuthenticationRepoImp implements AuthenticationRepo {
int? patientID, int? patientID,
int? loginType}) async { int? loginType}) async {
AppState appState = getIt.get<AppState>(); AppState appState = getIt.get<AppState>();
// if (isRegister) {
// newRequest["activationCode"] = activationCode ?? "0000";
// newRequest["isSilentLogin"] = activationCode != null ? false : true;
// } else {
// newRequest.activationCode = activationCode ?? "0000";
// newRequest.isSilentLogin = activationCode != null ? false : true;
// newRequest.projectOutSA = newRequest.zipCode == '966' ? false : true;
// newRequest.isDentalAllowedBackend = false;
// newRequest.forRegisteration = newRequest.isRegister ?? false;
// newRequest.isRegister = false;
// }
// Map<String, dynamic> familyRequest = {};
// if (isFormFamilyFile) {
// AppState appState = getIt.get<AppState>();
// familyRequest = {};
// familyRequest['PatientShareRequestID'] = patientShareRequestID;
// familyRequest['ResponseID'] = responseID;
// familyRequest['Status'] = 3;
// familyRequest["PatientID"] = appState.getAuthenticatedUser()!.patientId ?? 0;
// familyRequest["LogInTokenID"] = appState.getFamilyFileTokenID;
// familyRequest["activationCode"] = activationCode ?? "0000";
// familyRequest["PatientMobileNumber"] = newRequest.patientMobileNumber;
// familyRequest["PatientIdentificationID"] = newRequest.patientIdentificationID;
// }
// Map<String, dynamic> switchRequest = {};
// if (isSwitchUser) {
// switchRequest = newRequest.toJson();
//
// switchRequest['PatientID'] = responseID;
// switchRequest['IsSilentLogin'] = true;
// switchRequest['LogInTokenID'] = null;
// switchRequest['SearchType'] = 2;
// if (loginType != 0) {
// switchRequest['SuperUser'] = patientID;
// switchRequest['DeviceToken'] = null;
// } else {
// switchRequest["LoginType"] = 2;
// }
//
// if (appState.getSuperUserID == responseID) {
// // switchRequest['LoginType'] = 3;
// switchRequest['PatientIdentificationID'] = "";
// // switchRequest['ProjectOutSA'] = newRequest.zipCode == '966' ? false : true;
// switchRequest.remove('NationalID');
// switchRequest.remove('isDentalAllowedBackend');
// switchRequest.remove('ProjectOutSA');
// switchRequest.remove('ForRegisteration');
// appState.setSuperUserID = null;
// }
// }
if (isRegister) { if (isRegister) {
newRequest["activationCode"] = activationCode ?? "0000"; newRequest["activationCode"] = activationCode ?? "0000";
@ -321,7 +272,6 @@ class AuthenticationRepoImp implements AuthenticationRepo {
} }
} }
// Determine which API to use based on zipCode
final zipCode = _getZipCodeFromRequest(newRequest); final zipCode = _getZipCodeFromRequest(newRequest);
final isOthersCountry = zipCode == '0'; final isOthersCountry = zipCode == '0';
final endpoint = isFormFamilyFile final endpoint = isFormFamilyFile
@ -336,15 +286,40 @@ class AuthenticationRepoImp implements AuthenticationRepo {
GenericApiModel<dynamic>? apiResponse; GenericApiModel<dynamic>? apiResponse;
Failure? failure; Failure? failure;
await apiClient.post( // Determine the payload to send
endpoint, var requestBody = isFormFamilyFile
body: isFormFamilyFile
? familyRequest ? familyRequest
: isRegister : isRegister
? newRequest ? newRequest
: isSwitchUser : isSwitchUser
? switchRequest ? switchRequest
: newRequest.toJson(), : newRequest.toJson();
if (isSwitchUser) {
Map<String, dynamic> allUsersPayload;
var switchingPatientID;
var superUserPatientID;
bool isSwitchingToSuperUser = false;
allUsersPayload = appState.getUserSwitchPayloads;
switchingPatientID = switchRequest["PatientID"];
superUserPatientID = allUsersPayload['superUser']['PatientID'];
isSwitchingToSuperUser = (appState.getSuperUserID == responseID) || (allUsersPayload.containsKey('superUser') && superUserPatientID == switchingPatientID);
if (isSwitchingToSuperUser) {
var superUserPayload = appState.getUserSwitchPayloadByIndex(isSuperUser: true);
if (superUserPayload != null) {
requestBody['DeviceToken'] = newRequest.deviceToken;
requestBody['ProjectOutSA'] = 0;
requestBody['PatientIdentificationID'] = "";
requestBody.removeWhere((key, value) => ['NationalID', 'isDentalAllowedBackend', 'ForRegisteration'].contains(key));
}
}
}
await apiClient.post(
endpoint,
body: requestBody,
onFailure: (error, statusCode, {messageStatus, failureType}) { onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType; failure = failureType;
}, },
@ -611,7 +586,7 @@ class AuthenticationRepoImp implements AuthenticationRepo {
} }
@override @override
Future<Either<Failure, GenericApiModel<dynamic>>> getServicePrivilege() { Future<Either<Failure, GenericApiModel>> getServicePrivilege() {
Map<String, dynamic> mapDevice = {}; Map<String, dynamic> mapDevice = {};
try { try {
GenericApiModel<dynamic>? apiResponse; GenericApiModel<dynamic>? apiResponse;
@ -692,6 +667,7 @@ class AuthenticationRepoImp implements AuthenticationRepo {
@override @override
Future<Either<Failure, GenericApiModel<dynamic>>> getPatientBloodType() async { Future<Either<Failure, GenericApiModel<dynamic>>> getPatientBloodType() async {
// Map<String, dynamic> requestBody = {"PatientType": 1, "PatientTypeID": 1, "TokenID": "@dm!n", "PatientID": 5957754};
Map<String, dynamic> requestBody = {}; Map<String, dynamic> requestBody = {};
try { try {
GenericApiModel<dynamic>? apiResponse; GenericApiModel<dynamic>? apiResponse;

@ -31,6 +31,7 @@ import 'package:hmg_patient_app_new/features/authentication/models/resp_models/s
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/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/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/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/authentication/login.dart'; import 'package:hmg_patient_app_new/presentation/authentication/login.dart';
import 'package:hmg_patient_app_new/presentation/authentication/saved_login_screen.dart'; import 'package:hmg_patient_app_new/presentation/authentication/saved_login_screen.dart';
@ -100,7 +101,10 @@ class AuthenticationViewModel extends ChangeNotifier {
var healthId; var healthId;
int getDeviceLastLogin = 1; int getDeviceLastLogin = 1;
bool isInitialLoginNavigated = false;
Future<void> onLoginPressed() async { Future<void> onLoginPressed() async {
setIsInitialLoginNavigated(false);
try { try {
LoaderBottomSheet.showLoader(); LoaderBottomSheet.showLoader();
//TODO: We will remove this delay //TODO: We will remove this delay
@ -110,7 +114,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (data != null) { if (data != null) {
await _handleExistingImeiData(data); await _handleExistingImeiData(data);
} else { } else {
await _handleNewImeiRegistration(); await handleNewImeiRegistration();
} }
} catch (e) { } catch (e) {
log("Error in onLoginPressed: $e"); log("Error in onLoginPressed: $e");
@ -131,6 +135,8 @@ class AuthenticationViewModel extends ChangeNotifier {
pickedCountryByUAEUser = null; pickedCountryByUAEUser = null;
_appState.setUserRegistrationPayload = RegistrationDataModelPayload(); _appState.setUserRegistrationPayload = RegistrationDataModelPayload();
_appState.setNHICUserData = CheckUserStatusResponseNHIC(); _appState.setNHICUserData = CheckUserStatusResponseNHIC();
getIt.get<SymptomsCheckerViewModel>().setSelectedHeight(0);
getIt.get<SymptomsCheckerViewModel>().setSelectedWeight(0);
} }
void onCountryChange(CountryEnum country) { void onCountryChange(CountryEnum country) {
@ -196,6 +202,11 @@ class AuthenticationViewModel extends ChangeNotifier {
} }
} }
setIsInitialLoginNavigated(bool isInitialLoginNavigated) {
this.isInitialLoginNavigated = isInitialLoginNavigated;
notifyListeners();
}
void onTermAccepted() { void onTermAccepted() {
isTermsAccepted = !isTermsAccepted; isTermsAccepted = !isTermsAccepted;
notifyListeners(); notifyListeners();
@ -213,7 +224,7 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.deviceToken = await Utils.getStringFromPrefs(CacheConst.pushToken); _appState.deviceToken = await Utils.getStringFromPrefs(CacheConst.pushToken);
} }
Future<void> selectDeviceImei({required Function(dynamic data) onSuccess, Function(String)? onError}) async { Future<void> selectDeviceImei({bool isNavigate = true, required Function(dynamic data) onSuccess, Function(String)? onError}) async {
// LoadingUtils.showFullScreenLoading(); // LoadingUtils.showFullScreenLoading();
// String firebaseToken = _appState.deviceToken; // String firebaseToken = _appState.deviceToken;
String firebaseToken = await Utils.getStringFromPrefs(CacheConst.pushToken); String firebaseToken = await Utils.getStringFromPrefs(CacheConst.pushToken);
@ -228,7 +239,9 @@ class AuthenticationViewModel extends ChangeNotifier {
// LoadingUtils.hideFullScreenLoader(); // LoadingUtils.hideFullScreenLoader();
// await _errorHandlerService.handleError(failure: failure); // await _errorHandlerService.handleError(failure: failure);
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
if (isNavigate) {
_navigationService.pushPage(page: LoginScreen()); _navigationService.pushPage(page: LoginScreen());
}
}, },
(apiResponse) { (apiResponse) {
// LoadingUtils.hideFullScreenLoader(); // LoadingUtils.hideFullScreenLoader();
@ -260,8 +273,11 @@ class AuthenticationViewModel extends ChangeNotifier {
} }
} }
Future<void> _handleNewImeiRegistration() async { Future<void> handleNewImeiRegistration({bool isNavigate = true}) async {
await selectDeviceImei(onSuccess: (dynamic respData) async { print("handleNewImeiRegistration called");
await selectDeviceImei(
isNavigate: isNavigate,
onSuccess: (dynamic respData) async {
try { try {
if (respData != null) { if (respData != null) {
dynamic data = await SelectDeviceByImeiRespModelElement.fromJson(respData.toJson()); dynamic data = await SelectDeviceByImeiRespModelElement.fromJson(respData.toJson());
@ -271,18 +287,23 @@ class AuthenticationViewModel extends ChangeNotifier {
// TODO: Navigate to SavedLogin when available // TODO: Navigate to SavedLogin when available
// SelectDeviceByImeiRespModelElement savedData = // SelectDeviceByImeiRespModelElement savedData =
// SelectDeviceByImeiRespModelElement.fromJson(respData); // SelectDeviceByImeiRespModelElement.fromJson(respData);
if (!isInitialLoginNavigated) {
_navigationService.pushPage(page: SavedLogin()); _navigationService.pushPage(page: SavedLogin());
}
// _navigationService.pushPage(page: LoginScreen()); // _navigationService.pushPage(page: LoginScreen());
} else { } else {
print("print login........"); if (isNavigate) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
_navigationService.pushPage(page: LoginScreen()); _navigationService.pushPage(page: LoginScreen());
} }
}
} catch (e) { } catch (e) {
if (isNavigate) {
log("Error processing IMEI registration response: $e"); log("Error processing IMEI registration response: $e");
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
_navigationService.pushPage(page: LoginScreen()); _navigationService.pushPage(page: LoginScreen());
} }
}
}, onError: (String error) { }, onError: (String error) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
_dialogService.showErrorBottomSheet(message: error, onOkPressed: () {}); _dialogService.showErrorBottomSheet(message: error, onOkPressed: () {});
@ -382,7 +403,7 @@ class AuthenticationViewModel extends ChangeNotifier {
mobileNumber: phoneNumber, mobileNumber: phoneNumber,
selectedLoginType: otpTypeEnum.toInt(), selectedLoginType: otpTypeEnum.toInt(),
zipCode: selectedCountrySignup.countryCode, zipCode: selectedCountrySignup.countryCode,
nationalId:nationalIdOrFileNumber, nationalId: nationalIdOrFileNumber,
isFileNo: isForRegister ? isPatientHasFile(request: payload) : false, isFileNo: isForRegister ? isPatientHasFile(request: payload) : false,
patientId: isFormFamilyFile ? _appState.getAuthenticatedUser()!.patientId : 0, patientId: isFormFamilyFile ? _appState.getAuthenticatedUser()!.patientId : 0,
isForRegister: isForRegister, isForRegister: isForRegister,
@ -612,13 +633,21 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.setSuperUserID = null; _appState.setSuperUserID = null;
_appState.setIsChildLoggedIn = false; _appState.setIsChildLoggedIn = false;
activation.list!.first.isParentUser = true; activation.list!.first.isParentUser = true;
var allUsersPayload = _appState.getUserSwitchPayloads;
if ((allUsersPayload.containsKey('superUser') && allUsersPayload['superUser'] != null)) {
_appState.addUserSwitchPayload(activation.list!.first.toJson(), isSuperUser: false);
} else {
_appState.addUserSwitchPayload(activation.list!.first.toJson(), isSuperUser: true);
}
} else { } else {
_appState.setSuperUserID = _appState.getAuthenticatedUser()?.patientId; _appState.setSuperUserID = _appState.getAuthenticatedUser()?.patientId;
_appState.setIsChildLoggedIn = true; _appState.setIsChildLoggedIn = true;
activation.list!.first.isParentUser = false; activation.list!.first.isParentUser = false;
_appState.addUserSwitchPayload(activation.list!.first.toJson(), isSuperUser: false);
} }
} else { } else {
activation.list!.first.isParentUser = true; activation.list!.first.isParentUser = true;
_appState.addUserSwitchPayload(activation.list!.first.toJson(), isSuperUser: true);
} }
activation.list!.first.bloodGroup = activation.patientBloodType; activation.list!.first.bloodGroup = activation.patientBloodType;
activation.list!.first.zipCode = selectedCountrySignup == CountryEnum.others ? '0' : selectedCountrySignup.countryCode; activation.list!.first.zipCode = selectedCountrySignup == CountryEnum.others ? '0' : selectedCountrySignup.countryCode;
@ -627,7 +656,7 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.setUserBloodGroup = activation.patientBlodType ?? "N/A"; _appState.setUserBloodGroup = activation.patientBlodType ?? "N/A";
// Fetch patient blood type from new API // Fetch patient blood type from new API
await getPatientBloodTypeNew(); // await getPatientBloodTypeNew();
} }
// _appState.setUserBloodGroup = (activation.patientBlodType ?? ""); // _appState.setUserBloodGroup = (activation.patientBlodType ?? "");
_appState.setAppAuthToken = activation.authenticationTokenId; _appState.setAppAuthToken = activation.authenticationTokenId;
@ -719,6 +748,8 @@ class AuthenticationViewModel extends ChangeNotifier {
} }
Future<void> navigateToHomeScreen() async { Future<void> navigateToHomeScreen() async {
setIsInitialLoginNavigated(true);
getPatientBloodTypeNew();
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
_navigationService.navigatorKey.currentContext!, _navigationService.navigatorKey.currentContext!,
CustomPageRoute( CustomPageRoute(
@ -862,17 +893,17 @@ class AuthenticationViewModel extends ChangeNotifier {
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async {
if (apiResponse.data is String) { if (apiResponse.data is String) {
//TODO: This Section Need to Be Testing. //TODO: This Section Need to Be Testing.
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
_dialogService.showExceptionBottomSheet(message: apiResponse.data, onOkPressed: () {}, onCancelPressed: () {}); _dialogService.showExceptionBottomSheet(message: apiResponse.data, onOkPressed: () {}, onCancelPressed: () {});
//TODO: Here We Need to Show a Dialog Of Something in the case of Fail With OK and Cancel and the Display Variable WIll be result. //TODO: Here We Need to Show a Dialog Of Something in the case of Fail With OK and Cancel and the Display Variable WIll be result.
} else { } else {
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
if (apiResponse.data["MessageStatus"] == 1) { if (apiResponse.data["MessageStatus"] == 1) {
LoadingUtils.showFullScreenLoader(isSuccessDialog: true, loadingText: "Your medical file has been created successfully. \nPlease proceed to login."); LoaderBottomSheet.showLoader(loadingText: "Your medical file has been created successfully. \nPlease proceed to login.");
//TODO: Here We Need to Show a Dialog Of Something in the case of Success. //TODO: Here We Need to Show a Dialog Of Something in the case of Success.
await clearDefaultInputValues(); // This will Clear All Default Values Of User. await clearDefaultInputValues(); // This will Clear All Default Values Of User.
Future.delayed(Duration(seconds: 1), () { Future.delayed(Duration(seconds: 1), () {
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
// _navigationService.pushAndReplace(AppRoutes.loginScreen); // _navigationService.pushAndReplace(AppRoutes.loginScreen);
_navigationService.pushAndRemoveUntil(CustomPageRoute(page: LandingNavigation()), (r) => false); _navigationService.pushAndRemoveUntil(CustomPageRoute(page: LandingNavigation()), (r) => false);
_navigationService.push(CustomPageRoute(page: LoginScreen())); _navigationService.push(CustomPageRoute(page: LoginScreen()));
@ -1015,7 +1046,9 @@ class AuthenticationViewModel extends ChangeNotifier {
nationalId: _appState.getAuthenticatedUser()!.patientIdentificationNo, nationalId: _appState.getAuthenticatedUser()!.patientIdentificationNo,
gender: _appState.getAuthenticatedUser()!.gender) gender: _appState.getAuthenticatedUser()!.gender)
.toJson()); .toJson());
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { resultEither.fold((failure) async {
// await _errorHandlerService.handleError(failure: failure);
}, (apiResponse) async {
if (apiResponse.messageStatus == 2) {} if (apiResponse.messageStatus == 2) {}
if (apiResponse.messageStatus == 1) { if (apiResponse.messageStatus == 1) {
log("Insert Device Data Success"); log("Insert Device Data Success");
@ -1149,6 +1182,7 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.setVidaPlusProjectList([]); _appState.setVidaPlusProjectList([]);
_appState.setHMCProjectList([]); _appState.setHMCProjectList([]);
_appState.setProjectsDetailList([]); _appState.setProjectsDetailList([]);
_appState.clearUserSwitchPayloads();
await clearDefaultInputValues(); await clearDefaultInputValues();
_navigationService.pushAndReplace(AppRoutes.landingScreen); _navigationService.pushAndReplace(AppRoutes.landingScreen);
} catch (e) { } catch (e) {
@ -1168,7 +1202,7 @@ class AuthenticationViewModel extends ChangeNotifier {
(apiResponse) { (apiResponse) {
if (apiResponse.messageStatus == 1 && apiResponse.data != null) { if (apiResponse.messageStatus == 1 && apiResponse.data != null) {
// Extract blood type from response // Extract blood type from response
String? bloodType = apiResponse.data['GetPatientBloodType']; String? bloodType = apiResponse.data['GetPatientBloodType'][0]["BloodType"];
if (bloodType != null && bloodType.isNotEmpty) { if (bloodType != null && bloodType.isNotEmpty) {
_appState.setUserBloodGroup = bloodType; _appState.setUserBloodGroup = bloodType;
log("Blood type updated from new API: $bloodType"); log("Blood type updated from new API: $bloodType");

@ -26,7 +26,7 @@ class HospitalBottomSheetBodySelection extends StatelessWidget {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if(!isHideTitle) LocaleKeys.selectHospital.tr(context: context).toText16(weight: FontWeight.w500, color: AppColors.greyTextColor), if(!isHideTitle) LocaleKeys.selectHospital.tr(context: context).toText16(isBold: true, color: AppColors.greyTextColor),
SizedBox(height: 16.h), SizedBox(height: 16.h),
SizedBox( SizedBox(
height: MediaQuery.sizeOf(context).height * .4, height: MediaQuery.sizeOf(context).height * .4,
@ -75,7 +75,8 @@ class HospitalBottomSheetBodySelection extends StatelessWidget {
children: [ children: [
Utils.buildSvgWithAssets(icon: AppAssets.hmg).paddingOnly(right: 10), Utils.buildSvgWithAssets(icon: AppAssets.hmg).paddingOnly(right: 10),
Expanded( Expanded(
child: Text(hospital.projectName ?? "", style: TextStyle(fontWeight: FontWeight.w600, fontSize: 16.f, color: AppColors.blackColor)), child: (hospital.projectName ?? "").toString().toText16(isBold: true, color: AppColors.blackColor),
// Text(hospital.projectName ?? "", style: TextStyle(isBold: true, fontSize: 16.f, color: AppColors.blackColor)),
) )
], ],
); );

@ -2,6 +2,7 @@ import 'dart:async';
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:get_it/get_it.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/dependencies.dart';
import 'package:hmg_patient_app_new/core/location_util.dart'; import 'package:hmg_patient_app_new/core/location_util.dart';
@ -11,6 +12,7 @@ import 'package:hmg_patient_app_new/core/utils/loading_utils.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.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/models/LaserCategoryType.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/LaserCategoryType.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/free_slot.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/free_slot.dart';
@ -139,6 +141,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
bool applyFilters = false; bool applyFilters = false;
bool isWaitingAppointmentAvailable = false; bool isWaitingAppointmentAvailable = false;
bool isPatientRescheduleAppointment = false;
bool isWaitingAppointmentSelected = false; bool isWaitingAppointmentSelected = false;
int waitingAppointmentProjectID = 0; int waitingAppointmentProjectID = 0;
@ -150,6 +153,72 @@ class BookAppointmentsViewModel extends ChangeNotifier {
AppointmentNearestGateResponseModel? appointmentNearestGateResponseModel; AppointmentNearestGateResponseModel? appointmentNearestGateResponseModel;
///variables for laser clinic ///variables for laser clinic
bool isLaserHospitalsLoading = false;
List<PatientDoctorAppointmentList> laserHospitalsList = [];
int laserHospitalHmgCount = 0;
int laserHospitalHmcCount = 0;
Future<void> getLaserHospitals({Function(dynamic)? onSuccess, Function(String)? onError}) async {
isLaserHospitalsLoading = true;
laserHospitalsList.clear();
laserHospitalHmgCount = 0;
laserHospitalHmcCount = 0;
notifyListeners();
final result = await bookAppointmentsRepo.getDoctorsList(253, 0, false, 0, '');
result.fold(
(failure) async {
isLaserHospitalsLoading = false;
notifyListeners();
onError?.call(failure.message);
},
(apiResponse) async {
if (apiResponse.messageStatus == 1) {
var doctorList = apiResponse.data!;
var regionList = await DoctorMapper.getMappedDoctor(
doctorList,
isArabic: _appState.isArabic(),
lat: _appState.userLat,
long: _appState.userLong,
);
var isLocationEnabled = (_appState.userLat != 0) && (_appState.userLong != 0);
regionList = await DoctorMapper.sortList(isLocationEnabled, regionList);
// Flatten all hospitals across all regions into a single list
laserHospitalsList.clear();
Set<String> addedHospitals = {};
regionList.registeredDoctorMap?.forEach((region, regionData) {
for (var hospital in regionData?.hmgDoctorList ?? <PatientDoctorAppointmentList>[]) {
if (!addedHospitals.contains(hospital.filterName)) {
addedHospitals.add(hospital.filterName ?? '');
laserHospitalsList.add(hospital);
}
}
for (var hospital in regionData?.hmcDoctorList ?? <PatientDoctorAppointmentList>[]) {
if (!addedHospitals.contains(hospital.filterName)) {
addedHospitals.add(hospital.filterName ?? '');
laserHospitalsList.add(hospital);
}
}
});
laserHospitalHmgCount = laserHospitalsList.where((h) => h.isHMC != true).length;
laserHospitalHmcCount = laserHospitalsList.where((h) => h.isHMC == true).length;
isLaserHospitalsLoading = false;
notifyListeners();
onSuccess?.call(apiResponse);
} else {
isLaserHospitalsLoading = false;
notifyListeners();
onError?.call(apiResponse.errorMessage ?? 'Unknown error');
}
},
);
}
List<LaserCategoryType> femaleLaserCategory = [ List<LaserCategoryType> femaleLaserCategory = [
LaserCategoryType(1, 'bodyString'), LaserCategoryType(1, 'bodyString'),
LaserCategoryType(2, 'face'), LaserCategoryType(2, 'face'),
@ -157,7 +226,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
LaserCategoryType(11, 'retouch'), LaserCategoryType(11, 'retouch'),
]; ];
List<LaserCategoryType> maleLaserCategory = [ List<LaserCategoryType> maleLaserCategory = [
LaserCategoryType(1, 'body'), LaserCategoryType(1, 'bodyString'),
LaserCategoryType(2, 'face'), LaserCategoryType(2, 'face'),
LaserCategoryType(11, 'retouch'), LaserCategoryType(11, 'retouch'),
]; ];
@ -262,6 +331,42 @@ class BookAppointmentsViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void filterDoctors(String query) {
if (query.isEmpty) {
filteredDoctorList = List.from(doctorsList);
_groupDoctorsList();
setIsNearestAppointmentSelected(isNearestAppointmentSelected);
notifyListeners();
return;
}
filteredDoctorList = doctorsList.where((doctor) {
final name = (doctor.name ?? '').toLowerCase();
final clinicName = (doctor.clinicName ?? '').toLowerCase();
final projectName = (doctor.projectName ?? '').toLowerCase();
final q = query.toLowerCase();
return name.contains(q) || clinicName.contains(q) || projectName.contains(q);
}).toList();
// Re-group filtered list
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);
}
doctorsListByClinic = clinicMap.values.toList();
doctorsListByHospital = hospitalMap.values.toList();
doctorsListGrouped = isSortByClinic ? doctorsListByClinic : doctorsListByHospital;
notifyListeners();
}
void filterClinics(String? query) { void filterClinics(String? query) {
if (query!.isEmpty) { if (query!.isEmpty) {
_filteredClinicsList = List.from(clinicsList); _filteredClinicsList = List.from(clinicsList);
@ -289,14 +394,19 @@ class BookAppointmentsViewModel extends ChangeNotifier {
isContinueDentalPlan = false; isContinueDentalPlan = false;
isChiefComplaintsListLoading = true; isChiefComplaintsListLoading = true;
isWaitingAppointmentSelected = false; isWaitingAppointmentSelected = false;
isPatientRescheduleAppointment = false;
bodyTypes = [maleLaserCategory, femaleLaserCategory]; bodyTypes = [maleLaserCategory, femaleLaserCategory];
// getLocation(); // getLocation();
notifyListeners(); notifyListeners();
} }
refreshDoctorsList() {
setIsDoctorsListLoading(true);
getDoctorsList(isNearest: isNearestAppointmentSelected);
}
setIsNearestAppointmentSelected(bool isNearestAppointmentSelected) { setIsNearestAppointmentSelected(bool isNearestAppointmentSelected) {
this.isNearestAppointmentSelected = isNearestAppointmentSelected; this.isNearestAppointmentSelected = isNearestAppointmentSelected;
if (isNearestAppointmentSelected) { if (isNearestAppointmentSelected) {
for (var group in doctorsListGrouped) { for (var group in doctorsListGrouped) {
group.sort((a, b) { group.sort((a, b) {
@ -427,6 +537,11 @@ class BookAppointmentsViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
setIsPatientRescheduleAppointment(bool isPatientRescheduleAppointment) {
this.isPatientRescheduleAppointment = isPatientRescheduleAppointment;
notifyListeners();
}
void onTabChanged(int index) { void onTabChanged(int index) {
calculationID = null; calculationID = null;
isGetDocForHealthCal = false; isGetDocForHealthCal = false;
@ -535,8 +650,11 @@ class BookAppointmentsViewModel extends ChangeNotifier {
} }
//TODO: Make the API dynamic with parameters for ProjectID, isNearest, languageID, doctorId, doctorName //TODO: Make the API dynamic with parameters for ProjectID, isNearest, languageID, doctorId, doctorName
Future<void> getDoctorsList({int projectID = 0, bool isNearest = true, int doctorId = 0, String doctorName = "", Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getDoctorsList({int projectID = 0, bool isNearest = false, int doctorId = 0, String doctorName = "", Function(dynamic)? onSuccess, Function(String)? onError}) async {
doctorsList.clear(); doctorsList.clear();
filteredDoctorList.clear();
doctorsListGrouped.clear();
notifyListeners();
projectID = currentlySelectedHospitalFromRegionFlow != null ? int.parse(currentlySelectedHospitalFromRegionFlow!) : projectID; projectID = currentlySelectedHospitalFromRegionFlow != null ? int.parse(currentlySelectedHospitalFromRegionFlow!) : projectID;
final result = final result =
await bookAppointmentsRepo.getDoctorsList(selectedClinic.clinicID ?? 0, projectID, doctorName.isNotEmpty ? false : isNearest, doctorId, doctorName, isContinueDentalPlan: isContinueDentalPlan); await bookAppointmentsRepo.getDoctorsList(selectedClinic.clinicID ?? 0, projectID, doctorName.isNotEmpty ? false : isNearest, doctorId, doctorName, isContinueDentalPlan: isContinueDentalPlan);
@ -560,7 +678,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
clearSearchFilters(); clearSearchFilters();
getFiltersFromDoctorList(); getFiltersFromDoctorList();
_groupDoctorsList(); _groupDoctorsList();
setIsNearestAppointmentSelected(true); setIsNearestAppointmentSelected(isNearest);
notifyListeners(); notifyListeners();
if (onSuccess != null) { if (onSuccess != null) {
onSuccess(apiResponse); onSuccess(apiResponse);
@ -652,12 +770,14 @@ class BookAppointmentsViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
// Check if doctor is favorite after getting profile // Check if doctor is favorite after getting profile
if(_appState.isAuthenticated) {
checkIsFavouriteDoctor( checkIsFavouriteDoctor(
patientID: _appState.getAuthenticatedUser()!.patientId!, patientID: _appState.getAuthenticatedUser()!.patientId!,
projectID: doctorsProfileResponseModel.projectID ?? 0, projectID: doctorsProfileResponseModel.projectID ?? 0,
clinicID: doctorsProfileResponseModel.clinicID ?? 0, clinicID: doctorsProfileResponseModel.clinicID ?? 0,
doctorID: doctorsProfileResponseModel.doctorID ?? 0, doctorID: doctorsProfileResponseModel.doctorID ?? 0,
); );
}
if (onSuccess != null) { if (onSuccess != null) {
onSuccess(apiResponse); onSuccess(apiResponse);
@ -741,8 +861,8 @@ class BookAppointmentsViewModel extends ChangeNotifier {
} }
initialSlotDuration = apiResponse.data["InitialSlotDuration"]; initialSlotDuration = apiResponse.data["InitialSlotDuration"];
freeSlotsResponse = apiResponse.data['FreeTimeSlots']; freeSlotsResponse = apiResponse.data['FreeTimeSlots'];
isWaitingAppointmentAvailable = apiResponse.data["IsAllowToBookWaitingAppointment"]; // isWaitingAppointmentAvailable = apiResponse.data["IsAllowToBookWaitingAppointment"];
// isWaitingAppointmentAvailable = true; isWaitingAppointmentAvailable = true;
freeSlotsResponse.forEach((element) { freeSlotsResponse.forEach((element) {
// date = (isLiveCareSchedule != null && isLiveCareSchedule) // date = (isLiveCareSchedule != null && isLiveCareSchedule)
@ -852,10 +972,53 @@ class BookAppointmentsViewModel extends ChangeNotifier {
print(failure); print(failure);
onError!(failure.message); onError!(failure.message);
}, },
(apiResponse) { (apiResponse) async {
if (apiResponse.messageStatus == 2) { if (apiResponse.messageStatus == 2) {
// onError!(apiResponse); // onError!(apiResponse);
LoadingUtils.hideFullScreenLoader(); if (isPatientRescheduleAppointment) {
PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel = PatientAppointmentHistoryResponseModel(
appointmentNo: apiResponse.data["SameClinicApptList"][0]['AppointmentNo'],
clinicID: apiResponse.data["SameClinicApptList"][0]['ClinicID'],
projectID: apiResponse.data["SameClinicApptList"][0]['ProjectID'],
endDate: apiResponse.data["SameClinicApptList"][0]['EndTime'],
startTime: apiResponse.data["SameClinicApptList"][0]['StartTime'],
doctorID: apiResponse.data["SameClinicApptList"][0]['DoctorID'],
isLiveCareAppointment: apiResponse.data["SameClinicApptList"][0]['IsLiveCareAppointment'],
originalClinicID: 0,
originalProjectID: 0,
appointmentDate: apiResponse.data["SameClinicApptList"][0]['AppointmentDate'],
);
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async {
// LoaderBottomSheet.hideLoader();
Future.delayed(Duration(milliseconds: 50)).then((value) async {});
// LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingYourAppointment.tr());
await insertSpecificAppointment(
onError: (err) {},
onSuccess: (apiResp) async {
LoaderBottomSheet.hideLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async {
showCommonBottomSheetWithoutHeight(
GetIt.instance<NavigationService>().navigatorKey.currentContext!,
child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentSuccess.tr()).paddingSymmetrical(0.h, 24.h),
callBackFunc: () {
setIsPatientRescheduleAppointment(false);
Navigator.pushAndRemoveUntil(
navigationService.navigatorKey.currentContext!,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
},
isFullScreen: false,
isCloseButtonVisible: false,
isAutoDismiss: true
);
});
});
});
} else {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!), title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!),
navigationService.navigatorKey.currentContext!, navigationService.navigatorKey.currentContext!,
@ -886,22 +1049,28 @@ class BookAppointmentsViewModel extends ChangeNotifier {
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async { await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Future.delayed(Duration(milliseconds: 50)).then((value) async {}); Future.delayed(Duration(milliseconds: 50)).then((value) async {});
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: LocaleKeys.bookingYourAppointment.tr()); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingYourAppointment.tr());
await insertSpecificAppointment( await insertSpecificAppointment(
onError: (err) {}, onError: (err) {},
onSuccess: (apiResp) async { onSuccess: (apiResp) async {
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async { await Future.delayed(Duration(milliseconds: 50)).then((value) async {
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: true, loadingText: LocaleKeys.appointmentSuccess.tr()); showCommonBottomSheetWithoutHeight(
await Future.delayed(Duration(milliseconds: 4000)).then((value) { GetIt.instance<NavigationService>().navigatorKey.currentContext!,
LoadingUtils.hideFullScreenLoader(); child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentSuccess.tr()).paddingSymmetrical(0.h, 24.h),
callBackFunc: () {
setIsPatientRescheduleAppointment(false);
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
navigationService.navigatorKey.currentContext!, navigationService.navigatorKey.currentContext!,
CustomPageRoute( CustomPageRoute(
page: LandingNavigation(), page: LandingNavigation(),
), ),
(r) => false); (r) => false);
}); },
isFullScreen: false,
isCloseButtonVisible: false,
isAutoDismiss: true
);
}); });
}); });
}); });
@ -910,6 +1079,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true, isCloseButtonVisible: true,
); );
}
} else if (apiResponse.messageStatus == 1) { } else if (apiResponse.messageStatus == 1) {
if (apiResponse.data == null || apiResponse.data!.isEmpty) { if (apiResponse.data == null || apiResponse.data!.isEmpty) {
onError!("No free slots available".tr()); onError!("No free slots available".tr());
@ -946,7 +1116,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
(apiResponse) { (apiResponse) {
if (apiResponse.messageStatus == 2) { if (apiResponse.messageStatus == 2) {
// onError!(apiResponse); // onError!(apiResponse);
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!), title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!),
navigationService.navigatorKey.currentContext!, navigationService.navigatorKey.currentContext!,
@ -982,22 +1152,28 @@ class BookAppointmentsViewModel extends ChangeNotifier {
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async { await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async {
navigationService.pop(); navigationService.pop();
Future.delayed(Duration(milliseconds: 50)).then((value) async {}); Future.delayed(Duration(milliseconds: 50)).then((value) async {});
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: LocaleKeys.bookingYourAppointment.tr()); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.bookingYourAppointment.tr());
await insertSpecificAppointment( await insertSpecificAppointment(
onError: (err) {}, onError: (err) {},
onSuccess: (apiResp) async { onSuccess: (apiResp) async {
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async { await Future.delayed(Duration(milliseconds: 50)).then((value) async {
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: true, loadingText: LocaleKeys.appointmentSuccess.tr()); showCommonBottomSheetWithoutHeight(
await Future.delayed(Duration(milliseconds: 4000)).then((value) { GetIt.instance<NavigationService>().navigatorKey.currentContext!,
LoadingUtils.hideFullScreenLoader(); child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentSuccess.tr()).paddingSymmetrical(0.h, 24.h),
callBackFunc: () {
setIsPatientRescheduleAppointment(false);
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
navigationService.navigatorKey.currentContext!, navigationService.navigatorKey.currentContext!,
CustomPageRoute( CustomPageRoute(
page: LandingNavigation(), page: LandingNavigation(),
), ),
(r) => false); (r) => false);
}); },
isFullScreen: false,
isCloseButtonVisible: false,
isAutoDismiss: true
);
}); });
}); });
}); });
@ -1491,7 +1667,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
}, },
(apiResponse) { (apiResponse) {
if (apiResponse.messageStatus == 2) { if (apiResponse.messageStatus == 2) {
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!), title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!),
navigationService.navigatorKey.currentContext!, navigationService.navigatorKey.currentContext!,

@ -193,7 +193,7 @@ class DoctorsListResponseModel {
serviceID = json['ServiceID']; serviceID = json['ServiceID'];
setupID = json['SetupID']; setupID = json['SetupID'];
speciality = json['Speciality'] != null ? json['Speciality'].cast<String>() : []; speciality = json['Speciality'] != null ? json['Speciality'].cast<String>() : [];
// specialityN = json['SpecialityN'].cast<String>(); specialityN = json['SpecialityN'] != null ? json['SpecialityN'].cast<String>() : [];
transactionType = json['TransactionType']; transactionType = json['TransactionType'];
virtualEmploymentType = json['VirtualEmploymentType']; virtualEmploymentType = json['VirtualEmploymentType'];
workingHours = json['WorkingHours']; workingHours = json['WorkingHours'];

@ -61,4 +61,14 @@ class LaserBodyPart {
data['CategoryNameN'] = this.categoryNameN; data['CategoryNameN'] = this.categoryNameN;
return data; return data;
} }
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is LaserBodyPart &&
runtimeType == other.runtimeType &&
id == other.id;
@override
int get hashCode => id.hashCode;
} }

@ -530,6 +530,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
void setTransportationOption(PatientERTransportationMethod item) { void setTransportationOption(PatientERTransportationMethod item) {
selectedTransportOption = item; selectedTransportOption = item;
notifyListeners();
} }
void updateCallingPlace(AmbulanceCallingPlace? value) { void updateCallingPlace(AmbulanceCallingPlace? value) {

@ -919,8 +919,6 @@ class HmgServicesRepoImp implements HmgServicesRepo {
@override @override
Future<Either<Failure, GenericApiModel<List<VitalSignResModel>>>> getPatientVitalSign() async { Future<Either<Failure, GenericApiModel<List<VitalSignResModel>>>> getPatientVitalSign() async {
Map<String, dynamic> requestBody = { Map<String, dynamic> requestBody = {
}; };
try { try {

@ -1,4 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.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';
/// UI-only helper model for Vital Sign cards. /// UI-only helper model for Vital Sign cards.
@ -49,7 +51,7 @@ class VitalSignUiModel {
} }
// Warning for both low and overweight/underweight BMI, since they can indicate potential health issues. // Warning for both low and overweight/underweight BMI, since they can indicate potential health issues.
if (s.contains('low') || s.contains('underweight') || s.contains('overweight')) { if (s.contains('low') || s.contains("OverWeight") || s.contains("وزن زائد") || s.contains("UnderWeight") || s.contains("وزن ناقص")) {
final Color yellowBg = AppColors.highAndLow.withValues(alpha: 0.12); final Color yellowBg = AppColors.highAndLow.withValues(alpha: 0.12);
return VitalSignUiModel( return VitalSignUiModel(
iconBg: yellowBg, iconBg: yellowBg,
@ -96,13 +98,13 @@ class VitalSignUiModel {
final double bmiResult = double.tryParse(bmi.toString()) ?? 0; final double bmiResult = double.tryParse(bmi.toString()) ?? 0;
if (bmiResult >= 30) { if (bmiResult >= 30) {
bmiStatus = "High"; bmiStatus = LocaleKeys.obese.tr();
} else if (bmiResult < 30 && bmiResult >= 25) { } else if (bmiResult < 30 && bmiResult >= 25) {
bmiStatus = "Overweight"; bmiStatus = LocaleKeys.overWeight.tr();
} else if (bmiResult < 25 && bmiResult >= 18.5) { } else if (bmiResult < 25 && bmiResult >= 18.5) {
bmiStatus = "Normal"; bmiStatus = LocaleKeys.normal.tr();
} else if (bmiResult < 18.5) { } else if (bmiResult < 18.5) {
bmiStatus = "Underweight"; bmiStatus = LocaleKeys.underWeight.tr();
} }
// if (bmi == null) return 'N/A'; // if (bmi == null) return 'N/A';

@ -5,6 +5,7 @@ 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/api_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.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/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_clinic_schedule_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/models/resp_models/get_livecare_immediate_fees_response_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_immediate_fees_response_model.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_patient_livecare_history_response_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_patient_livecare_history_response_model.dart';
@ -13,6 +14,9 @@ import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class ImmediateLiveCareRepo { abstract class ImmediateLiveCareRepo {
Future<Either<Failure, GenericApiModel<List<GetLiveCareClinicListResponseModel>>>> getLiveCareImmediateClinicsList(int age, int genderID, {Function(dynamic)? onSuccess, Function(String)? onError}); Future<Either<Failure, GenericApiModel<List<GetLiveCareClinicListResponseModel>>>> getLiveCareImmediateClinicsList(int age, int genderID, {Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<List<LiveCareClinicScheduleResponse>>>> getLiveCareImmediateClinicSchedule(int age, int genderID, int serviceID,
{Function(dynamic)? onSuccess, Function(String)? onError});
Future<Either<Failure, GenericApiModel<LiveCareImmediateAppointmentFeesList>>> getLiveCareImmediateAppointmentFees(int age, int genderID, int serviceID, Future<Either<Failure, GenericApiModel<LiveCareImmediateAppointmentFeesList>>> getLiveCareImmediateAppointmentFees(int age, int genderID, int serviceID,
{Function(dynamic)? onSuccess, Function(String)? onError}); {Function(dynamic)? onSuccess, Function(String)? onError});
@ -203,4 +207,47 @@ class ImmediateLiveCareRepoImp implements ImmediateLiveCareRepo {
return Left(UnknownFailure(e.toString())); return Left(UnknownFailure(e.toString()));
} }
} }
@override
Future<Either<Failure, GenericApiModel<List<LiveCareClinicScheduleResponse>>>> getLiveCareImmediateClinicSchedule(int age, int genderID, int serviceID,
{Function(dynamic p1)? onSuccess, Function(String p1)? onError}) async {
Map<String, dynamic> mapDevice = {
"Age": age,
"Gender": genderID,
"ServiceID": serviceID,
};
try {
GenericApiModel<List<LiveCareClinicScheduleResponse>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_LIVECARE_CLINIC_TIMING,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
// onError!(error);
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final respObject = response['PatientER_GetClinicsServiceTimingsList'];
final liveCareScheduleObj = respObject.map((item) => LiveCareClinicScheduleResponse.fromJson(item as Map<String, dynamic>)).toList().cast<LiveCareClinicScheduleResponse>();
apiResponse = GenericApiModel<List<LiveCareClinicScheduleResponse>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: liveCareScheduleObj,
);
} 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()));
}
}
} }

@ -11,6 +11,7 @@ import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_repo.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_repo.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_clinic_schedule_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/models/resp_models/get_livecare_immediate_fees_response_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_immediate_fees_response_model.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_patient_livecare_history_response_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_patient_livecare_history_response_model.dart';
@ -46,6 +47,8 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
List<PatientLiveCareHistory> patientLiveCareHistoryList = []; List<PatientLiveCareHistory> patientLiveCareHistoryList = [];
bool patientHasPendingLiveCareRequest = false; bool patientHasPendingLiveCareRequest = false;
List<LiveCareClinicScheduleResponse> liveCareClinicScheduleList = [];
late AppState _appState; late AppState _appState;
Duration countdownDuration = Duration(minutes: 1, seconds: 0); Duration countdownDuration = Duration(minutes: 1, seconds: 0);
@ -265,6 +268,33 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
); );
} }
Future<void> getLiveCareImmediateClinicSchedule({int? serviceID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
liveCareClinicScheduleList.clear();
notifyListeners();
final result =
await immediateLiveCareRepo.getLiveCareImmediateClinicSchedule(_appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!, serviceID!);
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) {
liveCareClinicScheduleList = apiResponse.data!;
// immediateLiveCareClinicsList.sort((a, b) => b.isOnline!.compareTo(a.isOnline!));
// isImmediateLiveCareClinicsLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
void startTimer() { void startTimer() {
timer = Timer.periodic(const Duration(seconds: 1), (_) => addTime()); timer = Timer.periodic(const Duration(seconds: 1), (_) => addTime());
notifyListeners(); notifyListeners();

@ -0,0 +1,71 @@
class LiveCareClinicScheduleResponse {
int? iD;
int? serviceID;
int? dayOfWeek;
String? dayOfWeekStr;
bool? isActive;
String? createdOn;
String? createdBy;
bool? projectOutSA;
String? dayOfWeekStrN;
List<ShiftTimings>? shiftTimings;
LiveCareClinicScheduleResponse({this.iD, this.serviceID, this.dayOfWeek, this.dayOfWeekStr, this.isActive, this.createdOn, this.createdBy, this.projectOutSA, this.dayOfWeekStrN, this.shiftTimings});
LiveCareClinicScheduleResponse.fromJson(Map<String, dynamic> json) {
iD = json['ID'];
serviceID = json['ServiceID'];
dayOfWeek = json['DayOfWeek'];
dayOfWeekStr = json['DayOfWeekStr'];
isActive = json['IsActive'];
createdOn = json['CreatedOn'];
createdBy = json['CreatedBy'];
projectOutSA = json['ProjectOutSA'];
dayOfWeekStrN = json['DayOfWeekStrN'];
if (json['ShiftTimings'] != null) {
shiftTimings = <ShiftTimings>[];
json['ShiftTimings'].forEach((v) {
shiftTimings!.add(new ShiftTimings.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ID'] = this.iD;
data['ServiceID'] = this.serviceID;
data['DayOfWeek'] = this.dayOfWeek;
data['DayOfWeekStr'] = this.dayOfWeekStr;
data['IsActive'] = this.isActive;
data['CreatedOn'] = this.createdOn;
data['CreatedBy'] = this.createdBy;
data['ProjectOutSA'] = this.projectOutSA;
data['DayOfWeekStrN'] = this.dayOfWeekStrN;
if (this.shiftTimings != null) {
data['ShiftTimings'] = this.shiftTimings!.map((v) => v.toJson()).toList();
}
return data;
}
}
class ShiftTimings {
String? endTime;
int? shiftID;
String? startTime;
ShiftTimings({this.endTime, this.shiftID, this.startTime});
ShiftTimings.fromJson(Map<String, dynamic> json) {
endTime = json['EndTime'];
shiftID = json['ShiftID'];
startTime = json['StartTime'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['EndTime'] = this.endTime;
data['ShiftID'] = this.shiftID;
data['StartTime'] = this.startTime;
return data;
}
}

@ -4,6 +4,7 @@ import 'dart:core';
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/common_models/data_points.dart'; import 'package:hmg_patient_app_new/core/common_models/data_points.dart';
import 'package:hmg_patient_app_new/core/dependencies.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/core/utils/date_util.dart';
@ -71,6 +72,9 @@ class LabViewModel extends ChangeNotifier {
List<TestDetails> uniqueTestsList = []; List<TestDetails> uniqueTestsList = [];
List<String> indexedCharacterForUniqueTest = []; List<String> indexedCharacterForUniqueTest = [];
List<TestDetails> filteredUniqueTestsList = [];
List<String> filteredIndexedCharacterForUniqueTest = [];
double maxY = 0.0; double maxY = 0.0;
double minY = double.infinity; double minY = double.infinity;
double maxX = double.infinity; double maxX = double.infinity;
@ -84,6 +88,9 @@ class LabViewModel extends ChangeNotifier {
LabOrderResponseByAi? labOrderResponseByAi; LabOrderResponseByAi? labOrderResponseByAi;
LabOrdersResponseByAi? labOrdersResponseByAi; LabOrdersResponseByAi? labOrdersResponseByAi;
bool isLabAIAnalysisNeedsToBeShown = true;
bool isLabResultsHistoryShowMore = false;
LabViewModel({required this.labRepo, required this.errorHandlerService, required this.navigationService}); LabViewModel({required this.labRepo, required this.errorHandlerService, required this.navigationService});
initLabProvider() { initLabProvider() {
@ -93,6 +100,8 @@ class LabViewModel extends ChangeNotifier {
labOrderTests.clear(); labOrderTests.clear();
isLabOrdersLoading = true; isLabOrdersLoading = true;
isLabResultsLoading = true; isLabResultsLoading = true;
isLabAIAnalysisNeedsToBeShown = true;
isLabResultsHistoryShowMore = false;
patientLabOrdersByClinic.clear(); patientLabOrdersByClinic.clear();
patientLabOrdersByHospital.clear(); patientLabOrdersByHospital.clear();
patientLabOrdersViewList.clear(); patientLabOrdersViewList.clear();
@ -111,6 +120,16 @@ class LabViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
setIsLabAIAnalysisNeedsToBeShown(bool isLabAIAnalysisNeedsToBeShown) {
this.isLabAIAnalysisNeedsToBeShown = isLabAIAnalysisNeedsToBeShown;
notifyListeners();
}
setIsLabResultsHistoryShowMore() {
isLabResultsHistoryShowMore = !isLabResultsHistoryShowMore;
notifyListeners();
}
void setIsSortByClinic(bool value) { void setIsSortByClinic(bool value) {
isSortByClinic = value; isSortByClinic = value;
patientLabOrdersViewList = isSortByClinic ? patientLabOrdersByClinic : patientLabOrdersByHospital; patientLabOrdersViewList = isSortByClinic ? patientLabOrdersByClinic : patientLabOrdersByHospital;
@ -218,7 +237,8 @@ class LabViewModel extends ChangeNotifier {
final clinicMap = <String, List<PatientLabOrdersResponseModel>>{}; final clinicMap = <String, List<PatientLabOrdersResponseModel>>{};
final hospitalMap = <String, List<PatientLabOrdersResponseModel>>{}; final hospitalMap = <String, List<PatientLabOrdersResponseModel>>{};
if (query.isEmpty) { if (query.isEmpty) {
// filteredLabOrders = List.from(patientLabOrders); // reset filteredLabOrders = List.from(patientLabOrders); // reset
filteredUniqueTestsList = List.from(uniqueTestsList);
for (var order in patientLabOrders) { for (var order in patientLabOrders) {
final clinicKey = (order.clinicDescription ?? 'Unknown').trim(); final clinicKey = (order.clinicDescription ?? 'Unknown').trim();
clinicMap.putIfAbsent(clinicKey, () => []).add(order); clinicMap.putIfAbsent(clinicKey, () => []).add(order);
@ -234,7 +254,10 @@ class LabViewModel extends ChangeNotifier {
final descriptions = order.testDetails?.map((d) => d.description?.toLowerCase()).toList() ?? []; final descriptions = order.testDetails?.map((d) => d.description?.toLowerCase()).toList() ?? [];
return descriptions.any((desc) => desc != null && desc.contains(query.toLowerCase())); return descriptions.any((desc) => desc != null && desc.contains(query.toLowerCase()));
}).toList(); }).toList();
// patientLabOrders = filteredLabOrders; filteredUniqueTestsList = uniqueTestsList.where((test) {
final desc = test.description?.toLowerCase() ?? '';
return desc.contains(query.toLowerCase());
}).toList();
for (var order in filteredLabOrders) { for (var order in filteredLabOrders) {
final clinicKey = (order.clinicDescription ?? 'Unknown').trim(); final clinicKey = (order.clinicDescription ?? 'Unknown').trim();
clinicMap.putIfAbsent(clinicKey, () => []).add(order); clinicMap.putIfAbsent(clinicKey, () => []).add(order);
@ -246,6 +269,14 @@ class LabViewModel extends ChangeNotifier {
patientLabOrdersByHospital = hospitalMap.values.toList(); patientLabOrdersByHospital = hospitalMap.values.toList();
patientLabOrdersViewList = isSortByClinic ? patientLabOrdersByClinic : patientLabOrdersByHospital; patientLabOrdersViewList = isSortByClinic ? patientLabOrdersByClinic : patientLabOrdersByHospital;
} }
// Rebuild filtered indexed characters
filteredIndexedCharacterForUniqueTest = [];
for (var test in filteredUniqueTestsList) {
String label = test.description ?? "";
if (label.isEmpty) continue;
if (filteredIndexedCharacterForUniqueTest.contains(label[0].toLowerCase())) continue;
filteredIndexedCharacterForUniqueTest.add(label[0].toLowerCase());
}
notifyListeners(); notifyListeners();
} }
@ -280,6 +311,10 @@ class LabViewModel extends ChangeNotifier {
for (var element in uniqueTests) { for (var element in uniqueTests) {
labOrderTests.add(element.description ?? ""); labOrderTests.add(element.description ?? "");
} }
// Initialize filtered lists with full data
filteredUniqueTestsList = List.from(uniqueTestsList);
filteredIndexedCharacterForUniqueTest = List.from(indexedCharacterForUniqueTest);
} }
Future<void> getLabResultsByAppointmentNo( Future<void> getLabResultsByAppointmentNo(
@ -389,15 +424,17 @@ class LabViewModel extends ChangeNotifier {
} else if (apiResponse.messageStatus == 1) { } else if (apiResponse.messageStatus == 1) {
var sortedResult = sort(apiResponse.data!); var sortedResult = sort(apiResponse.data!);
var recentThree = sortedResult.take(3).toList(); var recentThree = sortedResult.take(3).toList();
mainLabResults = recentThree; mainLabResults = sortedResult;
double highRefrenceValue = double.negativeInfinity; double highRefrenceValue = double.negativeInfinity;
String? flagForHighReferenceRange; String? flagForHighReferenceRange;
double lowRefenceValue = double.infinity; double lowRefenceValue = double.infinity;
String? flagForLowReferenceRange; String? flagForLowReferenceRange;
sortedResult.take(3).toList().reversed.forEach((element) { sortedResult.toList().reversed.forEach((element) {
try { try {
shouldShowGraph = isNumeric(element.resultValue!);
// if(isNumeric(element.resultValue!)){
var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!); var dateTime = DateUtil.convertStringToDate(element.verifiedOnDateTime!);
var resultValue = double.parse(element.resultValue!); var resultValue = double.parse(element.resultValue!);
// var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? ""); // var transformedValue = transformValueInRange(double.parse(element.resultValue!), element.calculatedResultFlag ?? "");
@ -409,13 +446,22 @@ class LabViewModel extends ChangeNotifier {
if (resultValue < minY) { if (resultValue < minY) {
minY = resultValue; minY = resultValue;
} }
if (highRefrenceValue < double.parse(element.referenceHigh ?? "0.0")) { // if (highRefrenceValue < double.parse(element.referenceHigh ?? "0.0")) {
highRefrenceValue = double.parse(element.referenceHigh ?? "0.0"); highRefrenceValue = double.parse(element.referenceHigh ?? "0.0");
flagForHighReferenceRange = element.calculatedResultFlag; flagForHighReferenceRange = element.calculatedResultFlag;
} // }
if (lowRefenceValue > double.parse(element.referenceLow ?? "0.0")) { // if (lowRefenceValue > double.parse(element.referenceLow ?? "0.0")) {
lowRefenceValue = double.parse(element.referenceLow ?? "0.0"); lowRefenceValue = double.parse(element.referenceLow ?? "0.0");
flagForLowReferenceRange = element.calculatedResultFlag; flagForLowReferenceRange = element.calculatedResultFlag;
// }
if(double.parse(element.referenceHigh ?? "0.0") == 0 ){
highRefrenceValue = double.negativeInfinity;
}
if(double.parse(element.referenceLow ?? "0.0") == 0 ){
lowRefenceValue = double.negativeInfinity;
} }
filteredGraphValues.add(DataPoint( filteredGraphValues.add(DataPoint(
@ -427,28 +473,38 @@ class LabViewModel extends ChangeNotifier {
time: DateUtil.convertStringToDate(element.verifiedOnDateTime), time: DateUtil.convertStringToDate(element.verifiedOnDateTime),
referenceValue: element.calculatedResultFlag ?? "", referenceValue: element.calculatedResultFlag ?? "",
)); ));
} catch (e) {}
} catch (e) {
}
}); });
if (flagForLowReferenceRange == null && flagForHighReferenceRange == null) { if (flagForLowReferenceRange == null && flagForHighReferenceRange == null) {
highRefrenceValue = maxY; highRefrenceValue = maxY;
lowRefenceValue = minY; lowRefenceValue = minY;
} }
// //
if (minY > lowRefenceValue) { if (lowRefenceValue != double.negativeInfinity &&minY > lowRefenceValue) {
minY = lowRefenceValue - getInterval(); minY = lowRefenceValue - getInterval();
}else if (highRefrenceValue != double.negativeInfinity && minY > highRefrenceValue) {
minY = highRefrenceValue - getInterval();
} }
this.flagForHighReferenceRange = flagForHighReferenceRange; this.flagForHighReferenceRange = flagForHighReferenceRange;
this.flagForLowReferenceRange = flagForLowReferenceRange; this.flagForLowReferenceRange = flagForLowReferenceRange;
highTransformedReferenceValue = double.parse(transformValueInRange(highRefrenceValue, flagForHighReferenceRange ?? "").toStringAsFixed(1)); highTransformedReferenceValue = double.parse(transformValueInRange(highRefrenceValue, flagForHighReferenceRange ?? "").toStringAsFixed(1));
lowTransformedReferenceValue = double.parse(transformValueInRange(lowRefenceValue, flagForLowReferenceRange ?? "").toStringAsFixed(1)); lowTransformedReferenceValue = double.parse(transformValueInRange(lowRefenceValue, flagForLowReferenceRange ?? "").toStringAsFixed(1));
this.highRefrenceValue = double.parse(highRefrenceValue.toStringAsFixed(1)); this.highRefrenceValue = double.parse(highRefrenceValue.toStringAsFixed(2));
this.lowRefenceValue = double.parse(lowRefenceValue.toStringAsFixed(1)); this.lowRefenceValue = double.parse(lowRefenceValue.toStringAsFixed(2));
if(maxY<highRefrenceValue){ if(highRefrenceValue != double.negativeInfinity &&maxY<highRefrenceValue){
maxY = highRefrenceValue; maxY = highRefrenceValue+ getInterval();
maxX = maxY;
}else if(lowRefenceValue != double.negativeInfinity && maxY<lowRefenceValue){
maxY = lowRefenceValue+ getInterval()/2;
maxX = maxY; maxX = maxY;
} }
// if (maxY < highRefrenceValue) { // if (maxY < highRefrenceValue) {
// minY = highRefrenceValue - getInterval(); // minY = highRefrenceValue - getInterval();
// } // }
@ -470,6 +526,10 @@ class LabViewModel extends ChangeNotifier {
}, },
); );
} }
bool isNumeric(String s) {
return num.tryParse(s) != null;
}
num getInterval() { num getInterval() {
// return .1; // return .1;
var maxX = maxY; var maxX = maxY;
@ -787,7 +847,16 @@ class LabViewModel extends ChangeNotifier {
Future<void> getAiOverviewLabOrders({required PatientLabOrdersResponseModel labOrder, required String loadingText}) async { Future<void> getAiOverviewLabOrders({required PatientLabOrdersResponseModel labOrder, required String loadingText}) async {
// LoadingUtils.showFullScreenLoader(loadingText: "Loading and analysing your data,\nPlease be patient and let the AI do the magic. \nPlease be patient, This might take some time."); // LoadingUtils.showFullScreenLoader(loadingText: "Loading and analysing your data,\nPlease be patient and let the AI do the magic. \nPlease be patient, This might take some time.");
LoadingUtils.showFullScreenLoader(loadingText: loadingText); // LoadingUtils.showFullScreenLoader(loadingText: loadingText);
isLabAIAnalysisNeedsToBeShown = true;
notifyListeners();
LoaderBottomSheet.showLoader(
loadingText: loadingText,
showCloseButton: true,
onCloseTap: () {
setIsLabAIAnalysisNeedsToBeShown(false);
});
List<Map<String, dynamic>> results = []; List<Map<String, dynamic>> results = [];
Map<String, dynamic> orderData = {"order_date": labOrder.orderDate ?? "", "clinic": labOrder.clinicDescription ?? "", "doctor": labOrder.doctorName ?? "", "results": []}; Map<String, dynamic> orderData = {"order_date": labOrder.orderDate ?? "", "clinic": labOrder.clinicDescription ?? "", "doctor": labOrder.doctorName ?? "", "results": []};
List<Map<String, dynamic>> testResults = []; List<Map<String, dynamic>> testResults = [];
@ -809,26 +878,38 @@ class LabViewModel extends ChangeNotifier {
final result = await labRepo.getPatientAiOverViewLabOrders(results); final result = await labRepo.getPatientAiOverViewLabOrders(results);
result.fold( result.fold(
(failure) async { (failure) async {
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
if (isLabAIAnalysisNeedsToBeShown) {
await errorHandlerService.handleError(failure: failure); await errorHandlerService.handleError(failure: failure);
}
}, },
(apiResponse) { (apiResponse) {
LoadingUtils.hideFullScreenLoader(); LoaderBottomSheet.hideLoader();
if (apiResponse.messageStatus == 2) { if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) { } else if (apiResponse.messageStatus == 1) {
if (isLabAIAnalysisNeedsToBeShown) {
labOrdersResponseByAi = apiResponse.data; labOrdersResponseByAi = apiResponse.data;
navigationService.push( navigationService.push(
MaterialPageRoute(builder: (_) => LabAiAnalysisDetailedPage()), CustomPageRoute(
direction: AxisDirection.down,
page: LabAiAnalysisDetailedPage(),
),
); );
} }
}
}, },
); );
LoadingUtils.hideFullScreenLoader(); // LoadingUtils.hideFullScreenLoader();
} }
Future<void> getAiOverviewSingleLabResult({required String langId, required LabResult recentLabResult, required String loadingText}) async { Future<void> getAiOverviewSingleLabResult({required String langId, required LabResult recentLabResult, required String loadingText}) async {
LoaderBottomSheet.showLoader(loadingText: loadingText); LoaderBottomSheet.showLoader(
loadingText: loadingText,
showCloseButton: true,
onCloseTap: () {
setIsLabAIAnalysisNeedsToBeShown(false);
});
List<Map<String, dynamic>> results = []; List<Map<String, dynamic>> results = [];
results.add({ results.add({
"Description": recentLabResult.description ?? '', "Description": recentLabResult.description ?? '',
@ -838,20 +919,25 @@ class LabViewModel extends ChangeNotifier {
"ReferanceRange": recentLabResult.referanceRange ?? '', "ReferanceRange": recentLabResult.referanceRange ?? '',
}); });
var payload = {"patient_id": currentlySelectedPatientOrder!.patientID, "language_id": langId, "lab_results": results}; // var payload = {"patient_id": currentlySelectedPatientOrder!.patientID, "language_id": langId, "lab_results": results};
var payload = {"patient_id": getIt.get<AppState>().getAuthenticatedUser()!.patientId, "language_id": langId, "lab_results": results};
final result = await labRepo.getPatientAiOverViewLabOrder(payload); final result = await labRepo.getPatientAiOverViewLabOrder(payload);
result.fold( result.fold(
(failure) async { (failure) async {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
if (isLabAIAnalysisNeedsToBeShown) {
await errorHandlerService.handleError(failure: failure); await errorHandlerService.handleError(failure: failure);
}
}, },
(apiResponse) { (apiResponse) {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
if (apiResponse.messageStatus == 2) { if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) { } else if (apiResponse.messageStatus == 1) {
if (isLabAIAnalysisNeedsToBeShown) {
labOrderResponseByAi = apiResponse.data; labOrderResponseByAi = apiResponse.data;
notifyListeners(); notifyListeners();
} }
}
}, },
); );

@ -87,6 +87,8 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier {
hmcCount = registeredDoctorMap.hmcSize; hmcCount = registeredDoctorMap.hmcSize;
hmgCount = registeredDoctorMap.hmgSize; hmgCount = registeredDoctorMap.hmgSize;
hospitalList!.sort((a, b) => num.parse(a.distanceInKMs!).compareTo(num.parse(b.distanceInKMs!)));
getDisplayList(); getDisplayList();
} }

@ -0,0 +1,30 @@
class AppointmentRatedResponseModel {
int? appointmentNo;
int? clinicID;
int? doctorID;
bool? isAllowedToRate;
bool? isAppointmentRated;
int? projectID;
AppointmentRatedResponseModel({this.appointmentNo, this.clinicID, this.doctorID, this.isAllowedToRate, this.isAppointmentRated, this.projectID});
AppointmentRatedResponseModel.fromJson(Map<String, dynamic> json) {
appointmentNo = json['AppointmentNo'];
clinicID = json['ClinicID'];
doctorID = json['DoctorID'];
isAllowedToRate = json['IsAllowedToRate'];
isAppointmentRated = json['IsAppointmentRated'];
projectID = json['ProjectID'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['AppointmentNo'] = this.appointmentNo;
data['ClinicID'] = this.clinicID;
data['DoctorID'] = this.doctorID;
data['IsAllowedToRate'] = this.isAllowedToRate;
data['IsAppointmentRated'] = this.isAppointmentRated;
data['ProjectID'] = this.projectID;
return data;
}
}

@ -75,9 +75,7 @@ class HospitalsModel {
} }
String? getName(bool isArabic) { String? getName(bool isArabic) {
if (isArabic) {
return "$nameN";
}
return name; return name;
} }

@ -51,6 +51,7 @@ class PatientAppointmentHistoryResponseModel {
bool? isExecludeDoctor; bool? isExecludeDoctor;
dynamic isFollowup; dynamic isFollowup;
bool? isLiveCareAppointment; bool? isLiveCareAppointment;
bool? isLiveCareClinic;
bool? isInOutPatient; bool? isInOutPatient;
bool? isMedicalReportRequested; bool? isMedicalReportRequested;
bool? isOnlineCheckedIN; bool? isOnlineCheckedIN;
@ -73,6 +74,7 @@ class PatientAppointmentHistoryResponseModel {
num? patientShare; num? patientShare;
num? patientShareWithTax; num? patientShareWithTax;
num? patientTaxAmount; num? patientTaxAmount;
String? doctorNationalityFlagURL;
PatientAppointmentHistoryResponseModel({ PatientAppointmentHistoryResponseModel({
this.setupID, this.setupID,
@ -127,6 +129,7 @@ class PatientAppointmentHistoryResponseModel {
this.isExecludeDoctor, this.isExecludeDoctor,
this.isFollowup, this.isFollowup,
this.isLiveCareAppointment, this.isLiveCareAppointment,
this.isLiveCareClinic,
this.isMedicalReportRequested, this.isMedicalReportRequested,
this.isOnlineCheckedIN, this.isOnlineCheckedIN,
this.latitude, this.latitude,
@ -148,6 +151,7 @@ class PatientAppointmentHistoryResponseModel {
this.patientShare, this.patientShare,
this.patientShareWithTax, this.patientShareWithTax,
this.patientTaxAmount, this.patientTaxAmount,
this.doctorNationalityFlagURL,
}); });
PatientAppointmentHistoryResponseModel.fromJson(Map<String, dynamic> json) { PatientAppointmentHistoryResponseModel.fromJson(Map<String, dynamic> json) {
@ -203,6 +207,7 @@ class PatientAppointmentHistoryResponseModel {
isExecludeDoctor = json['IsExecludeDoctor']; isExecludeDoctor = json['IsExecludeDoctor'];
isFollowup = json['IsFollowup']; isFollowup = json['IsFollowup'];
isLiveCareAppointment = json['IsLiveCareAppointment']; isLiveCareAppointment = json['IsLiveCareAppointment'];
isLiveCareClinic = json['IsLiveCareClinic'];
isInOutPatient = json['IsInOutPatient']; isInOutPatient = json['IsInOutPatient'];
isMedicalReportRequested = json['IsMedicalReportRequested']; isMedicalReportRequested = json['IsMedicalReportRequested'];
isOnlineCheckedIN = json['IsOnlineCheckedIN']; isOnlineCheckedIN = json['IsOnlineCheckedIN'];
@ -235,6 +240,7 @@ class PatientAppointmentHistoryResponseModel {
patientShare = json['PatientShare']; patientShare = json['PatientShare'];
patientShareWithTax = json['PatientShareWithTax']; patientShareWithTax = json['PatientShareWithTax'];
patientTaxAmount = json['PatientTaxAmount']; patientTaxAmount = json['PatientTaxAmount'];
doctorNationalityFlagURL = json['DoctorNationalityFlagURL'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {

@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/core/exceptions/api_failure.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: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/book_appointments/models/resp_models/get_favorite_doctors_list.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_favorite_doctors_list.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/appointment_rated_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/rate_appointment_resp_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/rate_appointment_resp_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/get_tamara_installments_details_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/get_tamara_installments_details_response_model.dart';
@ -81,6 +82,13 @@ abstract class MyAppointmentsRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> convertPatientToCash({required int projectID}); Future<Either<Failure, GenericApiModel<dynamic>>> convertPatientToCash({required int projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> sendPatientUpdateRequest(); Future<Either<Failure, GenericApiModel<dynamic>>> sendPatientUpdateRequest();
Future<Either<Failure, GenericApiModel<dynamic>>> getDoctorsRatingCheck({
required int doctorID,
required int projectID,
required int clinicID,
required int appointmentNo,
});
} }
class MyAppointmentsRepoImp implements MyAppointmentsRepo { class MyAppointmentsRepoImp implements MyAppointmentsRepo {
@ -513,7 +521,10 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
try { try {
final list = response['PatientDoctorAppointmentResultList']; final list = response['PatientDoctorAppointmentResultList'];
final appointmentsList = list.map((item) => PatientAppointmentHistoryResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientAppointmentHistoryResponseModel>(); List<PatientAppointmentHistoryResponseModel> appointmentsList =
list.map((item) => PatientAppointmentHistoryResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientAppointmentHistoryResponseModel>();
// appointmentsList.removeWhere((element) => element.isActiveDoctorProfile == false);
apiResponse = GenericApiModel<List<PatientAppointmentHistoryResponseModel>>( apiResponse = GenericApiModel<List<PatientAppointmentHistoryResponseModel>>(
messageStatus: messageStatus, messageStatus: messageStatus,
@ -563,6 +574,8 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
final appointmentsList = (list as List).map((item) => GetFavoriteDoctorsListModel.fromJson(item as Map<String, dynamic>)).toList().cast<GetFavoriteDoctorsListModel>(); final appointmentsList = (list as List).map((item) => GetFavoriteDoctorsListModel.fromJson(item as Map<String, dynamic>)).toList().cast<GetFavoriteDoctorsListModel>();
appointmentsList.removeWhere((element) => element.isActive == false);
apiResponse = GenericApiModel<List<GetFavoriteDoctorsListModel>>( apiResponse = GenericApiModel<List<GetFavoriteDoctorsListModel>>(
messageStatus: messageStatus, messageStatus: messageStatus,
statusCode: statusCode, statusCode: statusCode,
@ -1072,4 +1085,50 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
return Left(UnknownFailure(e.toString())); return Left(UnknownFailure(e.toString()));
} }
} }
@override
Future<Either<Failure, GenericApiModel<AppointmentRatedResponseModel>>> getDoctorsRatingCheck({
required int doctorID,
required int projectID,
required int clinicID,
required int appointmentNo,
}) async {
Map<String, dynamic> mapDevice = {
"DoctorID": doctorID,
"ProjectID": projectID,
"ClinicID": clinicID,
"AppointmentNo": appointmentNo,
};
try {
GenericApiModel<AppointmentRatedResponseModel>? apiResponse;
Failure? failure;
await apiClient.post(
GET_DOCTORS_RATING_CHECK,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
AppointmentRatedResponseModel appointmentRatedResponseModel = AppointmentRatedResponseModel.fromJson(response['DoctorsRatingResponseModel'][0]);
apiResponse = GenericApiModel<AppointmentRatedResponseModel>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: appointmentRatedResponseModel,
);
} 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()));
}
}
} }

@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_favorite_doctors_list.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_favorite_doctors_list.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/appointemnet_filters.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/appointemnet_filters.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/appointment_rated_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ask_doctor_request_type_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/get_tamara_installments_details_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/get_tamara_installments_details_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
@ -87,6 +88,11 @@ class MyAppointmentsViewModel extends ChangeNotifier {
bool isShowNotEligibleDialog = false; bool isShowNotEligibleDialog = false;
String notEligibleErrorMsg = ""; String notEligibleErrorMsg = "";
bool isAppointmentAlreadyRated = false;
AppointmentRatedResponseModel? appointmentRatedResponseModel;
bool isAppointmentRatedResponseLoading = false;
MyAppointmentsViewModel({required this.myAppointmentsRepo, required this.errorHandlerService, required this.appState}); MyAppointmentsViewModel({required this.myAppointmentsRepo, required this.errorHandlerService, required this.appState});
void onTabChange(int index) { void onTabChange(int index) {
@ -94,6 +100,10 @@ class MyAppointmentsViewModel extends ChangeNotifier {
selectedTabIndex = index; selectedTabIndex = index;
start = null; start = null;
end = null; end = null;
// if (index == 0) {
// filteredAppointmentList.clear();
// filteredAppointmentList.addAll(patientAppointmentsHistoryList);
// }
notifyListeners(); notifyListeners();
} }
@ -666,9 +676,9 @@ class MyAppointmentsViewModel extends ChangeNotifier {
Future<void> getPatientFavouriteDoctors({bool forceRefresh = false, Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getPatientFavouriteDoctors({bool forceRefresh = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
// If data is already fetched and not forcing refresh, skip API call // If data is already fetched and not forcing refresh, skip API call
if (isFavouriteDoctorsDataFetched && !forceRefresh) { // if (isFavouriteDoctorsDataFetched && !forceRefresh) {
return; // return;
} // }
isPatientFavouriteDoctorsLoading = true; isPatientFavouriteDoctorsLoading = true;
patientFavouriteDoctorsList.clear(); patientFavouriteDoctorsList.clear();
@ -920,6 +930,7 @@ class MyAppointmentsViewModel extends ChangeNotifier {
isPatientHasQueueAppointment = false; isPatientHasQueueAppointment = false;
isAppointmentQueueDetailsLoading = true; isAppointmentQueueDetailsLoading = true;
notifyListeners(); notifyListeners();
final result = await myAppointmentsRepo.getPatientAppointmentQueueDetails( final result = await myAppointmentsRepo.getPatientAppointmentQueueDetails(
appointmentNo: patientArrivedAppointmentsHistoryList.first.appointmentNo, patientID: patientArrivedAppointmentsHistoryList.first.patientID); appointmentNo: patientArrivedAppointmentsHistoryList.first.appointmentNo, patientID: patientArrivedAppointmentsHistoryList.first.patientID);
@ -991,4 +1002,79 @@ class MyAppointmentsViewModel extends ChangeNotifier {
}, },
); );
} }
Future<void> getDoctorsRatingCheck({
required int doctorID,
required int projectID,
required int clinicID,
required int appointmentNo,
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
isAppointmentRatedResponseLoading = true;
notifyListeners();
final result = await myAppointmentsRepo.getDoctorsRatingCheck(
doctorID: doctorID,
projectID: projectID,
clinicID: clinicID,
appointmentNo: appointmentNo,
);
result.fold(
(failure) async {
// await errorHandlerService.handleError(failure: failure);
if (onError != null) onError(failure.message);
isAppointmentRatedResponseLoading = false;
notifyListeners();
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
if (onError != null) onError(apiResponse.errorMessage ?? "Unknown error");
isAppointmentRatedResponseLoading = false;
notifyListeners();
} else if (apiResponse.messageStatus == 1) {
appointmentRatedResponseModel = apiResponse.data!;
isAppointmentRatedResponseLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse.data);
}
}
},
);
}
Future<void> submitDoctorRating(
{required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel,
required int docRate,
required String docNote,
Function(dynamic)? onSuccess,
Function(String)? onError}) async {
final result = await myAppointmentsRepo.sendDoctorRate(
docRate,
patientAppointmentHistoryResponseModel.appointmentNo!,
patientAppointmentHistoryResponseModel.projectID!,
patientAppointmentHistoryResponseModel.doctorID!,
patientAppointmentHistoryResponseModel.clinicID!,
docNote,
patientAppointmentHistoryResponseModel.appointmentDate!,
patientAppointmentHistoryResponseModel.doctorNameObj!,
patientAppointmentHistoryResponseModel.projectName!,
patientAppointmentHistoryResponseModel.clinicName!);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError?.call(apiResponse.errorMessage ?? 'Unknown error');
} else if (apiResponse.messageStatus == 1) {
notifyListeners();
if (onSuccess != null) {
// onSuccess(apiResponse.data);
}
}
},
);
}
} }

@ -13,6 +13,8 @@ abstract class MyInvoicesRepo {
Future<Either<Failure, GenericApiModel<GetInvoiceDetailsResponseModel>>> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID}); Future<Either<Failure, GenericApiModel<GetInvoiceDetailsResponseModel>>> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> sendInvoiceEmail({required num appointmentNo, required int projectID}); Future<Either<Failure, GenericApiModel<dynamic>>> sendInvoiceEmail({required num appointmentNo, required int projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> downloadInvoice({required String setupId, required int invoiceNo, required int projectID});
} }
class MyInvoicesRepoImp implements MyInvoicesRepo { class MyInvoicesRepoImp implements MyInvoicesRepo {
@ -138,4 +140,42 @@ class MyInvoicesRepoImp implements MyInvoicesRepo {
return Left(UnknownFailure(e.toString())); return Left(UnknownFailure(e.toString()));
} }
} }
@override
Future<Either<Failure, GenericApiModel>> downloadInvoice({required String setupId, required int invoiceNo, required int projectID}) async {
Map<String, dynamic> mapDevice = {
"SetupID": setupId,
"ProjectID": projectID,
"InvoiceNo": invoiceNo,
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
DOWNLOAD_INVOICE_PDF,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response["InvoiceReportPDFContent"],
);
} 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()));
}
}
} }

@ -26,6 +26,8 @@ class MyInvoicesViewModel extends ChangeNotifier {
TextEditingController filterSearchController = TextEditingController(); TextEditingController filterSearchController = TextEditingController();
String? selectedFilterItem; String? selectedFilterItem;
String? downloadInvoicePDFBase64 = "";
MyInvoicesViewModel({required this.myInvoicesRepo, required this.errorHandlerService, required this.navServices}); MyInvoicesViewModel({required this.myInvoicesRepo, required this.errorHandlerService, required this.navServices});
setInvoicesListLoading() { setInvoicesListLoading() {
@ -68,7 +70,6 @@ class MyInvoicesViewModel extends ChangeNotifier {
Future<void> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myInvoicesRepo.getInvoiceDetails(appointmentNo: appointmentNo, invoiceNo: invoiceNo, projectID: projectID); final result = await myInvoicesRepo.getInvoiceDetails(appointmentNo: appointmentNo, invoiceNo: invoiceNo, projectID: projectID);
result.fold( result.fold(
(failure) async { (failure) async {
isInvoiceDetailsLoading = false; isInvoiceDetailsLoading = false;
@ -93,6 +94,32 @@ class MyInvoicesViewModel extends ChangeNotifier {
); );
} }
Future<void> downloadInvoicePDF({required String setupId, required int invoiceNo, required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myInvoicesRepo.downloadInvoice(setupId: setupId, invoiceNo: invoiceNo, projectID: projectID);
result.fold(
(failure) async {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data != null && apiResponse.data!.isNotEmpty) {
downloadInvoicePDFBase64 = apiResponse.data!;
} else {
downloadInvoicePDFBase64 = "";
}
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> sendInvoiceEmail({required num appointmentNo, required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> sendInvoiceEmail({required num appointmentNo, required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myInvoicesRepo.sendInvoiceEmail(appointmentNo: appointmentNo, projectID: projectID); final result = await myInvoicesRepo.sendInvoiceEmail(appointmentNo: appointmentNo, projectID: projectID);

@ -12,6 +12,10 @@ abstract class NotificationsRepo {
required int pagingSize, required int pagingSize,
required int currentPage, required int currentPage,
}); });
Future<Either<Failure, GenericApiModel<List<NotificationResponseModel>>>> markAsRead({
required int notificationID,
});
} }
class NotificationsRepoImp implements NotificationsRepo { class NotificationsRepoImp implements NotificationsRepo {
@ -75,4 +79,38 @@ class NotificationsRepoImp implements NotificationsRepo {
return Left(UnknownFailure(e.toString())); return Left(UnknownFailure(e.toString()));
} }
} }
@override
Future<Either<Failure, GenericApiModel<List<NotificationResponseModel>>>> markAsRead({required int notificationID}) async {
Map<String, dynamic> mapDevice = {"NotificationPoolID": notificationID};
try {
GenericApiModel<List<NotificationResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
PUSH_NOTIFICATION_SET_MESSAGES_FROM_POOL_AS_READ,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel<List<NotificationResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: [],
);
} 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()));
}
}
} }

@ -7,13 +7,15 @@ class NotificationsViewModel extends ChangeNotifier {
bool isNotificationsLoading = false; bool isNotificationsLoading = false;
bool hasMoreNotifications = true; bool hasMoreNotifications = true;
int unreadNotificationsCount = 0;
NotificationsRepo notificationsRepo; NotificationsRepo notificationsRepo;
ErrorHandlerService errorHandlerService; ErrorHandlerService errorHandlerService;
List<NotificationResponseModel> notificationsList = []; List<NotificationResponseModel> notificationsList = [];
int currentPage = 0; int currentPage = 0;
int pagingSize = 14; int pagingSize = 50;
int notificationStatusID = 2; // Default to status 2 (e.g., unread) int notificationStatusID = 2; // Default to status 2 (e.g., unread)
NotificationsViewModel({ NotificationsViewModel({
@ -46,6 +48,7 @@ class NotificationsViewModel extends ChangeNotifier {
Function(String)? onError, Function(String)? onError,
}) async { }) async {
isNotificationsLoading = true; isNotificationsLoading = true;
unreadNotificationsCount = 0;
notifyListeners(); notifyListeners();
final result = await notificationsRepo.getAllNotifications( final result = await notificationsRepo.getAllNotifications(
@ -78,6 +81,11 @@ class NotificationsViewModel extends ChangeNotifier {
} }
notificationsList.addAll(newNotifications); notificationsList.addAll(newNotifications);
for (var notification in notificationsList) {
if (notification.isRead == false) {
unreadNotificationsCount++;
}
}
currentPage++; currentPage++;
notifyListeners(); notifyListeners();
@ -89,6 +97,21 @@ class NotificationsViewModel extends ChangeNotifier {
); );
} }
Future<void> markAsRead({
int notificationID = 0,
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
final result = await notificationsRepo.markAsRead(notificationID: notificationID);
result.fold(
(failure) async {},
(apiResponse) {
refreshNotifications();
},
);
}
Future<void> refreshNotifications({ Future<void> refreshNotifications({
Function(dynamic)? onSuccess, Function(dynamic)? onSuccess,
Function(String)? onError, Function(String)? onError,

@ -54,6 +54,7 @@ abstract class SymptomsCheckerRepo {
Future<Either<Failure, GenericApiModel<List<GetClinicDetailsResponseModel>>>> getClinicDetails({ Future<Either<Failure, GenericApiModel<List<GetClinicDetailsResponseModel>>>> getClinicDetails({
required String categoryName, required String categoryName,
required String language,
required String userSessionToken, required String userSessionToken,
}); });
} }
@ -400,6 +401,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
@override @override
Future<Either<Failure, GenericApiModel<List<GetClinicDetailsResponseModel>>>> getClinicDetails({ Future<Either<Failure, GenericApiModel<List<GetClinicDetailsResponseModel>>>> getClinicDetails({
required String categoryName, required String categoryName,
required String language,
required String userSessionToken, required String userSessionToken,
}) async { }) async {
Map<String, String> headers = { Map<String, String> headers = {
@ -413,7 +415,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
Failure? failure; Failure? failure;
await apiClient.get( await apiClient.get(
"${ApiConsts.getClinicFromCondition}$categoryName", "${ApiConsts.getClinicFromCondition}$categoryName&language=$language",
apiHeaders: headers, apiHeaders: headers,
isExternal: true, isExternal: true,
isAllowAny: true, isAllowAny: true,

@ -1079,6 +1079,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
final result = await symptomsCheckerRepo.getClinicDetails( final result = await symptomsCheckerRepo.getClinicDetails(
categoryName: categoryName, categoryName: categoryName,
language: appState.isArabic() ? 'ar' : 'en',
userSessionToken: currentSessionAuthToken, userSessionToken: currentSessionAuthToken,
); );

@ -13,13 +13,13 @@ class TodoSectionViewModel extends ChangeNotifier {
String? notificationsCount = "0"; String? notificationsCount = "0";
initializeTodoSectionViewModel() async { initializeTodoSectionViewModel() async {
if (isAncillaryOrdersNeedReloading) { // if (isAncillaryOrdersNeedReloading) {
patientAncillaryOrdersList.clear(); patientAncillaryOrdersList.clear();
isAncillaryOrdersLoading = true; isAncillaryOrdersLoading = true;
isAncillaryDetailsProceduresLoading = true; isAncillaryDetailsProceduresLoading = true;
notificationsCount = "0"; notificationsCount = "0";
getPatientOnlineAncillaryOrderList(); getPatientOnlineAncillaryOrderList();
} // }
getPatientDashboard(); getPatientDashboard();
} }
@ -63,13 +63,14 @@ class TodoSectionViewModel extends ChangeNotifier {
} }
Future<void> getPatientOnlineAncillaryOrderList({Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getPatientOnlineAncillaryOrderList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
if (!isAncillaryOrdersNeedReloading) { // if (!isAncillaryOrdersNeedReloading) {
return; // return;
} // }
patientAncillaryOrdersList.clear(); patientAncillaryOrdersList.clear();
isAncillaryOrdersLoading = true; isAncillaryOrdersLoading = true;
notifyListeners(); notifyListeners();
final result = await todoSectionRepo.getOnlineAncillaryOrderList(); final result = await todoSectionRepo.getOnlineAncillaryOrderList();
result.fold( result.fold(

@ -0,0 +1,27 @@
import 'dart:convert';
import 'dart:io';
import 'dart:ui';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
class RemoteFileLoader extends AssetLoader {
@override
Future<Map<String, dynamic>?> load(String path, Locale locale) async {
final directory = await getApplicationDocumentsDirectory();
// easy_localization uses toLanguageTag() which gives 'en-US' or 'ar-SA'
final fileName = "${locale.toLanguageTag()}.json";
final file = File("${directory.path}/$fileName");
if (await file.exists()) {
final String jsonString = await file.readAsString();
return jsonDecode(jsonString);
} else {
// If the download failed or hasn't happened yet, load from local assets
// path is the 'path' property from the EasyLocalization widget
final localData = await rootBundle.loadString('$path/$fileName');
return jsonDecode(localData);
}
}
}

@ -0,0 +1,36 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
class TranslationService {
// Replace with your actual hosting URL
static final String baseUrl = ApiConsts.googleCloudStorageENTranslationFileBaseURL;
static Future<void> downloadTranslations() async {
final directory = await getApplicationDocumentsDirectory();
// Ensure these match your locale codes exactly (en-US, ar-SA)
List<String> files = ["en-US.json", "ar-SA.json"];
for (String fileName in files) {
try {
final String timestamp = DateTime.now().millisecondsSinceEpoch.toString();
String url = "$baseUrl/$fileName?v=$timestamp";
debugPrint(url);
// final response = await http.get(Uri.parse("$baseUrl/$fileName"));
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
final file = File("${directory.path}/$fileName");
await file.writeAsBytes(response.bodyBytes);
} else {
print("Failed to download $fileName: Status ${response.statusCode}");
}
} catch (e) {
print("Network error while downloading $fileName: $e");
}
}
}
}

@ -7,6 +7,8 @@ abstract class LocaleKeys {
static const arabic = 'arabic'; static const arabic = 'arabic';
static const login = 'login'; static const login = 'login';
static const noDataAvailable = 'noDataAvailable'; static const noDataAvailable = 'noDataAvailable';
static const noRatingAvailable = 'noRatingAvailable';
static const doctorDoesNotHaveRating = 'doctorDoesNotHaveRating';
static const confirm = 'confirm'; static const confirm = 'confirm';
static const loadingText = 'loadingText'; static const loadingText = 'loadingText';
static const kilometerUnit = 'kilometerUnit'; static const kilometerUnit = 'kilometerUnit';
@ -1597,6 +1599,7 @@ abstract class LocaleKeys {
static const timeFor = 'timeFor'; static const timeFor = 'timeFor';
static const hmgPolicies = 'hmgPolicies'; static const hmgPolicies = 'hmgPolicies';
static const darkMode = 'darkMode'; static const darkMode = 'darkMode';
static const featureComingSoonDescription = 'featureComingSoonDescription';
static const generateAiAnalysisResult = 'generateAiAnalysisResult'; static const generateAiAnalysisResult = 'generateAiAnalysisResult';
static const ratings = 'ratings'; static const ratings = 'ratings';
static const hmgPharmacyText = 'hmgPharmacyText'; static const hmgPharmacyText = 'hmgPharmacyText';
@ -1611,6 +1614,72 @@ abstract class LocaleKeys {
static const timeForFirstReminder = 'timeForFirstReminder'; static const timeForFirstReminder = 'timeForFirstReminder';
static const reminderRemovalNote = 'reminderRemovalNote'; static const reminderRemovalNote = 'reminderRemovalNote';
static const communicationLanguage = 'communicationLanguage'; static const communicationLanguage = 'communicationLanguage';
static const featureComingSoonDescription = 'featureComingSoonDescription'; static const cmcServiceHeader = 'cmcServiceHeader';
static const cmcServiceDescription = 'cmcServiceDescription';
static const eReferralServiceHeader = 'eReferralServiceHeader';
static const eReferralServiceDescription = 'eReferralServiceDescription';
static const bloodDonationServiceHeader = 'bloodDonationServiceHeader';
static const bloodDonationServiceDescription = 'bloodDonationServiceDescription';
static const healthTrackersServiceHeader = 'healthTrackersServiceHeader';
static const healthTrackersServiceDescription = 'healthTrackersServiceDescription';
static const waterConsumptionServiceHeader = 'waterConsumptionServiceHeader';
static const waterConsumptionServiceDescription = 'waterConsumptionServiceDescription';
static const smartWatchServiceHeader = 'smartWatchServiceHeader';
static const smartWatchServiceDescription = 'smartWatchServiceDescription';
static const liveChatServiceHeader = 'liveChatServiceHeader';
static const liveChatServiceDescription = 'liveChatServiceDescription';
static const emergencyServiceHeader = 'emergencyServiceHeader';
static const emergencyServiceDescription = 'emergencyServiceDescription';
static const homeHealthCareServiceHeader = 'homeHealthCareServiceHeader';
static const homeHealthCareServiceDescription = 'homeHealthCareServiceDescription';
static const profileOnlyText = 'profileOnlyText';
static const information = 'information';
static const noFavouriteDoctors = 'noFavouriteDoctors';
static const addDoctors = 'addDoctors';
static const favouriteList = 'favouriteList';
static const later = 'later';
static const cancelAppointmentConfirmMessage = 'cancelAppointmentConfirmMessage';
static const acknowledged = 'acknowledged';
static const searchLabResults = 'searchLabResults';
static const callForAssistance = 'callForAssistance';
static const oneWaySubtitle = 'oneWaySubtitle';
static const twoWaySubtitle = 'twoWaySubtitle';
static const toHospitalSubtitle = 'toHospitalSubtitle';
static const fromHospitalSubtitle = 'fromHospitalSubtitle';
static const clinicSchedule = 'clinicSchedule';
static const doctorAddedToFavourite = 'doctorAddedToFavourite';
static const doctorRemovedFromFavourite = 'doctorRemovedFromFavourite';
static const addNewFavorite = 'addNewFavorite';
static const favourites = 'favourites';
static const pendingAncillaryOrders = 'pendingAncillaryOrders';
static const liveCarePermissions = 'liveCarePermissions';
static const containsImage = 'containsImage';
static const servicesSelected = 'servicesSelected';
static const selectMedicalFileFromFamily = 'selectMedicalFileFromFamily';
static const anyFileFromHMG = 'anyFileFromHMG';
static const noDistance = 'noDistance';
static const enterAmount = 'enterAmount';
static const selectHospitalContinue = 'selectHospitalContinue';
static const year = 'year';
static const notifyPrescription = 'notifyPrescription';
static const doctorRatingAppointment = 'doctorRatingAppointment';
static const ratingSubmitted = 'ratingSubmitted';
static const rateTheDoctor = 'rateTheDoctor';
static const downloadInvoice = 'downloadInvoice';
static const approvalDetails = 'approvalDetails';
static const obese = 'obese';
static const overWeight = 'overWeight';
static const underWeight = 'underWeight';
static const nearestGate = 'nearestGate';
static const RRTDDetails = 'RRTDDetails';
static const normalMapType = 'normalMapType';
static const satelliteMapType = 'satelliteMapType';
static const terrainMapType = 'terrainMapType';
static const hybridMapType = 'hybridMapType';
static const openCamera = 'openCamera';
static const openGallery = 'openGallery';
static const openFiles = 'openFiles';
static const generateAiAnalysisRadResult = 'generateAiAnalysisRadResult';
static const grantLocationPermission = 'grantLocationPermission';
} }

@ -41,6 +41,8 @@ import 'package:hmg_patient_app_new/features/services_price_list/services_price_
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';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart'; import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart';
import 'package:hmg_patient_app_new/features/translations/custom_asset_loader.dart';
import 'package:hmg_patient_app_new/features/translations/translation_service.dart';
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_calculators_and_converts/health_calculator_view_model.dart'; import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/health_calculator_view_model.dart';
import 'package:hmg_patient_app_new/features/health_trackers/health_trackers_view_model.dart'; import 'package:hmg_patient_app_new/features/health_trackers/health_trackers_view_model.dart';
@ -95,6 +97,9 @@ Future<void> callInitializations() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized(); await EasyLocalization.ensureInitialized();
// Download the latest JSONs from your server
// await TranslationService.downloadTranslations();
// await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); // await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
try { try {
@ -125,6 +130,7 @@ void main() async {
Locale('ar', 'SA'), Locale('ar', 'SA'),
], ],
path: 'assets/langs', path: 'assets/langs',
// assetLoader: RemoteFileLoader(),
fallbackLocale: Locale('en', 'US'), fallbackLocale: Locale('en', 'US'),
child: MultiProvider(providers: <SingleChildWidget>[ child: MultiProvider(providers: <SingleChildWidget>[
ChangeNotifierProvider<LabViewModel>( ChangeNotifierProvider<LabViewModel>(

@ -137,7 +137,7 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
style: TextStyle( style: TextStyle(
color: AppColors.textColor, color: AppColors.textColor,
fontSize: 27.f, fontSize: 27.f,
fontWeight: FontWeight.w600)), fontWeight: FontWeight.w600,)),
SizedBox(height: 16.h), SizedBox(height: 16.h),
SizedBox( SizedBox(
height: 65.h, height: 65.h,
@ -163,7 +163,7 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
style: TextStyle( style: TextStyle(
color: AppColors.textColor, color: AppColors.textColor,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
), ),
), ),
WidgetSpan( WidgetSpan(
@ -174,7 +174,7 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: AppColors.textColor, color: AppColors.textColor,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
), ),
), ),
), ),
@ -184,7 +184,7 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
style: TextStyle( style: TextStyle(
color: AppColors.textColor, color: AppColors.textColor,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
), ),
), ),
], ],
@ -194,7 +194,7 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
style: TextStyle( style: TextStyle(
color: AppColors.primaryRedBorderColor, color: AppColors.primaryRedBorderColor,
fontSize: 12.f, fontSize: 12.f,
fontWeight: FontWeight.w500)), fontWeight: FontWeight.w600,)),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Expanded( Expanded(
child: SingleChildScrollView( child: SingleChildScrollView(
@ -630,7 +630,7 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
style: TextStyle( style: TextStyle(
fontSize: 12.f, fontSize: 12.f,
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
), ),
), ),
], ],
@ -722,7 +722,7 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
? AppColors.primaryRedBorderColor ? AppColors.primaryRedBorderColor
: AppColors.greyTextColor, : AppColors.greyTextColor,
fontSize: 11.f, fontSize: 11.f,
fontWeight: FontWeight.w500), fontWeight: FontWeight.w600,),
), ),
SizedBox(height: 5.h), SizedBox(height: 5.h),
Text("${date.day}", Text("${date.day}",

@ -31,12 +31,15 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/appointment_payment_page.dart'; import 'package:hmg_patient_app_new/presentation/appointments/appointment_payment_page.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_rating_widget.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/ask_doctor_request_type_select.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/ask_doctor_request_type_select.dart';
import 'package:hmg_patient_app_new/presentation/ask_doctor/ask_doctor_page.dart'; import 'package:hmg_patient_app_new/presentation/ask_doctor/ask_doctor_page.dart';
import 'package:hmg_patient_app_new/presentation/ask_doctor/doctor_response_page.dart'; import 'package:hmg_patient_app_new/presentation/ask_doctor/doctor_response_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart'; import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart';
import 'package:hmg_patient_app_new/services/dialog_service.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';
@ -72,11 +75,12 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
@override @override
void initState() { void initState() {
scheduleMicrotask(() async { scheduleMicrotask(() async {
if (!AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)) { if (AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)) {
CalenderUtilsNew calendarUtils = await CalenderUtilsNew.instance; myAppointmentsViewModel.getDoctorsRatingCheck(
var doesExist = await calendarUtils.checkIfEventExist("${widget.patientAppointmentHistoryResponseModel.appointmentNo}"); doctorID: widget.patientAppointmentHistoryResponseModel.doctorID,
myAppointmentsViewModel.setAppointmentReminder(doesExist, widget.patientAppointmentHistoryResponseModel); clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
setState(() {}); projectID: widget.patientAppointmentHistoryResponseModel.projectID,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo);
} }
}); });
@ -148,23 +152,38 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
}); });
}, },
onCancelTap: () async { onCancelTap: () async {
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.notice.tr(context: context),
context,
child: Utils.getWarningWidget(
loadingText: LocaleKeys.cancelAppointmentConfirmMessage.tr(context: context),
isShowActionButtons: true,
onCancelTap: () {
Navigator.of(context).pop();
},
onConfirmTap: () async {
Navigator.of(context).pop();
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.cancellingAppointmentPleaseWait.tr(context: context)); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.cancellingAppointmentPleaseWait.tr(context: context));
myAppointmentsViewModel.onTabChange(0);
myAppointmentsViewModel.updateListWRTTab(0);
await myAppointmentsViewModel.cancelAppointment( await myAppointmentsViewModel.cancelAppointment(
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onSuccess: (apiResponse) { onSuccess: (apiResponse) async {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.getPatientAppointments(true, false); myAppointmentsViewModel.getPatientAppointments(true, false);
showCommonBottomSheetWithoutHeight( showCommonBottomSheet(
context, context,
child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentCancelledSuccessfully.tr(context: context)), child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentCancelledSuccessfully.tr(context: context)),
callBackFunc: () { callBackFunc: (str) {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
title: "", title: "",
isCloseButtonVisible: true, isCloseButtonVisible: false,
isDismissible: false, isDismissible: false,
isFullScreen: false, isFullScreen: false,
isAutoDismiss: true,
height: ResponsiveExtension.screenHeight * 0.3,
); );
}, },
onError: (err) { onError: (err) {
@ -173,16 +192,17 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
context, context,
child: Utils.getErrorWidget(loadingText: err.toString()), child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {}, callBackFunc: () {},
title: "", title: "", isCloseButtonVisible: true, isDismissible: false, isFullScreen: false);
isCloseButtonVisible: true, });
isDismissible: false, }),
callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
isCloseButtonVisible: true,
); );
}); // var isEventAddedOrRemoved = await CalenderUtilsNew.instance.checkAndRemove( id:"${widget.patientAppointmentHistoryResponseModel.appointmentNo}", );
var isEventAddedOrRemoved = await CalenderUtilsNew.instance.checkAndRemove( id:"${widget.patientAppointmentHistoryResponseModel.appointmentNo}", ); // setState(() {
setState(() { // myAppointmentsViewModel.setAppointmentReminder(isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel);
myAppointmentsViewModel.setAppointmentReminder(isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel); // });
});
}, },
onRescheduleTap: () async { onRescheduleTap: () async {
openDoctorScheduleCalendar(); openDoctorScheduleCalendar();
@ -213,47 +233,53 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
LocaleKeys.appointmentStatus.tr(context: context).toText16(isBold: true), LocaleKeys.appointmentStatus.tr(context: context).toText16(isBold: true),
SizedBox(height: 4.h), SizedBox(height: 4.h),
(!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel) (!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel)
? LocaleKeys.notConfirmed.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500) ? LocaleKeys.notConfirmed.tr(context: context).toText12(color: AppColors.primaryRedColor, isBold: true)
: LocaleKeys.confirmed.tr(context: context).toText12(color: AppColors.successColor, fontWeight: FontWeight.w500)), : LocaleKeys.confirmed.tr(context: context).toText12(color: AppColors.successColor, isBold: true)),
SizedBox(height: 16.h), SizedBox(height: 16.h),
], ],
), ),
((!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel) && widget.patientAppointmentHistoryResponseModel.nextAction != 10) // ((!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel) && widget.patientAppointmentHistoryResponseModel.nextAction != 10)
? CustomButton( // ? CustomButton(
text: LocaleKeys.confirm.tr(), // text: LocaleKeys.confirm.tr(),
onPressed: () async { // onPressed: () async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingAppointmentPleaseWait.tr(context: context)); // LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingAppointmentPleaseWait.tr(context: context));
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.initAppointmentsViewModel(); // myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false); // // myAppointmentsViewModel.getPatientAppointments(true, false);
showCommonBottomSheetWithoutHeight( // showCommonBottomSheetWithoutHeight(
title: "", // title: "",
context, // context,
child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentConfirmedSuccessfully.tr(context: context)), // child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentConfirmedSuccessfully.tr(context: context)),
callBackFunc: () { // callBackFunc: () {
Navigator.of(context).pop(); // Navigator.pushAndRemoveUntil(
}, // context,
isFullScreen: false, // CustomPageRoute(
isCloseButtonVisible: true, // page: LandingNavigation(),
); // ),
}); // (r) => false);
}, // },
backgroundColor: AppColors.successColor, // isFullScreen: false,
borderColor: AppColors.successColor, // isCloseButtonVisible: false,
textColor: Colors.white, // isAutoDismiss: true
fontSize: 14.f, // );
fontWeight: FontWeight.w500, // });
borderRadius: 12.r, // },
height: 40.h, // backgroundColor: AppColors.successColor,
icon: AppAssets.confirm_appointment_icon, // borderColor: AppColors.successColor,
iconColor: Colors.white, // textColor: Colors.white,
iconSize: 16.h, // fontSize: 14.f,
) // isBold: true,
: SizedBox.shrink()) // borderRadius: 12.r,
// height: 40.h,
// icon: AppAssets.confirm_appointment_icon,
// iconColor: Colors.white,
// iconSize: 16.h,
// )
// : SizedBox.shrink())
], ],
), ),
//TODO Add countdown timer in case of LiveCare Appointment //TODO Add countdown timer in case of LiveCare Appointment
@ -266,7 +292,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.doctorWillCallYou.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), LocaleKeys.doctorWillCallYou.tr(context: context).toText14(color: AppColors.greyTextColor, isBold: true),
], ],
), ),
), ),
@ -312,7 +338,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01),
textColor: Colors.white, textColor: Colors.white,
fontSize: 14.f, fontSize: 14.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h, height: 40.h,
@ -333,11 +359,11 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
AppCustomChipWidget( AppCustomChipWidget(
labelText: bookAppointmentsVM.isAppointmentNearestGateLoading labelText: bookAppointmentsVM.isAppointmentNearestGateLoading
? "Floor: Ground Floor" ? "Floor: Ground Floor"
: "Floor: ${getIt.get<AppState>().isArabic() ? bookAppointmentsViewModel.appointmentNearestGateResponseModel!.clinicLocationN : bookAppointmentsViewModel.appointmentNearestGateResponseModel!.clinicLocation}", : "${LocaleKeys.floor.tr(context: context)}: ${getIt.get<AppState>().isArabic() ? bookAppointmentsViewModel.appointmentNearestGateResponseModel!.clinicLocationN : bookAppointmentsViewModel.appointmentNearestGateResponseModel!.clinicLocation}",
).toShimmer2(isShow: bookAppointmentsVM.isAppointmentNearestGateLoading), ).toShimmer2(isShow: bookAppointmentsVM.isAppointmentNearestGateLoading),
AppCustomChipWidget( AppCustomChipWidget(
labelText: labelText:
"Nearest Gate: ${getIt.get<AppState>().isArabic() ? bookAppointmentsVM.appointmentNearestGateResponseModel!.nearestGateNumberN : bookAppointmentsVM.appointmentNearestGateResponseModel!.nearestGateNumber}") "${LocaleKeys.nearestGate.tr(context: context)}: ${getIt.get<AppState>().isArabic() ? bookAppointmentsVM.appointmentNearestGateResponseModel!.nearestGateNumberN : bookAppointmentsVM.appointmentNearestGateResponseModel!.nearestGateNumber}")
.toShimmer2(isShow: bookAppointmentsVM.isAppointmentNearestGateLoading), .toShimmer2(isShow: bookAppointmentsVM.isAppointmentNearestGateLoading),
], ],
) : SizedBox.shrink(), ) : SizedBox.shrink(),
@ -362,7 +388,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),
LocaleKeys.notifyMeBeforeAppointment.tr(context: context).toText11(color: AppColors.textColorLight, weight: FontWeight.w500), LocaleKeys.notifyMeBeforeAppointment.tr(context: context).toText11(color: AppColors.textColorLight, isBold: true),
], ],
), ),
const Spacer(), const Spacer(),
@ -427,7 +453,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
], ],
) )
// : SizedBox.shrink() // : SizedBox.shrink()
: GridView( : Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
return GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, crossAxisCount: 3,
crossAxisSpacing: 16.h, crossAxisSpacing: 16.h,
@ -574,8 +601,47 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
), ),
); );
}), }),
], myAppointmentsVM.isAppointmentRatedResponseLoading
? MedicalFileCard(
label: "Medical File",
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.appointmentRatingIcon,
isLargeText: true,
iconSize: 36.w,
isLocked: false,
).toShimmer2()
: MedicalFileCard(
label: !((myAppointmentsVM.appointmentRatedResponseModel!).isAppointmentRated ?? true)
? LocaleKeys.ratingSubmitted.tr(context: context)
: LocaleKeys.doctorRatingAppointment.tr(context: context),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.appointmentRatingIcon,
isLargeText: true,
iconSize: 36.w,
isLocked: !(myAppointmentsVM.appointmentRatedResponseModel!.isAppointmentRated ?? true),
).onPress(() {
if(!(myAppointmentsVM.appointmentRatedResponseModel!.isAppointmentRated ?? true)) {
showCommonBottomSheetWithoutHeight(
context,
title: LocaleKeys.doctorRating.tr(context: context),
isCloseButtonVisible: true,
child: StatefulBuilder(
builder: (context, setState) {
return AppointmentRatingWidget(
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
);
},
), ),
isFullScreen: false,
);
}
}),
],
);
}),
// Column( // Column(
// crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
// children: [ // children: [
@ -662,7 +728,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
// // "Prescribed By: ${widget.patientAppointmentHistoryResponseModel.doctorTitle} ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}" // // "Prescribed By: ${widget.patientAppointmentHistoryResponseModel.doctorTitle} ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}"
// // .needTranslation // // .needTranslation
// // .toText10( // // .toText10(
// // weight: FontWeight.w500, // // weight: FontWeight.w600,
// // color: AppColors.greyTextColor, // // color: AppColors.greyTextColor,
// // letterSpacing: -0.4), // // letterSpacing: -0.4),
// // ], // // ],
@ -709,7 +775,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
// // // borderColor: AppColors.secondaryLightRedColor, // // // borderColor: AppColors.secondaryLightRedColor,
// // // textColor: AppColors.primaryRedColor, // // // textColor: AppColors.primaryRedColor,
// // // fontSize: 14, // // // fontSize: 14,
// // // fontWeight: FontWeight.w500, // // // isBold: true,
// // // borderRadius: 12.h, // // // borderRadius: 12.h,
// // // height: 40.h, // // // height: 40.h,
// // // icon: AppAssets.appointment_calendar_icon, // // // icon: AppAssets.appointment_calendar_icon,
@ -737,7 +803,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
// // borderColor: AppColors.secondaryLightRedColor, // // borderColor: AppColors.secondaryLightRedColor,
// // textColor: AppColors.primaryRedColor, // // textColor: AppColors.primaryRedColor,
// // fontSize: 14.f, // // fontSize: 14.f,
// // fontWeight: FontWeight.w500, // // isBold: true,
// // borderRadius: 12.r, // // borderRadius: 12.r,
// // height: 40.h, // // height: 40.h,
// // icon: AppAssets.requests, // // icon: AppAssets.requests,
@ -766,7 +832,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
// // borderColor: AppColors.secondaryLightRedColor, // // borderColor: AppColors.secondaryLightRedColor,
// // textColor: AppColors.primaryRedColor, // // textColor: AppColors.primaryRedColor,
// // fontSize: 14.f, // // fontSize: 14.f,
// // fontWeight: FontWeight.w500, // // isBold: true,
// // borderRadius: 12.r, // // borderRadius: 12.r,
// // height: 40.h, // // height: 40.h,
// // icon: AppAssets.requests, // // icon: AppAssets.requests,
@ -819,8 +885,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
children: [ children: [
Expanded( Expanded(
child: LocaleKeys.upcomingPaymentNow child: LocaleKeys.upcomingPaymentNow
.tr(context: context) .tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor)),
.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor)),
"VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})".toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -0.64), "VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})".toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -0.64),
], ],
), ),
@ -850,8 +915,9 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
? ?
(widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! || (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! ||
widget.patientAppointmentHistoryResponseModel.isExecludeDoctor! || widget.patientAppointmentHistoryResponseModel.isExecludeDoctor! ||
Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID)) !Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID))
? CustomButton( ? SizedBox.shrink()
: CustomButton(
text: LocaleKeys.rebookAppointment.tr(context: context), text: LocaleKeys.rebookAppointment.tr(context: context),
onPressed: () { onPressed: () {
openDoctorScheduleCalendar(); openDoctorScheduleCalendar();
@ -860,7 +926,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
textColor: Colors.white, textColor: Colors.white,
fontSize: 16.f, fontSize: 16.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 50.h, height: 50.h,
@ -868,7 +934,6 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
iconColor: Colors.white, iconColor: Colors.white,
iconSize: 18.h, iconSize: 18.h,
).paddingSymmetrical(16.h, 24.h) ).paddingSymmetrical(16.h, 24.h)
: SizedBox.shrink()
: CustomButton( : CustomButton(
text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction), text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction),
onPressed: () { onPressed: () {
@ -879,7 +944,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01), AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
textColor: widget.patientAppointmentHistoryResponseModel.nextAction == 15 ? AppColors.textColor : Colors.white, textColor: widget.patientAppointmentHistoryResponseModel.nextAction == 15 ? AppColors.textColor : Colors.white,
fontSize: 16.f, fontSize: 16.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 56.h, height: 56.h,
@ -909,7 +974,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
SizedBox(height: 4.h), SizedBox(height: 4.h),
LocaleKeys.confirmYourLocationDesc.tr(context: context).toText12( LocaleKeys.confirmYourLocationDesc.tr(context: context).toText12(
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
fontWeight: FontWeight.w500, isBold: true,
), ),
SizedBox(height: 24.h), SizedBox(height: 24.h),
CustomButton( CustomButton(
@ -923,7 +988,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
textColor: Colors.white, textColor: Colors.white,
fontSize: 16.f, fontSize: 16.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 56.h, height: 56.h,
@ -949,7 +1014,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
borderColor: AppColors.chipSecondaryLightRedColor, borderColor: AppColors.chipSecondaryLightRedColor,
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
fontSize: 16.f, fontSize: 16.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 56.h, height: 56.h,
@ -987,12 +1052,13 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
doctorImageURL: widget.patientAppointmentHistoryResponseModel.doctorImageURL, doctorImageURL: widget.patientAppointmentHistoryResponseModel.doctorImageURL,
doctorTitle: widget.patientAppointmentHistoryResponseModel.doctorTitle, doctorTitle: widget.patientAppointmentHistoryResponseModel.doctorTitle,
name: widget.patientAppointmentHistoryResponseModel.doctorNameObj, name: widget.patientAppointmentHistoryResponseModel.doctorNameObj,
nationalityFlagURL: "https://hmgwebservices.com/Images/flag/SYR.png", nationalityFlagURL: "",
speciality: [], speciality: [],
clinicName: widget.patientAppointmentHistoryResponseModel.clinicName, clinicName: widget.patientAppointmentHistoryResponseModel.clinicName,
projectName: widget.patientAppointmentHistoryResponseModel.projectName, projectName: widget.patientAppointmentHistoryResponseModel.projectName,
); );
bookAppointmentsViewModel.setSelectedDoctor(doctor); bookAppointmentsViewModel.setSelectedDoctor(doctor);
bookAppointmentsViewModel.setIsPatientRescheduleAppointment(true);
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingDoctorSchedulePleaseWait.tr(context: context)); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingDoctorSchedulePleaseWait.tr(context: context));
await bookAppointmentsViewModel.getDoctorFreeSlots( await bookAppointmentsViewModel.getDoctorFreeSlots(
isBookingForLiveCare: false, isBookingForLiveCare: false,
@ -1036,17 +1102,19 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
myAppointmentsViewModel.initAppointmentsViewModel(); myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false); myAppointmentsViewModel.getPatientAppointments(true, false);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, }, title: "", height: ResponsiveExtension.screenHeight * 0.3, isAutoDismiss: true, isCloseButtonVisible: true, isDismissible: false, isFullScreen: false,
title: "",
height: ResponsiveExtension.screenHeight * 0.3,
isCloseButtonVisible: true,
isDismissible: false,
isFullScreen: false,
isSuccessDialog: true); isSuccessDialog: true);
}); });
// LoaderBottomSheet.hideLoader(); // LoaderBottomSheet.hideLoader();
case 15: case 15:
break; getIt.get<DialogService>().showCommonBottomSheetWithoutH(
message: LocaleKeys.upcomingPaymentPending.tr(context: context),
label: LocaleKeys.notice.tr(),
onOkPressed: () {},
okLabel: "confirm",
cancelLabel: LocaleKeys.acknowledged.tr(context: context),
isConfirmButton: true,
);
case 20: case 20:
myAppointmentsViewModel.setIsPatientAppointmentShareLoading(true); myAppointmentsViewModel.setIsPatientAppointmentShareLoading(true);
Navigator.of(context).push( Navigator.of(context).push(

@ -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".toText16(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), LocaleKeys.mada.tr(context: context).toText16(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
], ],
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
@ -153,7 +153,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
], ],
).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Visa or Mastercard" LocaleKeys.visaOrMastercard.tr(context: context)
.toText16(isBold: true) .toText16(isBold: true)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), .toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
], ],
@ -193,7 +193,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
Image.asset(AppAssets.tamaraEng, width: 72.h, height: 25.h) Image.asset(AppAssets.tamaraEng, width: 72.h, height: 25.h)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), .toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
SizedBox(height: 16.h), SizedBox(height: 16.h),
"Tamara" LocaleKeys.tamara.tr(context: context)
.toText16(isBold: true) .toText16(isBold: true)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), .toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
], ],
@ -249,7 +249,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
LocaleKeys.insuranceExpiredOrInactive.tr(context: context) LocaleKeys.insuranceExpiredOrInactive.tr(context: context)
.toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500) .toText14(color: AppColors.primaryRedColor, isBold: true)
.paddingSymmetrical(24.h, 0.h), .paddingSymmetrical(24.h, 0.h),
CustomButton( CustomButton(
text: LocaleKeys.updateInsurance.tr(context: context), text: LocaleKeys.updateInsurance.tr(context: context),
@ -258,13 +258,14 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
CustomPageRoute( CustomPageRoute(
page: InsuranceHomePage(), page: InsuranceHomePage(),
), ),
); )
.then((val) {});
}, },
backgroundColor: AppColors.primaryRedColor, backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.secondaryLightRedBorderColor, borderColor: AppColors.secondaryLightRedBorderColor,
textColor: AppColors.whiteColor, textColor: AppColors.whiteColor,
fontSize: 10.f, fontSize: 10.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 8, borderRadius: 8,
padding: EdgeInsets.fromLTRB(15, 0, 15, 0), padding: EdgeInsets.fromLTRB(15, 0, 15, 0),
height: 30.h, height: 30.h,

@ -33,6 +33,11 @@ class AppointmentQueuePage extends StatelessWidget {
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: LocaleKeys.queueing.tr(context: context), title: LocaleKeys.queueing.tr(context: context),
child: RefreshIndicator(
color: AppColors.primaryRedColor,
onRefresh: () async {
await myAppointmentsVM.getPatientAppointmentQueueDetails();
},
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: EdgeInsets.all(24.0), padding: EdgeInsets.all(24.0),
@ -45,10 +50,7 @@ class AppointmentQueuePage extends StatelessWidget {
borderRadius: 20.h, borderRadius: 20.h,
hasShadow: false, hasShadow: false,
side: BorderSide( side: BorderSide(
color: myAppointmentsVM.isAppointmentQueueDetailsLoading color: myAppointmentsVM.isAppointmentQueueDetailsLoading ? AppColors.whiteColor : Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus), width: 2.w),
? AppColors.whiteColor
: Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus),
width: 2.w),
), ),
child: Padding( child: Padding(
padding: EdgeInsets.all(16.h), padding: EdgeInsets.all(16.h),
@ -67,21 +69,17 @@ 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}!!!".toText16(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
.toText16(isBold: true)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 8.h), SizedBox(height: 8.h),
LocaleKeys.thankYouForPatience.tr(context: context) LocaleKeys.thankYouForPatience
.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight) .tr(context: context)
.toText12(isBold: true, color: AppColors.textColorLight)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading), .toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 8.h), SizedBox(height: 8.h),
myAppointmentsVM.currentPatientQueueDetails.queueNo! myAppointmentsVM.currentPatientQueueDetails.queueNo!.toText32(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
.toText32(isBold: true)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 8.h), SizedBox(height: 8.h),
CustomButton( CustomButton(
text: Utils.getCardButtonText( text: Utils.getCardButtonText(myAppointmentsVM.currentQueueStatus, myAppointmentsVM.currentPatientQueueDetails.roomNo ?? ""),
myAppointmentsVM.currentQueueStatus, myAppointmentsVM.currentPatientQueueDetails.roomNo ?? ""),
onPressed: () {}, onPressed: () {},
backgroundColor: Utils.getCardButtonColor(myAppointmentsVM.currentQueueStatus), backgroundColor: Utils.getCardButtonColor(myAppointmentsVM.currentQueueStatus),
borderColor: Utils.getCardButtonColor(myAppointmentsVM.currentQueueStatus).withValues(alpha: 0.01), borderColor: Utils.getCardButtonColor(myAppointmentsVM.currentQueueStatus).withValues(alpha: 0.01),
@ -111,9 +109,7 @@ class AppointmentQueuePage extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.servingNow.tr(context: context) LocaleKeys.servingNow.tr(context: context).toText16(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
.toText16(isBold: true)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 18.h), SizedBox(height: 18.h),
ListView.separated( ListView.separated(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
@ -129,22 +125,15 @@ class AppointmentQueuePage extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
"Room: ${myAppointmentsVM.patientQueueDetailsList[index].roomNo}" "Room: ${myAppointmentsVM.patientQueueDetailsList[index].roomNo}".toText12(isBold: true),
.toText12(fontWeight: FontWeight.w500),
SizedBox(width: 8.w), SizedBox(width: 8.w),
AppCustomChipWidget( AppCustomChipWidget(
deleteIcon: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 deleteIcon: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 ? AppAssets.call_for_vitals : AppAssets.call_for_doctor,
? AppAssets.call_for_vitals
: AppAssets.call_for_doctor,
labelText: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 labelText: myAppointmentsVM.patientQueueDetailsList[index].callType == 1
? LocaleKeys.callForVitalSigns.tr(context: context) ? LocaleKeys.callForVitalSigns.tr(context: context)
: LocaleKeys.callForDoctor.tr(context: context), : LocaleKeys.callForDoctor.tr(context: context),
iconColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 iconColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 ? AppColors.primaryRedColor : AppColors.successColor,
? AppColors.primaryRedColor textColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 ? AppColors.primaryRedColor : AppColors.successColor,
: AppColors.successColor,
textColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1
? AppColors.primaryRedColor
: AppColors.successColor,
iconSize: 14.w, iconSize: 14.w,
backgroundColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 backgroundColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1
? AppColors.primaryRedColor.withValues(alpha: 0.1) ? AppColors.primaryRedColor.withValues(alpha: 0.1)
@ -183,21 +172,15 @@ class AppointmentQueuePage extends StatelessWidget {
], ],
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
"${LocaleKeys.improveOverallHealth.tr(context: context)}" "${LocaleKeys.improveOverallHealth.tr(context: context)}".toText12(isBold: true, color: AppColors.textColorLight),
.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"${LocaleKeys.routineScreenings.tr(context: context)}" "${LocaleKeys.routineScreenings.tr(context: context)}".toText12(isBold: true, color: AppColors.textColorLight),
.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"${LocaleKeys.whatIsThisMedicationFor.tr(context: context)}" "${LocaleKeys.whatIsThisMedicationFor.tr(context: context)}".toText12(isBold: true, color: AppColors.textColorLight),
.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"${LocaleKeys.sideEffectsToKnow.tr(context: context)}" "${LocaleKeys.sideEffectsToKnow.tr(context: context)}".toText12(isBold: true, color: AppColors.textColorLight),
.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"${LocaleKeys.whenFollowUp.tr(context: context)}" "${LocaleKeys.whenFollowUp.tr(context: context)}".toText12(isBold: true, color: AppColors.textColorLight),
.toText12(fontWeight: FontWeight.w500, color: AppColors.textColorLight),
SizedBox(height: 16.h), SizedBox(height: 16.h),
], ],
).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading), ).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
@ -209,6 +192,7 @@ class AppointmentQueuePage extends StatelessWidget {
), ),
), ),
), ),
),
Container( Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, color: AppColors.whiteColor,
@ -229,7 +213,7 @@ class AppointmentQueuePage extends StatelessWidget {
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor, textColor: AppColors.whiteColor,
fontSize: 16.f, fontSize: 16.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 50.h, height: 50.h,

@ -55,13 +55,15 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false); bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
return Scaffold( return Scaffold(
backgroundColor: AppColors.bgScaffoldColor, backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView( body: Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
return CollapsingListView(
title: LocaleKeys.appointmentsList.tr(context: context), title: LocaleKeys.appointmentsList.tr(context: context),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
SizedBox(height: 16.h), SizedBox(height: 16.h),
CustomTabBar( CustomTabBar(
initialIndex: myAppointmentsVM.selectedTabIndex,
activeTextColor: Color(0xffED1C2B), activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
tabs: [ tabs: [
@ -78,13 +80,15 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
context.read<DateRangeSelectorRangeViewModel>().flush(); context.read<DateRangeSelectorRangeViewModel>().flush();
}, },
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) { // Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
return getSelectedTabData(myAppointmentsVM.selectedTabIndex, myAppointmentsVM); // return
}), getSelectedTabData(myAppointmentsVM.selectedTabIndex, myAppointmentsVM),
// }),
], ],
), ),
), ),
), );
}),
); );
} }
@ -109,7 +113,7 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
borderColor: myAppointmentsVM.isAppointmentsSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), borderColor: myAppointmentsVM.isAppointmentsSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myAppointmentsVM.isAppointmentsSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, textColor: myAppointmentsVM.isAppointmentsSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 10, borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0), padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h, height: 40.h,
@ -124,7 +128,7 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
borderColor: myAppointmentsVM.isAppointmentsSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, borderColor: myAppointmentsVM.isAppointmentsSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor,
textColor: myAppointmentsVM.isAppointmentsSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, textColor: myAppointmentsVM.isAppointmentsSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor,
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 10, borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0), padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h, height: 40.h,
@ -144,7 +148,7 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
? myAppointmentsVM.patientAppointmentsViewList.length ? myAppointmentsVM.patientAppointmentsViewList.length
: 1, : 1,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final isExpanded = expandedIndex == index; final isExpanded = myAppointmentsVM.selectedTabIndex == 1 ? true : expandedIndex == index;
return myAppointmentsVM.isMyAppointmentsLoading return myAppointmentsVM.isMyAppointmentsLoading
? Container( ? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
@ -187,7 +191,7 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
labelText: labelText:
"${myAppointmentsVM.patientAppointmentsViewList[index].patientDoctorAppointmentList!.length} Appointments"), "${myAppointmentsVM.patientAppointmentsViewList[index].patientDoctorAppointmentList!.length} ${LocaleKeys.appointments.tr(context: context)}", isEnglishOnly: true,),
Icon(isExpanded ? Icons.expand_less : Icons.expand_more), Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
], ],
), ),
@ -262,7 +266,7 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
borderColor: Color(0xffFEE9EA), borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B), textColor: Color(0xffED1C2B),
fontSize: 14.f, fontSize: 14.f,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0),
height: 40.h, height: 40.h,

@ -89,7 +89,7 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
borderColor: isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2), borderColor: isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor, textColor: isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 10, borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0), padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h, height: 40.h,
@ -107,7 +107,7 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
borderColor: isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor, borderColor: isSortByClinic ? AppColors.textColor.withValues(alpha: 0.2) : AppColors.primaryRedColor,
textColor: isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor, textColor: isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor,
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 10, borderRadius: 10,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0), padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h, height: 40.h,
@ -218,14 +218,23 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
AppCustomChipWidget(labelText: "${group.length} ${'doctors'}"), AppCustomChipWidget(
richText: Row(
children: [
"${group.length} ".toText10(isEnglishOnly: true),
"${LocaleKeys.doctors.tr(context: context)} ".toText10()
],
),
// labelText: "${group.length} ${'doctors'}",
isEnglishOnly: true,
),
Icon(isExpanded ? Icons.expand_less : Icons.expand_more), Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
], ],
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
Text( Text(
displayName, displayName,
style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600), style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w600,),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
], ],
@ -267,7 +276,7 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
).circle(100), ).circle(100),
SizedBox(width: 8.h), SizedBox(width: 8.h),
Expanded( Expanded(
child: (doctor?.doctorName ?? "").toString().toText14(weight: FontWeight.w500), child: (doctor?.doctorName ?? "").toString().toText14(isBold: true),
), ),
], ],
), ),
@ -289,10 +298,10 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
flex: 2, flex: 2,
child: CustomButton( child: CustomButton(
icon: AppAssets.view_report_icon, icon: AppAssets.view_report_icon,
iconColor: AppColors.primaryRedColor, iconColor: doctor?.isActiveDoctorProfile == false ? AppColors.inputLabelTextColor.withValues(alpha: 1.0) : AppColors.primaryRedColor,
iconSize: 16.h, iconSize: 16.h,
text: LocaleKeys.viewProfile.tr(context: context), text: LocaleKeys.viewProfile.tr(context: context),
onPressed: () async { onPressed: doctor?.isActiveDoctorProfile == false ? () {} : () async {
bookAppointmentsViewModel.setSelectedDoctor(DoctorsListResponseModel( bookAppointmentsViewModel.setSelectedDoctor(DoctorsListResponseModel(
clinicID: doctor?.clinicID ?? 0, clinicID: doctor?.clinicID ?? 0,
projectID: doctor?.projectID ?? 0, projectID: doctor?.projectID ?? 0,
@ -309,7 +318,7 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: DoctorProfilePage(), page: DoctorProfilePage(isDoctorAllowedToBook: !doctor?.isLiveCareClinic),
), ),
); );
}, onError: (err) { }, onError: (err) {
@ -323,11 +332,11 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
); );
}); });
}, },
backgroundColor: AppColors.secondaryLightRedColor, backgroundColor: doctor?.isActiveDoctorProfile == false ? AppColors.inputLabelTextColor.withValues(alpha: 0.3) : AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor, borderColor: doctor?.isActiveDoctorProfile == false ? AppColors.inputLabelTextColor.withValues(alpha: 0.01) : AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor, textColor: doctor?.isActiveDoctorProfile == false ? AppColors.inputLabelTextColor.withValues(alpha: 1.0) : AppColors.primaryRedColor,
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 12, borderRadius: 12,
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h, height: 40.h,

@ -148,8 +148,8 @@ class AppointmentCard extends StatelessWidget {
Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h, iconColor: AppColors.ratingColorYellow), Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h, iconColor: AppColors.ratingColorYellow),
SizedBox(height: 2.h), SizedBox(height: 2.h),
(isFoldable || isTablet) (isFoldable || isTablet)
? "${patientAppointmentHistoryResponseModel.decimalDoctorRate}".toText9(isBold: true, color: AppColors.textColor) ? "${patientAppointmentHistoryResponseModel.decimalDoctorRate}".toText9(isBold: true, color: AppColors.textColor, isEnglishOnly: true)
: "${patientAppointmentHistoryResponseModel.decimalDoctorRate ?? "0.0"}".toText11(isBold: true, color: AppColors.textColor), : "${patientAppointmentHistoryResponseModel.decimalDoctorRate ?? "0.0"}".toText11(isBold: true, color: AppColors.textColor, isEnglishOnly: true),
], ],
), ),
).circle(100).toShimmer2(isShow: isLoading), ).circle(100).toShimmer2(isShow: isLoading),
@ -165,7 +165,16 @@ class AppointmentCard extends StatelessWidget {
children: [ children: [
(isLoading ? 'Dr' : "${patientAppointmentHistoryResponseModel.doctorTitle}").toText16(isBold: true, maxlines: 1), (isLoading ? 'Dr' : "${patientAppointmentHistoryResponseModel.doctorTitle}").toText16(isBold: true, maxlines: 1),
(isLoading ? 'John Doe' : " ${patientAppointmentHistoryResponseModel.doctorNameObj!.truncate(20)}") (isLoading ? 'John Doe' : " ${patientAppointmentHistoryResponseModel.doctorNameObj!.truncate(20)}")
.toText16(isBold: true, maxlines: 1, isEnglishOnly: !Utils.isArabicText(patientAppointmentHistoryResponseModel.doctorNameObj ?? "John Doe")) .toText16(isBold: true, maxlines: 1, isEnglishOnly: !Utils.isArabicText(patientAppointmentHistoryResponseModel.doctorNameObj ?? "John Doe")),
SizedBox(width: 12.w),
(patientAppointmentHistoryResponseModel.doctorNationalityFlagURL != null && patientAppointmentHistoryResponseModel.doctorNationalityFlagURL!.isNotEmpty)
? Image.network(
patientAppointmentHistoryResponseModel.doctorNationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SAU.png",
width: 20.h,
height: 15.h,
fit: BoxFit.cover,
)
: SizedBox.shrink(),
], ],
).toShimmer2(isShow: isLoading), ).toShimmer2(isShow: isLoading),
SizedBox(height: 8.h), SizedBox(height: 8.h),
@ -261,7 +270,7 @@ class AppointmentCard extends StatelessWidget {
borderColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
// height: isTablet || isFoldable ? 46.h : 40.h, // height: isTablet || isFoldable ? 46.h : 40.h,
@ -289,7 +298,7 @@ class AppointmentCard extends StatelessWidget {
borderColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
// height: isTablet || isFoldable ? 46.h : 40.h, // height: isTablet || isFoldable ? 46.h : 40.h,
@ -314,7 +323,7 @@ class AppointmentCard extends StatelessWidget {
borderColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), borderColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01),
textColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction), textColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction),
fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h, height: 40.h,
@ -394,7 +403,7 @@ class AppointmentCard extends StatelessWidget {
borderColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
// height: isTablet || isFoldable ? 46.h : 40.h, // height: isTablet || isFoldable ? 46.h : 40.h,
@ -413,7 +422,7 @@ class AppointmentCard extends StatelessWidget {
textColor: AppColors.blackColor, textColor: AppColors.blackColor,
borderWidth: 1.h, borderWidth: 1.h,
fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h, height: 40.h,
@ -456,7 +465,7 @@ class AppointmentCard extends StatelessWidget {
doctorImageURL: patientAppointmentHistoryResponseModel.doctorImageURL, doctorImageURL: patientAppointmentHistoryResponseModel.doctorImageURL,
doctorTitle: patientAppointmentHistoryResponseModel.doctorTitle, doctorTitle: patientAppointmentHistoryResponseModel.doctorTitle,
name: patientAppointmentHistoryResponseModel.doctorNameObj, name: patientAppointmentHistoryResponseModel.doctorNameObj,
nationalityFlagURL: 'https://hmgwebservices.com/Images/flag/SYR.png', nationalityFlagURL: '',
speciality: [], speciality: [],
clinicName: patientAppointmentHistoryResponseModel.clinicName, clinicName: patientAppointmentHistoryResponseModel.clinicName,
projectName: patientAppointmentHistoryResponseModel.projectName, projectName: patientAppointmentHistoryResponseModel.projectName,

@ -71,20 +71,20 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
} }
}); });
}), }),
SizedBox(height: 16.h), // SizedBox(height: 16.h),
checkInOptionCard( // checkInOptionCard(O
AppAssets.checkin_nfc_icon, // AppAssets.checkin_nfc_icon,
LocaleKeys.nfcNearFieldCommunication.tr(context: context), // LocaleKeys.nfcNearFieldCommunication.tr(context: context),
LocaleKeys.scanPhoneViaNFC.tr(context: context), // 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) {
Future.delayed(const Duration(milliseconds: 100), () { // Future.delayed(const Duration(milliseconds: 100), () {
sendCheckInRequest(nfcId, 1, context); // sendCheckInRequest(nfcId, 1, context);
}); // });
}, onCancel: () {}); // }, onCancel: () {});
}); // });
}), // }),
SizedBox(height: 16.h), SizedBox(height: 16.h),
checkInOptionCard( checkInOptionCard(
AppAssets.checkin_qr_icon, AppAssets.checkin_qr_icon,
@ -120,7 +120,7 @@ class AppointmentCheckinBottomSheet extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
title.toText16(isBold: true, color: AppColors.textColor), title.toText16(isBold: true, color: AppColors.textColor),
subTitle.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), subTitle.toText12(isBold: true, color: AppColors.greyTextColor),
], ],
), ),
), ),

@ -1,19 +1,27 @@
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';
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/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
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/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart'; import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_profile_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
class AppointmentDoctorCard extends StatelessWidget { class AppointmentDoctorCard extends StatelessWidget {
const AppointmentDoctorCard( const AppointmentDoctorCard(
{super.key, required this.patientAppointmentHistoryResponseModel, required this.onRescheduleTap, required this.onCancelTap, required this.onAskDoctorTap, this.renderWidgetForERDisplay = false}); {super.key, required this.patientAppointmentHistoryResponseModel, required this.onRescheduleTap, required this.onCancelTap, required this.onAskDoctorTap, this.renderWidgetForERDisplay = false});
@ -66,7 +74,7 @@ class AppointmentDoctorCard extends StatelessWidget {
children: [ children: [
Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h, iconColor: AppColors.ratingColorYellow), Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h, iconColor: AppColors.ratingColorYellow),
SizedBox(height: 2.h), SizedBox(height: 2.h),
"${patientAppointmentHistoryResponseModel.decimalDoctorRate ?? 0.0}".toText11(isBold: true, color: AppColors.textColor), "${patientAppointmentHistoryResponseModel.decimalDoctorRate ?? 0.0}".toText11(isBold: true, color: AppColors.textColor, isEnglishOnly: true),
], ],
), ),
).circle(100), ).circle(100),
@ -75,10 +83,24 @@ class AppointmentDoctorCard extends StatelessWidget {
), ),
SizedBox(width: 16.w), SizedBox(width: 16.w),
Expanded( Expanded(
flex: 9,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [ children: [
patientAppointmentHistoryResponseModel.doctorNameObj!.toText16(isBold: true, isEnglishOnly: !Utils.isArabicText(patientAppointmentHistoryResponseModel.doctorNameObj ?? "")), patientAppointmentHistoryResponseModel.doctorNameObj!.toText16(isBold: true, isEnglishOnly: !Utils.isArabicText(patientAppointmentHistoryResponseModel.doctorNameObj ?? "")),
SizedBox(width: 12.w),
(patientAppointmentHistoryResponseModel.doctorNationalityFlagURL != null && patientAppointmentHistoryResponseModel.doctorNationalityFlagURL!.isNotEmpty)
? Image.network(
patientAppointmentHistoryResponseModel.doctorNationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SAU.png",
width: 20.h,
height: 15.h,
fit: BoxFit.cover,
)
: SizedBox.shrink(),
],
),
SizedBox(height: 8.h), SizedBox(height: 8.h),
Wrap( Wrap(
direction: Axis.horizontal, direction: Axis.horizontal,
@ -120,6 +142,41 @@ class AppointmentDoctorCard extends StatelessWidget {
], ],
), ),
), ),
Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).onPress(() async {
DoctorsListResponseModel selectedDoctor = DoctorsListResponseModel();
selectedDoctor.doctorID = patientAppointmentHistoryResponseModel.doctorID;
selectedDoctor.doctorImageURL = patientAppointmentHistoryResponseModel.doctorImageURL;
selectedDoctor.name = patientAppointmentHistoryResponseModel.doctorNameObj;
selectedDoctor.doctorTitle = patientAppointmentHistoryResponseModel.doctorTitle;
selectedDoctor.nationalityFlagURL = "";
selectedDoctor.speciality = patientAppointmentHistoryResponseModel.doctorSpeciality;
selectedDoctor.clinicName = patientAppointmentHistoryResponseModel.clinicName;
selectedDoctor.projectName = patientAppointmentHistoryResponseModel.projectName;
selectedDoctor.clinicID = patientAppointmentHistoryResponseModel.clinicID;
selectedDoctor.projectID = patientAppointmentHistoryResponseModel.projectID;
getIt.get<BookAppointmentsViewModel>().setSelectedDoctor(selectedDoctor);
LoaderBottomSheet.showLoader();
await getIt.get<BookAppointmentsViewModel>().getDoctorProfile(onSuccess: (dynamic respData) {
LoaderBottomSheet.hideLoader();
Navigator.of(context).push(
CustomPageRoute(
page: DoctorProfilePage(
isDoctorAllowedToBook: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false),
),
),
);
}, onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
})
], ],
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
@ -147,7 +204,7 @@ class AppointmentDoctorCard extends StatelessWidget {
borderColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
fontSize: 14.f, fontSize: 14.f,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0),
height: 40.h, height: 40.h,
@ -166,7 +223,7 @@ class AppointmentDoctorCard extends StatelessWidget {
// borderColor: AppColors.greyColor, // borderColor: AppColors.greyColor,
// textColor: AppColors.blackColor, // textColor: AppColors.blackColor,
// fontSize: 12.f, // fontSize: 12.f,
// fontWeight: FontWeight.w500, // isBold: true,
// borderRadius: 12.r, // borderRadius: 12.r,
// padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), // padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0),
// height: 40.h, // height: 40.h,
@ -187,7 +244,7 @@ class AppointmentDoctorCard extends StatelessWidget {
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor, textColor: AppColors.whiteColor,
fontSize: 14.f, fontSize: 14.f,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 12.r, borderRadius: 12.r,
height: 40.h, height: 40.h,
icon: AppAssets.cancel, icon: AppAssets.cancel,
@ -206,7 +263,7 @@ class AppointmentDoctorCard extends StatelessWidget {
borderColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
fontSize: 14.f, fontSize: 14.f,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 12.r, borderRadius: 12.r,
height: 40.h, height: 40.h,
icon: AppAssets.appointment_calendar_icon, icon: AppAssets.appointment_calendar_icon,
@ -225,7 +282,7 @@ class AppointmentDoctorCard extends StatelessWidget {
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor, textColor: AppColors.whiteColor,
fontSize: 14.f, fontSize: 14.f,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 12.r, borderRadius: 12.r,
height: 40.h, height: 40.h,
icon: AppAssets.cancel, icon: AppAssets.cancel,

@ -0,0 +1,181 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/doctor_row_appointment_rating.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:provider/provider.dart';
class AppointmentRatingWidget extends StatefulWidget {
const AppointmentRatingWidget({super.key, required this.patientAppointmentHistoryResponseModel});
final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
@override
State<AppointmentRatingWidget> createState() => _AppointmentRatingWidgetState();
}
class _AppointmentRatingWidgetState extends State<AppointmentRatingWidget> {
late MyAppointmentsViewModel myAppointmentsViewModel;
late BookAppointmentsViewModel bookAppointmentsViewModel;
int rating = 0;
String notes = "";
@override
Widget build(BuildContext context) {
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context, listen: false);
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
return SizedBox(
height: MediaQuery.of(context).size.height * 0.6,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Scrollable main content
Expanded(
child: Padding(
padding: const EdgeInsets.only(top: 0.0, left: 0, right: 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// Doctor row
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: false,
),
child: BuildDoctorRowAppointmentRating(
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
)),
SizedBox(height: 16),
// Rating box
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: false,
),
width: double.infinity,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.rateTheDoctor.tr(context: context).toText16(isBold: true),
SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
...List.generate(
5,
(index) => AnimatedSwitcher(
duration: Duration(milliseconds: 1000),
switchInCurve: Curves.elasticOut,
switchOutCurve: Curves.elasticIn,
transitionBuilder: (Widget child, Animation<double> animation) {
return ScaleTransition(child: child, scale: animation);
},
child: Container(
key: ValueKey<int>(rating),
child: IconButton(
iconSize: 45.0,
onPressed: () {
setState(() {
rating = index + 1;
});
},
color: rating >= (index + 1) ? Color.fromRGBO(255, 186, 0, 1.0) : Colors.grey[400],
icon: Icon(rating >= (index + 1) ? Icons.star : Icons.star)),
),
),
)
],
),
],
),
),
),
SizedBox(height: 12),
// Note text field
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.0),
child: TextField(
maxLines: 4,
decoration: InputDecoration.collapsed(
hintText: LocaleKeys.notes.tr(context: context),
hintStyle: TextStyle(fontSize: 16.f, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.64, height: 23 / 16)),
onChanged: (value) {
setState(() {
notes = value;
});
},
))),
],
),
),
),
// Bottom action buttons pinned to bottom
SafeArea(
top: false,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: Row(
children: [
Expanded(
child: CustomButton(
text: LocaleKeys.later.tr(context: context),
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
onPressed: () {
Navigator.pop(context);
},
),
),
SizedBox(width: 10),
Expanded(
child: CustomButton(
text: LocaleKeys.submit.tr(context: context),
onPressed: () async {
// Set up clinic rating and show clinic rating view
// appointmentRatingViewModel!.setTitle(LocaleKeys.rateDoctor.tr(context: context),);
// appointmentRatingViewModel!.setSubTitle(LocaleKeys.howWasYourLastVisitWithDoctor.tr(context: context),);
// appointmentRatingViewModel!.setClinicOrDoctor(true);
LoaderBottomSheet.showLoader();
await myAppointmentsViewModel.submitDoctorRating(docRate: rating, docNote: notes, patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel);
// await appointmentRatingViewModel!.submitClinicRating(clinicRate: rating, clinicNote: note);
LoaderBottomSheet.hideLoader();
Navigator.pop(context);
setState(() {});
},
),
),
],
),
),
),
],
),
);
}
}

@ -47,7 +47,7 @@ class AskDoctorRequestTypeSelect extends StatelessWidget {
listTileTheme: ListTileThemeData(horizontalTitleGap: 4), listTileTheme: ListTileThemeData(horizontalTitleGap: 4),
), ),
child: RadioListTile<int>( child: RadioListTile<int>(
title: (askDoctorRequestTypeList[index].description ?? '').toText14(weight: FontWeight.w500), title: (askDoctorRequestTypeList[index].description ?? '').toText14(isBold: true),
value: index, value: index,
fillColor: WidgetStateProperty.resolveWith((states) { fillColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) { if (states.contains(WidgetState.selected)) {

@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/appointment_details_resp_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'dart:ui' as ui;
class BuildDoctorRowAppointmentRating extends StatelessWidget {
final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
BuildDoctorRowAppointmentRating({super.key, required this.patientAppointmentHistoryResponseModel});
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(16),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
patientAppointmentHistoryResponseModel.doctorImageURL!,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
).circle(100),
SizedBox(width: 16.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
patientAppointmentHistoryResponseModel.doctorNameObj!.toString().toText16(isBold: true, maxlines: 1),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(
labelText: patientAppointmentHistoryResponseModel.projectName.toString(),
),
AppCustomChipWidget(
labelText: patientAppointmentHistoryResponseModel.clinicName.toString(),
),
Directionality(
textDirection: ui.TextDirection.ltr,
child: AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -8.w, end: 6.w),
icon: AppAssets.ic_date_filter,
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false),
isEnglishOnly: true,
),
),
],
),
],
),
),
],
),
);
}
}

@ -82,7 +82,7 @@ class FacilitySelectionItem extends StatelessWidget {
subTitle, subTitle,
style: TextStyle( style: TextStyle(
fontSize: 12.h, fontSize: 12.h,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
), ),
), ),

@ -39,7 +39,7 @@ class FacilityTypeSelectionWidget extends StatelessWidget {
LocaleKeys.selectFacilitiesSubTitle.tr(), LocaleKeys.selectFacilitiesSubTitle.tr(),
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
), ),
), ),

@ -36,7 +36,7 @@ import '../../../emergency_services/call_ambulance/widgets/type_selection_widget
// LocaleKeys.selectHospital.tr(context: context), // LocaleKeys.selectHospital.tr(context: context),
// style: TextStyle( // style: TextStyle(
// fontSize: 21, // fontSize: 21,
// fontWeight: FontWeight.w600, // isBold: true,
// color: AppColors.blackColor, // color: AppColors.blackColor,
// ), // ),
// ), // ),
@ -44,7 +44,7 @@ import '../../../emergency_services/call_ambulance/widgets/type_selection_widget
// LocaleKeys.selectHospitalSubTitle.tr(context: context), // LocaleKeys.selectHospitalSubTitle.tr(context: context),
// style: TextStyle( // style: TextStyle(
// fontSize: 16, // fontSize: 16,
// fontWeight: FontWeight.w500, // isBold: true,
// color: AppColors.greyTextColor, // color: AppColors.greyTextColor,
// ), // ),
// ), // ),
@ -186,7 +186,7 @@ class HospitalBottomSheetBody extends StatelessWidget {
children: [ children: [
LocaleKeys.sortByLocation.tr(context: context).toText14(isBold: true), LocaleKeys.sortByLocation.tr(context: context).toText14(isBold: true),
// SizedBox(height: 4.h), // SizedBox(height: 4.h),
LocaleKeys.sortByNearestLocation.tr(context: context).toText11(color: AppColors.textColorLight, weight: FontWeight.w500), LocaleKeys.sortByNearestLocation.tr(context: context).toText11(color: AppColors.textColorLight, isBold: 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_export.dart'; import 'package:hmg_patient_app_new/core/app_export.dart';
@ -7,9 +8,12 @@ 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/models/resp_models/doctor_list_api_response.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.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/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'dart:ui' as ui;
class HospitalListItem extends StatelessWidget { class HospitalListItem extends StatelessWidget {
final PatientDoctorAppointmentList? hospitalData; final PatientDoctorAppointmentList? hospitalData;
final bool isLocationEnabled; final bool isLocationEnabled;
@ -76,12 +80,16 @@ class HospitalListItem extends StatelessWidget {
children: [ children: [
Visibility( Visibility(
visible: (hospitalData?.distanceInKMs != "0"), visible: (hospitalData?.distanceInKMs != "0"),
child: Directionality(
textDirection: ui.TextDirection.ltr,
child: AppCustomChipWidget( child: AppCustomChipWidget(
labelText: "${hospitalData?.distanceInKMs ?? ""} km", 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,
textColor: AppColors.errorColor, textColor: AppColors.errorColor,
isEnglishOnly: true,
),
), ),
), ),
Visibility( Visibility(
@ -89,7 +97,7 @@ class HospitalListItem extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
labelText: "Distance not available", labelText: LocaleKeys.noDistance.tr(),
textColor: AppColors.blackColor, textColor: AppColors.blackColor,
), ),
// SizedBox( // SizedBox(

@ -68,7 +68,7 @@ class RegionListItem extends StatelessWidget {
text: TextSpan( text: TextSpan(
text: count, text: count,
style: TextStyle(fontSize: 12.h, fontWeight: FontWeight.w700, color: AppColors.blackColor), style: TextStyle(fontSize: 12.h, fontWeight: FontWeight.w700, color: AppColors.blackColor),
children: [TextSpan(text: title, style: TextStyle(fontSize: 12.h, fontWeight: FontWeight.w500, color: AppColors.blackColor))])), children: [TextSpan(text: title, style: TextStyle(fontSize: 12.h, fontWeight: FontWeight.w600, color: AppColors.blackColor))])),
); );
} }
@ -93,7 +93,7 @@ class RegionListItem extends StatelessWidget {
subTitle, subTitle,
style: TextStyle( style: TextStyle(
fontSize: 12.h, fontSize: 12.h,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
), ),
), ),

@ -117,38 +117,38 @@ class _RegionBottomSheetBodyState extends State<RegionBottomSheetBody> {
height: MediaQuery.of(context).size.height * 0.5, height: MediaQuery.of(context).size.height * 0.5,
child: Column( child: Column(
children: [ children: [
Consumer<AppointmentViaRegionViewmodel>( // Consumer<AppointmentViaRegionViewmodel>(
builder: (context, regionVM, _) { // builder: (context, regionVM, _) {
return Padding( // return Padding(
padding: EdgeInsets.symmetric(horizontal: 4.w, vertical: 8.h), // padding: EdgeInsets.symmetric(horizontal: 4.w, vertical: 8.h),
child: Row( // child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ // children: [
Row( // Row(
children: [ // children: [
Utils.buildSvgWithAssets(icon: AppAssets.location, iconColor: AppColors.greyTextColor, width: 24.h, height: 24.h), // Utils.buildSvgWithAssets(icon: AppAssets.location, iconColor: AppColors.greyTextColor, width: 24.h, height: 24.h),
SizedBox(width: 12.w), // SizedBox(width: 12.w),
Column( // Column(
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
children: [ // children: [
LocaleKeys.sortByLocation.tr(context: context).toText14(isBold: true), // LocaleKeys.sortByLocation.tr(context: context).toText14(isBold: true),
// SizedBox(height: 4.h), // // SizedBox(height: 4.h),
LocaleKeys.sortByNearestLocation.tr(context: context).toText11(color: AppColors.textColorLight, weight: FontWeight.w500), // LocaleKeys.sortByNearestLocation.tr(context: context).toText11(color: AppColors.textColorLight, isBold: true),
], // ],
), // ),
], // ],
), // ),
Switch( // Switch(
value: regionVM.sortByLocation, // value: regionVM.sortByLocation,
onChanged: (value) => _handleSortByLocationToggle(value), // onChanged: (value) => _handleSortByLocationToggle(value),
activeThumbColor: AppColors.successColor, // activeThumbColor: AppColors.successColor,
activeTrackColor: AppColors.successColor.withValues(alpha: 0.15), // activeTrackColor: AppColors.successColor.withValues(alpha: 0.15),
), // ),
], // ],
), // ),
); // );
}, // },
), // ),
Expanded( Expanded(
child: ListView.separated( child: ListView.separated(
itemCount: myAppointmentsVM.hospitalList?.registeredDoctorMap?.length ?? 0, itemCount: myAppointmentsVM.hospitalList?.registeredDoctorMap?.length ?? 0,

@ -203,7 +203,7 @@ class AskDoctorAppointmentCard extends StatelessWidget {
borderColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
fontSize: 14.f, fontSize: 14.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
// height: isTablet || isFoldable ? 46.h : 40.h, // height: isTablet || isFoldable ? 46.h : 40.h,

@ -77,7 +77,7 @@ class DoctorResponseTransactions extends StatelessWidget {
borderColor: AppColors.greyColor, borderColor: AppColors.greyColor,
textColor: AppColors.textColor, textColor: AppColors.textColor,
fontSize: 14.f, fontSize: 14.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 10.r, borderRadius: 10.r,
height: 40.h, height: 40.h,
).paddingSymmetrical(16.w, 0.h), ).paddingSymmetrical(16.w, 0.h),
@ -93,7 +93,7 @@ class DoctorResponseTransactions extends StatelessWidget {
color: AppColors.infoColor.withAlpha(20), color: AppColors.infoColor.withAlpha(20),
borderRadius: BorderRadius.circular(8.r), borderRadius: BorderRadius.circular(8.r),
), ),
child: doctorResponseModel.requestTypeDescription!.toText12(color: AppColors.infoColor, fontWeight: FontWeight.w500), child: doctorResponseModel.requestTypeDescription!.toText12(color: AppColors.infoColor, isBold: true),
), ),
], ],
), ),
@ -115,7 +115,7 @@ class DoctorResponseTransactions extends StatelessWidget {
color: AppColors.infoColor.withAlpha(20), color: AppColors.infoColor.withAlpha(20),
borderRadius: BorderRadius.circular(8.r), borderRadius: BorderRadius.circular(8.r),
), ),
child: doctorResponseModel.transactions![index].doctorResponse!.toText12(color: AppColors.textColor, fontWeight: FontWeight.w500), child: doctorResponseModel.transactions![index].doctorResponse!.toText12(color: AppColors.textColor, isBold: true),
), ),
SizedBox(width: 8.w), SizedBox(width: 8.w),
Image.network("https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png", fit: BoxFit.cover, width: 42.w, height: 42.h).circle(100.r), Image.network("https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png", fit: BoxFit.cover, width: 42.w, height: 42.h).circle(100.r),

@ -116,7 +116,7 @@ class LoginScreenState extends State<LoginScreen> {
child: RichText( child: RichText(
textAlign: TextAlign.center, textAlign: TextAlign.center,
text: TextSpan( text: TextSpan(
style: context.dynamicTextStyle(color: AppColors.textColor, fontSize: 14.f, height: 26 / 16, fontWeight: FontWeight.w500), style: context.dynamicTextStyle(color: AppColors.textColor, fontSize: 14.f, height: 26 / 16, fontWeight: FontWeight.w600,),
children: <TextSpan>[ children: <TextSpan>[
TextSpan(text: LocaleKeys.dontHaveAccount.tr(context: context), style: context.dynamicTextStyle()), TextSpan(text: LocaleKeys.dontHaveAccount.tr(context: context), style: context.dynamicTextStyle()),
TextSpan(text: " "), TextSpan(text: " "),
@ -126,7 +126,7 @@ class LoginScreenState extends State<LoginScreen> {
color: AppColors.primaryRedColor, color: AppColors.primaryRedColor,
fontSize: 14.f, // Adjusted to sizer unit fontSize: 14.f, // Adjusted to sizer unit
height: 26 / 16, // Ratio height: 26 / 16, // Ratio
fontWeight: FontWeight.w500), fontWeight: FontWeight.w600,),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () { ..onTap = () {
Navigator.of(context).push( Navigator.of(context).push(

@ -49,13 +49,13 @@ class QuickLoginState extends State<QuickLogin> {
], ],
), ),
Utils.showLottie(context: context, assetPath: AppAnimations.checkmark, width: 120, height: 120, repeat: true), Utils.showLottie(context: context, assetPath: AppAnimations.checkmark, width: 120, height: 120, repeat: true),
LocaleKeys.allSet.tr(context: context).toText16(textAlign: TextAlign.center, weight: FontWeight.w500) LocaleKeys.allSet.tr(context: context).toText16(textAlign: TextAlign.center, isBold: true)
// Text( // Text(
// ' TranslationBase.of(context).allSet', // ' TranslationBase.of(context).allSet',
// textAlign: TextAlign.center, // textAlign: TextAlign.center,
// style: context.dynamicTextStyle( // style: context.dynamicTextStyle(
// fontSize: 16, // fontSize: 16,
// fontWeight: FontWeight.w500, // isBold: true,
// color: Colors.black, // color: Colors.black,
// ), // ),
// ), // ),

@ -160,7 +160,7 @@ class _RegisterNew extends State<RegisterNew> {
children: [ children: [
Text( Text(
LocaleKeys.iAcceptThe.tr(context: context), LocaleKeys.iAcceptThe.tr(context: context),
style: context.dynamicTextStyle(fontSize: 14.f, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), style: context.dynamicTextStyle(fontSize: 14.f, fontWeight: FontWeight.w600, color: Color(0xFF2E3039)),
), ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
@ -173,7 +173,7 @@ class _RegisterNew extends State<RegisterNew> {
" ${LocaleKeys.termsConditoins.tr(context: context)}", " ${LocaleKeys.termsConditoins.tr(context: context)}",
style: context.dynamicTextStyle( style: context.dynamicTextStyle(
fontSize: 14.f, fontSize: 14.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
color: AppColors.primaryRedColor, color: AppColors.primaryRedColor,
decoration: TextDecoration.underline, decoration: TextDecoration.underline,
decorationColor: AppColors.primaryRedBorderColor, decorationColor: AppColors.primaryRedBorderColor,
@ -185,7 +185,7 @@ class _RegisterNew extends State<RegisterNew> {
// Expanded( // Expanded(
// child: Text( // child: Text(
// LocaleKeys.iAcceptTermsConditions.tr(context: context).split("the").first, // LocaleKeys.iAcceptTermsConditions.tr(context: context).split("the").first,
// style: context.dynamicTextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), // style: context.dynamicTextStyle(fontSize: 14.fSize, isBold: true, color: Color(0xFF2E3039)),
// ), // ),
// ), // ),
], ],
@ -222,7 +222,7 @@ class _RegisterNew extends State<RegisterNew> {
color: Colors.black, color: Colors.black,
fontSize: 16.f, fontSize: 16.f,
height: 26 / 16, height: 26 / 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
), ),
children: <TextSpan>[ children: <TextSpan>[
TextSpan(text: LocaleKeys.alreadyHaveAccount.tr(context: context), style: context.dynamicTextStyle()), TextSpan(text: LocaleKeys.alreadyHaveAccount.tr(context: context), style: context.dynamicTextStyle()),
@ -233,7 +233,7 @@ class _RegisterNew extends State<RegisterNew> {
color: AppColors.primaryRedColor, color: AppColors.primaryRedColor,
fontSize: 16.f, fontSize: 16.f,
height: 26 / 16, height: 26 / 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
), ),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () { ..onTap = () {

@ -140,7 +140,7 @@ class _RegisterNew extends State<RegisterNewStep2> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
LocaleKeys.personalDetailsVerification.tr(context: context).toText26(color: AppColors.textColor, weight: FontWeight.w600, letterSpacing: -2), LocaleKeys.personalDetailsVerification.tr(context: context).toText26(color: AppColors.textColor, isBold: true, letterSpacing: -2),
SizedBox(height: 24.h), SizedBox(height: 24.h),
// Insurance Card Section // Insurance Card Section

@ -66,6 +66,7 @@ class _SavedLogin extends State<SavedLogin> {
appBar: CustomAppBar( appBar: CustomAppBar(
onBackPressed: () { onBackPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
authVm.setIsInitialLoginNavigated(true);
}, },
onLanguageChanged: (value) { onLanguageChanged: (value) {
context.setLocale(value == 'en' ? Locale('en', 'US') : Locale('ar', 'SA')); context.setLocale(value == 'en' ? Locale('en', 'US') : Locale('ar', 'SA'));
@ -84,7 +85,7 @@ class _SavedLogin extends State<SavedLogin> {
SizedBox(height: 16.h), SizedBox(height: 16.h),
appState.getSelectDeviceByImeiRespModelElement != null appState.getSelectDeviceByImeiRespModelElement != null
? appState.getSelectDeviceByImeiRespModelElement!.name!.toCamelCase ? appState.getSelectDeviceByImeiRespModelElement!.name!.toCamelCase
.toText26(isBold: true, height: 26 / 36, color: AppColors.textColor) .toText26(isBold: true, height: 26 / 36, color: AppColors.textColor, isEnglishOnly: true)
: SizedBox(), : SizedBox(),
SizedBox(height: 24.h), SizedBox(height: 24.h),
Container( Container(
@ -144,7 +145,7 @@ class _SavedLogin extends State<SavedLogin> {
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
textColor: Colors.white, textColor: Colors.white,
fontSize: 12.f, fontSize: 12.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
height: 40.h, height: 40.h,
padding: EdgeInsets.symmetric(vertical: 10.h), padding: EdgeInsets.symmetric(vertical: 10.h),
@ -161,7 +162,7 @@ class _SavedLogin extends State<SavedLogin> {
padding: EdgeInsets.symmetric(horizontal: 16.w), padding: EdgeInsets.symmetric(horizontal: 16.w),
child: Text( child: Text(
LocaleKeys.oR.tr(), LocaleKeys.oR.tr(),
style: context.dynamicTextStyle(fontSize: 16.f, fontWeight: FontWeight.w500), style: context.dynamicTextStyle(fontSize: 16.f, fontWeight: FontWeight.w600,),
), ),
), ),
SizedBox(height: 24.h), SizedBox(height: 24.h),
@ -206,7 +207,7 @@ class _SavedLogin extends State<SavedLogin> {
}, },
backgroundColor: AppColors.primaryRedColor, backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
textColor: AppColors.textColor, textColor: Colors.white,
icon: AppAssets.sms), icon: AppAssets.sms),
), ),
Row( Row(
@ -304,7 +305,7 @@ class _SavedLogin extends State<SavedLogin> {
borderColor: Color(0xffFEE9EA), borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B), textColor: Color(0xffED1C2B),
fontSize: 16.f, fontSize: 16.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.fromLTRB(0, 10.h, 0, 10.h), padding: EdgeInsets.fromLTRB(0, 10.h, 0, 10.h),
// icon: "assets/images/svg/apple-finder.svg", // icon: "assets/images/svg/apple-finder.svg",
@ -329,7 +330,7 @@ class _SavedLogin extends State<SavedLogin> {
borderColor: Color(0xffFEE9EA), borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B), textColor: Color(0xffED1C2B),
fontSize: 15.f, fontSize: 15.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.fromLTRB(0, 10.h, 0, 10.h), padding: EdgeInsets.fromLTRB(0, 10.h, 0, 10.h),
// icon: "assets/images/svg/apple-finder.svg", // icon: "assets/images/svg/apple-finder.svg",

@ -146,11 +146,11 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.city.tr().toText16(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.city.tr().toText16(color: AppColors.textColor, isBold: true),
(appState.isArabic() (appState.isArabic()
? (bloodDonationVM.selectedCity?.descriptionN ?? LocaleKeys.select.tr()) ? (bloodDonationVM.selectedCity?.descriptionN ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedCity?.description ?? LocaleKeys.select.tr(context: context)) : bloodDonationVM.selectedCity?.description ?? LocaleKeys.select.tr(context: context))
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), .toText14(color: AppColors.greyTextColor, isBold: true),
], ],
), ),
], ],
@ -174,11 +174,11 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.gender.tr().toText16(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.gender.tr().toText16(color: AppColors.textColor, isBold: true),
(appState.isArabic() (appState.isArabic()
? (bloodDonationVM.selectedGender?.typeAr ?? LocaleKeys.select.tr()) ? (bloodDonationVM.selectedGender?.typeAr ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedGender?.type ?? LocaleKeys.select.tr(context: context)) : bloodDonationVM.selectedGender?.type ?? LocaleKeys.select.tr(context: context))
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), .toText14(color: AppColors.greyTextColor, isBold: true),
], ],
), ),
], ],
@ -205,12 +205,12 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.bloodType.tr().toText16(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.bloodType.tr().toText16(color: AppColors.textColor, isBold: true),
// bloodDonationVM.selectedBloodType?.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), // bloodDonationVM.selectedBloodType?.toText14(color: AppColors.greyTextColor, isBold: true),
(appState.isArabic() (appState.isArabic()
? (bloodDonationVM.selectedBloodType ?? LocaleKeys.select.tr()) ? (bloodDonationVM.selectedBloodType ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedBloodType ?? LocaleKeys.select.tr(context: context)) : bloodDonationVM.selectedBloodType ?? LocaleKeys.select.tr(context: context))
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500) .toText14(color: AppColors.greyTextColor, isBold: true)
], ],
), ),
], ],
@ -264,7 +264,7 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
children: [ children: [
Text( Text(
"${LocaleKeys.iAcceptThe.tr()} ", "${LocaleKeys.iAcceptThe.tr()} ",
style: context.dynamicTextStyle(fontSize: 14.f, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), style: context.dynamicTextStyle(fontSize: 14.f, fontWeight: FontWeight.w600, color: Color(0xFF2E3039)),
), ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
@ -282,7 +282,7 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
LocaleKeys.termsConditoins.tr(), LocaleKeys.termsConditoins.tr(),
style: context.dynamicTextStyle( style: context.dynamicTextStyle(
fontSize: 14.f, fontSize: 14.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
color: AppColors.primaryRedColor, color: AppColors.primaryRedColor,
decoration: TextDecoration.underline, decoration: TextDecoration.underline,
decorationColor: AppColors.primaryRedBorderColor, decorationColor: AppColors.primaryRedBorderColor,
@ -294,7 +294,7 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
// Expanded( // Expanded(
// child: Text( // child: Text(
// LocaleKeys.iAcceptTermsConditions.tr().split("the").first, // LocaleKeys.iAcceptTermsConditions.tr().split("the").first,
// style: context.dynamicTextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), // style: context.dynamicTextStyle(fontSize: 14.fSize, isBold: true, color: Color(0xFF2E3039)),
// ), // ),
// ), // ),
], ],
@ -365,7 +365,7 @@ class _BloodDonationPageState extends State<BloodDonationPage> {
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor, textColor: AppColors.whiteColor,
fontSize: 16.f, fontSize: 16.f,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 50.h, height: 50.h,

@ -19,6 +19,7 @@ import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_liveca
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/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/my_doctors_page.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/faculity_selection/facility_type_selection_widget.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/faculity_selection/facility_type_selection_widget.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bottomsheet/region_list_widget.dart' show RegionBottomSheetBody; import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bottomsheet/region_list_widget.dart' show RegionBottomSheetBody;
import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_profile_page.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_profile_page.dart';
@ -119,7 +120,15 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
if (appState.isAuthenticated) ...[ if (appState.isAuthenticated) ...[
Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) { Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
return myAppointmentsVM.isPatientMyDoctorsLoading return myAppointmentsVM.isPatientMyDoctorsLoading
? Column( ? SizedBox(
height: 110.h,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: 5,
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.w, right: 24.w),
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Image.network( Image.network(
@ -129,8 +138,12 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
fit: BoxFit.cover, fit: BoxFit.cover,
).circle(100).toShimmer2(isShow: true, radius: 50.r), ).circle(100).toShimmer2(isShow: true, radius: 50.r),
SizedBox(height: 8.h), SizedBox(height: 8.h),
("Dr. John Smith Smith Smith").toString().toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2).toShimmer2(isShow: true), ("Dr. John").toString().toText12(isBold: true, isCenter: true, maxLine: 2).toShimmer2(isShow: true),
], ],
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 16.h),
),
) )
: myAppointmentsVM.patientMyDoctorsList.isEmpty : myAppointmentsVM.patientMyDoctorsList.isEmpty
? SizedBox() ? SizedBox()
@ -138,7 +151,25 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (appState.isAuthenticated) ...[], if (appState.isAuthenticated) ...[],
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.recentVisits.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.w, 0.h), LocaleKeys.recentVisits.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.w, 0.h),
Row(
children: [
LocaleKeys.viewAll.tr(context: context).toText14(color: AppColors.primaryRedColor, isBold: true),
SizedBox(width: 2.h),
Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 14.h),
],
).paddingSymmetrical(24.h, 0.h).onPress(() {
Navigator.of(context).push(
CustomPageRoute(
page: MyDoctorsPage(),
),
);
}),
],
),
SizedBox(height: 16.h), SizedBox(height: 16.h),
SizedBox( SizedBox(
height: 110.h, height: 110.h,
@ -170,7 +201,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
width: 80.w, width: 80.w,
child: (myAppointmentsVM.patientMyDoctorsList[index].doctorName) child: (myAppointmentsVM.patientMyDoctorsList[index].doctorName)
.toString() .toString()
.toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2) .toText12(isBold: true, isCenter: true, maxLine: 2)
.toShimmer2(isShow: false), .toShimmer2(isShow: false),
), ),
], ],
@ -186,7 +217,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: DoctorProfilePage(), page: DoctorProfilePage(isDoctorAllowedToBook: !(myAppointmentsVM.patientMyDoctorsList[index].isLiveCareClinic ?? false)),
), ),
); );
}, onError: (err) { }, onError: (err) {
@ -218,13 +249,14 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 24.h), SizedBox(height: 24.h),
LocaleKeys.favouriteDoctors.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.w, 0.h), LocaleKeys.favouriteList.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.w, 0.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
SizedBox( SizedBox(
height: 110.h, height: 110.h,
child: ListView.separated( child: ListView.separated(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: 3, // Show 3 shimmer items itemCount: 3,
// Show 3 shimmer items
shrinkWrap: true, shrinkWrap: true,
padding: EdgeInsets.only(left: 24.w, right: 24.w), padding: EdgeInsets.only(left: 24.w, right: 24.w),
itemBuilder: (context, index) { itemBuilder: (context, index) {
@ -264,21 +296,79 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
// Show empty state or actual list // Show empty state or actual list
return myAppointmentsVM.patientFavouriteDoctorsList.isEmpty return myAppointmentsVM.patientFavouriteDoctorsList.isEmpty
? SizedBox() ? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 16.h),
LocaleKeys.favouriteList.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.w, 0.h),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
padding: EdgeInsets.all(16.h),
child: Column(
children: [
Center(
child: LocaleKeys.noFavouriteDoctors.tr(context: context).toText14(color: AppColors.greyTextColor, isBold: true),
),
SizedBox(height: 12.h),
CustomButton(
text: LocaleKeys.add.tr(context: context),
onPressed: () {
Navigator.of(context).push(CustomPageRoute(page: SearchDoctorByName()));
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
fontSize: 14.f,
isBold: true,
padding: EdgeInsets.fromLTRB(10.h, 0, 10.h, 0),
icon: AppAssets.add_icon,
iconColor: AppColors.primaryRedColor,
height: 40.h,
),
],
),
).paddingSymmetrical(24.w, 0.h),
SizedBox(height: 24.h),
],
)
: Column( : Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 24.h), SizedBox(height: 24.h),
LocaleKeys.favouriteDoctors.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.w, 0.h), LocaleKeys.favourites.tr(context: context).toText18(isBold: true).paddingSymmetrical(24.w, 0.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
SizedBox( SizedBox(
height: 110.h, height: 110.h,
child: ListView.separated( child: ListView.separated(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: myAppointmentsVM.patientFavouriteDoctorsList.length, itemCount: myAppointmentsVM.patientFavouriteDoctorsList.length + 1,
shrinkWrap: true, shrinkWrap: true,
padding: EdgeInsets.only(left: 24.w, right: 24.w), padding: EdgeInsets.only(left: 24.w, right: 24.w),
itemBuilder: (context, index) { itemBuilder: (context, index) {
// Last item: static "Add" button
if (index == myAppointmentsVM.patientFavouriteDoctorsList.length) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.add_new_family_icon, height: 64.h, width: 64.h),
SizedBox(
width: 80.w,
child: LocaleKeys.add.tr(context: context).toText12(
color: AppColors.textColor,
isBold: true,
isCenter: true,
).paddingOnly(top: 4.h),
),
],
).onPress(() {
Navigator.of(context).push(CustomPageRoute(page: SearchDoctorByName()));
});
}
return AnimationConfiguration.staggeredList( return AnimationConfiguration.staggeredList(
position: index, position: index,
duration: const Duration(milliseconds: 1000), duration: const Duration(milliseconds: 1000),
@ -300,7 +390,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
width: 80.w, width: 80.w,
child: (myAppointmentsVM.patientFavouriteDoctorsList[index].doctorName) child: (myAppointmentsVM.patientFavouriteDoctorsList[index].doctorName)
.toString() .toString()
.toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2) .toText12(isBold: true, isCenter: true, maxLine: 2)
.toShimmer2(isShow: false), .toShimmer2(isShow: false),
), ),
], ],
@ -316,7 +406,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: DoctorProfilePage(), page: DoctorProfilePage(isDoctorAllowedToBook: true),
), ),
); );
}, onError: (err) { }, onError: (err) {
@ -381,8 +471,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.searchByClinic.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.searchByClinic.tr(context: context).toText14(color: AppColors.textColor, isBold: true),
LocaleKeys.tapToSelectClinic.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), LocaleKeys.tapToSelectClinic.tr(context: context).toText12(color: AppColors.primaryRedColor, isBold: true),
], ],
), ),
], ],
@ -413,8 +503,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.searchByDoctor.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.searchByDoctor.tr(context: context).toText14(color: AppColors.textColor, isBold: true),
LocaleKeys.tapToSelect.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), LocaleKeys.tapToSelect.tr(context: context).toText12(color: AppColors.primaryRedColor, isBold: true),
], ],
), ),
], ],
@ -443,8 +533,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.searchByRegion.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.searchByRegion.tr(context: context).toText14(color: AppColors.textColor, isBold: true),
LocaleKeys.centralRegion.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), LocaleKeys.centralRegion.tr(context: context).toText12(color: AppColors.primaryRedColor, isBold: true),
], ],
), ),
], ],
@ -487,8 +577,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.immediateConsultation.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.immediateConsultation.tr(context: context).toText14(color: AppColors.textColor, isBold: true),
LocaleKeys.tapToSelectClinic.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), LocaleKeys.tapToSelectClinic.tr(context: context).toText12(color: AppColors.primaryRedColor, isBold: true),
], ],
), ),
], ],
@ -529,8 +619,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.scheduledConsultation.tr(context: context).toText14(color: AppColors.textColor, weight: FontWeight.w500), LocaleKeys.scheduledConsultation.tr(context: context).toText14(color: AppColors.textColor, isBold: true),
LocaleKeys.tapToSelectClinic.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), LocaleKeys.tapToSelectClinic.tr(context: context).toText12(color: AppColors.primaryRedColor, isBold: true),
], ],
), ),
], ],
@ -570,10 +660,10 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.notSureHelpMeChooseClinic.tr(context: context).toText16(weight: FontWeight.w600, color: AppColors.textColor), LocaleKeys.notSureHelpMeChooseClinic.tr(context: context).toText16(isBold: true, color: AppColors.textColor),
SizedBox(height: 8.h), SizedBox(height: 8.h),
LocaleKeys.mentionYourSymptomsAndFindDoctors.tr(context: context).toText12( LocaleKeys.mentionYourSymptomsAndFindDoctors.tr(context: context).toText12(
fontWeight: FontWeight.w500, isBold: true,
color: AppColors.greyTextColor, color: AppColors.greyTextColor,
), ),
], ],
@ -733,7 +823,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
getTitle(AppointmentViaRegionViewmodel data) { getTitle(AppointmentViaRegionViewmodel data) {
if (data.selectedRegionId == null) { if (data.selectedRegionId == null) {
return LocaleKeys.selectRegion.tr(context: context).toText20(weight: FontWeight.w600); return LocaleKeys.selectRegion.tr(context: context).toText20(isBold: true);
} else { } else {
return Transform.flip( return Transform.flip(
flipX: data.isArabic ? true : false, flipX: data.isArabic ? true : false,
@ -761,7 +851,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.immediateService.tr(context: context).toText18(color: AppColors.textColor, isBold: true), LocaleKeys.immediateService.tr(context: context).toText18(color: AppColors.textColor, isBold: true),
LocaleKeys.noNeedToWaitGetMedicalConsultation.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), LocaleKeys.noNeedToWaitGetMedicalConsultation.tr(context: context).toText14(color: AppColors.greyTextColor, isBold: true),
], ],
), ),
), ),
@ -777,7 +867,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.noVisitRequired.tr(context: context).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, isBold: true),
], ],
), ),
), ),
@ -793,7 +883,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.doctorWillContact.tr(context: context).toText18(color: AppColors.textColor, isBold: true), LocaleKeys.doctorWillContact.tr(context: context).toText18(color: AppColors.textColor, isBold: true),
LocaleKeys.specialisedDoctorWillContactYou.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), LocaleKeys.specialisedDoctorWillContactYou.tr(context: context).toText14(color: AppColors.greyTextColor, isBold: true),
], ],
), ),
), ),
@ -809,7 +899,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.freeMedicineDelivery.tr(context: context).toText18(color: AppColors.textColor, isBold: true), LocaleKeys.freeMedicineDelivery.tr(context: context).toText18(color: AppColors.textColor, isBold: true),
LocaleKeys.offersFreeMedicineDelivery.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), LocaleKeys.offersFreeMedicineDelivery.tr(context: context).toText14(color: AppColors.greyTextColor, isBold: true),
], ],
), ),
), ),
@ -825,7 +915,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor, textColor: AppColors.whiteColor,
fontSize: 16.f, fontSize: 16.f,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 12.r, borderRadius: 12.r,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0), padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h, height: 50.h,
@ -848,7 +938,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
children: [ children: [
LocaleKeys.notSureHelpMeChooseClinic.tr(context: context).toText28(color: AppColors.textColor, isBold: true, height: 1.5), LocaleKeys.notSureHelpMeChooseClinic.tr(context: context).toText28(color: AppColors.textColor, isBold: true, height: 1.5),
SizedBox(height: 4.h), SizedBox(height: 4.h),
LocaleKeys.mentionYourSymptomsAndFindDoctors.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500,), LocaleKeys.mentionYourSymptomsAndFindDoctors.tr(context: context).toText12(color: AppColors.greyTextColor, isBold: true,),
SizedBox(height: 24.h), SizedBox(height: 24.h),
CustomButton( CustomButton(
text: LocaleKeys.yesPleaseINeedHelp.tr(context: context), text: LocaleKeys.yesPleaseINeedHelp.tr(context: context),
@ -860,7 +950,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor, textColor: AppColors.whiteColor,
fontSize: 16.f, fontSize: 16.f,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 12.r, borderRadius: 12.r,
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 56.h, height: 56.h,
@ -875,7 +965,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
borderColor: AppColors.chipSecondaryLightRedColor, borderColor: AppColors.chipSecondaryLightRedColor,
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
fontSize: 16.f, fontSize: 16.f,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 12.r, borderRadius: 12.r,
// padding: EdgeInsets.fromLTRB(10, 0, 10, 0), // padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 56.h, height: 56.h,

@ -70,7 +70,7 @@ class DoctorsFilters extends StatelessWidget{
LocaleKeys.clearAllFilters.tr(), LocaleKeys.clearAllFilters.tr(),
style:TextStyle( style:TextStyle(
fontFamily: 'Poppins', fontFamily: 'Poppins',
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
fontSize: 14.f, fontSize: 14.f,
color: AppColors.errorColor color: AppColors.errorColor
) )
@ -181,7 +181,7 @@ class DoctorsFilters extends StatelessWidget{
textColor: Colors.white, textColor: Colors.white,
fontSize: 16.f, fontSize: 16.f,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
borderRadius: 10.r, borderRadius: 10.r,
icon: AppAssets.add_icon, icon: AppAssets.add_icon,
iconColor: AppColors.primaryRedColor, iconColor: AppColors.primaryRedColor,

@ -1,5 +1,6 @@
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:intl/intl.dart' show NumberFormat;
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';
import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart';
@ -21,7 +22,9 @@ import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class DoctorProfilePage extends StatelessWidget { class DoctorProfilePage extends StatelessWidget {
const DoctorProfilePage({super.key}); const DoctorProfilePage({super.key, required this.isDoctorAllowedToBook});
final bool isDoctorAllowedToBook;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -33,17 +36,17 @@ class DoctorProfilePage extends StatelessWidget {
children: [ children: [
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: LocaleKeys.doctorProfile.tr(), title: LocaleKeys.profileOnlyText.tr(),
trailing: Consumer<BookAppointmentsViewModel>( trailing: appState.isAuthenticated
? Consumer<BookAppointmentsViewModel>(
builder: (context, viewModel, child) { builder: (context, viewModel, child) {
return SizedBox( return SizedBox(
width: 24.h, width: 24.h,
height: 24.h, height: 24.h,
child: Utils.buildSvgWithAssets( child: Icon(
icon: viewModel.isFavouriteDoctor ? AppAssets.bookmark_filled_icon : AppAssets.bookmark_icon, viewModel.isFavouriteDoctor ? Icons.bookmark : Icons.bookmark_border_outlined,
width: 24.h, size: 36.h,
height: 24.h, color: viewModel.isFavouriteDoctor ? AppColors.primaryRedColor : AppColors.textColor,
iconColor: viewModel.isFavouriteDoctor ? AppColors.primaryRedColor : AppColors.textColor,
).onPress(() async { ).onPress(() async {
viewModel.toggleFavouriteDoctor(); viewModel.toggleFavouriteDoctor();
await viewModel.insertFavouriteDoctor( await viewModel.insertFavouriteDoctor(
@ -53,11 +56,9 @@ class DoctorProfilePage extends StatelessWidget {
doctorID: viewModel.doctorsProfileResponseModel.doctorID ?? 0, doctorID: viewModel.doctorsProfileResponseModel.doctorID ?? 0,
isActive: viewModel.isFavouriteDoctor, isActive: viewModel.isFavouriteDoctor,
onSuccess: (response) { onSuccess: (response) {
Utils.showToast(viewModel.isFavouriteDoctor ? LocaleKeys.doctorAddedToFavourite.tr(context: context) : LocaleKeys.doctorRemovedFromFavourite.tr(context: context));
// Successfully added/removed favorite - refresh the favorites list // Successfully added/removed favorite - refresh the favorites list
getIt.get<MyAppointmentsViewModel>().refreshFavouriteDoctors(); getIt.get<MyAppointmentsViewModel>().refreshFavouriteDoctors();
print(
viewModel.isFavouriteDoctor ? "Doctor added to favorites" : "Doctor removed from favorites",
);
}, },
onError: (error) { onError: (error) {
// Revert the state on error // Revert the state on error
@ -68,7 +69,8 @@ class DoctorProfilePage extends StatelessWidget {
}), }),
); );
}, },
), )
: SizedBox.shrink(),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -98,7 +100,7 @@ class DoctorProfilePage extends StatelessWidget {
), ),
(bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.isNotEmpty ? bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.first : "") (bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.isNotEmpty ? bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.first : "")
.toString() .toString()
.toText18(weight: FontWeight.w500, color: AppColors.primaryRedColor), .toText18(isBold: true, color: AppColors.primaryRedColor),
], ],
), ),
], ],
@ -137,7 +139,7 @@ class DoctorProfilePage extends StatelessWidget {
children: [ children: [
Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_rating_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_rating_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false),
SizedBox(height: 16.h), SizedBox(height: 16.h),
LocaleKeys.ratings.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), LocaleKeys.ratings.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor),
bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate
.toString() .toString()
.toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"), .toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"),
@ -158,9 +160,8 @@ class DoctorProfilePage extends StatelessWidget {
children: [ children: [
Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_reviews_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false), Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_reviews_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false),
SizedBox(height: 16.h), SizedBox(height: 16.h),
LocaleKeys.reviews.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), LocaleKeys.reviews.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor),
bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate NumberFormat.decimalPattern().format(bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate ?? 0)
.toString()
.toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"), .toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"),
], ],
).onPress(() { ).onPress(() {
@ -179,15 +180,16 @@ class DoctorProfilePage extends StatelessWidget {
SizedBox(height: 16.h), SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h), SizedBox(height: 16.h),
LocaleKeys.docInfo.tr(context: context).toText14(weight: FontWeight.w600, color: AppColors.textColor), LocaleKeys.information.tr(context: context).toText14(isBold: true, color: AppColors.textColor),
SizedBox(height: 6.h), SizedBox(height: 6.h),
bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo!.toText12(fontWeight: FontWeight.w600, color: AppColors.greyTextColor), (bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo ?? "").trim().toText12(isBold: true, color: AppColors.greyTextColor),
SizedBox(height: 24.h),
], ],
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
), ),
), ),
), ),
Container( isDoctorAllowedToBook ? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, color: AppColors.whiteColor,
borderRadius: 24.h, borderRadius: 24.h,
@ -199,7 +201,11 @@ class DoctorProfilePage extends StatelessWidget {
bookAppointmentsViewModel.selectedDoctor.speciality = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty; bookAppointmentsViewModel.selectedDoctor.speciality = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty;
bookAppointmentsViewModel.selectedDoctor.specialityN = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty; bookAppointmentsViewModel.selectedDoctor.specialityN = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty;
bookAppointmentsViewModel.selectedDoctor.name = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName; bookAppointmentsViewModel.selectedDoctor.name = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName;
bookAppointmentsViewModel.selectedDoctor.name = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName; bookAppointmentsViewModel.selectedDoctor.doctorImageURL = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorImageURL;
bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL = bookAppointmentsViewModel.doctorsProfileResponseModel.nationalityFlagURL;
bookAppointmentsViewModel.selectedDoctor.clinicName = bookAppointmentsViewModel.doctorsProfileResponseModel.clinicDescription;
bookAppointmentsViewModel.selectedDoctor.projectName = bookAppointmentsViewModel.doctorsProfileResponseModel.projectName;
LoaderBottomSheet.showLoader(); LoaderBottomSheet.showLoader();
bookAppointmentsViewModel.isLiveCareSchedule bookAppointmentsViewModel.isLiveCareSchedule
? await bookAppointmentsViewModel.getLiveCareDoctorFreeSlots( ? await bookAppointmentsViewModel.getLiveCareDoctorFreeSlots(
@ -253,7 +259,7 @@ class DoctorProfilePage extends StatelessWidget {
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
textColor: Colors.white, textColor: Colors.white,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500, isBold: true,
borderRadius: 12, borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0), padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h, height: 50.h,
@ -261,7 +267,7 @@ class DoctorProfilePage extends StatelessWidget {
iconColor: Colors.white, iconColor: Colors.white,
iconSize: 20.h, iconSize: 20.h,
).paddingSymmetrical(24.h, 24.h), ).paddingSymmetrical(24.h, 24.h),
), ) : SizedBox.shrink(),
], ],
), ),
); );

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

Loading…
Cancel
Save