Merge branch 'refs/heads/master' into dev_sikander

# Conflicts:
#	lib/presentation/habib_wallet/habib_wallet_page.dart
#	lib/presentation/hmg_services/services_page.dart
#	lib/presentation/home/landing_page.dart
#	lib/presentation/home/widgets/habib_wallet_card.dart
#	lib/presentation/insurance/insurance_home_page.dart
#	lib/presentation/lab/lab_orders_page.dart
#	lib/presentation/medical_file/medical_file_page.dart
#	lib/presentation/profile_settings/profile_settings.dart
#	lib/presentation/radiology/radiology_orders_page.dart
#	lib/widgets/appbar/collapsing_list_view.dart
dev_sikander
Sikander Saleem 6 days ago
commit e38892ff2d

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

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

After

Width:  |  Height:  |  Size: 803 B

@ -0,0 +1,4 @@
<svg width="20" height="18" viewBox="0 0 20 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10C18 10.5523 18.4477 11 19 11C19.5523 11 20 10.5523 20 10C20 4.47715 15.5228 0 10 0C4.47715 0 0 4.47715 0 10C0 10.5523 0.447715 11 1 11C1.55228 11 2 10.5523 2 10Z" fill="white"/>
<path d="M10 6C10.5523 6 11 6.44772 11 7L11 12.1707C12.1652 12.5825 13 13.6938 13 15C13 16.6569 11.6569 18 10 18C8.34315 18 7 16.6569 7 15C7 13.6938 7.83481 12.5825 9 12.1707L9 7C9 6.44772 9.44772 6 10 6Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 568 B

@ -0,0 +1,3 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 6.75C4 3.02208 7.02208 0 10.75 0C14.4779 0 17.5 3.02208 17.5 6.75C17.5 6.81385 17.5 6.84578 17.4946 6.87394C17.4654 7.02516 17.324 7.13066 17.1708 7.11566C17.1422 7.11287 17.1041 7.10157 17.028 7.07899C16.306 6.86492 15.5414 6.75 14.75 6.75C11.4211 6.75 8.56706 8.78325 7.36206 11.6756C7.21403 12.031 7.14001 12.2086 6.99327 12.2449C6.84654 12.2812 6.71484 12.1723 6.45145 11.9546L6.45144 11.9546C4.95411 10.7165 4 8.84466 4 6.75ZM8 14.75C8 11.0221 11.0221 8 14.75 8C18.4779 8 21.5 11.0221 21.5 14.75C21.5 18.4779 18.4779 21.5 14.75 21.5C11.0221 21.5 8 18.4779 8 14.75ZM6.77538 14.11C6.75857 14.3217 6.75 14.5358 6.75 14.7519C6.75 16.87 7.57313 18.7958 8.91695 20.227L8.91696 20.227C9.22203 20.5519 9.37457 20.7143 9.33165 20.8754C9.28873 21.0365 9.09982 21.0941 8.72199 21.2093C8.09819 21.3996 7.43605 21.5019 6.75 21.5019C3.02208 21.5019 0 18.4798 0 14.7519C0 12.6572 0.954182 10.7853 2.45161 9.54723C2.715 9.32946 2.8467 9.22057 2.99343 9.25688C3.14016 9.29319 3.21416 9.4708 3.36215 9.82601C3.9893 11.3312 5.0627 12.6033 6.41512 13.4766L6.4968 13.5294C6.64871 13.6275 6.72467 13.6765 6.76134 13.7507C6.79802 13.8249 6.79047 13.9199 6.77538 14.11Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,4 @@
<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="M11.9998 21.25C11.5858 21.2503 11.2498 21.5859 11.2498 22C11.2498 22.4141 11.5858 22.7497 11.9998 22.75H14.3953C14.577 22.75 14.7553 22.7915 14.9158 22.8691L16.9578 23.8564C17.3233 24.0333 17.7251 24.125 18.1316 24.125H19.1746C19.601 24.1251 19.9516 24.3534 20.1277 24.6719L18.1931 25.207C17.9121 25.2847 17.6116 25.2563 17.3523 25.1309L15.1687 24.0752C14.7959 23.895 14.3471 24.051 14.1667 24.4238C13.9866 24.7966 14.1427 25.2454 14.5154 25.4258L16.699 26.4814C17.2874 26.7661 17.9622 26.8265 18.5925 26.6523L21.1335 25.9502C21.4836 25.8534 21.7498 25.5327 21.7498 25.1416C21.7498 25.1125 21.7468 25.0836 21.7458 25.0547L25.8132 23.8057L25.8162 23.8047C26.3135 23.6499 26.8624 23.8288 27.1892 24.2812C27.3052 24.4419 27.2446 24.6626 27.1033 24.7441L19.5876 29.0811C19.2867 29.2546 18.9351 29.2953 18.6082 29.1982L12.2136 27.3008C11.8165 27.1829 11.3988 27.4095 11.281 27.8066C11.1632 28.2037 11.3898 28.6214 11.7869 28.7393L18.1814 30.6367C18.9059 30.8517 19.6827 30.7578 20.3376 30.3799L27.8533 26.0439C28.7864 25.5055 29.0265 24.2639 28.405 23.4033C27.7121 22.4438 26.5013 22.0206 25.3708 22.3721L25.3699 22.373L21.241 23.6416C20.7675 23.0215 20.0117 22.6251 19.1746 22.625H18.1316C17.95 22.625 17.7716 22.5844 17.6111 22.5068L15.5691 21.5186C15.2035 21.3417 14.8017 21.25 14.3953 21.25H11.9998ZM22.6511 9.91992C21.7188 9.02657 20.2817 9.02657 19.3494 9.91992C18.7347 10.5091 17.9734 11.3294 17.3611 12.2773C16.7542 13.2169 16.2498 14.3489 16.2498 15.5469C16.2498 17.8542 18.0478 20.25 21.0007 20.25C23.9534 20.2497 25.7507 17.854 25.7507 15.5469C25.7507 14.3489 25.2463 13.2169 24.6394 12.2773C24.0271 11.3294 23.2657 10.5091 22.6511 9.91992ZM20.3875 11.0029C20.7396 10.6657 21.2609 10.6657 21.613 11.0029C22.181 11.5474 22.8538 12.2767 23.3796 13.0908C23.9109 13.9134 24.2507 14.7575 24.2507 15.5469C24.2507 17.1367 23.0181 18.7497 21.0007 18.75C18.9831 18.75 17.7498 17.1369 17.7498 15.5469C17.7498 14.7575 18.0895 13.9134 18.6208 13.0908C19.1467 12.2767 19.8195 11.5474 20.3875 11.0029Z" fill="#8F9AA3"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

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

After

Width:  |  Height:  |  Size: 800 B

@ -0,0 +1,5 @@
<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 fill-rule="evenodd" clip-rule="evenodd" d="M19.9999 9.25C17.9288 9.25 16.2499 10.9289 16.2499 13C16.2499 14.0736 16.805 15.1188 17.4741 15.8701C17.8161 16.2541 18.2118 16.5896 18.6284 16.8334C19.038 17.0732 19.5126 17.25 19.9999 17.25C20.4872 17.25 20.9617 17.0732 21.3714 16.8334C21.7879 16.5896 22.1837 16.2541 22.5257 15.8701C23.1947 15.1188 23.7499 14.0736 23.7499 13C23.7499 10.9289 22.0709 9.25 19.9999 9.25ZM17.7499 13C17.7499 11.7574 18.7572 10.75 19.9999 10.75C21.2425 10.75 22.2499 11.7574 22.2499 13C22.2499 13.5832 21.9259 14.2881 21.4054 14.8725C21.1526 15.1564 20.876 15.3853 20.6137 15.5388C20.3444 15.6964 20.1334 15.75 19.9999 15.75C19.8663 15.75 19.6554 15.6964 19.3861 15.5388C19.1238 15.3853 18.8471 15.1564 18.5943 14.8725C18.0738 14.2881 17.7499 13.5832 17.7499 13Z" fill="#8F9AA3"/>
<path d="M24.536 16.4361C24.2245 16.163 23.7507 16.1941 23.4776 16.5056C23.2045 16.817 23.2356 17.2909 23.5471 17.5639C24.916 18.7642 25.6946 20.6997 24.9738 22.4145C24.8973 22.5965 24.7277 22.7039 24.5514 22.7039C24.4876 22.7039 24.4316 22.7013 24.3593 22.6978C24.3058 22.6953 24.2432 22.6923 24.1618 22.6897C24.0028 22.6845 23.7976 22.6828 23.5892 22.7127C23.3824 22.7424 23.1208 22.8099 22.8813 22.9807C22.6237 23.1644 22.4437 23.4309 22.3633 23.7588L21.266 28.2337C21.1173 28.8402 20.5889 29.25 20.0001 29.25C19.4112 29.25 18.8828 28.8402 18.7341 28.2337L17.6368 23.7588C17.5564 23.4309 17.3764 23.1644 17.1188 22.9807C16.8793 22.8099 16.6177 22.7424 16.4109 22.7127C16.2025 22.6828 15.9973 22.6845 15.8383 22.6897C15.7569 22.6923 15.6944 22.6953 15.6408 22.6978C15.5685 22.7013 15.5125 22.7039 15.4487 22.7039C15.2724 22.7039 15.1028 22.5965 15.0263 22.4145C14.3055 20.6997 15.0841 18.7642 16.4531 17.5639C16.7645 17.2909 16.7956 16.817 16.5226 16.5056C16.2495 16.1941 15.7756 16.163 15.4642 16.4361C13.7871 17.9065 12.5919 20.4941 13.6435 22.9958C13.9489 23.7223 14.6555 24.2039 15.4487 24.2039C15.5413 24.2039 15.6638 24.1985 15.7652 24.1939C15.8118 24.1918 15.8541 24.1899 15.8869 24.1889C16.0232 24.1845 16.1226 24.1867 16.1979 24.1975L16.2 24.1978L17.2772 28.591C17.5861 29.8506 18.7022 30.75 20.0001 30.75C21.2979 30.75 22.414 29.8506 22.7229 28.591L23.8001 24.1978L23.8022 24.1975C23.8775 24.1867 23.9769 24.1845 24.1132 24.1889C24.146 24.1899 24.1881 24.1918 24.2346 24.1939C24.336 24.1984 24.4588 24.2039 24.5514 24.2039C25.3446 24.2039 26.0512 23.7223 26.3566 22.9958C27.4082 20.4941 26.213 17.9065 24.536 16.4361Z" fill="#8F9AA3"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -0,0 +1,3 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.0625 16.125C3.6097 16.125 0 12.5153 0 8.0625C0 3.6097 3.6097 0 8.0625 0C12.5153 0 16.125 3.6097 16.125 8.0625C16.125 12.5153 12.5153 16.125 8.0625 16.125ZM8.0625 4.3125C8.47671 4.3125 8.8125 4.64829 8.8125 5.0625V8.43749H8.93401C9.15181 8.43742 9.38226 8.43734 9.56413 8.45912C9.69673 8.47499 10.1846 8.53481 10.4097 8.99153C10.635 9.4486 10.3763 9.85561 10.3061 9.96553C10.2094 10.1169 10.0646 10.2914 9.92764 10.4564L9.90413 10.4848C9.68853 10.7449 9.43178 11.0409 9.1743 11.2764C9.04572 11.394 8.89699 11.5151 8.73553 11.6109C8.58584 11.6996 8.34945 11.8125 8.0625 11.8125C7.77556 11.8125 7.53916 11.6996 7.38947 11.6109C7.22801 11.5151 7.07929 11.394 6.95071 11.2764C6.69322 11.0409 6.43647 10.7449 6.22087 10.4848L6.19736 10.4564C6.06041 10.2914 5.91565 10.1169 5.81894 9.96552C5.74871 9.85561 5.49001 9.4486 5.71529 8.99153C5.94038 8.53481 6.42827 8.47499 6.56087 8.45912C6.74274 8.43734 6.9732 8.43742 7.191 8.43749H7.3125L7.3125 5.0625C7.3125 4.64829 7.64829 4.3125 8.0625 4.3125Z" fill="#FF9E15"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1,7 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="20" height="3" rx="1.5" fill="#18C273"/>
<rect y="4" width="20" height="3" rx="1.5" fill="#18C273" fill-opacity="0.7"/>
<rect y="8" width="20" height="3" rx="1.5" fill="#18C273" fill-opacity="0.5"/>
<rect y="12" width="20" height="3" rx="1.5" fill="#18C273" fill-opacity="0.35"/>
<rect y="16" width="20" height="3" rx="1.5" fill="#18C273" fill-opacity="0.2"/>
</svg>

After

Width:  |  Height:  |  Size: 476 B

@ -0,0 +1,3 @@
<svg width="22" height="21" viewBox="0 0 22 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.52965 0.0727261C9.98692 -0.024143 11.5101 -0.024341 12.9704 0.0727261C17.537 0.376286 21.1603 4.06258 21.4582 8.67235C21.5139 9.53477 21.5139 10.4268 21.4582 11.2892C21.1603 15.899 17.537 19.5853 12.9704 19.8889C11.5101 19.9859 9.98692 19.9857 8.52965 19.8889C7.96472 19.8513 7.34978 19.7177 6.80839 19.4948C6.5703 19.3967 6.40868 19.3304 6.29041 19.287C6.20909 19.3429 6.10108 19.4223 5.9438 19.5383C5.15136 20.1226 4.15092 20.5325 2.73117 20.498L2.68544 20.4969C2.41155 20.4903 2.11961 20.4834 1.88152 20.4373C1.59475 20.3818 1.23996 20.2431 1.01791 19.8645C0.776229 19.4525 0.873128 19.0358 0.966883 18.7734C1.05536 18.5257 1.20874 18.2352 1.36542 17.9385L1.3869 17.8978C1.85323 17.0141 1.98314 16.2919 1.73381 15.8104C0.901479 14.554 0.152725 13.0056 0.0418013 11.2892C-0.0139338 10.4268 -0.0139338 9.53477 0.0418013 8.67235C0.339716 4.06258 3.963 0.376286 8.52965 0.0727261ZM6.5 7.75C6.5 8.16421 6.83579 8.5 7.25 8.5H10.75C11.1642 8.5 11.5 8.16421 11.5 7.75C11.5 7.33579 11.1642 7 10.75 7L7.25 7C6.83579 7 6.5 7.33579 6.5 7.75ZM6.5 12.75C6.5 13.1642 6.83579 13.5 7.25 13.5L14.25 13.5C14.6642 13.5 15 13.1642 15 12.75C15 12.3358 14.6642 12 14.25 12L7.25 12C6.83579 12 6.5 12.3358 6.5 12.75Z" fill="#ED1C2B"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,3 @@
<svg width="20" height="22" viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.39392 1.28104e-06L11.1061 1.28104e-06C12.009 -2.95155e-05 12.7711 -5.55068e-05 13.3749 0.0704231C14.005 0.143956 14.6207 0.308473 15.1206 0.759151C15.3458 0.962221 15.5373 1.19899 15.6876 1.46113C15.9826 1.97573 16.0312 2.52334 15.9847 3.06609C16.9603 3.1787 17.7696 3.43604 18.4021 4.06966C19.0038 4.67238 19.2625 5.43113 19.3835 6.33241C19.5 7.2007 19.5 8.30477 19.5 9.67486V14.793C19.5 16.1631 19.5 17.2672 19.3835 18.1355C19.2625 19.0367 19.0038 19.7955 18.4021 20.3982C17.8002 21.0011 17.0423 21.2605 16.1419 21.3818C15.2749 21.4986 14.1725 21.4986 12.805 21.4985L6.69504 21.4985C5.32752 21.4986 4.22513 21.4986 3.35808 21.3818C2.45774 21.2605 1.69976 21.0011 1.0979 20.3982C0.496209 19.7955 0.237469 19.0367 0.116503 18.1355C-3.37213e-05 17.2672 -1.84605e-05 16.1631 4.81163e-07 14.7931L4.81163e-07 9.67484C-1.84605e-05 8.30478 -3.37213e-05 7.20069 0.116503 6.33241C0.237469 5.43113 0.496209 4.67238 1.0979 4.06966C1.73043 3.43604 2.53975 3.1787 3.51534 3.06608C3.46879 2.52334 3.51736 1.97573 3.81239 1.46113C3.96268 1.19899 4.15422 0.962221 4.37944 0.759151C4.8793 0.308473 5.49503 0.143956 6.12506 0.0704231C6.72893 -5.54994e-05 7.49097 -2.95155e-05 8.39392 1.28104e-06ZM6.35067 1.9573C5.88641 2.01149 5.74252 2.10241 5.67575 2.1626C5.5993 2.23154 5.53534 2.31095 5.48568 2.39756C5.44637 2.46613 5.39027 2.6108 5.44746 3.05137C5.50673 3.50797 5.66092 4.11081 5.89823 5.02796C6.08725 5.75848 6.21246 6.23783 6.34555 6.59684C6.47171 6.93716 6.57647 7.08584 6.6787 7.18308C6.75978 7.26021 6.85016 7.32847 6.9482 7.38631C7.07461 7.46091 7.2556 7.52465 7.63389 7.56094C7.88784 7.58531 8.19058 7.59448 8.58009 7.59793L9.30138 5.43404C9.47603 4.9101 10.0424 4.62694 10.5663 4.80159C11.0902 4.97624 11.3734 5.54256 11.1988 6.0665L10.6878 7.59935C11.1924 7.59743 11.5638 7.58994 11.8661 7.56094C12.2444 7.52465 12.4254 7.46091 12.5518 7.38631C12.6498 7.32847 12.7402 7.26021 12.8213 7.18308C12.9235 7.08584 13.0283 6.93716 13.1545 6.59684C13.2875 6.23783 13.4128 5.75848 13.6018 5.02796C13.8391 4.11081 13.9933 3.50797 14.0525 3.05137C14.1097 2.6108 14.0536 2.46613 14.0143 2.39756C13.9647 2.31095 13.9007 2.23153 13.8242 2.1626C13.7575 2.10241 13.6136 2.01149 13.1493 1.9573C12.6718 1.90157 12.0247 1.9 11.0479 1.9L8.45213 1.9C7.47532 1.9 6.82816 1.90157 6.35067 1.9573ZM7.75 15.75C7.19772 15.75 6.75 16.1977 6.75 16.75C6.75 17.3023 7.19772 17.75 7.75 17.75H11.75C12.3023 17.75 12.75 17.3023 12.75 16.75C12.75 16.1977 12.3023 15.75 11.75 15.75L7.75 15.75Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -408,7 +408,7 @@
"brand": "العلامة التجارية",
"power": "القوة",
"diameter": "القطر",
"remarks": "ملاحظات",
"remarks": "ملاحظات: ",
"activeMedications": "الأدوية النشطة",
"expDate": "تاريخ انتهاء الصلاحية النشط:",
"route": "الطريق",
@ -525,7 +525,7 @@
"payOnline": "الدفع عبر الإنترنت",
"cancelOrder": "إلغاء الطلب",
"confirmAddress": "تأكيد العنوان ",
"confirmLocation": "<EFBFBD><EFBFBD>أكيد الموقع ",
"confirmLocation": "أكيد الموقع ",
"conditionsHMG": "الشروط والأحكام ",
"conditions": "الشروط والأحكام لكوم",
"confirmDeleteMsg": "هل أنت متأكد! تريد الحذف ",
@ -694,11 +694,7 @@
"bikini": "بيكيني",
"totalMinutes": "إجمالي الدقائق",
"feedback": "ملاحظات",
"send": "أرسل",
"status": "الحالة",
"likeToHear": "نود سماع ملاحظاتك، ومخاوفك بشأن خدمات الرعاية الصحية وتجربة الخدمات الإلكترونية. يرجى استخدام النموذج أدناه",
"subject": "الموضوع",
"message": "رسالة",
"emptySubject": "يرجى إدخال الموضوع",
"emptyMessage": "يرجى إدخال الرسالة",
"selectAttachment": "اختر المرفق",
@ -877,5 +873,631 @@
"walkin": "زيارة بدون موعد",
"laserClinic": "عيادة الليزر",
"continueString": "يكمل",
"covid_info": "تجري مستشفيات د. سليمان الحبيب فحص فيروس كورونا المستجد وتصدر شهادات السفر على مدار الساعة، طوال أيام الأسبوع، وبسرعة ودقة عالية. يمكن للراغبين في الاستفادة من هذه الخدمة زيارة أحد فروع مستشفيات د. سليمان الحبيب وإجراء فحص كورونا خلال بضع دقائق والحصول على النتائج خلال عدة ساعات خدمة فحص فيروس كورونا Covid 19 بتقنية PCR للكشف عن الفيروس وفقاً لأعلى المعايير العالمية وبأحدث أجهزة RT-PCR عالية الدقة (GeneXpert الأمريكي وغيره)، وهي طرق معتمدة من قبل هيئة الغذاء والدواء وكذلك من قبل المركز السعودي للوقاية من الأمراض المُعدية"
}
"covid_info": "تجري مستشفيات د. سليمان الحبيب فحص فيروس كورونا المستجد وتصدر شهادات السفر على مدار الساعة، طوال أيام الأسبوع، وبسرعة ودقة عالية. يمكن للراغبين في الاستفادة من هذه الخدمة زيارة أحد فروع مستشفيات د. سليمان الحبيب وإجراء فحص كورونا خلال بضع دقائق والحصول على النتائج خلال عدة ساعات خدمة فحص فيروس كورونا Covid 19 بتقنية PCR للكشف عن الفيروس وفقاً لأعلى المعايير العالمية وبأحدث أجهزة RT-PCR عالية الدقة (GeneXpert الأمريكي وغيره)، وهي طرق معتمدة من قبل هيئة الغذاء والدواء وكذلك من قبل المركز السعودي للوقاية من الأمراض المُعدية",
"appointmentDetails": "تفاصيل الموعد",
"checkingDoctorAvailability": "جاري التحقق من توفر الطبيب...",
"cancellingAppointmentPleaseWait": "جاري إلغاء الموعد، يرجى الانتظار...",
"appointmentCancelledSuccessfully": "تم إلغاء الموعد بنجاح",
"notConfirmed": "غير مؤكد",
"appointmentStatus": "حالة الموعد",
"doctorWillCallYou": "سيتصل بك الطبيب عندما يقترب موعدك.",
"getDirections": "الحصول على الاتجاهات",
"notifyMeBeforeAppointment": "أبلغني قبل الموعد",
"fetchingLabResults": "جاري جلب نتائج المختبر...",
"fetchingRadiologyResults": "جاري جلب نتائج الأشعة...",
"fetchingAppointmentPrescriptions": "جاري جلب وصفات الموعد...",
"noPrescriptionsForAppointment": "ليس لديك أي وصفات طبية لهذا الموعد.",
"amountBeforeTax": "المبلغ قبل الضريبة",
"rebookAppointment": "إعادة حجز الموعد",
"fetchingDoctorSchedulePleaseWait": "جاري جلب جدول الطبيب، يرجى الانتظار...",
"pickADate": "اختر تاريخاً",
"confirmingAppointmentPleaseWait": "جاري تأكيد الموعد، يرجى الانتظار...",
"appointmentConfirmedSuccessfully": "تم تأكيد الموعد بنجاح",
"appointmentPayment": "دفع الموعد",
"checkingPaymentStatusPleaseWait": "جاري التحقق من حالة الدفع، يرجى الانتظار...",
"paymentFailedPleaseTryAgain": "فشل الدفع! يرجى المحاولة مرة أخرى.",
"appointmentCheckIn": "تسجيل حضور الموعد",
"insuranceExpiredOrInactive": "التأمين منتهي الصلاحية أو غير نشط",
"totalAmountToPay": "المبلغ الإجمالي المستحق",
"vat15": "ضريبة القيمة المضافة 15%",
"general": "عام",
"liveCare": "لايف كير",
"recentVisits": "الزيارات الأخيرة",
"searchByClinic": "البحث حسب العيادة",
"tapToSelectClinic": "انقر لاختيار العيادة",
"searchByDoctor": "البحث حسب الطبيب",
"tapToSelect": "انقر للاختيار",
"searchByRegion": "البحث حسب المنطقة",
"centralRegion": "المنطقة الوسطى",
"immediateConsultation": "استشارة فورية",
"scheduledConsultation": "استشارة مجدولة",
"pharmaLiveCare": "لايف كير الصيدلية",
"notSureHelpMeChooseClinic": "غير متأكد؟ ساعدني في اختيار عيادة!",
"mentionYourSymptomsAndFindDoctors": "اذكر أعراضك واعثر على قائمة الأطباء وفقاً لذلك",
"immediateService": "خدمة فورية",
"noNeedToWaitGetMedicalConsultation": "لا حاجة للانتظار، ستحصل على استشارة طبية فورية عبر مكالمة فيديو",
"noVisitRequired": "لا حاجة للزيارة",
"doctorWillContact": "سيتصل بك الطبيب",
"specialisedDoctorWillContactYou": "سيتصل بك طبيب متخصص وسيكون قادراً على الاطلاع على تاريخك الطبي",
"freeMedicineDelivery": "توصيل مجاني للأدوية",
"offersFreeMedicineDelivery": "يوفر توصيل مجاني للأدوية لموعد لايف كير",
"dentalChiefComplaints": "الشكاوى الرئيسة للأسنان",
"viewAvailableAppointments": "عرض المواعيد المتاحة",
"doctorProfile": "الملف للطبيب",
"waitingAppointment": "موعد الانتظار",
"hospitalInformation": "معلومات المستشفى",
"fetchingAppointmentShare": "جاري جلب تفاصيل الموعد...",
"bookingYourAppointment": "جاري حجز موعدك...",
"selectLiveCareClinic": "اختر عيادة لايف كير",
"checkingForExistingDentalPlan": "جاري التحقق من وجود خطة أسنان حالية، يرجى الانتظار...",
"dentalTreatmentPlan": "خطة علاج الأسنان",
"youHaveExistingTreatmentPlan": "لديك خطة علاج حالية: ",
"mins": "دقيقة",
"totalTimeRequired": "إجمالي الوقت المطلوب",
"wouldYouLikeToContinue": "هل تريد متابعتها؟",
"chooseDoctor": "اختر الطبيب",
"viewNearestAppos": "عرض أقرب المواعيد المتاحة",
"noDoctorFound": "لم يتم العثور على طبيب مطابق للمعايير المحددة...",
"yesPleasImInAHurry": "نعم من فضلك، أنا في عجلة من أمري",
"fetchingFeesPleaseWait": "جاري جلب الرسوم، يرجى الانتظار...",
"noThanksPhysicalVisit": "لا، شكراً. أفضل الزيارة الشخصية",
"offline": "غير متصل",
"videoCall": "مكالمة فيديو",
"liveVideoCallWithHMGDoctors": "مكالمة فيديو مباشرة مع أطباء مجموعة الحبيب الطبية",
"audioCall": "مكالمة صوتية",
"phoneCall": "مكالمة هاتفية",
"livePhoneCallWithHMGDoctors": "مكالمة هاتفية مباشرة مع أطباء مجموعة الحبيب الطبية",
"reviewLiveCareRequest": "مراجعة طلب لايف كير",
"selectedLiveCareType": "نوع لايف كير المحدد",
"selectLiveCareCallType": "اختر نوع مكالمة لايف كير",
"confirmingLiveCareRequest": "جاري تأكيد طلب لايف كير، يرجى الانتظار...",
"unknownErrorOccurred": "حدث خطأ غير معروف...",
"liveCarePermissionsMessage": "يتطلب لايف كير أذونات الكاميرا والميكروفون والموقع والإشعارات لتمكين الاستشارة الافتراضية بين المريض والطبيب، يرجى السماح بهذه الأذونات للمتابعة.",
"liveCarePayment": "دفع لايف كير",
"mada": "مدى",
"visaOrMastercard": "فيزا أو ماستركارد",
"tamara": "تمارا",
"fetchingApplePayDetails": "جاري جلب تفاصيل Apple Pay، يرجى الانتظار...",
"liveCarePendingRequest": "لايف كير حية معلق",
"callLiveCareSupport": "اتصل بدعم لايف كير",
"whatIsWaitingAppointment": "ما هو موعد الانتظار؟",
"waitingAppointmentsFeature": "تتيح لك ميزة مواعيد الانتظار حجز موعد أثناء تواجدك داخل مبنى المستشفى، وفي حال عدم توفر فتحة متاحة في جدول الطبيب.",
"appointmentWithDoctorConfirmed": "الموعد مع الطبيب مؤكد، ولكن وقت الدخول غير محدد.",
"paymentWithinTenMinutes": "ملاحظة: يجب عليك الدفع خلال 10 دقائق من الحجز، وإلا سيتم إلغاء موعدك تلقائياً",
"liveLocation": "الموقع المباشر",
"verifyYourLocationAtHospital": "تحقق من موقعك في المستشفى لتسجيل الحضور",
"error": "خطأ",
"ensureWithinHospitalLocation": "يرجى التأكد من أنك داخل موقع المستشفى لإجراء تسجيل الحضور عبر الإنترنت.",
"nfcNearFieldCommunication": "NFC (الاتصال قريب المدى)",
"scanPhoneViaNFC": "امسح هاتفك عبر لوحة NFC لتسجيل الحضور",
"qrCode": "رمز QR",
"scanQRCodeToCheckIn": "امسح رمز QR بالكاميرا لتسجيل الحضور",
"processingCheckIn": "جاري معالجة تسجيل الحضور...",
"bookingWaitingAppointment": "جاري حجز موعد الانتظار، يرجى الانتظار...",
"enterValidIDorIqama": "يرجى إدخال رقم هوية وطنية أو رقم ملف صالح",
"selectAppointment": "حدد الموعد",
"rebookSameDoctor": "أعد الحجز مع نفس الطبيب",
"queueing": "قائمة الانتظار",
"inQueue": "في قائمة الانتظار",
"yourTurn": "دورك",
"halaFirstName": "هلا {firstName}!!!",
"thankYouForPatience": "شكراً لصبرك، هذا هو رقم قائمة الانتظار الخاص بك.",
"servingNow": "يُخدم الآن",
"callForVitalSigns": "نداء للعلامات الحيوية",
"callForDoctor": "نداء للطبيب",
"thingsToAskDoctor": "أشياء تسأل طبيبك عنها اليوم",
"improveOverallHealth": "ماذا يمكنني أن أفعل لتحسين صحتي العامة؟",
"routineScreenings": "هل هناك أي فحوصات روتينية يجب أن أجريها؟",
"whatIsThisMedicationFor": "لماذا هذا الدواء؟",
"sideEffectsToKnow": "هل هناك أي آثار جانبية يجب أن أعرفها؟",
"whenFollowUp": "متى يجب أن أعود للمتابعة؟",
"goToHomepage": "الذهاب إلى الصفحة الرئيسية",
"appointmentsList": "قائمة المواعيد",
"allAppt": "جميع المواعيد",
"upcoming": "القادمة",
"completed": "المكتملة",
"noAppointmentsYet": "ليس لديك أي مواعيد بعد.",
"viewProfile": "عرض الملف الشخصي",
"choosePreferredHospitalForService": "اختر المستشفى المفضل لديك للخدمة",
"noHospitalsFound": "لم يتم العثور على مستشفيات",
"cancelOrderConfirmation": "هل أنت متأكد أنك تريد إلغاء هذا الطلب؟",
"orderCancelledSuccessfully": "تم إلغاء الطلب بنجاح",
"requestID": "معرف الطلب:",
"noCMCOrdersYet": "ليس لديك أي طلبات فحص شامل بعد.",
"cmcOrders": "طلبات الفحص الشامل",
"summary": "الملخص",
"selectedService": "الخدمة المحددة",
"requestSubmittedSuccessfully": "تم إرسال طلبك بنجاح.",
"hereIsYourRequestNumber": "هذا هو رقم طلبك #: ",
"pleaseSelectHospitalToContinue": "يرجى اختيار مستشفى للمتابعة",
"confirmSubmitRequest": "هل أنت متأكد أنك تريد إرسال هذا الطلب؟",
"pendingOrderWait": "لديك طلب معلق. يرجى الانتظار حتى تتم معالجته.",
"noServicesAvailable": "لا توجد خدمات متاحة",
"selectAService": "اختر خدمة",
"comprehensiveCheckup": "الفحص الشامل",
"viewNearestHMGLocations": "عرض أقرب مواقع مجموعة الحبيب الطبية",
"provideFeedbackOnServices": "قدم ملاحظاتك على خدماتنا",
"liveChatWithHMG": "خيار الدردشة المباشرة مع مجموعة الحبيب الطبية",
"send": "إرسال",
"status": "الحالة",
"sendingFeedback": "جاري إرسال الملاحظات...",
"selectFeedbackType": "اختر نوع الملاحظات",
"loadingAppointmentsList": "جاري تحميل قائمة المواعيد...",
"noAppointmentsForFeedback": "ليس لديك أي مواعيد لتقديم ملاحظات عنها.",
"selectedAppointment": "الموعد المحدد:",
"subject": "الموضوع",
"enterSubjectHere": "أدخل الموضوع هنا",
"message": "الرسالة",
"enterMessageHere": "أدخل الرسالة هنا",
"filesSelected": "تم تحديد {count} ملف(ات)",
"otherDetails": "تفاصيل أخرى",
"medicalReport": "التقرير الطبي",
"medicalReportNumber": "التقرير الطبي {number}",
"patientIsInsured": "المريض مؤمن عليه",
"insuranceDocument": "وثيقة التأمين",
"selectBranch": "اختر الفرع",
"patientInformation": "معلومات المريض",
"patientLocation": "أين يتواجد المريض",
"identificationNumber": "رقم الهوية",
"enterIdentificationNumber": "أدخل رقم الهوية*",
"patientName": "اسم المريض*",
"referralRequesterInformation": "معلومات مقدم طلب الإحالة",
"enterReferralRequesterName": "أدخل اسم مقدم طلب الإحالة*",
"requesterName": "اسم مقدم الطلب",
"relationship": "العلاقة",
"selectRelation": "اختر العلاقة",
"otherName": "اسم آخر",
"otherNameHint": "اسم آخر*",
"requesterNameRequired": "اسم مقدم طلب الإحالة مطلوب",
"selectRelationshipRequired": "يرجى اختيار العلاقة",
"otherRelationshipNameRequired": "اسم العلاقة الأخرى مطلوب",
"identificationNumberRequired": "رقم الهوية مطلوب",
"patientNameRequired": "اسم المريض مطلوب",
"enterPatientPhoneRequired": "يرجى إدخال رقم هاتف المريض",
"selectPatientCityRequired": "يرجى اختيار مدينة المريض",
"medicalReportRequired": "مطلوب تقرير طبي واحد على الأقل",
"selectBranchRequired": "يرجى اختيار الفرع",
"insuranceDocumentRequired": "وثيقة التأمين مطلوبة للمرضى المؤمن عليهم",
"searchResult": "نتيجة البحث",
"referralNo": "رقم الإحالة {number}",
"eReferral": "الإحالة الإلكترونية",
"referralCreatedSuccessfully": "تم إنشاء إحالتك بنجاح.",
"hereIsYourReferralNumber": "هذا هو رقم الإحالة الخاص بك #: ",
"searchEReferral": "البحث عن إحالة إلكترونية",
"enterRequiredInfoToSearch": "يرجى إدخال المعلومات المطلوبة للبحث عن إحالة إلكترونية",
"selectPickupDirection": "اختر اتجاه الاستلام",
"selectDirection": "اختر الاتجاه",
"toHospital": "إلى المستشفى",
"fromHospital": "من المستشفى",
"selectWay": "اختر الطريقة",
"oneWay": "اتجاه واحد",
"twoWay": "اتجاهين",
"selectPickupDetails": "اختر تفاصيل الاستلام",
"pleaseSelectDetailsOfPickup": " يرجى تحديد تفاصيل الاستلام",
"selectDetails": "اختر التفاصيل",
"work": "العمل",
"pick": "استلام",
"insideTheHome": "داخل المنزل",
"haveAnyAppointment": "هل لديك أي موعد",
"amountPaidAtHospital": "سيتم دفع المبلغ في المستشفى",
"submitRequest": "إرسال الطلب",
"enterPickupLocationManually": "أدخل موقع الاستلام يدوياً",
"enterPickupLocation": "أدخل موقع الاستلام",
"trackingDetails": "تفاصيل التتبع",
"cancelRequest": "إلغاء الطلب",
"shareLocationWhatsapp": "مشاركة موقعك المباشر على واتساب",
"pleaseWaitForCall": "يرجى انتظار المكالمة",
"toHospitalLower": "إلى المستشفى",
"contact": "اتصال",
"failed": "فشل",
"confirmationCall": "مكالمة التأكيد",
"pickupFromHome": "الاستلام من المنزل",
"onTheWayToHospital": " في الطريق إلى المستشفى",
"arrivedAtHospital": "وصل إلى المستشفى",
"orderCancel": "إلغاء الطلب",
"emergencyCheckIn": "تسجيل الطوارئ الإلكتروني",
"erOnlineCheckInDescription": "تتيح هذه الخدمة للمرضى تسجيل موعد الطوارئ قبل الوصول.",
"erOnlineCheckInSuccess": "تم تسجيل وصول الطوارئ بنجاح. الرجاء التوجه إلى منطقة الانتظار.",
"erOnlineCheckInError": "حدث خطأ غير متوقع أثناء عملية التسجيل. يرجى التواصل مع الدعم.",
"fetchingHospitalsList": "جاري جلب قائمة المستشفيات...",
"fetchingPaymentInformation": "جاري جلب معلومات الدفع...",
"erVisitDetails": "تفاصيل زيارة الطوارئ",
"erClinic": "عيادة الطوارئ",
"vatWithAmount": "الضريبة 15% ({amount})",
"erAppointmentBookedSuccess": "تم حجز موعدك بنجاح. يرجى إتمام إجراءات تسجيل الوصول عند وصولك إلى المستشفى.",
"underProcessing": "قيد المعالجة",
"canceledByPatient": "ملغى بواسطة المريض",
"rapidResponseTeam": "فريق الاستجابة السريع",
"allFacilities": "جميع المرافق",
"selectLocation": "اختر الموقع",
"pleaseSelectTheLocation": "يرجى اختيار الموقع",
"viewLocationGoogleMaps": "عرض الموقع على خرائط جوجل",
"callAmbulance": "استدعاء سيارة إسعاف",
"requestAmbulanceInEmergency": "طلب سيارة إسعاف في حالة الطوارئ من المنزل أو المستشفى",
"confirmation": "تأكيد",
"areYouSureYouWantToCallAmbulance": "هل أنت متأكد أنك تريد استدعاء سيارة إسعاف؟",
"getDetailsOfNearestBranch": "احصل على تفاصيل أقرب فرع بما في ذلك الاتجاهات",
"areYouSureYouWantToCallRRT": "هل أنت متأكد أنك تريد استدعاء فريق الاستجابة السريعة (RRT)؟",
"priorERCheckInToSkipLine": "تسجيل الوصول المسبق في الطوارئ لتجاوز الطابور والدفع في الاستقبال.",
"areYouSureYouWantToMakeERCheckIn": "هل أنت متأكد أنك تريد إجراء تسجيل وصول الطوارئ؟",
"checkingYourERAppointmentStatus": "جاري التحقق من حالة موعد الطوارئ الخاص بك...",
"transportOptions": "خيارات النقل",
"selectHospitalForAdvancePayment": "يرجى اختيار المستشفى الذي ترغب في دفع مبلغ مقدم له.",
"recharge": "إعادة الشحن",
"activityLevel": "مستوى النشاط",
"selectActivityLevel": "حدد مستوى النشاط",
"caloriesPerDay": "السعرات الحرارية في اليوم الواحد",
"dietType": "نوع النظام الغذائي",
"selectDietType": "حدد نوع النظام الغذائي",
"bodyFrameSize": "حجم إطار الجسم",
"selectBodyFrameSize": "حدد حجم إطار الجسم",
"averageCycleLength": "متوسط طول الدورة الشهرية (عادةً 28 يومًا)",
"averageLutealPhase": "متوسط طول المرحلة الأصفرية (عادةً 14 يومًا)",
"convert": "يتحول",
"calculate": "احسب",
"healthCalculators": "حاسبات الصحة",
"healthConverters": "محولات الصحة",
"generalHealth": "الصحة العامة",
"relatedToBMICalories": "متعلق بمؤشر كتلة الجسم والسعرات الحرارية ودهون الجسم وما إلى ذلك للبقاء على اطلاع دائم بصحتك.",
"selectCalculator": "اختر الآلة الحاسبة",
"womensHealth": "صحة المرأة",
"relatedToPeriodsOvulation": "متعلق بالدورة الشهرية والإباضة والحمل ومواضيع أخرى.",
"bloodSugar": "سكر الدم",
"trackYourGlucoseLevels": "تتبع مستويات الجلوكوز لديك، وفهم الاتجاهات، واحصل على رؤى مخصصة لصحة أفضل.",
"bloodCholesterol": "كوليسترول الدم",
"monitorCholesterolLevels": "راقب مستويات الكوليسترول، وقيّم مخاطر صحة القلب، واتخذ خطوات استباقية للرفاهية.",
"triglyceridesFatBlood": "الدهون الثلاثية في الدم",
"understandTriglyceridesImpact": "افهم تأثير الدهون الثلاثية على صحة القلب مع رؤى مخصصة وتوصيات الخبراء.",
"bmiCalculator": "حاسبة\nمؤشر كتلة الجسم",
"caloriesCalculator": "حاسبة\nالسعرات الحرارية",
"bmrCalculator": "حاسبة\nمعدل الأيض الأساسي",
"idealBodyWeight": "الوزن المثالي\nللجسم",
"bodyFatCalculator": "حاسبة\nدهون الجسم",
"carbsProteinFat": "الكربوهيدرات\nالبروتين والدهون",
"ovulationPeriod": "فترة\nالإباضة",
"deliveryDueDate": "تاريخ الولادة\nالمتوقع",
"low": "منخفض",
"preDiabetic": "ما قبل السكري",
"high": "مرتفع",
"elevated": "مرتفع قليلاً",
"recorded": "مسجل",
"noRecordsYet": "لا توجد سجلات بعد",
"lastRecord": "آخر سجل",
"addBloodSugar": "إضافة سكر الدم",
"addBloodPressure": "إضافة ضغط الدم",
"addWeight": "إضافة الوزن",
"bloodSugarDataSavedSuccessfully": "تم حفظ بيانات سكر الدم بنجاح",
"bloodPressureDataSavedSuccessfully": "تم حفظ بيانات ضغط الدم بنجاح",
"weightDataSavedSuccessfully": "تم حفظ بيانات الوزن بنجاح",
"pleaseWait": "يرجى الانتظار",
"selectUnit": "اختر الوحدة",
"selectMeasureTime": "اختر وقت القياس",
"selectArm": "اختر الذراع",
"enterBloodSugar": "أدخل سكر الدم",
"enterSystolicValue": "أدخل القيمة الانقباضية",
"enterDiastolicValue": "أدخل القيمة الانبساطية",
"enterWeight": "أدخل الوزن",
"selectDuration": "اختر المدة",
"systolic": "الانقباضي",
"diastolic": "الانبساطي",
"sendReportByEmail": "إرسال التقرير عبر البريد الإلكتروني",
"enterYourEmailToReceiveReport": "أدخل عنوان بريدك الإلكتروني لاستلام التقرير",
"addNewRecord": "إضافة سجل جديد",
"healthTrackers": "متتبعات الصحة",
"monitorBloodPressureLevels": "راقب مستويات ضغط الدم لديك، وتتبع القراءات الانقباضية والانبساطية، وحافظ على صحة قلبك.",
"trackWeightProgress": "تتبع تقدم وزنك، وضع الأهداف، وحافظ على كتلة جسم صحية من أجل العافية الشاملة.",
"bookAppointment": "حجز\nموعد",
"completeCheckup": "الفحص الشامل",
"indoorNavigation": "الملاحة الداخلية",
"eReferralServices": "خدمات الإحالة الإلكترونية",
"bloodDonation": "التبرع بالدم",
"dailyWaterMonitor": "مراقب الماء اليومي",
"fetchingYourWaterIntakeDetails": "جاري جلب تفاصيل استهلاك الماء الخاص بك.",
"healthCalculatorsServices": "حاسبات\nالصحة",
"healthConvertersServices": "محولات\nالصحة",
"smartWatchesServices": "الساعات\nالذكية",
"exploreServices": "استكشف الخدمات",
"medicalAndCareServices": "الخدمات الطبية والرعاية",
"hmgServices": "خدمات مجموعة الحبيب الطبية",
"personalServices": "الخدمات الشخصية",
"habibWallet": "محفظة الحبيب",
"loginToViewWalletBalance": "سجل الدخول لعرض رصيد محفظتك",
"recharge": "إعادة الشحن",
"loginToViewMedicalFile": "سجل الدخول لعرض ملفك الطبي",
"addMember": "إضافة عضو",
"addFamilyMember": "إضافة فرد من العائلة",
"pleaseFillBelowFieldToAddNewFamilyMember": "يرجى ملء الحقل أدناه لإضافة فرد جديد من العائلة إلى ملفك الشخصي",
"healthTools": "أدوات الصحة",
"supportServices": "خدمات الدعم",
"virtualTour": "جولة افتراضية",
"carParking": "موقف السيارات",
"latestNews": "آخر الأخبار",
"hmgContact": "اتصل بمجموعة الحبيب الطبية",
"durationCannotExceed90": "لا يجوز أن تتجاوز المدة 90 دقيقة",
"unexpectedError": "حدث خطأ غير متوقع",
"gettingAmbulanceTransportOption": "جاري الحصول على خيارات نقل الإسعاف",
"fetchingAppointment": "جاري جلب الموعد",
"doYouWantToCancelTheRequest": "هل تريد إلغاء الطلب",
"cancellingRequest": "جاري إلغاء الطلب",
"fetchingTermsAndConditions": "جاري جلب الشروط والأحكام",
"selectLocationPrescriptionDelivery": "يرجى تحديد موقع توصيل الوصفة الطبية",
"noRadiologyOrders": "لم يتم العثور على أي طلبات تصوير شعاعي",
"ageIsRequired": "العمر مطلوب",
"invalidAge": "العمر غير صالح",
"ageMustBeBetween11And120": "يجب أن يكون العمر بين 11 و 120",
"heightIsRequired": "الطول مطلوب",
"invalidHeight": "الطول غير صالح",
"weightIsRequired": "الوزن مطلوب",
"invalidWeight": "الوزن غير صالح",
"timeToDrinkWater": "حان وقت شرب الماء! 💧",
"stayHydratedDrinkWater": "ابق رطبًا! اشرب {amount} مل من الماء.",
"visitPharmacyOnline": "زيارة الصيدلة على الانترنت",
"howAreYouFeelingToday": "كيف حالك اليوم؟",
"checkYourSymptomsWithScale": "تحقق من أعراضك باستخدام ذا المقياس",
"checkYourSymptoms": "تحقق من أعراضك",
"noUpcomingAppointmentPleaseBook": "ليس لديك أي مواعيد قادمة. يرجى حجز موعد",
"youHaveEROnlineCheckInRequest": "لديك طلب تسجيل وصول عبر الإنترنت للطوارئ",
"quickLinks": "روابط سريعة",
"viewMedicalFileLandingPage": "عرض الملف الطبي",
"immediateLiveCareRequest": "طلب LiveCare الفوري",
"yourTurnIsAfterPatients": "دورك بعد {count} مريض.",
"dontHaveHHCOrders": "ليس لديك أي أوامر رعاية صحية منزلية حتى الآن.",
"hhcOrders": "أوامر الرعاية الصحية المنزلية",
"requestedServices": "الخدمات المطلوبة",
"selectServices": "اختر الخدمات",
"selectedServices": "الخدمات المختارة",
"createNewRequest": "إنشاء طلب جديد",
"youHaveNoPendingRequests": "ليس لديك أي طلبات معلقة.",
"noInsuranceDataFound": "لم يتم العثور على بيانات التأمين...",
"noInsuranceUpdateRequest": "لم يتم العثور على أي طلبات لتحديث بيانات التأمين.",
"policyNumberInsurancePage": "الوثيقة: {number}",
"insuranceExpired": "التأمين منتهي الصلاحية",
"insuranceActive": "التأمين نشط",
"patientCardID": "رقم بطاقة المريض: {id}",
"noInsuranceApprovals": "لم تحصل على أي موافقات تأمينية حتى الآن.",
"noInsuranceWithHMG": "ليس لديك تأمين مسجل لدى مجموعة حبيب الطبية.",
"referenceRange": "النطاق المرجعي",
"downloadReport": "تنزيل التقرير",
"generatingReport": "جارٍ إنشاء التقرير، يرجى الانتظار...",
"noLabResults": "ليس لديك أي نتائج مختبرية حتى الآن.",
"labResultDetails": "تفاصيل نتائج المختبر",
"resultOf": "نتيجة",
"whatIsThisResult": "ما هي هذه النتيجة؟",
"lastTested": "آخر اختبار",
"byVisit": "حسب الزيارة",
"byTest": "حسب التحليل",
"results": "نتائج",
"viewResults": "عرض النتائج",
"rebook": "إعادة الحجز",
"noOphthalmologyAppointments": "لم يتم العثور على أي مواعيد في قسم طب العيون...",
"noVitalSignsRecordedYet": "لا توجد علامات حيوية مسجلة بعد",
"appointmentsAndVisits": "المواعيد والزيارات",
"labAndRadiology": "المختبر والأشعة",
"activeMedicationsAndPrescriptions": "الأدوية النشطة والوصفات الطبية",
"allPrescriptions": "جميع الوصفات",
"allMedications": "جميع الأدوية",
"youDontHaveAnyPrescriptionsYet": "ليس لديك أي وصفات طبية بعد.",
"youDontHaveAnyCompletedVisitsYet": "ليس لديك أي زيارات مكتملة بعد",
"others": "أخرى",
"allergyInfo": "معلومات الحساسية",
"vaccineInfo": "معلومات اللقاحات",
"updateInsuranceInfo": "تحديث التأمين",
"myInvoicesList": "قائمة فواتيري",
"ancillaryOrdersList": "قائمة الطلبات المساعدة",
"youDontHaveAnySickLeavesYet": "ليس لديك أي إجازات مرضية بعد.",
"medicalReports": "التقارير الطبية",
"sickLeaveReport": "تقرير الإجازة المرضية",
"weightTracker": "متتبع الوزن",
"askYourDoctor": "اسأل طبيبك",
"internetPairing": "الاقتران بالإنترنت",
"requested": "مطلوب",
"youDontHaveAnyMedicalReportsYet": "ليس لديك أي تقارير طبية بعد.",
"requestMedicalReport": "طلب تقرير طبي",
"youDoNotHaveAnyAppointmentsToRequestMedicalReport": "ليس لديك أي مواعيد لطلب تقرير طبي.",
"areYouSureYouWantToRequestMedicalReport": "هل أنت متأكد أنك تريد طلب تقرير طبي لهذا الموعد؟",
"yourMedicalReportRequestSubmittedSuccessfully": "تم إرسال طلب التقرير الطبي بنجاح.",
"monthlyHealthSummaryReportDisclaimer": "يعكس تقرير الملخص الصحي الشهري هذا المؤشرات الصحية ونتائج التحليل لأحدث الزيارات. يرجى ملاحظة أن هذا سيتم إرساله تلقائيًا من النظام ولا يعتبر تقريرًا رسميًا لذا لا ينبغي اتخاذ أي قرار طبي بناءً عليه",
"updatingMonthlyReportStatus": "جاري تحديث حالة التقرير الشهري...",
"monthlyReportStatusUpdatedSuccessfully": "تم تحديث حالة التقرير الشهري بنجاح",
"whoCanViewMyMedicalFile": "من يمكنه عرض ملفي الطبي؟",
"acceptedYourRequestToBeYourFamilyMember": "{status} طلبك لتكون فردًا من عائلتك",
"canViewYourFile": "يمكنه عرض ملفك",
"hasARequestPendingToBeYourFamilyMember": "لديه طلب {status} ليكون فردًا من عائلتك",
"wantsToAddYouAsTheirFamilyMember": "يريد إضافتك كفرد من عائلته",
"rejectedYourRequestToBeYourFamilyMember": "{status} طلبك لتكون فردًا من عائلتك",
"rejectedYourFamilyMemberRequest": "{status} طلب فرد عائلتك",
"notAvailable": "غير متاح",
"selectAProfile": "الرجاء تحديد ملف تعريف",
"switchFamilyFile": "قم بالتبديل من قائمة الملفات الطبية أدناه",
"medicalFiles": "الملفات الطبية",
"addANewFamilyMember": "إضافة فرد جديد من العائلة",
"viewInvoiceDetails": "عرض تفاصيل الفاتورة",
"outPatient": "مريض خارجي",
"invoiceDetails": "تفاصيل الفاتورة",
"sendingEmailPleaseWait": "جاري إرسال ال<D8A7><D984>ريد الإلكتروني، يرجى الانتظار...",
"emailSentSuccessfullyMessage": "تم إرسال البريد الإلكتروني بنجاح.",
"discount": "خصم",
"paid": "مدفوع",
"fetchingInvoiceDetails": "جارٍ جلب تفاصيل الفاتورة، يرجى الانتظار...",
"scanQRCode": "مسح رمز الاستجابة السريعة",
"parkingSlotDetails": "تفاصيل موقف السيارة",
"slotNumber": "رقم الموقف: {code}",
"basement": "الطابق: {description}",
"parkingDate": "التاريخ: {date}",
"parkedSince": "متوقف منذ: {time}",
"resetDirection": "إعادة تعيين الاتجاه",
"noPrescriptionOrdersYet": "ليس لديك أي طلبات وصفات طبية حتى الآن.",
"fetchingPrescriptionPDFPleaseWait": "جاري جلب ملف الوصفة الطبية، يرجى الانتظار...",
"ratingValue": "التقييم: {rating}",
"downloadPrescription": "تحميل الوصفة الطبية",
"fetchingPrescriptionDetails": "جاري جلب تفاصيل الوصفة الطبية...",
"switchBackFamilyFile": "العودة إلى ملف العائلة",
"profileAndSettings": "الملف الشخصي والإعدادات",
"quickActions": "إجراءات سريعة",
"notificationsSettings": "إعدادات الإشعارات",
"touchIDFaceIDServices": "خدمات Touch ID / Face ID",
"personalInformation": "المعلومات الشخصية",
"updateEmailAddress": "تحديث عنوان البريد الإلكتروني",
"helpAndSupport": "المساعدة والدعم",
"permissionsProfile": "الأذونات",
"privacyPolicy": "سياسة الخصوصية",
"deactivateAccount": "إلغاء تنشيط الحساب",
"ageYearsOld": "{age} {yearsOld}",
"youDontHaveRadiologyOrders": "ليس لديك أي نتائج للأشعة حتى الآن.",
"radiologyResult": "نتيجة الأشعة",
"viewRadiologyImage": "عرض صورة الأشعة",
"rateClinic": "تقييم العيادة",
"back": "رجوع",
"rateDoctor": "تقييم الطبيب",
"howWasYourLastVisitWithDoctor": "كيف كانت زيارتك الأخيرة مع الطبيب؟",
"dateOfBirthSymptoms": "ما هو تاريخ ميلادك؟",
"genderSymptoms": "ما هو جنسك؟",
"heightSymptoms": "كم طولك؟",
"weightSymptoms": "ما هو وزنك؟",
"femaleGender": "أنثى",
"previous": "سابق",
"selectedOrgans": "الهيئات المختارة",
"noOrgansSelected": "لم يتم تحديد أي أعضاء بعد",
"organSelector": "محدد الأعضاء",
"noPredictionsAvailable": "لا توجد تنبؤات متاحة",
"areYouSureYouWantToRestartOrganSelection": "هل أنت متأكد أنك تريد إعادة تشغيل اختيار الأعضاء؟",
"possibleConditions": "الحالات المحتملة",
"pleaseSelectAtLeastOneRiskBeforeProceeding": "يرجى اختيار عامل خطر واحد على الأقل قبل المتابعة",
"aboveYouSeeCommonRiskFactors": "أعلاه ترى عوامل الخطر الأكثر شيوعًا. على الرغم من أن /diagnosis قد تعيد أسئلة حول عوامل الخطر، ",
"readMore": "اقرأ المزيد",
"riskFactors": "عوامل الخطر",
"noRiskFactorsFound": "لم يتم العثور على عوامل خطر",
"basedOnYourSelectedSymptomsNoRiskFactors": "بناءً على الأعراض المحددة، لم يتم تحديد عوامل خطر إضافية.",
"messageNotification": "الرسالة",
"attachedImage": "الصورة المرفقة",
"failedToLoadImage": "فشل تحميل الصورة",
"typeNotification": "النوع",
"pleaseSelectAtLeastOneOptionBeforeProceeding": "يرجى اختيار خيار واحد على الأقل قبل المتابعة",
"suggestions": "الاقتراحات",
"pleaseGoBackAndSelectOrgansFirst": "يرجى العودة واختيار الأعضاء أولاً",
"symptomsSelector": "محدد الأعراض",
"emergencyTriage": "طوارئ",
"emergencyEvidenceDetected": "تم اكتشاف دليل طوارئ. يرجى طلب العناية الطبية.",
"noQuestionItemsAvailable": "لا توجد عناصر أسئلة متاحة",
"pleaseAnswerAllQuestionsBeforeProceeding": "يرجى الإجابة على جميع الأسئلة قبل المتابعة",
"triage": "الفرز",
"areYouSureYouWantToExitProgress": "هل أنت متأكد أنك تريد الخروج؟ سيتم فقدان تقدمك.",
"noQuestionAvailable": "لا يوجد سؤال متاح",
"possibleSymptom": "عرض محتمل: ",
"symptomsCheckerFindingScore": "- درجة نتائج فاحص الأعراض",
"notSet": "غير محدد",
"years": "سنوات",
"symptomsChecker": "فاحص الأعراض",
"helloIsYourInformationUpToDate": "مرحباً {name}، هل معلوماتك محدثة؟",
"noEditAll": "لا، تعديل الكل",
"yesItIs": "نعم، إنها كذلك",
"age": "العمر",
"youDontHaveAnyAncillaryOrdersYet": "ليس لديك أي طلبات مساعدة بعد.",
"invoiceWithNumber": "الفاتورة: {invoiceNo}",
"queued": "في قائمة الانتظار",
"checkInReady": "جاهز للتسجيل",
"checkIn": "تسجيل الوصول",
"viewDetails": "عرض التفاصيل",
"selectPaymentMethod": "اختر طريقة الدفع",
"processingPaymentPleaseWait": "جاري معالجة الدفع، يرجى الانتظار...",
"finalizingPaymentPleaseWait": "جاري إتمام الدفع، يرجى الانتظار...",
"generatingInvoicePleaseWait": "جاري إنشاء الفاتورة، يرجى الانتظار...",
"hereIsYourInvoiceNumber": "هذا هو رقم فاتورتك #: ",
"paymentCompletedSuccessfully": "تم الدفع بنجاح",
"failedToInitializeApplePay": "فشل في تهيئة Apple Pay. يرجى المحاولة مرة أخرى.",
"cash": "نقدي",
"approved": "موافق عليه",
"approvalRejectedPleaseVisitReceptionist": "تم رفض الموافقة - يرجى زيارة موظف الاستقبال",
"sentForApproval": "تم إرساله للموافقة",
"ancillaryOrderDetails": "تفاصيل الطلب المساعد",
"noProceduresAvailableForSelectedOrder": "لا توجد إجراءات متاحة للطلب المحدد.",
"procedures": "الإجراءات",
"totalAmount": "المبلغ الإجمالي",
"covered": "مغطى",
"vatPercent": "ضريبة القيمة المضافة (15%)",
"proceedToPayment": "المتابعة للدفع",
"supportedSmartWatches": "الساعات الذكية المدعومة",
"pleaseMakeSureSamsungWatchConnected": "يرجى التأكد من أن ساعة Samsung الخاصة بك متصلة بهاتفك، ومتزامنة ومحدثة بشكل نشط.",
"beforeSyncingDataFollowInstructions": "قبل مزامنة البيانات، يرجى التأكد من اتباع التعليمات بشكل صحيح.",
"viewWatchInstructions": "عرض تعليمات الساعة",
"healthConnectAppNotInstalled": "يبدو أنه ليس لديك تطبيق Health Connect مثبتًا. يرجى تثبيته من متجر Play لمزامنة بيانات صحتك.",
"setTimerOfReminder": "ضبط مؤقت التذكير",
"youHaveAppointmentWithDr": "لديك موعد مع د. ",
"hours": "ساعات",
"secs": "ثواني",
"noAllergiesDataFound": "لم يتم العثور على بيانات الحساسية...",
"heartRateDescription": "معدل ضربات قلبك يشير إلى عدد المرات التي ينبض فيها قلبك في الدقيقة",
"bloodOxygenDescription": "مستوى الأكسجين في الدم يشير إلى كمية الأكسجين التي تحملها خلايا الدم الحمراء",
"stepsDescription": "عدد الخطوات المتخذة على مدار اليوم",
"caloriesDescription": "السعرات الحرارية المحروقة أثناء النشاط البدني",
"distanceDescription": "المسافة المقطوعة على مدار اليوم",
"overview": "نظرة عامة",
"details": "التفاصيل",
"healthy": "صحي",
"warning": "تحذير",
"vitalSignDetails": "تفاصيل العلامات الحيوية",
"resultOf": "نتيجة {date}",
"resultOfNoDate": "نتيجة --",
"referenceRangeBetween": "النطاق المرجعي: {low} {high} {unit}",
"referenceRangeMin": "النطاق المرجعي: ≥ {low} {unit}",
"referenceRangeMax": "النطاق المرجعي: ≤ {high} {unit}",
"noHistoryAvailable": "لا يوجد تاريخ متاح",
"bmiDescription": "مؤشر كتلة الجسم هو قياس يعتمد على الطول والوزن لتقدير دهون الجسم.",
"heightDescription": "يقاس الطول بالسنتيمتر ويستخدم لحساب مؤشر كتلة الجسم وتوصيات الجرعات.",
"weightDescription": "الوزن يساعد في تتبع الصحة العامة والتغذية والتغيرات مع مرور الوقت.",
"bloodPressureDescription": "ضغط الدم يعكس قوة الدم على جدران الشرايين. يظهر كانقباضي/انبساطي.",
"temperatureDescription": "درجة حرارة الجسم تعكس مدى سخونة جسمك وقد تتغير مع العدوى أو الالتهاب.",
"heartRateDescriptionVital": "معدل ضربات القلب يشير إلى عدد نبضات القلب في الدقيقة.",
"respiratoryRateDescription": "معدل التنفس هو عدد الأنفاس المأخوذة في الدقيقة.",
"bmiAdvice": "حافظ على نظام غذائي متوازن ونشاط منتظم. إذا كان مؤشر كتلة جسمك مرتفعًا أو منخفضًا، فكر في استشارة طبيبك.",
"heightAdvice": "لا حاجة لاتخاذ أي إجراء إلا إذا بدا قياسك غير صحيح. قم بتحديثه في زيارتك القادمة.",
"weightAdvice": "راقب تغيرات الوزن. الزيادة أو الخسارة المفاجئة قد تتطلب استشارة طبية.",
"bloodPressureAdvice": "استمر في تتبع ضغط دمك. يجب مناقشة القراءات المرتفعة أو المنخفضة مع طبيبك.",
"temperatureAdvice": "إذا كان لديك حمى مستمرة أو أعراض، اتصل بمقدم الرعاية الصحية.",
"heartRateAdvice": "تتبع اتجاهات معدل ضربات قلبك. إذا شعرت بدوار أو ألم في الصدر، اطلب الرعاية الطبية.",
"respiratoryRateAdvice": "إذا لاحظت ضيقًا في التنفس أو تنفسًا غير طبيعي، اطلب المشورة الطبية.",
"whatShouldIDoNext": "ماذا يجب أن أفعل بعد ذلك؟",
"customizeDrinkCup": "قم بتخصيص كوب مشروبك",
"tipsToStayHydrated": "نصائح للبقاء رطبًا",
"drinkBeforeYouFeelThirsty": "اشرب قبل أن تشعر بالعطش",
"keepRefillableBottleNextToYou": "احتفظ بزجاجة قابلة لإعادة التعبئة بجانبك",
"trackYourDailyIntakeToStayMotivated": "تتبع كمية الماء اليومية للحفاظ على الحافز",
"chooseSparklingWaterInsteadOfSoda": "اختر الماء الفوار بدلاً من الصودا",
"switchCup": "تبديل الكوب",
"plainWater": "ماء عادي",
"yourGoal": "هدفك",
"remaining": "المتبقي",
"hydrationStatus": "حالة الترطيب",
"areYouSureYouWantToCancelAllWaterReminders": "هل أنت متأكد أنك تريد إلغاء جميع تذكيرات الماء؟",
"remindersSet": "تم ضبط التذكيرات!",
"dailyWaterRemindersScheduledAt": "تم جدولة تذكيرات الماء اليومية في:",
"waterConsumption": "استهلاك المياه",
"selectNumberOfReminders": "حدد عدد التذكيرات",
"h2oSettings": "إعدادات H20",
"settingsSavedSuccessfully": "تم حفظ الإعدادات بنجاح",
"yourName": "اسمك",
"ageYears": "العمر (11-120) سنة",
"numberOfRemindersInADay": "عدد التذكيرات في اليوم",
"medications": "الأدوية",
"someRemarksAboutPrescription": "ستجدون هنا بعض الملاحظات حول الوصفة الطبية",
"notifyMeBeforeConsumptionTime": "أبلغني قبل وقت الاستهلاك",
"noMedicationsToday": "لا أدوية اليوم",
"route": "Route: {route}",
"frequency": "Frequency: {frequency}",
"instruction": "Instruction: {instruction}",
"duration": "Duration: {days}",
"reminders": "تذكيرات",
"reminderAddedToCalendar": "تمت إضافة تذكير إلى التقويم ✅",
"errorWhileSettingCalendar": "حدث خطأ أثناء ضبط التقويم:{error}",
"instructions": "التعليمات",
"requests": "الطلبات",
"thisWeek": "هذا الأسبوع",
"lastMonth": "الشهر الماضي",
"lastSixMonths": "آخر 6 أشهر",
"selectTime": "حدد الوقت",
"pleaseWaitYouWillBeCalledForVitalSigns": "يرجى الانتظار! سيتم استدعاؤك لقياس العلامات الحيوية",
"pleaseVisitRoomForVitalSigns": "يرجى زيارة الغرفة {roomNumber} لقياس العلامات الحيوية",
"pleaseVisitRoomToTheDoctor": "يرجى زيارة الغرفة {roomNumber} لمقابلة الطبيب"
}

@ -406,11 +406,8 @@
"brand": "Brand",
"power": "Power",
"diameter": "Diameter",
"remarks": "Remarks",
"activeMedications": "Active Medications",
"expDate": "Active Exp Date :",
"route": "Route",
"frequency": "Frequency",
"dailyQuantity": "Daily Quantity :",
"addReminder": "Add Reminder",
"cancelReminder": "Cancel Reminder",
@ -689,11 +686,7 @@
"bikini": "Bikini",
"totalMinutes": "Total Minutes",
"feedback": "Feedback",
"send": "أرسل",
"status": "الحالة",
"likeToHear": "We would love to hear the feedback, concerns on healthcare services and eServices experience. Please use the below form",
"subject": "الموضوع",
"message": "رسالة",
"emptySubject": "Please enter the subject",
"emptyMessage": "Please enter message",
"selectAttachment": "Select Attachment",
@ -864,7 +857,7 @@
"endDate": "End Date",
"hmgHospitals": "HMG Hospitals",
"hmcMedicalClinic": "HMC Medical Centers",
"applyFilter": "AppLy Filter",
"applyFilter": "Apply Filter",
"facilityAndLocation": "Facility and Location",
"regionAndLocation": "Region And Locations",
"clearAllFilters": "Clear all filters",
@ -873,5 +866,629 @@
"walkin": "Walk In",
"continueString": "Continue",
"laserClinic": "Laser Clinic",
"covid_info" :"Dr. Sulaiman Al Habib hospitals are conducting a test for the emerging corona virus and issuing travel certificates 24/7 in a short time and with high accuracy. Those wishing to benefit from this service can visit one of Dr. Sulaiman Al Habib branches to conduct a corona test within few minutes, and obtain the result within several hours. Corona Virus Covid 19 testing service with PCR technology to detect the virus according to the highest international standards and with the latest high-precision RT-PCR devices (American GeneXpert and others), That is approved by the Food and Drug Authority as well as by the Saudi Center for Infectious Diseases Prevention."
}
"covid_info" :"Dr. Sulaiman Al Habib hospitals are conducting a test for the emerging corona virus and issuing travel certificates 24/7 in a short time and with high accuracy. Those wishing to benefit from this service can visit one of Dr. Sulaiman Al Habib branches to conduct a corona test within few minutes, and obtain the result within several hours. Corona Virus Covid 19 testing service with PCR technology to detect the virus according to the highest international standards and with the latest high-precision RT-PCR devices (American GeneXpert and others), That is approved by the Food and Drug Authority as well as by the Saudi Center for Infectious Diseases Prevention.",
"appointmentDetails": "Appointment Details",
"checkingDoctorAvailability": "Checking doctor availability...",
"cancellingAppointmentPleaseWait": "Cancelling Appointment, Please Wait...",
"appointmentCancelledSuccessfully": "Appointment Cancelled Successfully",
"notConfirmed": "Not Confirmed",
"appointmentStatus": "Appointment Status",
"doctorWillCallYou": "The doctor will call you once the appointment time approaches.",
"getDirections": "Get Directions",
"notifyMeBeforeAppointment": "Notify me before the appointment",
"fetchingLabResults": "Fetching Lab Results...",
"fetchingRadiologyResults": "Fetching Radiology Results...",
"fetchingAppointmentPrescriptions": "Fetching Appointment Prescriptions...",
"noPrescriptionsForAppointment": "You don't have any prescriptions for this appointment.",
"amountBeforeTax": "Amount before tax",
"rebookAppointment": "Re-book Appointment",
"fetchingDoctorSchedulePleaseWait": "Fetching Doctor Schedule, Please Wait...",
"pickADate": "Pick a Date",
"confirmingAppointmentPleaseWait": "Confirming Appointment, Please Wait...",
"appointmentConfirmedSuccessfully": "Appointment Confirmed Successfully",
"appointmentPayment": "Appointment Payment",
"checkingPaymentStatusPleaseWait": "Checking payment status, Please wait...",
"paymentFailedPleaseTryAgain": "Payment Failed! Please try again.",
"appointmentCheckIn": "Appointment check in",
"insuranceExpiredOrInactive": "Insurance expired or inactive",
"totalAmountToPay": "Total amount to pay",
"vat15": "VAT 15%",
"general": "General",
"liveCare": "LiveCare",
"recentVisits": "Recent Visits",
"searchByClinic": "Search By Clinic",
"tapToSelectClinic": "Tap to select clinic",
"searchByDoctor": "Search By Doctor",
"tapToSelect": "Tap to select",
"searchByRegion": "Search By Region",
"centralRegion": "Central Region",
"immediateConsultation": "Immediate Consultation",
"scheduledConsultation": "Scheduled Consultation",
"pharmaLiveCare": "Pharma LiveCare",
"notSureHelpMeChooseClinic": "Not sure? help me choose a clinic!",
"mentionYourSymptomsAndFindDoctors": "Mention your symptoms and find the list of doctors accordingly",
"immediateService": "Immediate service",
"noNeedToWaitGetMedicalConsultation": "No need to wait, you will get medical consultation immediately via video call",
"noVisitRequired": "No visit required",
"doctorWillContact": "Doctor will contact",
"specialisedDoctorWillContactYou": "A specialised doctor will contact you and will be able to view your medical history",
"freeMedicineDelivery": "Free medicine delivery",
"offersFreeMedicineDelivery": "Offers free medicine delivery for the LiveCare appointment",
"dentalChiefComplaints": "Dental Chief Complaints",
"viewAvailableAppointments": "View available appointments",
"doctorProfile": "Doctor Profile",
"waitingAppointment": "Waiting Appointment",
"hospitalInformation": "Hospital Information",
"fetchingAppointmentShare": "Fetching Appointment Share...",
"bookingYourAppointment": "Booking your appointment...",
"selectLiveCareClinic": "Select LiveCare Clinic",
"checkingForExistingDentalPlan": "Checking for an existing dental plan, Please wait...",
"dentalTreatmentPlan": "Dental treatment plan",
"youHaveExistingTreatmentPlan": "You have an existing treatment plan: ",
"mins": "Mins",
"totalTimeRequired": "Total time required",
"wouldYouLikeToContinue": "Would you like to continue it?",
"chooseDoctor": "Choose Doctor",
"viewNearestAppos": "View nearest available appointments",
"noDoctorFound": "No Doctor found for selected criteria...",
"yesPleasImInAHurry": "Yes please, I am in a hurry",
"fetchingFeesPleaseWait": "Fetching fees, Please wait...",
"noThanksPhysicalVisit": "No, Thanks. I would like a physical visit",
"offline": "Offline",
"videoCall": "Video Call",
"liveVideoCallWithHMGDoctors": "Live Video Call with HMG Doctors",
"audioCall": "Audio Call",
"phoneCall": "Phone Call",
"livePhoneCallWithHMGDoctors": "Live Phone Call with HMG Doctors",
"reviewLiveCareRequest": "Review LiveCare Request",
"selectedLiveCareType": "Selected LiveCare Type",
"selectLiveCareCallType": "Select LiveCare call type",
"confirmingLiveCareRequest": "Confirming LiveCare request, Please wait...",
"unknownErrorOccurred": "Unknown error occurred...",
"liveCarePermissionsMessage": "LiveCare requires Camera, Microphone, Location & Notifications permissions to enable virtual consultation between patient & doctor, Please allow these to proceed.",
"liveCarePayment": "LiveCare Payment",
"mada": "Mada",
"visaOrMastercard": "Visa or Mastercard",
"tamara": "Tamara",
"fetchingApplePayDetails": "Fetching Apple Pay details, Please wait...",
"liveCarePendingRequest": "LiveCare Pending Request",
"callLiveCareSupport": "Call LiveCare Support",
"whatIsWaitingAppointment": "What is Waiting Appointment?",
"waitingAppointmentsFeature": "The waiting appointments feature allows you to book an appointment while you are inside the hospital building, and in case there is no available slot in the doctor's schedule.",
"appointmentWithDoctorConfirmed": "The appointment with the doctor is confirmed, but the time of entry is uncertain.",
"paymentWithinTenMinutes": "Note: You must have to pay within 10 minutes of booking, otherwise your appointment will be cancelled automatically",
"liveLocation": "Live Location",
"verifyYourLocationAtHospital": "Verify your location to be at hospital to check in",
"error": "Error",
"ensureWithinHospitalLocation": "Please ensure you're within the hospital location to perform online check-in.",
"nfcNearFieldCommunication": "NFC (Near Field Communication)",
"scanPhoneViaNFC": "Scan your phone via NFC board to check in",
"qrCode": "QR Code",
"scanQRCodeToCheckIn": "Scan QR code with your camera to check in",
"processingCheckIn": "Processing Check-In...",
"bookingWaitingAppointment": "Booking Waiting Appointment, Please wait...",
"enterValidIDorIqama": "Please enter a valid national ID or file number",
"selectAppointment": "Select Appointment",
"rebookSameDoctor": "Rebook with same doctor",
"queueing": "Queueing",
"inQueue": "In Queue",
"yourTurn": "Your Turn",
"halaFirstName": "Hala {firstName}!!!",
"thankYouForPatience": "Thank you for your patience, here is your queue number.",
"servingNow": "Serving Now",
"callForVitalSigns": "Call for vital signs",
"callForDoctor": "Call for Doctor",
"thingsToAskDoctor": "Things to ask your doctor today",
"improveOverallHealth": "What can I do to improve my overall health?",
"routineScreenings": "Are there any routine screenings I should get?",
"whatIsThisMedicationFor": "What is this medication for?",
"sideEffectsToKnow": "Are there any side effects I should know about?",
"whenFollowUp": "When should I come back for a follow-up?",
"goToHomepage": "Go to homepage",
"appointmentsList": "Appointments List",
"allAppt": "All Appt.",
"upcoming": "Upcoming",
"completed": "Completed",
"noAppointmentsYet": "You don't have any appointments yet.",
"viewProfile": "View Profile",
"choosePreferredHospitalForService": "Choose your preferred hospital for the service",
"noHospitalsFound": "No hospitals Found",
"cancelOrderConfirmation": "Are you sure you want to cancel this order?",
"orderCancelledSuccessfully": "Order has been cancelled successfully",
"requestID": "Request ID:",
"noCMCOrdersYet": "You don't have any CMC orders yet.",
"cmcOrders": "CMC Orders",
"summary": "Summary",
"selectedService": "Selected Service",
"requestSubmittedSuccessfully": "Your request has been successfully submitted.",
"hereIsYourRequestNumber": "Here is your request #: ",
"pleaseSelectHospitalToContinue": "Please select a hospital to continue",
"confirmSubmitRequest": "Are you sure you want to submit this request?",
"pendingOrderWait": "You have a pending order. Please wait for it to be processed.",
"noServicesAvailable": "No services available",
"selectAService": "Select a Service",
"comprehensiveCheckup": "Comprehensive Checkup",
"viewNearestHMGLocations": "View your nearest HMG locations",
"provideFeedbackOnServices": "Provide your feedback on our services",
"liveChatWithHMG": "Live chat option with HMG",
"send": "Send",
"status": "Status",
"sendingFeedback": "Sending Feedback...",
"selectFeedbackType": "Select Feedback Type",
"loadingAppointmentsList": "Loading appointments list...",
"noAppointmentsForFeedback": "You do not have any appointments to submit a feedback.",
"selectedAppointment": "Selected Appointment:",
"subject": "Subject",
"enterSubjectHere": "Enter subject here",
"message": "Message",
"enterMessageHere": "Enter message here",
"filesSelected": "{count} file(s) selected",
"otherDetails": "Other Details",
"medicalReport": "Medical Report",
"medicalReportNumber": "Medical Report {number}",
"patientIsInsured": "Patient is Insured",
"insuranceDocument": "Insurance Document",
"selectBranch": "Select Branch",
"patientInformation": "Patient information",
"patientLocation": "Where the patient located",
"identificationNumber": "Identification Number",
"enterIdentificationNumber": "Enter Identification Number*",
"patientName": "Patient Name*",
"referralRequesterInformation": "Referral requester information",
"enterReferralRequesterName": "Enter Referral Requester Name*",
"requesterName": "Requester Name",
"relationship": "Relationship",
"selectRelation": "Select Relation",
"otherName": "Other Name",
"otherNameHint": "Other Name*",
"requesterNameRequired": "Referral requester name is required",
"selectRelationshipRequired": "Please select a relationship",
"otherRelationshipNameRequired": "Other relationship name is required",
"identificationNumberRequired": "Identification number is required",
"patientNameRequired": "Patient name is required",
"enterPatientPhoneRequired": "Please Enter patient phone number",
"selectPatientCityRequired": "Please select patient city",
"medicalReportRequired": "At least one medical report is required",
"selectBranchRequired": "Please select a branch",
"insuranceDocumentRequired": "Insurance document is required for insured patients",
"searchResult": "Search Result",
"referralNo": "Referral No {number}",
"eReferral": "E Referral",
"referralCreatedSuccessfully": "Your Referral has been created Successfully.",
"hereIsYourReferralNumber": "Here is your Referral #: ",
"searchEReferral": "Search E-Referral",
"enterRequiredInfoToSearch": "Please enter the required information to search for an e-referral",
"selectPickupDirection": "Select Pickup Direction",
"selectDirection": "Select Direction",
"toHospital": "To Hospital",
"fromHospital": "From Hospital",
"selectWay": "Select Way",
"oneWay": "One Way",
"twoWay": "Two Way",
"selectPickupDetails": "Select Pickup Details",
"pleaseSelectDetailsOfPickup": " Please select the details of pickup",
"selectDetails": "Select Details",
"work": "Work",
"pick": "Pick",
"insideTheHome": "Inside the home",
"haveAnyAppointment": "Have any appointment",
"amountPaidAtHospital": "Amount will be paid at the hospital",
"submitRequest": "Submit Request",
"enterPickupLocationManually": "Enter Pickup Location Manually",
"enterPickupLocation": "Enter Pickup Location",
"trackingDetails": "Tracking Details",
"cancelRequest": "Cancel Request",
"shareLocationWhatsapp": "Share Your Live Location on Whatsapp",
"pleaseWaitForCall": "Please wait for the call",
"toHospitalLower": "to hospital",
"contact": "Contact",
"failed": "Failed",
"confirmationCall": "Confirmation Call",
"pickupFromHome": "Pickup Up from Home",
"onTheWayToHospital": " On The Way To Hospital",
"arrivedAtHospital": "Arrived at Hospital",
"orderCancel": "Order Cancel",
"emergencyCheckIn": "Emergency Check-In",
"erOnlineCheckInDescription": "This service lets patients register their ER appointment prior to arrival.",
"erOnlineCheckInSuccess": "Your ER Online Check-In has been successfully done. Please proceed to the waiting area.",
"erOnlineCheckInError": "Unexpected error occurred during check-in. Please contact support.",
"fetchingHospitalsList": "Fetching hospitals list...",
"fetchingPaymentInformation": "Fetching payment information...",
"erVisitDetails": "ER Visit Details",
"erClinic": "ER Clinic",
"vatWithAmount": "VAT 15% ({amount})",
"erAppointmentBookedSuccess": "Your appointment has been booked successfully. Please perform Check-In once you arrive at the hospital.",
"underProcessing": "Under processing",
"canceledByPatient": "Cancelled by patient",
"rapidResponseTeam": "Rapid Response Team",
"allFacilities": "All Facilities",
"selectLocation": "Select Location",
"pleaseSelectTheLocation": "Please select the location",
"viewLocationGoogleMaps": "View Location on Google Maps",
"callAmbulance": "Call Ambulance",
"requestAmbulanceInEmergency": "Request an ambulance in emergency from home or hospital",
"confirmation": "Confirmation",
"areYouSureYouWantToCallAmbulance": "Are you sure you want to call an ambulance?",
"getDetailsOfNearestBranch": "Get the details of nearest branch including directions",
"areYouSureYouWantToCallRRT": "Are you sure you want to call Rapid Response Team (RRT)?",
"priorERCheckInToSkipLine": "Prior ER Check-In to skip the line & payment at the reception.",
"areYouSureYouWantToMakeERCheckIn": "Are you sure you want to make ER Check-In?",
"checkingYourERAppointmentStatus": "Checking your ER Appointment status...",
"transportOptions": "Transport Options",
"selectHospitalForAdvancePayment": "Please select the hospital you want to make an advance payment for.",
"recharge": "Recharge",
"activityLevel": "Activity Level",
"selectActivityLevel": "Select Activity Level",
"caloriesPerDay": "Calories Per Day",
"dietType": "Diet Type",
"selectDietType": "Select Diet Type",
"bodyFrameSize": "Body Frame Size",
"selectBodyFrameSize": "Select Body Frame Size",
"averageCycleLength": "Average Cycle Length (Usually 28 days)",
"averageLutealPhase": "Average Luteal Phase Length(Usually 14 days)",
"convert": "Convert",
"calculate": "Calculate",
"healthCalculators": "Health Calculators",
"healthConverters": "Health Converters",
"generalHealth": "General Health",
"relatedToBMICalories": "Related To BMI, calories, body fat, etc to stay updated with your health.",
"selectCalculator": "Select Calculator",
"womensHealth": "Women's Health",
"relatedToPeriodsOvulation": "Related To periods, ovulation, pregnancy, and other topics.",
"bloodSugar": "Blood Sugar",
"trackYourGlucoseLevels": "Track your glucose levels, understand trends, and get personalized insights for better health.",
"bloodCholesterol": "Blood Cholesterol",
"monitorCholesterolLevels": "Monitor cholesterol levels, assess heart health risks, and take proactive steps for well-being.",
"triglyceridesFatBlood": "Triglycerides Fat Blood",
"understandTriglyceridesImpact": "Understand triglycerides' impact on heart health with personalized insights and expert recommendations.",
"bmiCalculator": "BMI\nCalculator",
"caloriesCalculator": "Calories\nCalculator",
"bmrCalculator": "BMR\nCalculator",
"idealBodyWeight": "Ideal Body\nWeight",
"bodyFatCalculator": "Body Fat\nCalculator",
"carbsProteinFat": "Carbs\nProtein & Fat",
"ovulationPeriod": "Ovulation\nPeriod",
"deliveryDueDate": "Delivery\nDue Date",
"low": "Low",
"preDiabetic": "Pre-diabetic",
"high": "High",
"elevated": "Elevated",
"recorded": "Recorded",
"noRecordsYet": "No records yet",
"lastRecord": "Last Record",
"addBloodSugar": "Add Blood Sugar",
"addBloodPressure": "Add Blood Pressure",
"addWeight": "Add Weight",
"bloodSugarDataSavedSuccessfully": "Blood Sugar Data saved successfully",
"bloodPressureDataSavedSuccessfully": "Blood Pressure Data saved successfully",
"weightDataSavedSuccessfully": "Weight Data saved successfully",
"pleaseWait": "Please wait",
"selectUnit": "Select Unit",
"selectMeasureTime": "Select Measure Time",
"selectArm": "Select Arm",
"enterBloodSugar": "Enter Blood Sugar",
"enterSystolicValue": "Enter Systolic Value",
"enterDiastolicValue": "Enter Diastolic Value",
"enterWeight": "Enter Weight",
"selectDuration": "Select Duration",
"systolic": "Systolic",
"diastolic": "Diastolic",
"sendReportByEmail": "Send Report by Email",
"enterYourEmailToReceiveReport": "Enter your email address to receive the report",
"addNewRecord": "Add new Record",
"healthTrackers": "Health Trackers",
"monitorBloodPressureLevels": "Monitor your blood pressure levels, track systolic and diastolic readings, and maintain a healthy heart.",
"trackWeightProgress": "Track your weight progress, set goals, and maintain a healthy body mass for overall wellness.",
"bookAppointment": "Book\nAppointment",
"completeCheckup": "Complete Checkup",
"indoorNavigation": "Indoor Navigation",
"eReferralServices": "E-Referral Services",
"dailyWaterMonitor": "Daily Water Monitor",
"fetchingYourWaterIntakeDetails": "Fetching your water intake details.",
"healthCalculatorsServices": "Health\nCalculators",
"healthConvertersServices": "Health\nConverters",
"smartWatchesServices": "Smart\nWatches",
"exploreServices": "Explore Services",
"medicalAndCareServices": "Medical & Care Services",
"hmgServices": "HMG Services",
"personalServices": "Personal Services",
"habibWallet": "Habib Wallet",
"loginToViewWalletBalance": "Login to view your wallet balance",
"loginToViewMedicalFile": "Login to view your medical file",
"addMember": "Add Member",
"addFamilyMember": "Add Family Member",
"pleaseFillBelowFieldToAddNewFamilyMember": "Please fill the below field to add a new family member to your profile",
"healthTools": "Health Tools",
"supportServices": "Support Services",
"virtualTour": "Virtual Tour",
"carParking": "Car Parking",
"latestNews": "Latest News",
"hmgContact": "HMG Contact",
"durationCannotExceed90": "Duration can not exceed 90 mins",
"unexpectedError": "Unexpected Error Occurred",
"gettingAmbulanceTransportOption": "Getting Ambulance Transport Option",
"fetchingAppointment": "Fetching Appointment",
"doYouWantToCancelTheRequest": "Do you want to cancel the request",
"cancellingRequest": "Cancelling request",
"fetchingTermsAndConditions": "Fetching Terms And Conditions",
"selectLocationPrescriptionDelivery": "Please select the location for prescription delivery",
"noRadiologyOrders": "No Radiology Orders Found",
"ageIsRequired": "Age is required",
"invalidAge": "Invalid age",
"ageMustBeBetween11And120": "Age must be between 11 and 120",
"heightIsRequired": "Height is required",
"invalidHeight": "Invalid height",
"weightIsRequired": "Weight is required",
"invalidWeight": "Invalid weight",
"timeToDrinkWater": "Time to Drink Water! 💧",
"stayHydratedDrinkWater": "Stay hydrated! Drink {amount}ml of water.",
"visitPharmacyOnline": "Visit Pharmacy Online",
"howAreYouFeelingToday": "How are you feeling today?",
"checkYourSymptomsWithScale": "Check your symptoms with this scale",
"checkYourSymptoms": "Check your symptoms",
"noUpcomingAppointmentPleaseBook": "You do not have any upcoming appointment. Please book an appointment",
"youHaveEROnlineCheckInRequest": "You have ER Online Check-In Request",
"quickLinks": "Quick Links",
"viewMedicalFileLandingPage": "View medical file",
"immediateLiveCareRequest": "Immediate LiveCare Request",
"yourTurnIsAfterPatients": "Your turn is after {count} patients.",
"dontHaveHHCOrders": "You don't have any Home Health Care orders yet.",
"hhcOrders": "HHC Orders",
"requestedServices": "Requested Services",
"selectServices": "Select Services",
"selectedServices": "Selected Services",
"createNewRequest": "Create new request",
"youHaveNoPendingRequests": "You have no pending requests.",
"noInsuranceDataFound": "No insurance data found...",
"noInsuranceUpdateRequest": "No insurance update requests found.",
"policyNumberInsurancePage": "Policy: {number}",
"insuranceExpired": "Insurance Expired",
"insuranceActive": "Insurance Active",
"patientCardID": "Patient Card ID: {id}",
"noInsuranceApprovals": "You don't have any insurance approvals yet.",
"noInsuranceWithHMG": "You don't have insurance registered with HMG.",
"referenceRange": "Reference Range",
"downloadReport": "Download report",
"generatingReport": "Generating report, Please wait...",
"noLabResults": "You don't have any lab results yet.",
"labResultDetails": "Lab Result Details",
"resultOf": "Result of",
"whatIsThisResult": "What is this result?",
"lastTested": "Last Tested",
"byVisit": "By Visit",
"byTest": "By Test",
"results": "results",
"viewResults": "View Results",
"rebook": "Rebook",
"noOphthalmologyAppointments": "No Ophthalmology appointments found...",
"noVitalSignsRecordedYet": "No vital signs recorded yet",
"appointmentsAndVisits": "Appointments & visits",
"labAndRadiology": "Lab & Radiology",
"activeMedicationsAndPrescriptions": "Active Medications & Prescriptions",
"allPrescriptions": "All Prescriptions",
"allMedications": "All Medications",
"youDontHaveAnyPrescriptionsYet": "You don't have any prescriptions yet.",
"youDontHaveAnyCompletedVisitsYet": "You don't have any completed visits yet",
"others": "Others",
"allergyInfo": "Allergy Info",
"vaccineInfo": "Vaccine Info",
"updateInsuranceInfo": "Update Insurance",
"myInvoicesList": "My Invoices List",
"ancillaryOrdersList": "Ancillary Orders List",
"youDontHaveAnySickLeavesYet": "You don't have any sick leaves yet.",
"medicalReports": "Medical Reports",
"sickLeaveReport": "Sick Leave Report",
"weightTracker": "Weight Tracker",
"askYourDoctor": "Ask Your Doctor",
"internetPairing": "Internet Pairing",
"requested": "Requested",
"youDontHaveAnyMedicalReportsYet": "You don't have any medical reports yet.",
"requestMedicalReport": "Request medical report",
"youDoNotHaveAnyAppointmentsToRequestMedicalReport": "You do not have any appointments to request a medical report.",
"areYouSureYouWantToRequestMedicalReport": "Are you sure you want to request a medical report for this appointment?",
"yourMedicalReportRequestSubmittedSuccessfully": "Your medical report request has been successfully submitted.",
"monthlyHealthSummaryReportDisclaimer": "This monthly health summary report reflects the health indicators and analysis results of the latest visits. Please note that this will be sent automatically from the system and it's not considered as a official report so no medical decision should be taken based on it",
"updatingMonthlyReportStatus": "Updating Monthly Report Status...",
"monthlyReportStatusUpdatedSuccessfully": "Monthly Report Status Updated Successfully",
"whoCanViewMyMedicalFile": "Who can view my medical file?",
"acceptedYourRequestToBeYourFamilyMember": "{status} your request to be your family member",
"canViewYourFile": "can view your file",
"hasARequestPendingToBeYourFamilyMember": "has a request {status} to be your family member",
"wantsToAddYouAsTheirFamilyMember": "wants to add you as their family member",
"rejectedYourRequestToBeYourFamilyMember": "{status} your request to be your family member",
"rejectedYourFamilyMemberRequest": "{status} your family member request",
"notAvailable": "N/A",
"selectAProfile": "Please select a profile",
"switchFamilyFile": "Switch from the below list of medical file",
"medicalFiles": "Medical Files",
"addANewFamilyMember": "Add a new family member",
"viewInvoiceDetails": "View invoice details",
"outPatient": "OutPatient",
"invoiceDetails": "Invoice Details",
"sendingEmailPleaseWait": "Sending email, Please wait...",
"emailSentSuccessfullyMessage": "Email sent successfully.",
"discount": "Discount",
"paid": "Paid",
"fetchingInvoiceDetails": "Fetching invoice details, Please wait...",
"scanQRCode": "Scan QR code",
"parkingSlotDetails": "Parking Slot Details",
"slotNumber": "Slot: {code}",
"basement": "Basement: {description}",
"parkingDate": "Date: {date}",
"parkedSince": "Parked Since: {time}",
"resetDirection": "Reset Direction",
"noPrescriptionOrdersYet": "You don't have any prescription orders yet.",
"fetchingPrescriptionPDFPleaseWait": "Fetching prescription PDF, Please wait...",
"ratingValue": "Rating: {rating}",
"downloadPrescription": "Download Prescription",
"fetchingPrescriptionDetails": "Fetching prescription details...",
"switchBackFamilyFile": "Switch Back To Family File",
"profileAndSettings": "Profile & Settings",
"quickActions": "Quick Actions",
"notificationsSettings": "Notifications Settings",
"touchIDFaceIDServices": "Touch ID / Face ID Services",
"personalInformation": "Personal Information",
"updateEmailAddress": "Update Email Address",
"helpAndSupport": "Help & Support",
"permissionsProfile": "Permissions",
"privacyPolicy": "Privacy Policy",
"deactivateAccount": "Deactivate account",
"ageYearsOld": "{age} {yearsOld}",
"youDontHaveRadiologyOrders": "You don't have any radiology results yet.",
"radiologyResult": "Radiology Result",
"viewRadiologyImage": "View Radiology Image",
"rateClinic": "Rate Clinic",
"back": "Back",
"rateDoctor": "Rate Doctor",
"howWasYourLastVisitWithDoctor": "How was your last visit with doctor?",
"dateOfBirthSymptoms": "What is your Date of Birth?",
"genderSymptoms": "What is your gender?",
"heightSymptoms": "How tall are you?",
"weightSymptoms": "What is your weight?",
"femaleGender": "Female",
"previous": "Previous",
"selectedOrgans": "Selected Organs",
"noOrgansSelected": "No organs selected yet",
"organSelector": "Organ Selector",
"noPredictionsAvailable": "No Predictions available",
"areYouSureYouWantToRestartOrganSelection": "Are you sure you want to restart the organ selection?",
"possibleConditions": "Possible Conditions",
"pleaseSelectAtLeastOneRiskBeforeProceeding": "Please select at least one risk before proceeding",
"aboveYouSeeCommonRiskFactors": "Above you see the most common risk factors. Although /diagnosis may return questions about risk factors, ",
"readMore": "Read more",
"riskFactors": "Risk Factors",
"noRiskFactorsFound": "No risk factors found",
"basedOnYourSelectedSymptomsNoRiskFactors": "Based on your selected symptoms, no additional risk factors were identified.",
"messageNotification": "Message",
"attachedImage": "Attached Image",
"failedToLoadImage": "Failed to load image",
"typeNotification": "Type",
"pleaseSelectAtLeastOneOptionBeforeProceeding": "Please select at least one option before proceeding",
"suggestions": "Suggestions",
"pleaseGoBackAndSelectOrgansFirst": "Please go back and select organs first",
"symptomsSelector": "Symptoms Selector",
"emergencyTriage": "Emergency",
"emergencyEvidenceDetected": "Emergency evidence detected. Please seek medical attention.",
"noQuestionItemsAvailable": "No question items available",
"pleaseAnswerAllQuestionsBeforeProceeding": "Please answer all questions before proceeding",
"triage": "Triage",
"areYouSureYouWantToExitProgress": "Are you sure you want to exit? Your progress will be lost.",
"noQuestionAvailable": "No question available",
"possibleSymptom": "Possible symptom: ",
"symptomsCheckerFindingScore": "- Symptoms checker finding score",
"notSet": "Not set",
"years": "Years",
"symptomsChecker": "Symptoms Checker",
"helloIsYourInformationUpToDate": "Hello {name}, Is your information up to date?",
"noEditAll": "No, Edit all",
"yesItIs": "Yes, It is",
"age": "Age",
"youDontHaveAnyAncillaryOrdersYet": "You don't have any ancillary orders yet.",
"invoiceWithNumber": "Invoice: {invoiceNo}",
"queued": "Queued",
"checkInReady": "Check-in Ready",
"checkIn": "Check In",
"viewDetails": "View Details",
"selectPaymentMethod": "Select Payment Method",
"processingPaymentPleaseWait": "Processing payment, Please wait...",
"finalizingPaymentPleaseWait": "Finalizing payment, Please wait...",
"generatingInvoicePleaseWait": "Generating invoice, Please wait...",
"hereIsYourInvoiceNumber": "Here is your invoice #: ",
"paymentCompletedSuccessfully": "Payment Completed Successfully",
"failedToInitializeApplePay": "Failed to initialize Apple Pay. Please try again.",
"cash": "Cash",
"approved": "Approved",
"approvalRejectedPleaseVisitReceptionist": "Approval Rejected - Please visit receptionist",
"sentForApproval": "Sent For Approval",
"ancillaryOrderDetails": "Ancillary Order Details",
"noProceduresAvailableForSelectedOrder": "No Procedures available for the selected order.",
"procedures": "Procedures",
"totalAmount": "Total Amount",
"covered": "Covered",
"vatPercent": "VAT (15%)",
"proceedToPayment": "Proceed to Payment",
"supportedSmartWatches": "Supported Smart Watches",
"pleaseMakeSureSamsungWatchConnected": "Please make sure that your Samsung Watch is connected to your Phone, is actively synced & updated.",
"beforeSyncingDataFollowInstructions": "Before syncing data, please make sure that you have followed the instructions properly.",
"viewWatchInstructions": "View watch instructions",
"healthConnectAppNotInstalled": "Seems like you do not have Health Connect App installed. Please install it from the Play Store to sync your health data.",
"setTimerOfReminder": "Set the timer of reminder",
"youHaveAppointmentWithDr": "You have appointment with Dr. ",
"hours": "Hours",
"secs": "Secs",
"noAllergiesDataFound": "No allergies data found...",
"heartRateDescription": "Your heart rate indicates how many times your heart beats per minute",
"bloodOxygenDescription": "Blood oxygen level indicates how much oxygen your red blood cells are carrying",
"stepsDescription": "Number of steps taken throughout the day",
"caloriesDescription": "Calories burned during physical activity",
"distanceDescription": "Distance covered throughout the day",
"overview": "Overview",
"details": "Details",
"healthy": "Healthy",
"warning": "Warning",
"vitalSignDetails": "Vital Sign Details",
"resultOf": "Result of {date}",
"resultOfNoDate": "Result of --",
"referenceRangeBetween": "Reference range: {low} {high} {unit}",
"referenceRangeMin": "Reference range: ≥ {low} {unit}",
"referenceRangeMax": "Reference range: ≤ {high} {unit}",
"noHistoryAvailable": "No history available",
"bmiDescription": "BMI is a measurement based on height and weight that estimates body fat.",
"heightDescription": "Height is measured in centimeters and is used to calculate BMI and dosage recommendations.",
"weightDescription": "Weight helps track overall health, nutrition, and changes over time.",
"bloodPressureDescription": "Blood pressure reflects the force of blood against artery walls. It is shown as systolic/diastolic.",
"temperatureDescription": "Body temperature reflects how hot your body is and may change with infection or inflammation.",
"heartRateDescriptionVital": "Heart rate refers to the number of heart beats per minute.",
"respiratoryRateDescription": "Respiratory rate is the number of breaths taken per minute.",
"bmiAdvice": "Maintain a balanced diet and regular activity. If your BMI is high or low, consider consulting your doctor.",
"heightAdvice": "No action is needed unless your measurement looks incorrect. Update it during your next visit.",
"weightAdvice": "Monitor weight changes. Sudden gain or loss may require medical advice.",
"bloodPressureAdvice": "Keep tracking your blood pressure. High or low readings should be discussed with your doctor.",
"temperatureAdvice": "If you have a persistent fever or symptoms, contact your healthcare provider.",
"heartRateAdvice": "Track your heart rate trends. If you feel dizziness or chest pain, seek medical care.",
"respiratoryRateAdvice": "If you notice shortness of breath or abnormal breathing, seek medical advice.",
"whatShouldIDoNext": "What should I do next?",
"customizeDrinkCup": "Customize your drink cup",
"tipsToStayHydrated": "Tips to stay hydrated",
"drinkBeforeYouFeelThirsty": "Drink before you feel thirsty",
"keepRefillableBottleNextToYou": "Keep a refillable bottle next to you",
"trackYourDailyIntakeToStayMotivated": "Track your daily intake to stay motivated",
"chooseSparklingWaterInsteadOfSoda": "Choose sparkling water instead of soda",
"switchCup": "Switch Cup",
"plainWater": "Plain Water",
"yourGoal": "Your Goal",
"remaining": "Remaining",
"hydrationStatus": "Hydration Status",
"areYouSureYouWantToCancelAllWaterReminders": "Are you sure you want to cancel all water reminders?",
"remindersSet": "Reminders Set!",
"dailyWaterRemindersScheduledAt": "Daily water reminders scheduled at:",
"waterConsumption": "Water Consumption",
"selectActivityLevel": "Select Activity Level",
"selectNumberOfReminders": "Select Number of Reminders",
"h2oSettings": "H20 Settings",
"settingsSavedSuccessfully": "Settings saved successfully",
"yourName": "Your Name",
"ageYears": "Age (11-120) yrs",
"numberOfRemindersInADay": "Number of reminders in a day",
"medications": "Medications",
"remarks": "Remarks: ",
"someRemarksAboutPrescription": "some remarks about the prescription will be here",
"notifyMeBeforeConsumptionTime": "Notify me before the consumption time",
"noMedicationsToday": "No medications today",
"route": "Route: {route}",
"frequency": "Frequency: {frequency}",
"instruction": "Instruction: {instruction}",
"duration": "Duration: {days}",
"reminders": "Reminders",
"reminderAddedToCalendar": "Reminder added to calendar ✅",
"errorWhileSettingCalendar": "Error while setting calendar: {error}",
"instructions": "Instructions",
"requests": "Requests",
"thisWeek": "This Week",
"lastMonth": "Last Month",
"lastSixMonths": "Last 6 Months",
"selectTime": "Select Time",
"pleaseWaitYouWillBeCalledForVitalSigns": "Please wait! you will be called for vital signs",
"pleaseVisitRoomForVitalSigns": "Please visit Room {roomNumber} for vital signs",
"pleaseVisitRoomToTheDoctor": "Please visit Room {roomNumber} to the Doctor"
}

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

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

@ -19,7 +19,7 @@ abstract class ApiClient {
Future<void> post(
String endPoint, {
required dynamic body,
required Map<String, dynamic> body,
required Function(dynamic response, int statusCode, {int? messageStatus, String? errorMessage}) onSuccess,
required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure,
bool isAllowAny,
@ -210,7 +210,7 @@ class ApiClientImp implements ApiClient {
final int statusCode = response.statusCode;
log("uri: ${Uri.parse(url.trim())}");
log("body: ${json.encode(body)}");
// log("response.body: ${response.body}");
log("response.body: ${response.body}");
if (statusCode < 200 || statusCode >= 400) {
onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data"));
logApiEndpointError(endPoint, 'Error While Fetching data', statusCode);

@ -151,6 +151,7 @@ var GET_FINDUS_REQUEST = 'Services/Lists.svc/REST/Get_HMG_Locations';
///LiveChat
var GET_LIVECHAT_REQUEST = 'Services/Patients.svc/REST/GetPatientICProjects';
var GET_LIVECHAT_REQUEST_ID = 'Services/Patients.svc/REST/Patient_ICChatRequest_Insert';
///babyInformation
var GET_BABYINFORMATION_REQUEST = 'Services/Community.svc/REST/GetBabyByUserID';
@ -207,7 +208,7 @@ var GET_APPOINTMENT_DETAILS_BY_NO = 'Services/MobileNotifications.svc/REST/GetAp
var NEW_RATE_APPOINTMENT_URL = "Services/Doctors.svc/REST/AppointmentsRating_InsertAppointmentRate";
var NEW_RATE_DOCTOR_URL = "Services/Doctors.svc/REST/DoctorsRating_InsertDoctorRate";
var GET_QR_PARKING = 'Services/SWP.svc/REST/GetQRParkingByID';
//var GET_QR_PARKING = 'Services/SWP.svc/REST/GetQRParkingByID';
//URL to get clinic list
var GET_CLINICS_LIST_URL = "Services/lists.svc/REST/GetClinicCentralized";
@ -398,6 +399,9 @@ var GET_COVID_DRIVETHRU_PROCEDURES_LIST = 'Services/Doctors.svc/REST/COVID19_Get
var GET_PATIENT_LAST_RECORD = 'Services/Patients.svc/REST/Med_GetPatientLastRecord';
var INSERT_PATIENT_HEALTH_DATA = 'Services/Patients.svc/REST/Med_InsertTransactions';
///Push Notifications
var GET_ALL_NOTIFICATIONS = 'Services/MobileNotifications.svc/REST/PushNotification_GetAllNotifications';
///My Trackers
var GET_DIABETIC_RESULT_AVERAGE = 'Services/Patients.svc/REST/Patient_GetDiabeticResultAverage';
var GET_DIABTEC_RESULT = 'Services/Patients.svc/REST/Patient_GetDiabtecResults';
@ -420,7 +424,6 @@ var GET_QUESTION_TYPES = 'Services/OUTPs.svc/REST/getQuestionsTypes';
var UPDATE_DIABETIC_RESULT = 'Services/Patients.svc/REST/Patient_UpdateDiabeticResult';
var SEND_AVERAGE_BLOOD_SUGAR_REPORT = 'Services/Notifications.svc/REST/SendAverageBloodSugarReport';
var DEACTIVATE_DIABETIC_STATUS = 'services/Patients.svc/REST/Patient_DeactivateDiabeticStatus';
var DEACTIVATE_BLOOD_PRESSURES_STATUS = 'services/Patients.svc/REST/Patient_DeactivateBloodPressureStatus';
@ -672,10 +675,12 @@ const FAMILY_FILES = 'Services/Authentication.svc/REST/GetAllSharedRecordsByStat
var GET_PRESCRIPTION_INSTRUCTIONS_PDF = 'Services/ChatBot_Service.svc/REST/Chatbot_SendMedicationInstructionByWhatsApp';
const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard';
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
@ -799,6 +804,11 @@ class ApiConsts {
static final String getAllSharedRecordsByStatus = 'Services/Authentication.svc/REST/GetAllSharedRecordsByStatus';
static final String removeFileFromFamilyMembers = 'Services/Authentication.svc/REST/ActiveDeactive_PatientFile';
static final String acceptAndRejectFamilyFile = 'Services/Authentication.svc/REST/Update_FileStatus';
static final String getActivePrescriptionsDetails = 'Services/Patients.svc/Rest/GetActivePrescriptionReportByPatientID';
static final String getTermsConditions = 'Services/Patients.svc/Rest/GetUserTermsAndConditions';
static final String getMonthlyReports = 'Services/Patients.svc/Rest/UpdatePateintHealthSummaryReport';
static final String updatePatientEmail = 'Services/Patients.svc/Rest/UpdatePateintEmail';
static final String getQrParkingDetails = 'Services/SWP.svc/REST/GetQRParkingByID';
// Ancillary Order Apis
static final String getOnlineAncillaryOrderList = 'Services/Doctors.svc/REST/GetOnlineAncillaryOrderList';
@ -825,11 +835,12 @@ class ApiConsts {
static final String updateHHCOrder = 'api/hhc/update';
static final String addHHCOrder = 'api/HHC/add';
// SYMPTOMS CHECKER
// SYMPTOMS CHECKER API
static final String symptomsUserLogin = '$symptomsCheckerApi/user_login';
static final String getBodySymptomsByName = '$symptomsCheckerApi/GetBodySymptomsByName';
static final String getRiskFactors = '$symptomsCheckerApi/GetRiskFactors';
static final String getSuggestions = '$symptomsCheckerApi/GetSuggestion';
static final String diagnosis = '$symptomsCheckerApi/diagnosis';
static final String diagnosis = '$symptomsCheckerApi/GetDiagnosis';
static final String explain = '$symptomsCheckerApi/explain';
//E-REFERRAL SERVICES
@ -848,6 +859,37 @@ class ApiConsts {
static String h2oUpdateUserDetail = "Services/H2ORemainder.svc/REST/H2O_UpdateUserDetails_New";
static String h2oUndoUserActivity = "Services/H2ORemainder.svc/REST/H2o_UndoUserActivity";
// HEALTH TRACKERS
// Blood Sugar (Diabetic)
static String getDiabeticResultAverage = 'Services/Patients.svc/REST/Patient_GetDiabeticResultAverage';
static String getDiabeticResult = 'Services/Patients.svc/REST/Patient_GetDiabtecResults';
static String addDiabeticResult = 'Services/Patients.svc/REST/Patient_AddDiabtecResult';
static String updateDiabeticResult = 'Services/Patients.svc/REST/Patient_UpdateDiabtecResult';
static String deactivateDiabeticStatus = 'Services/Patients.svc/REST/Patient_DeactivateDiabeticStatus';
static String sendAverageBloodSugarReport = 'Services/Notifications.svc/REST/SendAverageBloodSugarReport';
// Blood Pressure
static String getBloodPressureResultAverage = 'Services/Patients.svc/REST/Patient_GetBloodPressureResultAverage';
static String getBloodPressureResult = 'Services/Patients.svc/REST/Patient_GetBloodPressureResult';
static String addBloodPressureResult = 'Services/Patients.svc/REST/Patient_AddBloodPressureResult';
static String updateBloodPressureResult = 'Services/Patients.svc/REST/Patient_UpdateBloodPressureResult';
static String deactivateBloodPressureStatus = 'Services/Patients.svc/REST/Patient_DeactivateBloodPressureStatus';
static String sendAverageBloodPressureReport = 'Services/Notifications.svc/REST/SendAverageBloodPressureReport';
// Weight Measurement
static String getWeightMeasurementResultAverage = 'Services/Patients.svc/REST/Patient_GetWeightMeasurementResultAverage';
static String getWeightMeasurementResult = 'Services/Patients.svc/REST/Patient_GetWeightMeasurementResult';
static String addWeightMeasurementResult = 'Services/Patients.svc/REST/Patient_AddWeightMeasurementResult';
static String updateWeightMeasurementResult = 'Services/Patients.svc/REST/Patient_UpdateWeightMeasurementResult';
static String deactivateWeightMeasurementStatus = 'Services/Patients.svc/REST/Patient_DeactivateWeightMeasurementStatus';
static String sendAverageBodyWeightReport = 'Services/Notifications.svc/REST/SendAverageBodyWeightReport';
//Blood Donation
static String bloodGroupUpdate = "Services/PatientVarification.svc/REST/BloodDonation_RegisterBloodType";
static String userAgreementForBloodGroupUpdate = "Services/PatientVarification.svc/REST/AddUserAgreementForBloodDonation";
static String getProjectsHaveBDClinics = "Services/OUTPs.svc/REST/BD_getProjectsHaveBDClinics";
static String getClinicsBDFreeSlots = "Services/OUTPs.svc/REST/BD_GetFreeSlots";
// ************ static values for Api ****************
static final double appVersionID = 50.3;
static final int appChannelId = 3;

@ -220,11 +220,16 @@ class AppAssets {
static const String activity = '$svgBasePath/activity.svg';
static const String age = '$svgBasePath/age_icon.svg';
static const String gender = '$svgBasePath/gender_icon.svg';
static const String genderInputIcon = '$svgBasePath/genderInputIcon.svg';
static const String bloodType = '$svgBasePath/blood_type.svg';
static const String trade_down_yellow = '$svgBasePath/trade_down_yellow.svg';
static const String trade_down_red = '$svgBasePath/trade_down_red.svg';
static const String pharmacy_icon = '$svgBasePath/phramacy_icon.svg';
static const String forward_top_nav_icon = '$svgBasePath/forward_top_nav_icon.svg';
static const String back_top_nav_icon = '$svgBasePath/back_top_nav_icon.svg';
//bottom navigation//
static const String homeBottom = '$svgBasePath/home_bottom.svg';
static const String homeBottomFill = '$svgBasePath/home_bottom_fill.svg';
@ -278,16 +283,21 @@ class AppAssets {
static const String yellowArrowDownIcon = '$svgBasePath/yellow_arrow_down_icon.svg';
static const String greenTickIcon = '$svgBasePath/green_tick_icon.svg';
// PNGS
static const String bloodSugar = '$svgBasePath/bloodsugar.svg';
static const String bloodCholestrol = '$svgBasePath/bloodcholestrol.svg';
static const String triglycerides = '$svgBasePath/triglycerides.svg';
static const String bulb = '$svgBasePath/bulb.svg';
static const String switchBtn = '$svgBasePath/switch.svg';
//Health Trackers
static const String bloodPressureIcon = '$svgBasePath/blood_pressure_icon.svg';
static const String bloodSugarOnlyIcon = '$svgBasePath/blood_sugar_only_icon.svg';
static const String weightIcon = '$svgBasePath/weight_icon.svg';
static const String normalStatusGreenIcon = '$svgBasePath/normal_status_green_icon.svg';
static const String sendEmailIcon = '$svgBasePath/send_email_icon.svg';
static const String lowIndicatorIcon = '$svgBasePath/low_indicator_icon.svg';
// Health Calculators
static const String ovulationAccordion = '$svgBasePath/approximate_ovulation_accordion.svg';
static const String nextPeriodAccordion = '$svgBasePath/next_period_accordion.svg';
static const String fertileAccordion = '$svgBasePath/fertile_window_accordion.svg';
@ -296,9 +306,7 @@ class AppAssets {
static const String covid19icon = '$svgBasePath/covid_19.svg';
//vital sign
static const String heartRate = '$svgBasePath/heart_rate.svg';
static const String respRate = '$svgBasePath/resp_rate.svg';
static const String weightVital = '$svgBasePath/weight_2.svg';
@ -307,8 +315,6 @@ class AppAssets {
static const String bloodPressure = '$svgBasePath/blood_pressure.svg';
static const String temperature = '$svgBasePath/temperature.svg';
// PNGS //
static const String hmgLogo = '$pngBasePath/hmg_logo.png';
static const String liveCareService = '$pngBasePath/livecare_service.png';
@ -335,8 +341,6 @@ class AppAssets {
static const String fullBodyFront = '$pngBasePath/full_body_front.png';
static const String fullBodyBack = '$pngBasePath/full_body_back.png';
static const String bmiFullBody = '$pngBasePath/bmi_image_1.png';
}
class AppAnimations {
@ -357,6 +361,5 @@ class AppAnimations {
static const String ambulance = '$lottieBasePath/ambulance.json';
static const String ambulanceAlert = '$lottieBasePath/ambulance_alert.json';
static const String rrtAmbulance = '$lottieBasePath/rrt_ambulance.json';
}

@ -10,6 +10,8 @@ import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_repo.
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/active_prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/models/active_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/common/common_repo.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_repo.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart';
@ -18,6 +20,7 @@ import 'package:hmg_patient_app_new/features/emergency_services/emergency_servic
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_repo.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/health_trackers/health_trackers_repo.dart';
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_repo.dart';
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_repo.dart';
@ -32,17 +35,21 @@ import 'package:hmg_patient_app_new/features/medical_file/medical_file_repo.dart
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/monthly_report/monthly_report_repo.dart';
import 'package:hmg_patient_app_new/features/monthly_report/monthly_report_view_model.dart';
import 'package:hmg_patient_app_new/features/monthly_reports/monthly_reports_repo.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_repo.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
import 'package:hmg_patient_app_new/features/notifications/notifications_repo.dart';
import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_repo.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/features/qr_parking/qr_parking_repo.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_provider.dart';
@ -52,6 +59,7 @@ import 'package:hmg_patient_app_new/features/todo_section/todo_section_repo.dart
import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart';
import 'package:hmg_patient_app_new/features/water_monitor/water_monitor_repo.dart';
import 'package:hmg_patient_app_new/features/water_monitor/water_monitor_view_model.dart';
import 'package:hmg_patient_app_new/presentation/health_trackers/health_trackers_view_model.dart';
import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
@ -66,8 +74,14 @@ import 'package:local_auth/local_auth.dart';
import 'package:logger/web.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../features/monthly_reports/monthly_reports_repo.dart';
import '../features/qr_parking/qr_parking_view_model.dart';
import '../presentation/health_calculators_and_converts/health_calculator_view_model.dart';
import '../features/active_prescriptions/active_prescriptions_repo.dart';
import '../features/monthly_reports/terms_conditions_repo.dart';
import '../features/monthly_reports/terms_conditions_view_model.dart';
GetIt getIt = GetIt.instance;
class AppDependencies {
@ -143,7 +157,15 @@ class AppDependencies {
getIt.registerLazySingleton<BloodDonationRepo>(() => BloodDonationRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<WaterMonitorRepo>(() => WaterMonitorRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<MyInvoicesRepo>(() => MyInvoicesRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<HealthTrackersRepo>(() => HealthTrackersRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<MonthlyReportRepo>(() => MonthlyReportRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<ActivePrescriptionsRepo>(() => ActivePrescriptionsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<TermsConditionsRepo>(() => TermsConditionsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerFactory<TermsConditionsViewModel>(() => TermsConditionsViewModel(termsConditionsRepo: getIt<TermsConditionsRepo>(), errorHandlerService: getIt<ErrorHandlerService>(),
),);
getIt.registerLazySingleton<MonthlyReportsRepo>(() => MonthlyReportsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<QrParkingRepo>(() => QrParkingRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<NotificationsRepo>(() => NotificationsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels
// Global/shared VMs LazySingleton
@ -154,26 +176,20 @@ class AppDependencies {
() => RadiologyViewModel(radiologyRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt()),
);
getIt.registerLazySingleton<PrescriptionsViewModel>(
() => PrescriptionsViewModel(prescriptionsRepo: getIt(), errorHandlerService: getIt(), navServices: getIt()));
getIt.registerLazySingleton<PrescriptionsViewModel>(() => PrescriptionsViewModel(prescriptionsRepo: getIt(), errorHandlerService: getIt(), navServices: getIt()));
getIt.registerLazySingleton<InsuranceViewModel>(() => InsuranceViewModel(insuranceRepo: getIt(), errorHandlerService: getIt()));
getIt.registerLazySingleton<MyAppointmentsViewModel>(
() => MyAppointmentsViewModel(myAppointmentsRepo: getIt(), errorHandlerService: getIt(), appState: getIt()));
getIt.registerLazySingleton<MyAppointmentsViewModel>(() => MyAppointmentsViewModel(myAppointmentsRepo: getIt(), errorHandlerService: getIt(), appState: getIt()));
getIt.registerLazySingleton<AppointmentRatingViewModel>(
() => AppointmentRatingViewModel(myAppointmentsRepo: getIt(), errorHandlerService: getIt(), appState: getIt()));
getIt.registerLazySingleton<AppointmentRatingViewModel>(() => AppointmentRatingViewModel(myAppointmentsRepo: getIt(), errorHandlerService: getIt(), appState: getIt()));
getIt.registerLazySingleton<PayfortViewModel>(
() => PayfortViewModel(payfortRepo: getIt(), errorHandlerService: getIt()),
);
getIt.registerLazySingleton<HabibWalletViewModel>(
() => HabibWalletViewModel(
habibWalletRepo: getIt(),
errorHandlerService: getIt()
),
() => HabibWalletViewModel(habibWalletRepo: getIt(), errorHandlerService: getIt()),
);
getIt.registerLazySingleton<MedicalFileViewModel>(
@ -185,12 +201,7 @@ class AppDependencies {
getIt.registerLazySingleton<BookAppointmentsViewModel>(
() => BookAppointmentsViewModel(
bookAppointmentsRepo: getIt(),
errorHandlerService: getIt(),
navigationService: getIt(),
myAppointmentsViewModel: getIt(),
locationUtils: getIt(),
dialogService: getIt()),
bookAppointmentsRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt(), myAppointmentsViewModel: getIt(), locationUtils: getIt(), dialogService: getIt()),
);
getIt.registerLazySingleton<ImmediateLiveCareViewModel>(
@ -204,13 +215,7 @@ class AppDependencies {
getIt.registerLazySingleton<AuthenticationViewModel>(
() => AuthenticationViewModel(
authenticationRepo: getIt(),
cacheService: getIt(),
navigationService: getIt(),
dialogService: getIt(),
appState: getIt(),
errorHandlerService: getIt(),
localAuthService: getIt()),
authenticationRepo: getIt(), cacheService: getIt(), navigationService: getIt(), dialogService: getIt(), appState: getIt(), errorHandlerService: getIt(), localAuthService: getIt()),
);
getIt.registerLazySingleton<ProfileSettingsViewModel>(() => ProfileSettingsViewModel());
@ -271,15 +276,35 @@ class AppDependencies {
navigationService: getIt(),
dialogService: getIt(),
appState: getIt(),
navServices: getIt(),
),
);
getIt.registerLazySingleton<HealthProvider>(() => HealthProvider());
getIt.registerLazySingleton<WaterMonitorViewModel>(() => WaterMonitorViewModel(waterMonitorRepo: getIt()));
getIt.registerLazySingleton<WaterMonitorViewModel>(() => WaterMonitorViewModel(waterMonitorRepo: getIt(), errorHandlerService: getIt()));
//commenting this because its already define there was on run time error because of this.
getIt.registerLazySingleton<MyInvoicesViewModel>(() => MyInvoicesViewModel(myInvoicesRepo: getIt(), errorHandlerService: getIt(), navServices: getIt()));
getIt.registerLazySingleton<MonthlyReportViewModel>(() => MonthlyReportViewModel(errorHandlerService: getIt(), monthlyReportRepo: getIt()));
getIt.registerLazySingleton<NotificationsViewModel>(() => NotificationsViewModel(notificationsRepo: getIt(), errorHandlerService: getIt()));
getIt.registerLazySingleton<HealthTrackersViewModel>(() => HealthTrackersViewModel(healthTrackersRepo: getIt(), errorHandlerService: getIt()));
getIt.registerLazySingleton<ActivePrescriptionsViewModel>(
() => ActivePrescriptionsViewModel(
errorHandlerService: getIt(),
activePrescriptionsRepo: getIt()
),
);
getIt.registerFactory<QrParkingViewModel>(
() => QrParkingViewModel(
qrParkingRepo: getIt<QrParkingRepo>(),
errorHandlerService: getIt<ErrorHandlerService>(),
cacheService: getIt<CacheService>(),
),
);
}
}

@ -16,7 +16,7 @@ enum CountryEnum { saudiArabia, unitedArabEmirates }
enum CalenderEnum { gregorian, hijri }
enum SelectionTypeEnum { dropdown, calendar, search }
enum SelectionTypeEnum { dropdown, calendar, search, time }
enum GenderTypeEnum { male, female }
@ -38,7 +38,19 @@ enum HealthCalConEnum { calculator, converter }
enum HealthCalculatorEnum { general, women }
enum HealthCalculatorsTypeEnum { bmi, calories, bmr, idealBodyWeight, bodyFat, crabsProteinFat, ovulation, deliveryDueDate, bloodSugar, bloodCholesterol, triglycerides }
enum HealthCalculatorsTypeEnum {
bmi,
calories,
bmr,
idealBodyWeight,
bodyFat,
crabsProteinFat,
ovulation,
deliveryDueDate,
bloodSugar,
bloodCholesterol,
triglycerides
}
extension HealthCalculatorExtenshion on HealthCalculatorsTypeEnum {
String get displayName {
@ -297,3 +309,5 @@ extension ServiceTypeEnumExt on ServiceTypeEnum {
// SymptomsChecker
enum PossibleConditionsSeverityEnum { seekMedicalAdvice, monitorOnly, emergency }
enum HealthTrackerTypeEnum { bloodSugar, bloodPressure, weightTracker }

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

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

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

@ -7,16 +7,14 @@ import 'package:flutter/material.dart'; // These are the Viewport values of your
const num figmaDesignWidth = 430; // iPhone X / 12 base width,
const num figmaDesignHeight = 927; // iPhone X / 12 base height
extension ConstrainedResponsive on num {
/// Width with max cap for tablets
double get wCapped => isTablet ? math.min( w, this * 1.3) : w;
double get wCapped => isTablet ? math.min(w, this * 1.3) : w;
/// Height with max cap for tablets
double get hCapped => isTablet ? math.min(h, this * 1.3) : h;
}
extension ResponsiveExtension on num {
double get _screenWidth => SizeUtils.width;

@ -43,7 +43,7 @@ class Utils {
{
"Desciption": "Sahafa Hospital",
"DesciptionN": "مستشفى الصحافة",
"ID": 1,
"ID": 1, // Campus ID
"LegalName": "Sahafa Hospital",
"LegalNameN": "مستشفى الصحافة",
"Name": "Sahafa Hospital",
@ -55,19 +55,20 @@ class Utils {
"IsActive": true,
"IsHmg": true,
"IsVidaPlus": false,
"Latitude": "24.8113774",
"Longitude": "46.6239813",
"Latitude": "24.8111548",
"Longitude": "46.6217912",
"MainProjectID": 130,
"ProjectOutSA": false,
"UsingInDoctorApp": false
"UsingInDoctorApp": false,
"IsHMC": false
},{
"Desciption": "Jeddah Hospital",
"DesciptionN": "مستشفى الصحافة",
"ID": 3,
"LegalName": "Jeddah Hospital",
"LegalNameN": "مستشفى الصحافة",
"Name": "Jeddah Hospital",
"NameN": "مستشفى الصحافة",
"Desciption": "Jeddah Fayhaa Hospital",
"DesciptionN": "مستشفى جدة الفيحاء",
"ID": 3, // Campus ID
"LegalName": "Jeddah Fayhaa Hospital",
"LegalNameN": "مستشفى جدة الفيحاء",
"Name": "Jeddah Fayhaa Hospital",
"NameN": "مستشفى جدة الفيحاء",
"PhoneNumber": "+966115222222",
"SetupID": "013311",
"DistanceInKilometers": 0,
@ -75,11 +76,12 @@ class Utils {
"IsActive": true,
"IsHmg": true,
"IsVidaPlus": false,
"Latitude": "24.8113774",
"Longitude": "46.6239813",
"Latitude": "21.5086703",
"Longitude": "39.2121855",
"MainProjectID": 130,
"ProjectOutSA": false,
"UsingInDoctorApp": false
"UsingInDoctorApp": false,
"IsHMC": false
}
];
@ -262,16 +264,6 @@ class Utils {
return await prefs.remove(key);
}
static void showLoading({bool isNeedBinding = true}) {
if (isNeedBinding) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showLoadingDialog();
});
} else {
showLoadingDialog();
}
}
static void showLoadingDialog() {
_isLoadingVisible = true;
showDialog(
@ -288,18 +280,6 @@ class Utils {
);
}
static void hideLoading() {
try {
if (_isLoadingVisible) {
_isLoadingVisible = false;
Navigator.of(navigationService.navigatorKey.currentContext!).pop();
}
_isLoadingVisible = false;
} catch (e) {
log("errr: ${e.toString()}");
}
}
static List<T> uniqueBy<T, K>(List<T> list, K Function(T) keySelector) {
final seenKeys = <K>{};
return list.where((item) => seenKeys.add(keySelector(item))).toList();
@ -980,11 +960,11 @@ class Utils {
static String getCardButtonText(int currentQueueStatus, String roomNumber) {
switch (currentQueueStatus) {
case 0:
return "Please wait! you will be called for vital signs".needTranslation;
return LocaleKeys.pleaseWaitYouWillBeCalledForVitalSigns.tr();
case 1:
return "Please visit Room $roomNumber for vital signs".needTranslation;
return LocaleKeys.pleaseVisitRoomForVitalSigns.tr(namedArgs: {'roomNumber': roomNumber.toString()});
case 2:
return "Please visit Room $roomNumber to the Doctor".needTranslation;
return LocaleKeys.pleaseVisitRoomToTheDoctor.tr(namedArgs: {'roomNumber': roomNumber.toString()});
}
return "";
}

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

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

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

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

@ -3,14 +3,26 @@ import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_hospitals_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_response_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/cities_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class BloodDonationRepo {
Future<Either<Failure, GenericApiModel<List<CitiesModel>>>> getAllCities();
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList();
Future<Either<Failure, GenericApiModel<List<BdGetProjectsHaveBdClinic>>>> getBloodDonationProjectsList();
Future<Either<Failure, GenericApiModel<List_BloodGroupDetailsModel>>> getPatientBloodGroupDetails();
Future<Either<Failure, GenericApiModel<dynamic>>> updateBloodGroup({required Map<String, dynamic> request});
Future<Either<Failure, GenericApiModel<dynamic>>> getFreeBloodDonationSlots({required Map<String, dynamic> request});
Future<Either<Failure, GenericApiModel<dynamic>>> addUserAgreementForBloodDonation({required Map<String, dynamic> request});
}
class BloodDonationRepoImp implements BloodDonationRepo {
@ -93,4 +105,186 @@ class BloodDonationRepoImp implements BloodDonationRepo {
return Left(UnknownFailure(e.toString()));
}
}
}
@override
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList() async {
Map<String, dynamic> request = {};
try {
GenericApiModel<List<HospitalsModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PROJECT_LIST,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['ListProject'];
final appointmentsList = list.map((item) => HospitalsModel.fromJson(item as Map<String, dynamic>)).toList().cast<HospitalsModel>();
apiResponse = GenericApiModel<List<HospitalsModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: appointmentsList,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<BdGetProjectsHaveBdClinic>>>> getBloodDonationProjectsList() async {
Map<String, dynamic> request = {};
try {
GenericApiModel<List<BdGetProjectsHaveBdClinic>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getProjectsHaveBDClinics,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final listData = (response['BD_getProjectsHaveBDClinics'] as List<dynamic>);
final list = listData.map((item) => BdGetProjectsHaveBdClinic.fromJson(item as Map<String, dynamic>)).toList();
apiResponse = GenericApiModel<List<BdGetProjectsHaveBdClinic>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: list,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<dynamic>>>> updateBloodGroup({required Map<String, dynamic> request}) async {
try {
GenericApiModel<List<dynamic>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.bloodGroupUpdate,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// final list = response['ListProject'];
// final appointmentsList = list.map((item) => HospitalsModel.fromJson(item as Map<String, dynamic>)).toList().cast<HospitalsModel>();
apiResponse = GenericApiModel<List<dynamic>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<dynamic>>>> getFreeBloodDonationSlots({required Map<String, dynamic> request}) async {
try {
GenericApiModel<List<dynamic>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getClinicsBDFreeSlots,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// final list = response['ListProject'];
// final appointmentsList = list.map((item) => HospitalsModel.fromJson(item as Map<String, dynamic>)).toList().cast<HospitalsModel>();
apiResponse = GenericApiModel<List<dynamic>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<dynamic>>>> addUserAgreementForBloodDonation({required Map<String, dynamic> request}) async {
try {
GenericApiModel<List<dynamic>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.userAgreementForBloodGroupUpdate,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// final list = response['ListProject'];
// final appointmentsList = list.map((item) => HospitalsModel.fromJson(item as Map<String, dynamic>)).toList().cast<HospitalsModel>();
apiResponse = GenericApiModel<List<dynamic>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -1,15 +1,25 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.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/enums.dart';
import 'package:hmg_patient_app_new/core/utils/doctor_response_mapper.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_repo.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_hospitals_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_list_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_response_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/cities_model.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/facility_selection.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/hospital_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
class BloodDonationViewModel extends ChangeNotifier {
final DialogService dialogService;
@ -17,8 +27,21 @@ class BloodDonationViewModel extends ChangeNotifier {
ErrorHandlerService errorHandlerService;
final NavigationService navigationService;
final AppState appState;
bool isTermsAccepted = false;
BdGetProjectsHaveBdClinic? selectedHospital;
CitiesModel? selectedCity;
BloodGroupListModel? selectedBloodGroup;
int _selectedHospitalIndex = 0;
int _selectedBloodTypeIndex = 0;
GenderTypeEnum? selectedGender;
String? selectedBloodType;
final NavigationService navServices;
List<BdGetProjectsHaveBdClinic> hospitalList = [];
List<CitiesModel> citiesList = [];
List_BloodGroupDetailsModel patientBloodGroupDetailsModel = List_BloodGroupDetailsModel();
List<BloodGroupListModel> bloodGroupList = [
BloodGroupListModel("O+", 0),
BloodGroupListModel("O-", 1),
@ -30,35 +53,34 @@ class BloodDonationViewModel extends ChangeNotifier {
BloodGroupListModel("B-", 7),
];
List<BloodGroupListModel> genderList = [
BloodGroupListModel(LocaleKeys.malE.tr(), 1),
BloodGroupListModel("Female".needTranslation.tr(), 2),
];
late CitiesModel selectedCity;
late BloodGroupListModel selectedBloodGroup;
int _selectedHospitalIndex = 0;
int _selectedBloodTypeIndex = 0;
String selectedBloodType = '';
List_BloodGroupDetailsModel patientBloodGroupDetailsModel = List_BloodGroupDetailsModel();
BloodDonationViewModel({required this.bloodDonationRepo, required this.errorHandlerService, required this.navigationService, required this.dialogService, required this.appState});
BloodDonationViewModel({
required this.bloodDonationRepo,
required this.errorHandlerService,
required this.navigationService,
required this.dialogService,
required this.appState,
required this.navServices,
});
setSelectedCity(CitiesModel city) {
selectedCity = city;
notifyListeners();
}
void onGenderChange(String? status) {
selectedGender = GenderTypeExtension.fromType(status)!;
notifyListeners();
}
setSelectedBloodGroup(BloodGroupListModel bloodGroup) {
selectedBloodGroup = bloodGroup;
selectedBloodType = selectedBloodGroup.name;
selectedBloodType = selectedBloodGroup!.name;
notifyListeners();
}
Future<void> getRegionSelectedClinics({Function(dynamic)? onSuccess, Function(String)? onError}) async {
citiesList.clear();
selectedCity = CitiesModel();
selectedCity = null;
notifyListeners();
final result = await bloodDonationRepo.getAllCities();
@ -71,6 +93,7 @@ class BloodDonationViewModel extends ChangeNotifier {
onError!(apiResponse.errorMessage ?? 'An unexpected error occurred');
} else if (apiResponse.messageStatus == 1) {
citiesList = apiResponse.data!;
citiesList.sort((a, b) => a.description!.compareTo(b.description!));
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
@ -100,7 +123,7 @@ class BloodDonationViewModel extends ChangeNotifier {
citiesModel.descriptionN = citiesList[_selectedHospitalIndex].descriptionN;
selectedCity = citiesModel;
selectedBloodType = patientBloodGroupDetailsModel.bloodGroup!;
_selectedBloodTypeIndex = getBloodIndex(selectedBloodType);
_selectedBloodTypeIndex = getBloodIndex(selectedBloodType ?? '');
notifyListeners();
if (onSuccess != null) {
@ -113,11 +136,11 @@ class BloodDonationViewModel extends ChangeNotifier {
int getSelectedCityID() {
int cityID = 1;
citiesList.forEach((element) {
for (var element in citiesList) {
if (element.description == patientBloodGroupDetailsModel.city) {
cityID = element.iD!;
}
});
}
return cityID;
}
@ -144,4 +167,120 @@ class BloodDonationViewModel extends ChangeNotifier {
return 0;
}
}
void onTermAccepted() {
isTermsAccepted = !isTermsAccepted;
notifyListeners();
}
bool isUserAuthanticated() {
print("the app state is ${appState.isAuthenticated}");
if (!appState.isAuthenticated) {
return false;
} else {
return true;
}
}
Future<void> fetchHospitalsList() async {
// hospitalList.clear();
notifyListeners();
final result = await bloodDonationRepo.getBloodDonationProjectsList();
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
hospitalList = apiResponse.data!;
hospitalList.sort((a, b) => a.projectName!.compareTo(b.projectName!));
notifyListeners();
}
},
);
}
Future<void> getFreeBloodDonationSlots({required Map<String, dynamic> request}) async {
final result = await bloodDonationRepo.getFreeBloodDonationSlots(request: request);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
} else if (apiResponse.messageStatus == 1) {
// TODO: Handle free slots data
print(apiResponse.data['BD_FreeSlots']);
notifyListeners();
}
},
);
}
bool isLocationEnabled() {
return appState.userLong != 0.0 && appState.userLong != 0.0;
}
setSelectedHospital(BdGetProjectsHaveBdClinic hospital) {
selectedHospital = hospital;
notifyListeners();
}
Future<bool> validateSelections() async {
if (selectedCity == null) {
await dialogService.showErrorBottomSheet(
message: "Please choose city",
);
return false;
}
if (selectedBloodGroup == null) {
await dialogService.showErrorBottomSheet(
message: "Please choose Gender",
);
return false;
}
if (selectedBloodType == null) {
await dialogService.showErrorBottomSheet(
message: "Please choose Blood Group",
);
return false;
}
if (!isTermsAccepted) {
await dialogService.showErrorBottomSheet(
message: "Please accept Terms and Conditions to continue",
);
return false;
}
return true;
}
Future<void> updateBloodGroup() async {
LoaderBottomSheet.showLoader();
// body['City'] = detailsModel.city;
// body['cityCode'] = detailsModel.cityCode;
// body['Gender'] = detailsModel.gender;
// body['BloodGroup'] = detailsModel.bloodGroup;
// body['CellNumber'] = user.mobileNumber;
// body['LanguageID'] = languageID;
// body['NationalID'] = user.nationalityID;
// body['ZipCode'] = user.zipCode ?? "+966";
// body['isDentalAllowedBackend'] = false;
Map<String, dynamic> payload = {
"City": selectedCity?.description,
"cityCode": selectedCity?.iD,
"Gender": selectedGender?.value,
"isDentalAllowedBackend": false
// "Gender": selectedGender?.value,
};
await bloodDonationRepo.updateBloodGroup(request: payload);
await addUserAgreementForBloodDonation();
LoaderBottomSheet.hideLoader();
}
Future<void> addUserAgreementForBloodDonation() async {
Map<String, dynamic> payload = {"IsAgreed": true};
await bloodDonationRepo.addUserAgreementForBloodDonation(request: payload);
}
}

@ -0,0 +1,81 @@
import 'dart:convert';
class BdProjectsHaveBdClinicsModel {
List<BdGetProjectsHaveBdClinic>? bdGetProjectsHaveBdClinics;
BdProjectsHaveBdClinicsModel({
this.bdGetProjectsHaveBdClinics,
});
factory BdProjectsHaveBdClinicsModel.fromRawJson(String str) => BdProjectsHaveBdClinicsModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory BdProjectsHaveBdClinicsModel.fromJson(Map<String, dynamic> json) => BdProjectsHaveBdClinicsModel(
bdGetProjectsHaveBdClinics: json["BD_getProjectsHaveBDClinics"] == null ? [] : List<BdGetProjectsHaveBdClinic>.from(json["BD_getProjectsHaveBDClinics"]!.map((x) => BdGetProjectsHaveBdClinic.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"BD_getProjectsHaveBDClinics": bdGetProjectsHaveBdClinics == null ? [] : List<dynamic>.from(bdGetProjectsHaveBdClinics!.map((x) => x.toJson())),
};
}
class BdGetProjectsHaveBdClinic {
int? rowId;
int? id;
int? projectId;
int? numberOfRooms;
bool? isActive;
int? createdBy;
String? createdOn;
dynamic editedBy;
dynamic editedOn;
String? projectName;
dynamic projectNameN;
BdGetProjectsHaveBdClinic({
this.rowId,
this.id,
this.projectId,
this.numberOfRooms,
this.isActive,
this.createdBy,
this.createdOn,
this.editedBy,
this.editedOn,
this.projectName,
this.projectNameN,
});
factory BdGetProjectsHaveBdClinic.fromRawJson(String str) => BdGetProjectsHaveBdClinic.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory BdGetProjectsHaveBdClinic.fromJson(Map<String, dynamic> json) => BdGetProjectsHaveBdClinic(
rowId: json["RowID"],
id: json["ID"],
projectId: json["ProjectID"],
numberOfRooms: json["NumberOfRooms"],
isActive: json["IsActive"],
createdBy: json["CreatedBy"],
createdOn: json["CreatedOn"],
editedBy: json["EditedBy"],
editedOn: json["EditedON"],
projectName: json["ProjectName"],
projectNameN: json["ProjectNameN"],
);
Map<String, dynamic> toJson() => {
"RowID": rowId,
"ID": id,
"ProjectID": projectId,
"NumberOfRooms": numberOfRooms,
"IsActive": isActive,
"CreatedBy": createdBy,
"CreatedOn": createdOn,
"EditedBy": editedBy,
"EditedON": editedOn,
"ProjectName": projectName,
"ProjectNameN": projectNameN,
};
}

@ -0,0 +1,81 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/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/blood_donation/blood_donation_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_hospitals_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors;
import 'package:provider/provider.dart';
class HospitalBottomSheetBodySelection extends StatelessWidget {
final Function(BdGetProjectsHaveBdClinic userSelection) onUserHospitalSelection;
const HospitalBottomSheetBodySelection({super.key, required this.onUserHospitalSelection(BdGetProjectsHaveBdClinic userSelection)});
@override
Widget build(BuildContext context) {
final bloodDonationVm = Provider.of<BloodDonationViewModel>(context, listen: false);
AppState appState = getIt.get<AppState>();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.selectHospital.tr(context: context).toText16(weight: FontWeight.w500, color: AppColors.greyTextColor),
SizedBox(height: 16.h),
SizedBox(
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
itemBuilder: (_, index) {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [
hospitalName(bloodDonationVm.hospitalList[index]).onPress(() {
onUserHospitalSelection(bloodDonationVm.hospitalList[index]);
Navigator.of(context).pop();
})
],
),
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.blackColor, width: 40.h, height: 40.h, fit: BoxFit.contain),
),
],
).paddingSymmetrical(16.h, 16.h),
).onPress(() {
bloodDonationVm.setSelectedHospital(bloodDonationVm.hospitalList[index]);
Navigator.of(context).pop();
});
},
separatorBuilder: (_, __) => SizedBox(height: 16.h),
itemCount: bloodDonationVm.hospitalList.length),
)
],
);
}
Widget hospitalName(dynamic hospital) => Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.hmg).paddingOnly(right: 10),
Expanded(
child: Text(hospital.projectName ?? "", style: TextStyle(fontWeight: FontWeight.w600, fontSize: 16, color: AppColors.blackColor)),
)
],
);
}

@ -49,9 +49,13 @@ class BookAppointmentsViewModel extends ChangeNotifier {
bool isLiveCareSchedule = false;
bool isGetDocForHealthCal = false;
bool showSortFilterButtons = false;
int? calculationID = 0;
bool isSortByClinic = true;
// Accordion expansion state
int? expandedGroupIndex;
int initialSlotDuration = 0;
bool isNearestAppointmentSelected = false;
@ -157,13 +161,65 @@ class BookAppointmentsViewModel extends ChangeNotifier {
bool isBodyPartsLoading = false;
int duration = 0;
setIsSortByClinic(bool value) {
isSortByClinic = value;
doctorsListGrouped = isSortByClinic ? doctorsListByClinic : doctorsListByHospital;
notifyListeners();
}
// Toggle accordion expansion
void toggleGroupExpansion(int index) {
if (expandedGroupIndex == index) {
expandedGroupIndex = null;
} else {
expandedGroupIndex = index;
}
notifyListeners();
}
// Reset accordion expansion
void resetGroupExpansion() {
expandedGroupIndex = null;
notifyListeners();
}
// Sort filtered doctor list by clinic or hospital
void sortFilteredDoctorList(bool sortByClinic) {
isSortByClinic = sortByClinic;
if (sortByClinic) {
// Sort by clinic name
filteredDoctorList.sort((a, b) {
final clinicA = (a.clinicName ?? 'Unknown').toLowerCase();
final clinicB = (b.clinicName ?? 'Unknown').toLowerCase();
return clinicA.compareTo(clinicB);
});
} else {
// Sort by hospital/project name
filteredDoctorList.sort((a, b) {
final hospitalA = (a.projectName ?? 'Unknown').toLowerCase();
final hospitalB = (b.projectName ?? 'Unknown').toLowerCase();
return hospitalA.compareTo(hospitalB);
});
}
notifyListeners();
}
// Group filtered doctors list for accordion display
List<List<DoctorsListResponseModel>> getGroupedFilteredDoctorsList() {
final clinicMap = <String, List<DoctorsListResponseModel>>{};
final hospitalMap = <String, List<DoctorsListResponseModel>>{};
for (var doctor in filteredDoctorList) {
final clinicKey = (doctor.clinicName ?? 'Unknown').trim();
clinicMap.putIfAbsent(clinicKey, () => []).add(doctor);
final hospitalKey = (doctor.projectName ?? 'Unknown').trim();
hospitalMap.putIfAbsent(hospitalKey, () => []).add(doctor);
}
return isSortByClinic ? clinicMap.values.toList() : hospitalMap.values.toList();
}
// Group doctors by clinic and hospital
void _groupDoctorsList() {
final clinicMap = <String, List<DoctorsListResponseModel>>{};
@ -200,8 +256,10 @@ class BookAppointmentsViewModel extends ChangeNotifier {
void filterClinics(String? query) {
if (query!.isEmpty) {
_filteredClinicsList = List.from(clinicsList);
showSortFilterButtons = false;
} else {
_filteredClinicsList = clinicsList.where((clinic) => clinic.clinicDescription?.toLowerCase().contains(query!.toLowerCase()) ?? false).toList();
showSortFilterButtons = query.length >= 3;
}
notifyListeners();
}
@ -213,6 +271,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
isDoctorProfileLoading = true;
isLiveCareSchedule = false;
currentlySelectedHospitalFromRegionFlow = null;
expandedGroupIndex = null; // Reset accordion state
clinicsList.clear();
doctorsList.clear();
liveCareClinicsList.clear();
@ -230,9 +289,24 @@ class BookAppointmentsViewModel extends ChangeNotifier {
this.isNearestAppointmentSelected = isNearestAppointmentSelected;
if (isNearestAppointmentSelected) {
doctorsList.sort((a, b) => DateUtil.convertStringToDate(a.nearestFreeSlot!).compareTo(DateUtil.convertStringToDate(b.nearestFreeSlot!)));
for (var group in doctorsListGrouped) {
group.sort((a, b) {
var aSlot = a.nearestFreeSlot;
var bSlot = b.nearestFreeSlot;
if (aSlot == null || bSlot == null) return 0;
return DateUtil.convertStringToDate(aSlot).compareTo(DateUtil.convertStringToDate(bSlot));
});
}
} else {
doctorsList.sort((a, b) => b.decimalDoctorRate!.compareTo(a.decimalDoctorRate!));
for (var group in doctorsListGrouped) {
group.sort((a, b) {
var aSlot = a.decimalDoctorRate;
var bSlot = b.decimalDoctorRate;
if (aSlot == null || bSlot == null) return 0;
return bSlot.compareTo(aSlot);
});
}
// doctorsList.sort((a, b) => b.decimalDoctorRate!.compareTo(a.decimalDoctorRate!));
}
notifyListeners();
@ -399,7 +473,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
result.fold(
(failure) async {
onError!("No doctors found for the search criteria".needTranslation);
onError!(LocaleKeys.noDoctorFound.tr());
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
@ -427,7 +501,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
result.fold(
(failure) async {
isDoctorsListLoading = false;
if (onError != null) onError("No doctors found for the search criteria".needTranslation);
if (onError != null) onError(LocaleKeys.noDoctorFound.tr());
notifyListeners();
},
@ -459,7 +533,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
result.fold(
(failure) async {
isDoctorsListLoading = false;
if (onError != null) onError("No doctors found for the search criteria".needTranslation);
if (onError != null) onError(LocaleKeys.noDoctorFound.tr());
notifyListeners();
},
@ -495,7 +569,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
result.fold(
(failure) async {
onError?.call("No doctors found for the search criteria".needTranslation);
onError?.call(LocaleKeys.noDoctorFound.tr());
},
(apiResponse) async {
if (apiResponse.messageStatus == 2) {
@ -710,7 +784,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
showCommonBottomSheet(navigationService.navigatorKey.currentContext!,
child: Utils.getLoadingWidget(loadingText: "Cancelling your previous appointment....".needTranslation),
child: Utils.getLoadingWidget(loadingText: LocaleKeys.cancellingAppointmentPleaseWait.tr()),
callBackFunc: (str) {},
title: "",
height: ResponsiveExtension.screenHeight * 0.3,
@ -720,7 +794,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async {
navigationService.pop();
Future.delayed(Duration(milliseconds: 50)).then((value) async {});
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: "Booking your appointment...".needTranslation);
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: LocaleKeys.bookingYourAppointment.tr());
await insertSpecificAppointment(
onError: (err) {},
onSuccess: (apiResp) async {
@ -806,7 +880,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
showCommonBottomSheet(navigationService.navigatorKey.currentContext!,
child: Utils.getLoadingWidget(loadingText: "Cancelling your previous appointment....".needTranslation),
child: Utils.getLoadingWidget(loadingText: LocaleKeys.cancellingAppointmentPleaseWait.tr()),
callBackFunc: (str) {},
title: "",
height: ResponsiveExtension.screenHeight * 0.3,
@ -816,7 +890,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
await cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel).then((val) async {
navigationService.pop();
Future.delayed(Duration(milliseconds: 50)).then((value) async {});
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: "Booking your appointment...".needTranslation);
LoadingUtils.showFullScreenLoader(barrierDismissible: true, isSuccessDialog: false, loadingText: LocaleKeys.bookingYourAppointment.tr());
await insertSpecificAppointment(
onError: (err) {},
onSuccess: (apiResp) async {
@ -1130,7 +1204,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
result.fold(
(failure) async {
onError!("No doctors found for the search criteria...".needTranslation);
onError!(LocaleKeys.noDoctorFound.tr());
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
@ -1217,18 +1291,18 @@ class BookAppointmentsViewModel extends ChangeNotifier {
notifyListeners();
} else {
if (this.duration == 90) {
dialogService.showErrorBottomSheet(
message: "Duration can not exceed 90 min".needTranslation,
);
return;
}
// if (this.duration == 90) {
// dialogService.showErrorBottomSheet(
// message: "Duration can not exceed 90 min".needTranslation,
// );
// return;
// }
selectedBodyPartList.add(part);
var duration = getDuration();
if (duration > 90) {
selectedBodyPartList.remove(part);
dialogService.showErrorBottomSheet(
message: "Duration Exceeds 90 min".needTranslation,
message: LocaleKeys.durationCannotExceed90.tr(),
);
return;
}
@ -1262,7 +1336,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
result.fold(
(failure) async {
onError!("Invalid verification point scanned.".needTranslation);
onError!("Invalid verification point scanned.");
},
(apiResponse) {
// if (apiResponse.data['returnValue'] == 0) {
@ -1336,7 +1410,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
);
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data == null || apiResponse.data!.isEmpty) {
onError!("Unexpected Error Occurred".needTranslation);
onError!(LocaleKeys.unexpectedError.tr());
return;
}
notifyListeners();

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

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

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart' as GMSMapServices;
import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -32,6 +33,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/facility_sel
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/RRT/rrt_request_type_select.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/RRT/terms_and_condition.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/call_ambulance_page.dart';
@ -152,7 +154,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
print("the app state is ${appState.isAuthenticated}");
if (!appState.isAuthenticated) {
dialogService.showErrorBottomSheet(
message: "You Need To Login First To Continue".needTranslation,
message: LocaleKeys.loginToUseService.tr(),
onOkPressed: () {
navServices.pop();
getIt<AuthenticationViewModel>().onLoginPressed();
@ -196,7 +198,6 @@ class EmergencyServicesViewModel extends ChangeNotifier {
}
void filterErList(String query) {
print("the query is $query");
if (query.isEmpty) {
nearestERFilteredList = nearestERList;
} else {
@ -277,7 +278,6 @@ class EmergencyServicesViewModel extends ChangeNotifier {
flushData();
selectedFacility = FacilitySelection.ALL;
print("the app state is ${appState.isAuthenticated}");
if (appState.isAuthenticated) {
locationUtils!.getLocation(
isShowConfirmDialog: true,
@ -289,7 +289,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
});
} else {
dialogService.showErrorBottomSheet(
message: "You Need To Login First To Continue".needTranslation,
message: LocaleKeys.loginToUseService.tr(),
onOkPressed: () {
navServices.pop();
navServices.pushAndReplace(AppRoutes.loginScreen);
@ -311,7 +311,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
void updateBottomSheetState(BottomSheetType sheetType) {
if (sheetType == BottomSheetType.EXPANDED && selectedHospital == null) {
dialogService.showErrorBottomSheet(message: "Kindly Select Hospital".needTranslation);
dialogService.showErrorBottomSheet(message: LocaleKeys.selectHospital.tr());
return;
}
bottomSheetType = sheetType;
@ -481,21 +481,18 @@ class EmergencyServicesViewModel extends ChangeNotifier {
Future<void> getTransportationOption() async {
//handle the cache if the data is present then dont fetch it in the authenticated lifecycle
print("the app state is ${appState.isAuthenticated}");
if (appState.isAuthenticated == false) {
dialogService.showErrorBottomSheet(
message: "You Need To Login First To Continue".needTranslation,
message: LocaleKeys.loginToUseService.tr(),
onOkPressed: () {
navServices.pop();
print("inside the ok button");
getIt<AuthenticationViewModel>().onLoginPressed();
});
return;
}
int? id = appState.getAuthenticatedUser()?.patientId;
LoaderBottomSheet.showLoader(loadingText: "Getting Ambulance Transport Option".needTranslation);
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.gettingAmbulanceTransportOption.tr());
notifyListeners();
var response = await emergencyServicesRepo.getTransportationMethods(id: id);
@ -514,7 +511,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
Future<void> getTransportationMethods() async {
int? id = appState.getAuthenticatedUser()?.patientId;
LoaderBottomSheet.showLoader(loadingText: "Getting Ambulance Transport Option".needTranslation);
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.gettingAmbulanceTransportOption.tr());
notifyListeners();
var response = await emergencyServicesRepo.getTransportationMethods(id: id);
@ -703,7 +700,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
}
Future<void> getAppointments() async {
LoaderBottomSheet.showLoader(loadingText: "Fetching Appointment".needTranslation);
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingAppointment.tr());
var result = await appointmentRepo.getPatientAppointments(isActiveAppointment: true, isArrivedAppointments: false);
LoaderBottomSheet.hideLoader();
@ -860,10 +857,10 @@ class EmergencyServicesViewModel extends ChangeNotifier {
Future<void> cancelOrder(AmbulanceRequestOrdersModel? order, {bool shouldPop = false}) async {
dialogService.showCommonBottomSheetWithoutH(
message: "Do you want to cancel the request".needTranslation,
message: LocaleKeys.doYouWantToCancelTheRequest.tr(),
onOkPressed: () async {
navServices.pop();
LoaderBottomSheet.showLoader(loadingText: "Cancelling request".needTranslation);
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.cancellingRequest.tr());
var response = await emergencyServicesRepo.cancelOrder(order?.iD, appState.getAuthenticatedUser()?.patientId ?? 0);
LoaderBottomSheet.hideLoader();
response.fold((failure) => errorHandlerService.handleError(failure: failure), (success) {
@ -968,10 +965,10 @@ class EmergencyServicesViewModel extends ChangeNotifier {
FutureOr<void> cancelRRTOrder(int? orderID, {bool shouldPop = false}) async {
dialogService.showCommonBottomSheetWithoutH(
message: "Do you want to cancel the request".needTranslation,
message: LocaleKeys.doYouWantToCancelTheRequest.tr(),
onOkPressed: () async {
navServices.pop();
LoaderBottomSheet.showLoader(loadingText: "Cancelling request".needTranslation);
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.cancellingRequest.tr());
var response = await emergencyServicesRepo.cancelRRTOrder(orderID);
LoaderBottomSheet.hideLoader();
response.fold((failure) => errorHandlerService.handleError(failure: failure), (success) {
@ -1001,11 +998,10 @@ class EmergencyServicesViewModel extends ChangeNotifier {
}
void openRRT() {
print("the app state is ${appState.isAuthenticated}");
if (appState.isAuthenticated) {
if (agreedToTermsAndCondition == false) {
dialogService.showErrorBottomSheet(
message: "You Need To Agree To Terms And Conditions".needTranslation,
message: LocaleKeys.pleaseAcceptTermsConditions.tr(),
onOkPressed: () {
if (navServices.context == null) return;
showCommonBottomSheetWithoutHeight(
@ -1042,9 +1038,9 @@ class EmergencyServicesViewModel extends ChangeNotifier {
bool result = await navServices.push(
CustomPageRoute(
page: MapUtilityScreen(
confirmButtonString: "Submit Request".needTranslation,
titleString: "Select Location".needTranslation,
subTitleString: "Please select the location".needTranslation,
confirmButtonString: LocaleKeys.submitRequest.tr(),
titleString: LocaleKeys.selectLocation.tr(),
subTitleString: LocaleKeys.pleaseSelectTheLocation.tr(),
isGmsAvailable: appState.isGMSAvailable,
),
direction: AxisDirection.down),
@ -1059,7 +1055,7 @@ class EmergencyServicesViewModel extends ChangeNotifier {
});
} else {
dialogService.showErrorBottomSheet(
message: "You Need To Login First To Continue".needTranslation,
message: LocaleKeys.loginToUseService.tr(),
onOkPressed: () {
navServices.pop();
getIt<AuthenticationViewModel>().onLoginPressed();
@ -1072,12 +1068,11 @@ class EmergencyServicesViewModel extends ChangeNotifier {
}
FutureOr<void> getTermsAndConditions() async {
LoaderBottomSheet.showLoader(loadingText: "Fetching Terms And Conditions".needTranslation);
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingTermsAndConditions.tr());
var response = await emergencyServicesRepo.getTermsAndCondition();
LoaderBottomSheet.hideLoader();
response.fold((failure) => errorHandlerService.handleError(failure: failure), (success) {
termsAndConditions = success.data;
print("the response terms are $termsAndConditions");
notifyListeners();
navServices.push(
CustomPageRoute(page: TermsAndCondition(termsAndCondition: success.data ?? ""), direction: AxisDirection.down),

@ -0,0 +1,873 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
/// Progress types to request different ranges from the progress API.
enum ProgressType { today, week, month }
abstract class HealthTrackersRepo {
// ==================== BLOOD SUGAR (DIABETIC) ====================
/// Get blood sugar result averages (week, month, year).
Future<Either<Failure, GenericApiModel<dynamic>>> getDiabeticResultAverage();
/// Get blood sugar results (week, month, year).
Future<Either<Failure, GenericApiModel<dynamic>>> getDiabeticResults();
/// Add new blood sugar result.
Future<Either<Failure, GenericApiModel<dynamic>>> addDiabeticResult({
required String bloodSugarDateChart,
required String bloodSugarResult,
required String diabeticUnit,
required int measuredTime,
});
/// Update existing blood sugar result.
Future<Either<Failure, GenericApiModel<dynamic>>> updateDiabeticResult({
required DateTime month,
required DateTime hour,
required String bloodSugarResult,
required String diabeticUnit,
required int measuredTime,
required int lineItemNo,
});
/// Deactivate blood sugar record.
Future<Either<Failure, GenericApiModel<dynamic>>> deactivateDiabeticStatus({
required int lineItemNo,
});
/// Send blood sugar report by email.
Future<Either<Failure, GenericApiModel<dynamic>>> sendBloodSugarReportByEmail({
required String email,
});
// ==================== BLOOD PRESSURE ====================
/// Get blood pressure result averages (week, month, year).
Future<Either<Failure, GenericApiModel<dynamic>>> getBloodPressureResultAverage();
/// Get blood pressure results (week, month, year).
Future<Either<Failure, GenericApiModel<dynamic>>> getBloodPressureResults();
/// Add new blood pressure result.
Future<Either<Failure, GenericApiModel<dynamic>>> addBloodPressureResult({
required String bloodPressureDate,
required String diastolicPressure,
required String systolicePressure,
required int measuredArm,
});
/// Update existing blood pressure result.
Future<Either<Failure, GenericApiModel<dynamic>>> updateBloodPressureResult({
required String bloodPressureDate,
required String diastolicPressure,
required String systolicePressure,
required int measuredArm,
required int lineItemNo,
});
/// Deactivate blood pressure record.
Future<Either<Failure, GenericApiModel<dynamic>>> deactivateBloodPressureStatus({
required int lineItemNo,
});
/// Send blood pressure report by email.
Future<Either<Failure, GenericApiModel<dynamic>>> sendBloodPressureReportByEmail({
required String email,
});
// ==================== WEIGHT MEASUREMENT ====================
/// Get weight measurement result averages (week, month, year).
Future<Either<Failure, GenericApiModel<dynamic>>> getWeightMeasurementResultAverage();
/// Get weight measurement results (week, month, year).
Future<Either<Failure, GenericApiModel<dynamic>>> getWeightMeasurementResults();
/// Add new weight measurement result.
Future<Either<Failure, GenericApiModel<dynamic>>> addWeightMeasurementResult({
required String weightDate,
required String weightMeasured,
required int weightUnit,
});
/// Update existing weight measurement result.
Future<Either<Failure, GenericApiModel<dynamic>>> updateWeightMeasurementResult({
required int lineItemNo,
required int weightUnit,
required String weightMeasured,
required String weightDate,
});
/// Deactivate weight measurement record.
Future<Either<Failure, GenericApiModel<dynamic>>> deactivateWeightMeasurementStatus({
required int lineItemNo,
});
/// Send weight report by email.
Future<Either<Failure, GenericApiModel<dynamic>>> sendWeightReportByEmail({
required String email,
});
}
class HealthTrackersRepoImp implements HealthTrackersRepo {
final ApiClient apiClient;
final LoggerService loggerService;
HealthTrackersRepoImp({required this.loggerService, required this.apiClient});
// ==================== BLOOD SUGAR (DIABETIC) METHODS ====================
@override
Future<Either<Failure, GenericApiModel<dynamic>>> getDiabeticResultAverage() async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getDiabeticResultAverage,
body: {},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
dynamic extracted;
if (response is Map) {
// Extract average lists
extracted = {
'monthAverageList': response['List_MonthDiabtectResultAverage'] ?? [],
'weekAverageList': response['List_WeekDiabtectResultAverage'] ?? [],
'yearAverageList': response['List_YearDiabtecResultAverage'] ?? [],
};
} else {
extracted = response;
}
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: extracted,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> getDiabeticResults() async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getDiabeticResult,
body: {},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
dynamic extracted;
if (response is Map) {
// Extract patient result lists
extracted = {
'monthResultList': response['List_MonthDiabtecPatientResult'] ?? [],
'weekResultList': response['List_WeekDiabtecPatientResult'] ?? [],
'yearResultList': response['List_YearDiabtecPatientResult'] ?? [],
};
} else {
extracted = response;
}
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: extracted,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> addDiabeticResult({
required String bloodSugarDateChart,
required String bloodSugarResult,
required String diabeticUnit,
required int measuredTime,
}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
Map<String, dynamic> body = {
'BloodSugerDateChart': bloodSugarDateChart,
'BloodSugerResult': bloodSugarResult,
'DiabtecUnit': diabeticUnit,
'MeasuredTime': measuredTime + 1, // Add 1 as per old service
};
await apiClient.post(
ApiConsts.addDiabeticResult,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> updateDiabeticResult({
required DateTime month,
required DateTime hour,
required String bloodSugarResult,
required String diabeticUnit,
required int measuredTime,
required int lineItemNo,
}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
// Format: 'YYYY-MM-DD HH:MM:SS' as per old service
String formattedDate = '${month.year}-${month.month}-${month.day} ${hour.hour}:${hour.minute}:00';
Map<String, dynamic> body = {
'BloodSugerDateChart': formattedDate,
'BloodSugerResult': bloodSugarResult,
'DiabtecUnit': diabeticUnit,
'MeasuredTime': measuredTime + 1, // Add 1 as per old service
'LineItemNo': lineItemNo,
};
await apiClient.post(
ApiConsts.updateDiabeticResult,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> deactivateDiabeticStatus({
required int lineItemNo,
}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
Map<String, dynamic> body = {
'LineItemNo': lineItemNo,
};
await apiClient.post(
ApiConsts.deactivateDiabeticStatus,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> sendBloodSugarReportByEmail({
required String email,
}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
Map<String, dynamic> body = {
'To': email,
};
await apiClient.post(
ApiConsts.sendAverageBloodSugarReport,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
// ==================== BLOOD PRESSURE METHODS ====================
@override
Future<Either<Failure, GenericApiModel<dynamic>>> getBloodPressureResultAverage() async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getBloodPressureResultAverage,
body: {},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
dynamic extracted;
if (response is Map) {
// Extract all three list types
extracted = {
'monthList': response['List_MonthBloodPressureResultAverage'] ?? [],
'weekList': response['List_WeekBloodPressureResultAverage'] ?? [],
'yearList': response['List_YearBloodPressureResultAverage'] ?? [],
};
} else {
extracted = response;
}
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: extracted,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> getBloodPressureResults() async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getBloodPressureResult,
body: {},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
dynamic extracted;
if (response is Map) {
// Extract all three list types
extracted = {
'weekList': response['List_WeekBloodPressureResult'] ?? [],
'monthList': response['List_MonthBloodPressureResult'] ?? [],
'yearList': response['List_YearBloodPressureResult'] ?? [],
};
} else {
extracted = response;
}
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: extracted,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> addBloodPressureResult({
required String bloodPressureDate,
required String diastolicPressure,
required String systolicePressure,
required int measuredArm,
}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
Map<String, dynamic> body = {
'BloodPressureDate': bloodPressureDate,
'DiastolicPressure': diastolicPressure,
'SystolicePressure': systolicePressure,
'MeasuredArm': measuredArm,
};
await apiClient.post(
ApiConsts.addBloodPressureResult,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> updateBloodPressureResult({
required String bloodPressureDate,
required String diastolicPressure,
required String systolicePressure,
required int measuredArm,
required int lineItemNo,
}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
Map<String, dynamic> body = {
'BloodPressureDate': bloodPressureDate,
'DiastolicPressure': diastolicPressure,
'SystolicePressure': systolicePressure,
'MeasuredArm': measuredArm,
'LineItemNo': lineItemNo,
};
await apiClient.post(
ApiConsts.updateBloodPressureResult,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> deactivateBloodPressureStatus({
required int lineItemNo,
}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
Map<String, dynamic> body = {
'LineItemNo': lineItemNo,
};
await apiClient.post(
ApiConsts.deactivateBloodPressureStatus,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> sendBloodPressureReportByEmail({
required String email,
}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
Map<String, dynamic> body = {
'To': email,
};
await apiClient.post(
ApiConsts.sendAverageBloodPressureReport,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
// ==================== WEIGHT MEASUREMENT METHODS ====================
@override
Future<Either<Failure, GenericApiModel<dynamic>>> getWeightMeasurementResultAverage() async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getWeightMeasurementResultAverage,
body: {},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
dynamic extracted;
if (response is Map) {
// Extract average lists
extracted = {
'monthAverageList': response['List_MonthWeightMeasurementResultAverage'] ?? [],
'weekAverageList': response['List_WeekWeightMeasurementResultAverage'] ?? [],
'yearAverageList': response['List_YearWeightMeasurementResultAverage'] ?? [],
};
} else {
extracted = response;
}
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: extracted,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> getWeightMeasurementResults() async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getWeightMeasurementResult,
body: {},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
dynamic extracted;
if (response is Map) {
// Extract result lists
extracted = {
'weekResultList': response['List_WeekWeightMeasurementResult'] ?? [],
'monthResultList': response['List_MonthWeightMeasurementResult'] ?? [],
'yearResultList': response['List_YearWeightMeasurementResult'] ?? [],
};
} else {
extracted = response;
}
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: extracted,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> addWeightMeasurementResult({
required String weightDate,
required String weightMeasured,
required int weightUnit,
}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
Map<String, dynamic> body = {
'WeightDate': weightDate,
'WeightMeasured': weightMeasured,
'weightUnit': weightUnit,
};
await apiClient.post(
ApiConsts.addWeightMeasurementResult,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> updateWeightMeasurementResult({
required int lineItemNo,
required int weightUnit,
required String weightMeasured,
required String weightDate,
}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
Map<String, dynamic> body = {
'LineItemNo': lineItemNo,
'weightUnit': '$weightUnit', // Convert to string as per old service
'WeightMeasured': weightMeasured,
'WeightDate': weightDate,
};
await apiClient.post(
ApiConsts.updateWeightMeasurementResult,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> deactivateWeightMeasurementStatus({required int lineItemNo}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
Map<String, dynamic> body = {
'LineItemNo': lineItemNo,
};
await apiClient.post(
ApiConsts.deactivateWeightMeasurementStatus,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<dynamic>>> sendWeightReportByEmail({
required String email,
}) async {
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
Map<String, dynamic> body = {
'To': email,
};
await apiClient.post(
ApiConsts.sendAverageBodyWeightReport,
body: body,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: response,
);
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -0,0 +1,87 @@
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
class BloodPressureResult {
int? patientID;
int? lineItemNo;
DateTime? bloodPressureDate;
int? measuredArm;
int? systolicePressure;
int? diastolicPressure;
dynamic remark;
bool? isActive;
int? chartYear;
String? chartMonth;
dynamic yearSystolicePressureAverageResult;
dynamic monthSystolicePressureResult;
dynamic weekSystolicePressureResult;
int? yearDiastolicPressureAverageResult;
dynamic monthDiastolicPressureResult;
dynamic weekDiastolicPressureResult;
String? measuredArmDesc;
dynamic weekDesc;
BloodPressureResult(
{this.patientID,
this.lineItemNo,
this.bloodPressureDate,
this.measuredArm,
this.systolicePressure,
this.diastolicPressure,
this.remark,
this.isActive,
this.chartYear,
this.chartMonth,
this.yearSystolicePressureAverageResult,
this.monthSystolicePressureResult,
this.weekSystolicePressureResult,
this.yearDiastolicPressureAverageResult,
this.monthDiastolicPressureResult,
this.weekDiastolicPressureResult,
this.measuredArmDesc,
this.weekDesc});
BloodPressureResult.fromJson(Map<String, dynamic> json) {
patientID = json['PatientID'];
lineItemNo = json['LineItemNo'];
bloodPressureDate = DateUtil.convertStringToDate(json['BloodPressureDate']);
measuredArm = json['MeasuredArm'];
systolicePressure = json['SystolicePressure'];
diastolicPressure = json['DiastolicPressure'];
remark = json['Remark'];
isActive = json['IsActive'];
chartYear = json['ChartYear'];
chartMonth = json['ChartMonth'];
yearSystolicePressureAverageResult = json['YearSystolicePressureAverageResult'];
monthSystolicePressureResult = json['MonthSystolicePressureResult'];
weekSystolicePressureResult = json['WeekSystolicePressureResult'];
yearDiastolicPressureAverageResult = json['YearDiastolicPressureAverageResult'];
monthDiastolicPressureResult = json['MonthDiastolicPressureResult'];
weekDiastolicPressureResult = json['WeekDiastolicPressureResult'];
measuredArmDesc = json['MeasuredArmDesc'];
weekDesc = json['WeekDesc'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['PatientID'] = patientID;
data['LineItemNo'] = lineItemNo;
data['BloodPressureDate'] = bloodPressureDate;
data['MeasuredArm'] = measuredArm;
data['SystolicePressure'] = systolicePressure;
data['DiastolicPressure'] = diastolicPressure;
data['Remark'] = remark;
data['IsActive'] = isActive;
data['ChartYear'] = chartYear;
data['ChartMonth'] = chartMonth;
data['YearSystolicePressureAverageResult'] = yearSystolicePressureAverageResult;
data['MonthSystolicePressureResult'] = monthSystolicePressureResult;
data['WeekSystolicePressureResult'] = weekSystolicePressureResult;
data['YearDiastolicPressureAverageResult'] = yearDiastolicPressureAverageResult;
data['MonthDiastolicPressureResult'] = monthDiastolicPressureResult;
data['WeekDiastolicPressureResult'] = weekDiastolicPressureResult;
data['MeasuredArmDesc'] = measuredArmDesc;
data['WeekDesc'] = weekDesc;
return data;
}
}

@ -0,0 +1,58 @@
class MonthBloodPressureResultAverage {
dynamic weekfourSystolicePressureAverageResult;
dynamic weekfourDiastolicPressureAverageResult;
dynamic weekthreeSystolicePressureAverageResult;
dynamic weekthreeDiastolicPressureAverageResult;
dynamic weektwoSystolicePressureAverageResult;
dynamic weektwoDiastolicPressureAverageResult;
dynamic weekoneSystolicePressureAverageResult;
dynamic weekoneDiastolicPressureAverageResult;
String? weekDesc;
int? weekDiastolicPressureAverageResult;
int? weekSystolicePressureAverageResult;
MonthBloodPressureResultAverage({
this.weekfourSystolicePressureAverageResult,
this.weekfourDiastolicPressureAverageResult,
this.weekthreeSystolicePressureAverageResult,
this.weekthreeDiastolicPressureAverageResult,
this.weektwoSystolicePressureAverageResult,
this.weektwoDiastolicPressureAverageResult,
this.weekoneSystolicePressureAverageResult,
this.weekoneDiastolicPressureAverageResult,
this.weekDesc,
this.weekDiastolicPressureAverageResult,
this.weekSystolicePressureAverageResult,
});
MonthBloodPressureResultAverage.fromJson(Map<String, dynamic> json) {
weekfourSystolicePressureAverageResult = json['weekfourSystolicePressureAverageResult'];
weekfourDiastolicPressureAverageResult = json['weekfourDiastolicPressureAverageResult'];
weekthreeSystolicePressureAverageResult = json['weekthreeSystolicePressureAverageResult'];
weekthreeDiastolicPressureAverageResult = json['weekthreeDiastolicPressureAverageResult'];
weektwoSystolicePressureAverageResult = json['weektwoSystolicePressureAverageResult'];
weektwoDiastolicPressureAverageResult = json['weektwoDiastolicPressureAverageResult'];
weekoneSystolicePressureAverageResult = json['weekoneSystolicePressureAverageResult'];
weekoneDiastolicPressureAverageResult = json['weekoneDiastolicPressureAverageResult'];
weekDesc = json['WeekDesc'];
weekDiastolicPressureAverageResult = json['WeekDiastolicPressureAverageResult'];
weekSystolicePressureAverageResult = json['WeekSystolicePressureAverageResult'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['weekfourSystolicePressureAverageResult'] = weekfourSystolicePressureAverageResult;
data['weekfourDiastolicPressureAverageResult'] = weekfourDiastolicPressureAverageResult;
data['weekthreeSystolicePressureAverageResult'] = weekthreeSystolicePressureAverageResult;
data['weekthreeDiastolicPressureAverageResult'] = weekthreeDiastolicPressureAverageResult;
data['weektwoSystolicePressureAverageResult'] = weektwoSystolicePressureAverageResult;
data['weektwoDiastolicPressureAverageResult'] = weektwoDiastolicPressureAverageResult;
data['weekoneSystolicePressureAverageResult'] = weekoneSystolicePressureAverageResult;
data['weekoneDiastolicPressureAverageResult'] = weekoneDiastolicPressureAverageResult;
data['WeekDesc'] = weekDesc;
data['WeekDiastolicPressureAverageResult'] = weekDiastolicPressureAverageResult;
data['WeekSystolicePressureAverageResult'] = weekSystolicePressureAverageResult;
return data;
}
}

@ -0,0 +1,24 @@
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
class WeekBloodPressureResultAverage {
int? dailySystolicePressureAverageResult;
int? dailyDiastolicPressureAverageResult;
DateTime? bloodPressureDate;
WeekBloodPressureResultAverage({this.dailySystolicePressureAverageResult, this.dailyDiastolicPressureAverageResult, this.bloodPressureDate});
WeekBloodPressureResultAverage.fromJson(Map<String, dynamic> json) {
dailySystolicePressureAverageResult = json['DailySystolicePressureAverageResult'];
dailyDiastolicPressureAverageResult = json['DailyDiastolicPressureAverageResult'];
bloodPressureDate = DateUtil.convertStringToDate(json['BloodPressureDate']);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['DailySystolicePressureAverageResult'] = dailySystolicePressureAverageResult;
data['DailyDiastolicPressureAverageResult'] = dailyDiastolicPressureAverageResult;
data['BloodPressureDate'] = bloodPressureDate;
return data;
}
}

@ -0,0 +1,37 @@
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
class YearBloodPressureResultAverage {
int? monthSystolicePressureAverageResult;
int? monthDiastolicPressureAverageResult;
dynamic monthNumber;
String? monthName;
String? yearName;
DateTime? date;
YearBloodPressureResultAverage({
this.monthSystolicePressureAverageResult,
this.monthDiastolicPressureAverageResult,
this.monthNumber,
this.monthName,
this.yearName,
});
YearBloodPressureResultAverage.fromJson(Map<String, dynamic> json) {
monthSystolicePressureAverageResult = json['monthSystolicePressureAverageResult'];
monthDiastolicPressureAverageResult = json['monthDiastolicPressureAverageResult'];
monthNumber = json['monthNumber'];
monthName = json['monthName'];
yearName = json['yearName'];
date = DateUtil.getMonthDateTime(monthName!, yearName);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['monthSystolicePressureAverageResult'] = monthSystolicePressureAverageResult;
data['monthDiastolicPressureAverageResult'] = monthDiastolicPressureAverageResult;
data['monthNumber'] = monthNumber;
data['monthName'] = monthName;
data['yearName'] = yearName;
return data;
}
}

@ -0,0 +1,99 @@
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
class DiabeticPatientResult {
String? chartMonth;
var chartYear;
DateTime? dateChart;
var description;
var descriptionN;
int? diabtecAvarage;
bool? isActive;
int? lineItemNo;
var listMonth;
var listWeek;
int? measured;
String? measuredDesc;
var monthAverageResult;
int? patientID;
var remark;
var resultDesc;
dynamic resultValue;
String? unit;
var weekAverageResult;
String? weekDesc;
var yearAverageResult;
DiabeticPatientResult(
{this.chartMonth,
this.chartYear,
this.dateChart,
this.description,
this.descriptionN,
this.diabtecAvarage,
this.isActive,
this.lineItemNo,
this.listMonth,
this.listWeek,
this.measured,
this.measuredDesc,
this.monthAverageResult,
this.patientID,
this.remark,
this.resultDesc,
this.resultValue,
this.unit,
this.weekAverageResult,
this.weekDesc,
this.yearAverageResult});
DiabeticPatientResult.fromJson(Map<String, dynamic> json) {
chartMonth = json['ChartMonth'];
chartYear = json['ChartYear'];
dateChart = DateUtil.convertStringToDate(json['DateChart']);
description = json['Description'];
descriptionN = json['DescriptionN'];
diabtecAvarage = json['DiabtecAvarage'];
isActive = json['IsActive'];
lineItemNo = json['LineItemNo'];
listMonth = json['List_Month'];
listWeek = json['List_Week'];
measured = json['Measured'];
measuredDesc = json['MeasuredDesc'];
monthAverageResult = json['MonthAverageResult'];
patientID = json['PatientID'];
remark = json['Remark'];
resultDesc = json['ResultDesc'];
resultValue = json['ResultValue'];
unit = json['Unit'];
weekAverageResult = json['WeekAverageResult'];
weekDesc = json['WeekDesc'];
yearAverageResult = json['YearAverageResult'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['ChartMonth'] = chartMonth;
data['ChartYear'] = chartYear;
data['DateChart'] = DateUtil.convertDateToString(dateChart!);
data['Description'] = description;
data['DescriptionN'] = descriptionN;
data['DiabtecAvarage'] = diabtecAvarage;
data['IsActive'] = isActive;
data['LineItemNo'] = lineItemNo;
data['List_Month'] = listMonth;
data['List_Week'] = listWeek;
data['Measured'] = measured;
data['MeasuredDesc'] = measuredDesc;
data['MonthAverageResult'] = monthAverageResult;
data['PatientID'] = patientID;
data['Remark'] = remark;
data['ResultDesc'] = resultDesc;
data['ResultValue'] = resultValue;
data['Unit'] = unit;
data['WeekAverageResult'] = weekAverageResult;
data['WeekDesc'] = weekDesc;
data['YearAverageResult'] = yearAverageResult;
return data;
}
}

@ -0,0 +1,37 @@
class MonthDiabeticResultAverage {
var weekfourAverageResult;
var weekthreeAverageResult;
var weektwoAverageResult;
var weekoneAverageResult;
dynamic weekAverageResult;
String? weekDesc;
MonthDiabeticResultAverage(
{this.weekfourAverageResult,
this.weekthreeAverageResult,
this.weektwoAverageResult,
this.weekoneAverageResult,
this.weekAverageResult,
this.weekDesc});
MonthDiabeticResultAverage.fromJson(Map<String, dynamic> json) {
weekfourAverageResult = json['weekfourAverageResult'];
weekthreeAverageResult = json['weekthreeAverageResult'];
weektwoAverageResult = json['weektwoAverageResult'];
weekoneAverageResult = json['weekoneAverageResult'];
weekAverageResult = json['WeekAverageResult'];
weekDesc = json['WeekDesc'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['weekfourAverageResult'] = weekfourAverageResult;
data['weekthreeAverageResult'] = weekthreeAverageResult;
data['weektwoAverageResult'] = weektwoAverageResult;
data['weekoneAverageResult'] = weekoneAverageResult;
data['WeekAverageResult'] = weekAverageResult;
data['WeekDesc'] = weekDesc;
return data;
}
}

@ -0,0 +1,21 @@
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
class WeekDiabeticResultAverage {
dynamic dailyAverageResult;
DateTime? dateChart;
WeekDiabeticResultAverage({this.dailyAverageResult, this.dateChart});
WeekDiabeticResultAverage.fromJson(Map<String, dynamic> json) {
dailyAverageResult = json['DailyAverageResult'];
dateChart = DateUtil.convertStringToDate(json['DateChart']);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['DailyAverageResult'] = dailyAverageResult;
data['DateChart'] = DateUtil.convertDateToString(dateChart!);
return data;
}
}

@ -0,0 +1,35 @@
import 'dart:developer';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
class YearDiabeticResultAverage {
dynamic monthAverageResult;
var monthNumber;
String? monthName;
String? yearName;
DateTime? date;
YearDiabeticResultAverage({this.monthAverageResult, this.monthNumber, this.monthName, this.yearName});
YearDiabeticResultAverage.fromJson(Map<String, dynamic> json) {
try {
monthAverageResult = json['monthAverageResult'];
monthNumber = json['monthNumber'];
monthName = json['monthName'];
yearName = json['yearName'];
date = DateUtil.getMonthDateTime(monthName!, yearName);
} catch (e) {
log(e.toString());
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['monthAverageResult'] = monthAverageResult;
data['monthNumber'] = monthNumber;
data['monthName'] = monthName;
data['yearName'] = yearName;
return data;
}
}

@ -0,0 +1,37 @@
class MonthWeightMeasurementResultAverage {
dynamic weekfourAverageResult;
dynamic weekthreeAverageResult;
dynamic weektwoAverageResult;
dynamic weekoneAverageResult;
dynamic weekAverageResult;
String? weekDesc;
MonthWeightMeasurementResultAverage(
{this.weekfourAverageResult,
this.weekthreeAverageResult,
this.weektwoAverageResult,
this.weekoneAverageResult,
this.weekAverageResult,
this.weekDesc});
MonthWeightMeasurementResultAverage.fromJson(Map<String, dynamic> json) {
weekfourAverageResult = json['weekfourAverageResult'];
weekthreeAverageResult = json['weekthreeAverageResult'];
weektwoAverageResult = json['weektwoAverageResult'];
weekoneAverageResult = json['weekoneAverageResult'];
weekAverageResult = json['WeekAverageResult'];
weekDesc = json['WeekDesc'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['weekfourAverageResult'] = weekfourAverageResult;
data['weekthreeAverageResult'] = weekthreeAverageResult;
data['weektwoAverageResult'] = weektwoAverageResult;
data['weekoneAverageResult'] = weekoneAverageResult;
data['WeekAverageResult'] = weekAverageResult;
data['WeekDesc'] = weekDesc;
return data;
}
}

@ -0,0 +1,21 @@
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
class WeekWeightMeasurementResultAverage {
dynamic dailyAverageResult;
DateTime? weightDate;
WeekWeightMeasurementResultAverage({this.dailyAverageResult, this.weightDate});
WeekWeightMeasurementResultAverage.fromJson(Map<String, dynamic> json) {
dailyAverageResult = json['DailyAverageResult'];
weightDate = DateUtil.convertStringToDate(json['WeightDate']);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['DailyAverageResult'] = dailyAverageResult;
data['WeightDate'] = weightDate;
return data;
}
}

@ -0,0 +1,77 @@
import 'dart:developer';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
class WeightMeasurementResult {
int? patientID;
int? lineItemNo;
int? weightMeasured;
DateTime? weightDate;
dynamic remark;
bool? isActive;
int? measured;
dynamic unit;
int? chartYear;
dynamic chartMonth;
double? yearAverageResult;
dynamic monthAverageResult;
dynamic weekAverageResult;
dynamic weekDesc;
WeightMeasurementResult(
{this.patientID,
this.lineItemNo,
this.weightMeasured,
this.weightDate,
this.remark,
this.isActive,
this.measured,
this.unit,
this.chartYear,
this.chartMonth,
this.yearAverageResult,
this.monthAverageResult,
this.weekAverageResult,
this.weekDesc});
WeightMeasurementResult.fromJson(Map<String, dynamic> json) {
try {
patientID = json['PatientID'];
lineItemNo = json['LineItemNo'];
weightMeasured = json['WeightMeasured'];
weightDate = DateUtil.convertStringToDate(json['WeightDate']);
remark = json['Remark'];
isActive = json['IsActive'];
measured = json['Measured'];
unit = json['Unit'];
chartYear = json['ChartYear'];
chartMonth = json['ChartMonth'];
// Convert to double safely since API may return int
yearAverageResult = json['YearAverageResult'] != null ? (json['YearAverageResult'] as num).toDouble() : null;
monthAverageResult = json['MonthAverageResult'];
weekAverageResult = json['WeekAverageResult'];
weekDesc = json['WeekDesc'];
} catch (e) {
log(e.toString());
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['PatientID'] = patientID;
data['LineItemNo'] = lineItemNo;
data['WeightMeasured'] = weightMeasured;
data['WeightDate'] = weightDate;
data['Remark'] = remark;
data['IsActive'] = isActive;
data['Measured'] = measured;
data['Unit'] = unit;
data['ChartYear'] = chartYear;
data['ChartMonth'] = chartMonth;
data['YearAverageResult'] = yearAverageResult;
data['MonthAverageResult'] = monthAverageResult;
data['WeekAverageResult'] = weekAverageResult;
data['WeekDesc'] = weekDesc;
return data;
}
}

@ -0,0 +1,29 @@
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
class YearWeightMeasurementResultAverage {
dynamic monthAverageResult;
int? monthNumber;
String? monthName;
String? yearName;
DateTime? date;
YearWeightMeasurementResultAverage({this.monthAverageResult, this.monthNumber, this.monthName, this.yearName});
YearWeightMeasurementResultAverage.fromJson(Map<String, dynamic> json) {
monthAverageResult = json['monthAverageResult'];
monthNumber = json['monthNumber'];
monthName = json['monthName'];
yearName = json['yearName'];
date = DateUtil.getMonthDateTime(monthName!, yearName);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['monthAverageResult'] = monthAverageResult;
data['monthNumber'] = monthNumber;
data['monthName'] = monthName;
data['yearName'] = yearName;
return data;
}
}

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

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

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

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

@ -293,14 +293,13 @@ class MedicalFileRepoImp implements MedicalFileRepo {
Failure? failure;
await apiClient.post(
ApiConsts.getAllSharedRecordsByStatus,
body: {if (status != null) "Status": status, "PatientID": patientID},
body: {if (status != null) "Status": status, "PatientID": patientID.toString()},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['GetAllSharedRecordsByStatusList'];
final list = response['GetAllSharedRecordsByStatusList'] ?? [];
final familyLists = list.map((item) => FamilyFileResponseModelLists.fromJson(item as Map<String, dynamic>)).toList().cast<FamilyFileResponseModelLists>();
@ -336,7 +335,7 @@ class MedicalFileRepoImp implements MedicalFileRepo {
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['GetAllPendingRecordsList'];
final list = response['GetAllPendingRecordsList'] ?? [];
final familyLists = list.map((item) => FamilyFileResponseModelLists.fromJson(item as Map<String, dynamic>)).toList().cast<FamilyFileResponseModelLists>();
apiResponse = GenericApiModel<List<FamilyFileResponseModelLists>>(

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

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

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

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

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

@ -84,7 +84,7 @@ class AppointmentType {
static String getNextActionText(nextAction) {
switch (nextAction) {
case 0:
return "No Action".needTranslation;
return LocaleKeys.upcomingNoAction.tr();
case 10:
return LocaleKeys.confirm.tr();
case 15:
@ -96,7 +96,7 @@ class AppointmentType {
case 90:
return LocaleKeys.checkinOption.tr();
default:
return "No Action".needTranslation;
return LocaleKeys.upcomingNoAction.tr();
}
}

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

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

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

@ -245,8 +245,8 @@ class PrescriptionsViewModel extends ChangeNotifier {
CustomPageRoute(
page: MapUtilityScreen(
confirmButtonString: LocaleKeys.next.tr(),
titleString: "Select Location".needTranslation,
subTitleString: "Please select the location for prescription delivery".needTranslation,
titleString: LocaleKeys.selectLocation.tr(),
subTitleString: LocaleKeys.selectLocationPrescriptionDelivery.tr(),
isGmsAvailable: getIt.get<AppState>().isGMSAvailable,
),
direction: AxisDirection.down),

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

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

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

@ -1,7 +1,9 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/radiology/radiology_result_page.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -97,7 +99,7 @@ class RadiologyViewModel extends ChangeNotifier {
);
} else {
if (onError != null) {
onError("No Radiology Orders Found".needTranslation);
onError(LocaleKeys.noRadiologyOrders.tr());
}
}
}

@ -0,0 +1,188 @@
class SymptomsUserDetailsResponseModel {
final TokenDetails? tokenDetails;
final UserDetails? userDetails;
final String? sessionId;
SymptomsUserDetailsResponseModel({
this.tokenDetails,
this.userDetails,
this.sessionId,
});
factory SymptomsUserDetailsResponseModel.fromJson(Map<String, dynamic> json) {
return SymptomsUserDetailsResponseModel(
tokenDetails: json['tokenDetails'] != null ? TokenDetails.fromJson(json['tokenDetails']) : null,
userDetails: json['userDetails'] != null ? UserDetails.fromJson(json['userDetails']) : null,
sessionId: json['sessionId'],
);
}
Map<String, dynamic> toJson() {
return {
'tokenDetails': tokenDetails?.toJson(),
'userDetails': userDetails?.toJson(),
'sessionId': sessionId,
};
}
}
class TokenDetails {
final String? id;
final String? authToken;
final int? expiresIn;
TokenDetails({
this.id,
this.authToken,
this.expiresIn,
});
factory TokenDetails.fromJson(Map<String, dynamic> json) {
return TokenDetails(
id: json['id'],
authToken: json['auth_token'],
expiresIn: json['expires_in'],
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'auth_token': authToken,
'expires_in': expiresIn,
};
}
}
class UserDetails {
final String? fileNo;
final String? nationalId;
final String? email;
final String? dateOfBirth;
final String? dateOfBirthHijri;
final int? age;
final UserName? name;
final int? maritalStatus;
final String? maritalStatusCode;
final String? nationality;
final String? nationalityIsoCode;
final String? occupation;
final int? idType;
final int? gender;
final String? jwtToken;
final String? countryDialCode;
final String? phoneNo;
UserDetails({
this.fileNo,
this.nationalId,
this.email,
this.dateOfBirth,
this.dateOfBirthHijri,
this.age,
this.name,
this.maritalStatus,
this.maritalStatusCode,
this.nationality,
this.nationalityIsoCode,
this.occupation,
this.idType,
this.gender,
this.jwtToken,
this.countryDialCode,
this.phoneNo,
});
factory UserDetails.fromJson(Map<String, dynamic> json) {
return UserDetails(
fileNo: json['FileNo'],
nationalId: json['national_id'],
email: json['email'],
dateOfBirth: json['date_of_birth'],
dateOfBirthHijri: json['date_of_birth_hijri'],
age: json['age'],
name: json['name'] != null ? UserName.fromJson(json['name']) : null,
maritalStatus: json['marital_status'],
maritalStatusCode: json['marital_status_code'],
nationality: json['nationality'],
nationalityIsoCode: json['nationality_iso_code'],
occupation: json['occupation'],
idType: json['id_type'],
gender: json['gender'],
jwtToken: json['jwt_token'],
countryDialCode: json['country_dial_code'],
phoneNo: json['phone_no'],
);
}
Map<String, dynamic> toJson() {
return {
'FileNo': fileNo,
'national_id': nationalId,
'email': email,
'date_of_birth': dateOfBirth,
'date_of_birth_hijri': dateOfBirthHijri,
'age': age,
'name': name?.toJson(),
'marital_status': maritalStatus,
'marital_status_code': maritalStatusCode,
'nationality': nationality,
'nationality_iso_code': nationalityIsoCode,
'occupation': occupation,
'id_type': idType,
'gender': gender,
'jwt_token': jwtToken,
'country_dial_code': countryDialCode,
'phone_no': phoneNo,
};
}
// Helper method to get full name
String getFullName(bool isArabic) {
if (name == null) return '';
if (isArabic) {
return '${name!.firstNameAr ?? ''} ${name!.middleNameAr ?? ''} ${name!.lastNameAr ?? ''}'.trim();
}
return '${name!.firstName ?? ''} ${name!.middleName ?? ''} ${name!.lastName ?? ''}'.trim();
}
}
class UserName {
final String? firstName;
final String? middleName;
final String? lastName;
final String? firstNameAr;
final String? middleNameAr;
final String? lastNameAr;
UserName({
this.firstName,
this.middleName,
this.lastName,
this.firstNameAr,
this.middleNameAr,
this.lastNameAr,
});
factory UserName.fromJson(Map<String, dynamic> json) {
return UserName(
firstName: json['first_name'],
middleName: json['middle_name'],
lastName: json['last_name'],
firstNameAr: json['first_name_ar'],
middleNameAr: json['middle_name_ar'],
lastNameAr: json['last_name_ar'],
);
}
Map<String, dynamic> toJson() {
return {
'first_name': firstName,
'middle_name': middleName,
'last_name': lastName,
'first_name_ar': firstNameAr,
'middle_name_ar': middleNameAr,
'last_name_ar': lastNameAr,
};
}
}

@ -0,0 +1,209 @@
class TriageDataDetails {
final TriageQuestion? question;
final List<TriageCondition>? conditions;
final bool? hasEmergencyEvidence;
final bool? shouldStop;
final String? interviewToken;
final String? message;
final List<String>? errorList;
final int? id;
final String? language;
final String? generalId;
final String? createDate;
final String? lastEditDate;
final String? createdBy;
final String? lastEditBy;
final bool? active;
final int? sortOrder;
final int? userType;
final String? userId;
TriageDataDetails({
this.question,
this.conditions,
this.hasEmergencyEvidence,
this.shouldStop,
this.interviewToken,
this.message,
this.errorList,
this.id,
this.language,
this.generalId,
this.createDate,
this.lastEditDate,
this.createdBy,
this.lastEditBy,
this.active,
this.sortOrder,
this.userType,
this.userId,
});
factory TriageDataDetails.fromJson(Map<String, dynamic> json) {
return TriageDataDetails(
question: json['question'] != null ? TriageQuestion.fromJson(json['question']) : null,
conditions: json['conditions'] != null ? (json['conditions'] as List).map((item) => TriageCondition.fromJson(item)).toList() : null,
hasEmergencyEvidence: json['has_emergency_evidence'],
shouldStop: json['should_stop'],
interviewToken: json['interview_token'],
message: json['Message'],
errorList: json['ErrorList'] != null ? List<String>.from(json['ErrorList']) : null,
id: json['Id'],
language: json['language'],
generalId: json['generalId'],
createDate: json['CreateDate'],
lastEditDate: json['LastEditDate'],
createdBy: json['CreatedBy'],
lastEditBy: json['LastEditBy'],
active: json['Active'],
sortOrder: json['SortOrder'],
userType: json['userType'],
userId: json['userId'],
);
}
Map<String, dynamic> toJson() {
return {
'question': question?.toJson(),
'conditions': conditions?.map((item) => item.toJson()).toList(),
'has_emergency_evidence': hasEmergencyEvidence,
'should_stop': shouldStop,
'interview_token': interviewToken,
'Message': message,
'ErrorList': errorList,
'Id': id,
'language': language,
'generalId': generalId,
'CreateDate': createDate,
'LastEditDate': lastEditDate,
'CreatedBy': createdBy,
'LastEditBy': lastEditBy,
'Active': active,
'SortOrder': sortOrder,
'userType': userType,
'userId': userId,
};
}
}
class TriageQuestion {
final int? type;
final String? text;
final List<TriageQuestionItem>? items;
TriageQuestion({
this.type,
this.text,
this.items,
});
factory TriageQuestion.fromJson(Map<String, dynamic> json) {
return TriageQuestion(
type: json['type'],
text: json['text'],
items: json['items'] != null ? (json['items'] as List).map((item) => TriageQuestionItem.fromJson(item)).toList() : null,
);
}
Map<String, dynamic> toJson() {
return {
'type': type,
'text': text,
'items': items?.map((item) => item.toJson()).toList(),
};
}
}
class TriageQuestionItem {
final String? id;
final String? name;
final List<TriageChoice>? choices;
TriageQuestionItem({
this.id,
this.name,
this.choices,
});
factory TriageQuestionItem.fromJson(Map<String, dynamic> json) {
return TriageQuestionItem(
id: json['id'],
name: json['name'],
choices: json['choices'] != null ? (json['choices'] as List).map((item) => TriageChoice.fromJson(item)).toList() : null,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'choices': choices?.map((item) => item.toJson()).toList(),
};
}
}
class TriageChoice {
final String? id;
final String? label;
TriageChoice({
this.id,
this.label,
});
factory TriageChoice.fromJson(Map<String, dynamic> json) {
return TriageChoice(
id: json['id'],
label: json['label'],
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'label': label,
};
}
}
class TriageCondition {
final String? id;
final String? name;
final String? commonName;
final double? probability;
final dynamic conditionDetails;
TriageCondition({
this.id,
this.name,
this.commonName,
this.probability,
this.conditionDetails,
});
factory TriageCondition.fromJson(Map<String, dynamic> json) {
return TriageCondition(
id: json['id'],
name: json['name'],
commonName: json['common_name'],
probability: json['probability']?.toDouble(),
conditionDetails: json['condition_details'],
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'common_name': commonName,
'probability': probability,
'condition_details': conditionDetails,
};
}
/// Get probability as percentage
String getProbabilityPercentage() {
if (probability == null) return '0%';
return '${(probability! * 100).toStringAsFixed(1)}%';
}
}

@ -1,5 +1,4 @@
import 'dart:convert';
import 'dart:developer';
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
@ -8,25 +7,56 @@ import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/body_symptom_response_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/risk_and_suggestions_response_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/symptoms_user_details_response_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/triage_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class SymptomsCheckerRepo {
Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>> getBodySymptomsByName({
Future<Either<Failure, GenericApiModel<SymptomsUserDetailsResponseModel>>>
getUserDetails({
required String userName,
required String password,
});
Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>>
getBodySymptomsByName({
required List<String> organNames,
required String userSessionToken,
required int gender,
});
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>>
getRiskFactors({
required int age,
required String sex,
required List<String> evidenceIds,
required String language,
required String userSessionToken,
required int gender,
required String sessionId,
});
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> getRiskFactors({
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>>
getSuggestions({
required int age,
required String sex,
required List<String> evidenceIds,
required String language,
required String userSessionToken,
required String sessionId,
required int gender,
});
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> getSuggestions({
Future<Either<Failure, GenericApiModel<TriageDataDetails>>>
getDiagnosisForTriage({
required int age,
required String sex,
required List<String> evidenceIds,
List<Map<String, String>>? triageEvidence,
required String language,
required String userSessionToken,
required int gender,
required String sessionId,
});
}
@ -34,14 +64,79 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
final ApiClient apiClient;
final LoggerService loggerService;
SymptomsCheckerRepoImp({required this.apiClient, required this.loggerService});
SymptomsCheckerRepoImp(
{required this.apiClient, required this.loggerService});
@override
Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>> getBodySymptomsByName({required List<String> organNames}) async {
log("GetBodySymptomsByName Request URL: ${ApiConsts.getBodySymptomsByName}");
log("GetBodySymptomsByName Request Body: ${jsonEncode(organNames)}");
Future<Either<Failure, GenericApiModel<SymptomsUserDetailsResponseModel>>>
getUserDetails({
required String userName,
required String password,
}) async {
Map<String, String> body = {"userName": userName, "password": password};
try {
GenericApiModel<SymptomsUserDetailsResponseModel>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.symptomsUserLogin,
body: body,
isExternal: true,
isAllowAny: true,
isBodyPlainText: false,
onFailure: (error, statusCode, {messageStatus, failureType}) {
loggerService.logError("getUserDetails API Failed: $error");
failure = failureType ?? ServerFailure(error);
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// Parse response if it's a string
final Map<String, dynamic> responseData =
response is String ? jsonDecode(response) : response;
Map<String, String> headers = {'Content-Type': 'application/json', 'Accept': 'text/plain'};
SymptomsUserDetailsResponseModel symptomsUserDetailsResponseModel =
SymptomsUserDetailsResponseModel.fromJson(responseData);
apiResponse = GenericApiModel<SymptomsUserDetailsResponseModel>(
messageStatus: messageStatus ?? 1,
statusCode: statusCode,
errorMessage: errorMessage,
data: symptomsUserDetailsResponseModel,
);
} catch (e, stackTrace) {
loggerService.logError("Error parsing getUserDetails response: $e");
loggerService.logError("StackTrace: $stackTrace");
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e, stackTrace) {
loggerService.logError("Exception in getUserDetails: $e");
loggerService.logError("StackTrace: $stackTrace");
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>>
getBodySymptomsByName({
required List<String> organNames,
required String userSessionToken,
required int gender,
}) async {
Map<String, String> headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer $userSessionToken',
};
Map<String, dynamic> body = {
'bodyPartName': organNames,
'gender': gender,
};
try {
GenericApiModel<BodySymptomResponseModel>? apiResponse;
@ -50,22 +145,17 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
await apiClient.post(
ApiConsts.getBodySymptomsByName,
apiHeaders: headers,
body: jsonEncode(organNames),
body: body,
isExternal: true,
isAllowAny: true,
isBodyPlainText: true,
isBodyPlainText: false,
onFailure: (error, statusCode, {messageStatus, failureType}) {
loggerService.logError("GetBodySymptomsByName API Failed: $error");
log("GetBodySymptomsByName Failed: $error, Status: $statusCode");
failure = failureType ?? ServerFailure(error);
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
log("GetBodySymptomsByName Response Status: $statusCode");
loggerService.logInfo("GetBodySymptomsByName API Success: $response");
log("GetBodySymptomsByName Response: $response");
BodySymptomResponseModel bodySymptomResponse = BodySymptomResponseModel.fromJson(response);
BodySymptomResponseModel bodySymptomResponse =
BodySymptomResponseModel.fromJson(response);
apiResponse = GenericApiModel<BodySymptomResponseModel>(
messageStatus: messageStatus ?? 1,
@ -74,9 +164,9 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
data: bodySymptomResponse,
);
} catch (e, stackTrace) {
loggerService.logError("Error parsing GetBodySymptomsByName response: $e");
loggerService
.logError("Error parsing GetBodySymptomsByName response: $e");
loggerService.logError("StackTrace: $stackTrace");
log("Parse Error: $e");
failure = DataParsingFailure(e.toString());
}
},
@ -88,17 +178,20 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
} catch (e, stackTrace) {
loggerService.logError("Exception in getBodySymptomsByName: $e");
loggerService.logError("StackTrace: $stackTrace");
log("Exception: $e");
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> getRiskFactors({
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>>
getRiskFactors({
required int age,
required String sex,
required List<String> evidenceIds,
required String language,
required String userSessionToken,
required int gender,
required String sessionId,
}) async {
final Map<String, dynamic> body = {
"age": {
@ -107,6 +200,12 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
"sex": sex,
"evidence": evidenceIds.map((id) => {"id": id}).toList(),
"language": language,
"generalId": sessionId,
};
Map<String, String> headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer $userSessionToken',
};
try {
@ -115,21 +214,22 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
await apiClient.post(
ApiConsts.getRiskFactors,
apiHeaders: headers,
body: body,
isExternal: true,
isAllowAny: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
log("GetRiskFactors Failed: $error, Status: $statusCode");
loggerService.logError("GetRiskFactors API Failed: $error");
failure = failureType ?? ServerFailure(error);
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
log("GetRiskFactors Response: $response");
// Parse response if it's a string
final Map<String, dynamic> responseData = response is String ? jsonDecode(response) : response;
final Map<String, dynamic> responseData =
response is String ? jsonDecode(response) : response;
RiskAndSuggestionsResponseModel riskFactorsResponse = RiskAndSuggestionsResponseModel.fromJson(responseData);
RiskAndSuggestionsResponseModel riskFactorsResponse =
RiskAndSuggestionsResponseModel.fromJson(responseData);
apiResponse = GenericApiModel<RiskAndSuggestionsResponseModel>(
messageStatus: messageStatus ?? 1,
@ -140,7 +240,6 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
} catch (e, stackTrace) {
loggerService.logError("Error parsing GetRiskFactors response: $e");
loggerService.logError("StackTrace: $stackTrace");
log("Parse Error: $e");
failure = DataParsingFailure(e.toString());
}
},
@ -152,17 +251,111 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
} catch (e, stackTrace) {
loggerService.logError("Exception in getRiskFactors: $e");
loggerService.logError("StackTrace: $stackTrace");
log("Exception: $e");
return Left(UnknownFailure(e.toString()));
}
}
Future<Either<Failure, GenericApiModel<TriageDataDetails>>>
getDiagnosisForTriage({
required int age,
required String sex,
required List<String> evidenceIds,
List<Map<String, String>>?
triageEvidence, // Additional triage-specific evidence
required String language,
required String userSessionToken,
required int gender,
required String sessionId,
}) async {
// Build evidence list: combine initial symptoms with triage evidence
List<Map<String, dynamic>> evidenceList = [];
// Add initial evidence as simple IDs
for (var id in evidenceIds) {
evidenceList.add({"id": id});
}
// Add triage evidence with proper format (id, choice_id, source)
if (triageEvidence != null && triageEvidence.isNotEmpty) {
evidenceList.addAll(triageEvidence);
}
final Map<String, dynamic> body = {
"age": {
"value": age,
},
"sex": sex,
"evidence": evidenceList,
"language": language,
"suggest_method": "diagnosis",
"generalId": sessionId,
};
Map<String, String> headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer $userSessionToken',
};
try {
GenericApiModel<TriageDataDetails>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.diagnosis,
apiHeaders: headers,
body: body,
isExternal: true,
isAllowAny: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
loggerService.logError("getDiagnosisForTriage API Failed: $error");
failure = failureType ?? ServerFailure(error);
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// Parse response if it's a string
final Map<String, dynamic> responseData =
response is String ? jsonDecode(response) : response;
final updatedResponseData = responseData['dataDetails'];
TriageDataDetails riskFactorsResponse =
TriageDataDetails.fromJson(updatedResponseData);
apiResponse = GenericApiModel<TriageDataDetails>(
messageStatus: messageStatus ?? 1,
statusCode: statusCode,
errorMessage: errorMessage,
data: riskFactorsResponse,
);
} catch (e, stackTrace) {
loggerService
.logError("Error parsing getDiagnosisForTriage response: $e");
loggerService.logError("StackTrace: $stackTrace");
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e, stackTrace) {
loggerService.logError("Exception in getDiagnosisForTriage: $e");
loggerService.logError("StackTrace: $stackTrace");
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> getSuggestions({
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>>
getSuggestions({
required int age,
required String sex,
required List<String> evidenceIds,
required String language,
required String userSessionToken,
required String sessionId,
required int gender,
}) async {
final Map<String, dynamic> body = {
"age": {
@ -171,6 +364,12 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
"sex": sex,
"evidence": evidenceIds.map((id) => {"id": id}).toList(),
"language": language,
"generalId": sessionId,
};
Map<String, String> headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer $userSessionToken',
};
try {
@ -179,21 +378,22 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
await apiClient.post(
ApiConsts.getSuggestions,
apiHeaders: headers,
body: body,
isExternal: true,
isAllowAny: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
log("getSuggestions Failed: $error, Status: $statusCode");
loggerService.logError("GetSuggestions API Failed: $error");
failure = failureType ?? ServerFailure(error);
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
log("getSuggestions Response: $response");
// Parse response if it's a string
final Map<String, dynamic> responseData = response is String ? jsonDecode(response) : response;
final Map<String, dynamic> responseData =
response is String ? jsonDecode(response) : response;
RiskAndSuggestionsResponseModel riskFactorsResponse = RiskAndSuggestionsResponseModel.fromJson(responseData);
RiskAndSuggestionsResponseModel riskFactorsResponse =
RiskAndSuggestionsResponseModel.fromJson(responseData);
apiResponse = GenericApiModel<RiskAndSuggestionsResponseModel>(
messageStatus: messageStatus ?? 1,
@ -202,9 +402,8 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
data: riskFactorsResponse,
);
} catch (e, stackTrace) {
loggerService.logError("Error parsing getSuggestions response: $e");
loggerService.logError("Error parsing GetSuggestions response: $e");
loggerService.logError("StackTrace: $stackTrace");
log("Parse Error: $e");
failure = DataParsingFailure(e.toString());
}
},
@ -216,7 +415,6 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
} catch (e, stackTrace) {
loggerService.logError("Exception in getSuggestions: $e");
loggerService.logError("StackTrace: $stackTrace");
log("Exception: $e");
return Left(UnknownFailure(e.toString()));
}
}

@ -7,6 +7,8 @@ import 'package:hmg_patient_app_new/features/symptoms_checker/data/organ_mapping
import 'package:hmg_patient_app_new/features/symptoms_checker/models/organ_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/body_symptom_response_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/risk_and_suggestions_response_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/symptoms_user_details_response_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/triage_response_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
@ -35,11 +37,23 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
bool isBodySymptomsLoading = false;
bool isRiskFactorsLoading = false;
bool isSuggestionsLoading = false;
bool isTriageDiagnosisLoading = false;
// API data storage - using API models directly
SymptomsUserDetailsResponseModel? symptomsUserDetailsResponseModel;
BodySymptomResponseModel? bodySymptomResponse;
RiskAndSuggestionsResponseModel? riskFactorsResponse;
RiskAndSuggestionsResponseModel? suggestionsResponse;
TriageDataDetails? triageDataDetails;
// Triage state
int?
_selectedTriageChoiceIndex; // Deprecated - keeping for backward compatibility
final Map<String, int> _selectedTriageChoicesByItemId =
{}; // Map of itemId -> choiceIndex for multi-item questions
final List<Map<String, String>> _triageEvidenceList =
[]; // Store triage evidence with proper format
int _triageQuestionCount = 0; // Track number of triage questions answered
// Selected risk factors tracking
final Set<String> _selectedRiskFactorIds = {};
@ -52,7 +66,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
// User Info Flow State
int _userInfoCurrentPage = 0;
bool _isSinglePageEditMode = false; // Track if editing single page or full flow
bool _isSinglePageEditMode =
false; // Track if editing single page or full flow
String? _selectedGender;
DateTime? _dateOfBirth;
int? _selectedAge;
@ -92,8 +107,54 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
String? get tooltipOrganId => _tooltipOrganId;
String get currentSessionAuthToken =>
symptomsUserDetailsResponseModel?.tokenDetails?.authToken ?? "";
String get currentSessionId =>
symptomsUserDetailsResponseModel?.sessionId ?? "";
// Triage-related getters
bool get shouldStopTriage => triageDataDetails?.shouldStop ?? false;
bool get hasEmergencyEvidence =>
triageDataDetails?.hasEmergencyEvidence ?? false;
String? get currentInterviewToken => triageDataDetails?.interviewToken;
TriageQuestion? get currentTriageQuestion => triageDataDetails?.question;
List<TriageCondition>? get currentConditions => triageDataDetails?.conditions;
int? get selectedTriageChoiceIndex => _selectedTriageChoiceIndex;
/// Get the number of triage questions answered
int get triageQuestionCount => _triageQuestionCount;
/// Get choice index for a specific item
int? getTriageChoiceForItem(String itemId) {
return _selectedTriageChoicesByItemId[itemId];
}
/// Check if all items in current question have been answered
bool get areAllTriageItemsAnswered {
if (currentTriageQuestion?.items == null ||
currentTriageQuestion!.items!.isEmpty) {
return false;
}
// Check if we have an answer for each item
for (var item in currentTriageQuestion!.items!) {
if (item.id != null &&
!_selectedTriageChoicesByItemId.containsKey(item.id)) {
return false;
}
}
return true;
}
/// Get organs for current view
List<OrganModel> get currentOrgans => OrganData.getOrgansForView(_currentView);
List<OrganModel> get currentOrgans =>
OrganData.getOrgansForView(_currentView);
/// Get all selected organs from both views
List<OrganModel> get selectedOrgans {
@ -101,7 +162,9 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
...OrganData.frontViewOrgans,
...OrganData.backViewOrgans,
];
return allOrgans.where((organ) => _selectedOrganIds.contains(organ.id)).toList();
return allOrgans
.where((organ) => _selectedOrganIds.contains(organ.id))
.toList();
}
/// Check if any organs are selected
@ -118,11 +181,13 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}
int get totalSelectedSymptomsCount {
return _selectedSymptomsByOrgan.values.fold(0, (sum, symptomIds) => sum + symptomIds.length);
return _selectedSymptomsByOrgan.values
.fold(0, (sum, symptomIds) => sum + symptomIds.length);
}
bool get hasSelectedSymptoms {
return _selectedSymptomsByOrgan.values.any((symptomIds) => symptomIds.isNotEmpty);
return _selectedSymptomsByOrgan.values
.any((symptomIds) => symptomIds.isNotEmpty);
}
/// Get risk factors list
@ -148,7 +213,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}
void toggleView() {
_currentView = _currentView == BodyView.front ? BodyView.back : BodyView.front;
_currentView =
_currentView == BodyView.front ? BodyView.back : BodyView.front;
notifyListeners();
}
@ -251,7 +317,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
return;
}
List<String> organNames = selectedOrgans.map((organ) => organ.name).toList();
List<String> organNames =
selectedOrgans.map((organ) => organ.name).toList();
await getBodySymptomsByName(
organNames: organNames,
@ -301,7 +368,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}
}
if (matchingOrganId != null && _selectedSymptomsByOrgan.containsKey(matchingOrganId)) {
if (matchingOrganId != null &&
_selectedSymptomsByOrgan.containsKey(matchingOrganId)) {
final selectedIds = _selectedSymptomsByOrgan[matchingOrganId]!;
if (organResult.bodySymptoms != null) {
@ -352,7 +420,10 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Get all selected risk factors
List<RiskAndSuggestionsItemModel> getAllSelectedRiskFactors() {
return riskFactorsList.where((factor) => factor.id != null && _selectedRiskFactorIds.contains(factor.id)).toList();
return riskFactorsList
.where((factor) =>
factor.id != null && _selectedRiskFactorIds.contains(factor.id))
.toList();
}
/// Clear all risk factor selections
@ -385,12 +456,14 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}
// Extract symptom IDs
List<String> evidenceIds = selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList();
List<String> evidenceIds =
selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList();
await getRiskFactors(
age: _selectedAge!,
sex: _selectedGender!.toLowerCase(),
evidenceIds: evidenceIds,
sessionId: currentSessionId,
language: appState.isArabic() ? 'ar' : 'en',
onSuccess: (response) {
if (onSuccess != null) {
@ -409,6 +482,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
Future<void> getRiskFactors({
required int age,
required String sex,
required String sessionId,
required List<String> evidenceIds,
required String language,
Function(RiskAndSuggestionsResponseModel)? onSuccess,
@ -422,6 +496,9 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
sex: sex,
evidenceIds: evidenceIds,
language: language,
sessionId: sessionId,
userSessionToken: currentSessionAuthToken,
gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2,
);
result.fold(
@ -438,8 +515,10 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
if (apiResponse.messageStatus == 1 && apiResponse.data != null) {
riskFactorsResponse = apiResponse.data;
if (riskFactorsResponse != null && riskFactorsResponse!.dataDetails != null) {
RiskAndSuggestionsItemModel riskFactorItem = RiskAndSuggestionsItemModel(
if (riskFactorsResponse != null &&
riskFactorsResponse!.dataDetails != null) {
RiskAndSuggestionsItemModel riskFactorItem =
RiskAndSuggestionsItemModel(
id: "not_applicable",
commonName: "Not Applicable",
name: "Not Applicable",
@ -493,7 +572,10 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Get all selected risk factors
List<RiskAndSuggestionsItemModel> getAllSelectedSuggestions() {
return suggestionsList.where((factor) => factor.id != null && _selectedSuggestionsIds.contains(factor.id)).toList();
return suggestionsList
.where((factor) =>
factor.id != null && _selectedSuggestionsIds.contains(factor.id))
.toList();
}
/// Clear all risk factor selections
@ -502,6 +584,30 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
notifyListeners();
}
/// Get all evidence IDs (symptoms + risk factors + suggestions) for triage/diagnosis
List<String> getAllEvidenceIds() {
List<String> evidenceIds = [];
// Add selected symptoms
final selectedSymptoms = getAllSelectedSymptoms();
evidenceIds
.addAll(selectedSymptoms.where((s) => s.id != null).map((s) => s.id!));
// Add selected risk factors (excluding "not_applicable")
final selectedRiskFactors = getAllSelectedRiskFactors();
evidenceIds.addAll(selectedRiskFactors
.where((rf) => rf.id != null && rf.id != "not_applicable")
.map((rf) => rf.id!));
// Add selected suggestions (excluding "not_applicable")
final selectedSuggestions = getAllSelectedSuggestions();
evidenceIds.addAll(selectedSuggestions
.where((s) => s.id != null && s.id != "not_applicable")
.map((s) => s.id!));
return evidenceIds;
}
/// Fetch risk factors based on selected symptoms
Future<void> fetchSuggestions({
Function()? onSuccess,
@ -526,13 +632,17 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}
// Extract symptom IDs
List<String> evidenceIds = selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList();
List<String> evidenceIds =
selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList();
// Get all selected symptoms
final selectedRisks = getAllSelectedRiskFactors();
if (selectedRisks.isNotEmpty) {
List<String> evidenceRisksIds = selectedRisks.where((s) => s.id != null && s.id != "not_applicable").map((s) => s.id!).toList();
List<String> evidenceRisksIds = selectedRisks
.where((s) => s.id != null && s.id != "not_applicable")
.map((s) => s.id!)
.toList();
evidenceIds.addAll(evidenceRisksIds);
}
@ -571,6 +681,9 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
sex: sex,
evidenceIds: evidenceIds,
language: language,
sessionId: currentSessionId,
userSessionToken: currentSessionAuthToken,
gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2,
);
result.fold(
@ -587,8 +700,10 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
if (apiResponse.messageStatus == 1 && apiResponse.data != null) {
suggestionsResponse = apiResponse.data;
if (suggestionsResponse != null && suggestionsResponse!.dataDetails != null) {
RiskAndSuggestionsItemModel riskFactorItem = RiskAndSuggestionsItemModel(
if (suggestionsResponse != null &&
suggestionsResponse!.dataDetails != null) {
RiskAndSuggestionsItemModel riskFactorItem =
RiskAndSuggestionsItemModel(
id: "not_applicable",
commonName: "Not Applicable",
name: "Not Applicable",
@ -612,15 +727,155 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
);
}
/// Call Diagnosis API for Triage - This is called iteratively until shouldStop is true
Future<void> getDiagnosisForTriage({
required int age,
required String sex,
required List<String> evidenceIds,
List<Map<String, String>>? triageEvidence,
required String language,
Function(TriageDataDetails)? onSuccess,
Function(String)? onError,
}) async {
isTriageDiagnosisLoading = true;
notifyListeners();
final result = await symptomsCheckerRepo.getDiagnosisForTriage(
age: age,
sex: sex,
evidenceIds: evidenceIds,
triageEvidence: triageEvidence,
language: language,
sessionId: currentSessionId,
userSessionToken: currentSessionAuthToken,
gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2,
);
result.fold(
(failure) async {
isTriageDiagnosisLoading = false;
notifyListeners();
await errorHandlerService.handleError(failure: failure);
if (onError != null) {
onError(failure.toString());
}
},
(apiResponse) {
isTriageDiagnosisLoading = false;
if (apiResponse.messageStatus == 1 && apiResponse.data != null) {
triageDataDetails = apiResponse.data;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse.data!);
}
} else {
notifyListeners();
if (onError != null) {
onError(apiResponse.errorMessage ?? 'Failed to fetch diagnosis');
}
}
},
);
}
/// Convenience method to start or continue the triage process
/// This automatically uses all selected evidence (symptoms + risk factors + suggestions)
Future<void> startOrContinueTriage({
Function()? onSuccess,
Function(String)? onError,
}) async {
// Validate user info
if (_selectedAge == null || _selectedGender == null) {
if (onError != null) {
onError('User information is incomplete');
}
return;
}
// Get all evidence IDs
final evidenceIds = getAllEvidenceIds();
if (evidenceIds.isEmpty) {
if (onError != null) {
onError('No evidence selected');
}
return;
}
await getDiagnosisForTriage(
age: _selectedAge!,
sex: _selectedGender!.toLowerCase(),
evidenceIds: evidenceIds,
language: appState.isArabic() ? 'ar' : 'en',
onSuccess: (response) {
if (onSuccess != null) {
onSuccess();
}
},
onError: (error) {
if (onError != null) {
onError(error);
}
},
);
}
/// Select a triage choice option (for backward compatibility with single-item questions)
void selectTriageChoice(int choiceIndex) {
_selectedTriageChoiceIndex = choiceIndex;
notifyListeners();
}
/// Select a choice for a specific item (for multi-item questions)
void selectTriageChoiceForItem(String itemId, int choiceIndex) {
_selectedTriageChoicesByItemId[itemId] = choiceIndex;
notifyListeners();
}
/// Reset triage choice selection and increment question count
void resetTriageChoice() {
_selectedTriageChoiceIndex = null;
_selectedTriageChoicesByItemId.clear();
_triageQuestionCount++; // Increment question count
notifyListeners();
}
/// Add triage evidence in the proper format
void addTriageEvidence(String itemId, String choiceId) {
_triageEvidenceList.add({
"id": itemId,
"choice_id": choiceId,
"source": "triage",
});
notifyListeners();
}
/// Get all triage evidence
List<Map<String, String>> getTriageEvidence() {
return List.from(_triageEvidenceList);
}
/// Clear triage evidence
void clearTriageEvidence() {
_triageEvidenceList.clear();
notifyListeners();
}
void reset() {
_currentView = BodyView.front;
_selectedOrganIds.clear();
_selectedSymptomsByOrgan.clear();
_selectedRiskFactorIds.clear();
_selectedSuggestionsIds.clear();
_triageEvidenceList.clear();
_selectedTriageChoicesByItemId.clear();
_triageQuestionCount = 0; // Reset question count
bodySymptomResponse = null;
riskFactorsResponse = null;
suggestionsResponse = null;
triageDataDetails = null;
isTriageDiagnosisLoading = false;
_selectedTriageChoiceIndex = null;
_isBottomSheetExpanded = false;
_tooltipTimer?.cancel();
_tooltipOrganId = null;
@ -686,7 +941,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
// Calculate age from date of birth
final now = DateTime.now();
int age = now.year - dateOfBirth.year;
if (now.month < dateOfBirth.month || (now.month == dateOfBirth.month && now.day < dateOfBirth.day)) {
if (now.month < dateOfBirth.month ||
(now.month == dateOfBirth.month && now.day < dateOfBirth.day)) {
age--;
}
_selectedAge = age;
@ -725,6 +981,44 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
};
}
Future<void> getSymptomsUserDetails({
required String userName,
required String password,
Function()? onSuccess,
Function(String)? onError,
}) async {
isBodySymptomsLoading = true;
notifyListeners();
final result = await symptomsCheckerRepo.getUserDetails(
userName: userName, password: password);
result.fold(
(failure) async {
isBodySymptomsLoading = false;
notifyListeners();
await errorHandlerService.handleError(failure: failure);
if (onError != null) {
onError(failure.toString());
}
},
(apiResponse) {
isBodySymptomsLoading = false;
if (apiResponse.messageStatus == 1 && apiResponse.data != null) {
symptomsUserDetailsResponseModel = apiResponse.data;
notifyListeners();
if (onSuccess != null) {
onSuccess();
}
} else {
notifyListeners();
if (onError != null) {
onError(apiResponse.errorMessage ?? 'Failed to fetch symptoms');
}
}
},
);
}
Future<void> getBodySymptomsByName({
required List<String> organNames,
Function(BodySymptomResponseModel)? onSuccess,
@ -735,6 +1029,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
final result = await symptomsCheckerRepo.getBodySymptomsByName(
organNames: organNames,
userSessionToken: currentSessionAuthToken,
gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2,
);
result.fold(

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

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

@ -1,5 +1,6 @@
import 'dart:developer';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -14,16 +15,22 @@ import 'package:hmg_patient_app_new/features/water_monitor/models/update_user_de
import 'package:hmg_patient_app_new/features/water_monitor/models/user_progress_models.dart';
import 'package:hmg_patient_app_new/features/water_monitor/models/water_cup_model.dart';
import 'package:hmg_patient_app_new/features/water_monitor/water_monitor_repo.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/services/notification_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class WaterMonitorViewModel extends ChangeNotifier {
WaterMonitorRepo waterMonitorRepo;
ErrorHandlerService errorHandlerService;
WaterMonitorViewModel({required this.waterMonitorRepo});
WaterMonitorViewModel({
required this.waterMonitorRepo,
required this.errorHandlerService,
});
// Controllers
final TextEditingController nameController = TextEditingController();
@ -190,9 +197,9 @@ class WaterMonitorViewModel extends ChangeNotifier {
identificationNo: identification,
);
result.fold((failure) {
log('Error fetching user progress: ${failure.message}');
}, (apiModel) {
result.fold(
(failure) => errorHandlerService.handleError(failure: failure),
(apiModel) {
log("User Progress Data ($_selectedDuration): ${apiModel.data.toString()}");
// Parse the response based on progress type
@ -300,10 +307,13 @@ class WaterMonitorViewModel extends ChangeNotifier {
identificationNo: identification,
);
result.fold((failure) {
_userDetailData = null;
if (onError != null) onError(failure.message);
}, (apiModel) {
result.fold(
(failure) {
errorHandlerService.handleError(failure: failure);
_userDetailData = null;
if (onError != null) onError(failure.message);
},
(apiModel) {
_userDetailData = apiModel.data;
// Populate form fields from the fetched data
@ -322,7 +332,7 @@ class WaterMonitorViewModel extends ChangeNotifier {
if (_userDetailData == null) {
try {
_navigationService.pushAndReplace(AppRoutes.waterMonitorSettingsScreen);
_navigationService.pushAndReplace(AppRoutes.waterMonitorSettingsPage);
} catch (navErr) {
log('Navigation to water monitor settings failed: $navErr');
}
@ -590,36 +600,36 @@ class WaterMonitorViewModel extends ChangeNotifier {
String? validateAge() {
if (ageController.text.trim().isEmpty) {
return 'Age is required'.needTranslation;
return LocaleKeys.ageIsRequired.tr();
}
final age = int.tryParse(ageController.text.trim());
if (age == null) {
return 'Invalid age'.needTranslation;
return LocaleKeys.invalidAge.tr();
}
if (age < 11 || age > 120) {
return 'Age must be between 11 and 120'.needTranslation;
return LocaleKeys.ageMustBeBetween11And120.tr();
}
return null;
}
String? validateHeight() {
if (heightController.text.trim().isEmpty) {
return 'Height is required'.needTranslation;
return LocaleKeys.heightIsRequired.tr();
}
final height = double.tryParse(heightController.text.trim());
if (height == null || height <= 0) {
return 'Invalid height'.needTranslation;
return LocaleKeys.invalidHeight.tr();
}
return null;
}
String? validateWeight() {
if (weightController.text.trim().isEmpty) {
return 'Weight is required'.needTranslation;
return LocaleKeys.weightIsRequired.tr();
}
final weight = double.tryParse(weightController.text.trim());
if (weight == null || weight <= 0) {
return 'Invalid weight'.needTranslation;
return LocaleKeys.invalidWeight.tr();
}
return null;
}
@ -686,6 +696,7 @@ class WaterMonitorViewModel extends ChangeNotifier {
return result.fold(
(failure) {
errorHandlerService.handleError(failure: failure);
_validationError = failure.message;
_isLoading = false;
notifyListeners();
@ -1060,14 +1071,14 @@ class WaterMonitorViewModel extends ChangeNotifier {
return result.fold(
(failure) {
errorHandlerService.handleError(failure: failure);
log('Error inserting user activity: ${failure.message}');
_isLoading = false;
notifyListeners();
return false;
},
(apiModel) {
(apiModel) async {
log("Insert user activity success: ${apiModel.data.toString()}");
// Update consumed amount and goal from the response
if (apiModel.data != null && apiModel.data is List && (apiModel.data as List).isNotEmpty) {
final progressData = (apiModel.data as List).first;
if (progressData is Map) {
@ -1090,7 +1101,7 @@ class WaterMonitorViewModel extends ChangeNotifier {
}
// Refresh progress data to ensure consistency
fetchUserProgressForMonitoring();
await fetchUserProgressForMonitoring();
}
_isLoading = false;
@ -1135,12 +1146,13 @@ class WaterMonitorViewModel extends ChangeNotifier {
return result.fold(
(failure) {
errorHandlerService.handleError(failure: failure);
log('Error undoing user activity: ${failure.message}');
_isLoading = false;
notifyListeners();
return false;
},
(apiModel) {
(apiModel) async {
log("Undo user activity success: ${apiModel.data.toString()}");
// Update consumed amount and goal from the response
@ -1164,8 +1176,8 @@ class WaterMonitorViewModel extends ChangeNotifier {
}
}
}
await fetchUserProgressForMonitoring();
}
fetchUserProgressForMonitoring();
_isLoading = false;
notifyListeners();
return true;
@ -1202,8 +1214,8 @@ class WaterMonitorViewModel extends ChangeNotifier {
// Schedule water reminders
await notificationService.scheduleWaterReminders(
reminderTimes: reminderTimes,
title: 'Time to Drink Water! 💧'.needTranslation,
body: 'Stay hydrated! Drink ${selectedCupCapacityMl}ml of water.'.needTranslation,
title: LocaleKeys.timeToDrinkWater.tr(),
body: LocaleKeys.stayHydratedDrinkWater.tr(namedArgs: {'amount': selectedCupCapacityMl.toString()}),
);
// Save reminder enabled state to cache
@ -1324,8 +1336,8 @@ class WaterMonitorViewModel extends ChangeNotifier {
await notificationService.scheduleNotification(
id: 9999,
// Use a unique ID for test notifications
title: 'Time to Drink Water! 💧'.needTranslation,
body: 'Stay hydrated! Drink ${selectedCupCapacityMl}ml of water.'.needTranslation,
title: LocaleKeys.timeToDrinkWater.tr(),
body: LocaleKeys.stayHydratedDrinkWater.tr(namedArgs: {'amount': selectedCupCapacityMl.toString()}),
scheduledDate: scheduledTime,
payload: 'test_notification',
);

@ -693,11 +693,7 @@ abstract class LocaleKeys {
static const bikini = 'bikini';
static const totalMinutes = 'totalMinutes';
static const feedback = 'feedback';
static const send = 'send';
static const status = 'status';
static const likeToHear = 'likeToHear';
static const subject = 'subject';
static const message = 'message';
static const emptySubject = 'emptySubject';
static const emptyMessage = 'emptyMessage';
static const selectAttachment = 'selectAttachment';
@ -876,5 +872,621 @@ abstract class LocaleKeys {
static const laserClinic = 'laserClinic';
static const continueString = 'continueString';
static const covid_info = 'covid_info';
static const appointmentDetails = 'appointmentDetails';
static const checkingDoctorAvailability = 'checkingDoctorAvailability';
static const cancellingAppointmentPleaseWait = 'cancellingAppointmentPleaseWait';
static const appointmentCancelledSuccessfully = 'appointmentCancelledSuccessfully';
static const notConfirmed = 'notConfirmed';
static const appointmentStatus = 'appointmentStatus';
static const doctorWillCallYou = 'doctorWillCallYou';
static const getDirections = 'getDirections';
static const notifyMeBeforeAppointment = 'notifyMeBeforeAppointment';
static const fetchingLabResults = 'fetchingLabResults';
static const fetchingRadiologyResults = 'fetchingRadiologyResults';
static const fetchingAppointmentPrescriptions = 'fetchingAppointmentPrescriptions';
static const noPrescriptionsForAppointment = 'noPrescriptionsForAppointment';
static const amountBeforeTax = 'amountBeforeTax';
static const rebookAppointment = 'rebookAppointment';
static const fetchingDoctorSchedulePleaseWait = 'fetchingDoctorSchedulePleaseWait';
static const pickADate = 'pickADate';
static const confirmingAppointmentPleaseWait = 'confirmingAppointmentPleaseWait';
static const appointmentConfirmedSuccessfully = 'appointmentConfirmedSuccessfully';
static const appointmentPayment = 'appointmentPayment';
static const checkingPaymentStatusPleaseWait = 'checkingPaymentStatusPleaseWait';
static const paymentFailedPleaseTryAgain = 'paymentFailedPleaseTryAgain';
static const appointmentCheckIn = 'appointmentCheckIn';
static const insuranceExpiredOrInactive = 'insuranceExpiredOrInactive';
static const totalAmountToPay = 'totalAmountToPay';
static const vat15 = 'vat15';
static const liveCare = 'liveCare';
static const recentVisits = 'recentVisits';
static const searchByClinic = 'searchByClinic';
static const tapToSelectClinic = 'tapToSelectClinic';
static const searchByDoctor = 'searchByDoctor';
static const tapToSelect = 'tapToSelect';
static const searchByRegion = 'searchByRegion';
static const centralRegion = 'centralRegion';
static const immediateConsultation = 'immediateConsultation';
static const scheduledConsultation = 'scheduledConsultation';
static const pharmaLiveCare = 'pharmaLiveCare';
static const notSureHelpMeChooseClinic = 'notSureHelpMeChooseClinic';
static const mentionYourSymptomsAndFindDoctors = 'mentionYourSymptomsAndFindDoctors';
static const immediateService = 'immediateService';
static const noNeedToWaitGetMedicalConsultation = 'noNeedToWaitGetMedicalConsultation';
static const noVisitRequired = 'noVisitRequired';
static const doctorWillContact = 'doctorWillContact';
static const specialisedDoctorWillContactYou = 'specialisedDoctorWillContactYou';
static const freeMedicineDelivery = 'freeMedicineDelivery';
static const offersFreeMedicineDelivery = 'offersFreeMedicineDelivery';
static const dentalChiefComplaints = 'dentalChiefComplaints';
static const viewAvailableAppointments = 'viewAvailableAppointments';
static const doctorProfile = 'doctorProfile';
static const waitingAppointment = 'waitingAppointment';
static const hospitalInformation = 'hospitalInformation';
static const fetchingAppointmentShare = 'fetchingAppointmentShare';
static const bookingYourAppointment = 'bookingYourAppointment';
static const selectLiveCareClinic = 'selectLiveCareClinic';
static const checkingForExistingDentalPlan = 'checkingForExistingDentalPlan';
static const dentalTreatmentPlan = 'dentalTreatmentPlan';
static const youHaveExistingTreatmentPlan = 'youHaveExistingTreatmentPlan';
static const mins = 'mins';
static const totalTimeRequired = 'totalTimeRequired';
static const wouldYouLikeToContinue = 'wouldYouLikeToContinue';
static const chooseDoctor = 'chooseDoctor';
static const viewNearestAppos = 'viewNearestAppos';
static const noDoctorFound = 'noDoctorFound';
static const yesPleasImInAHurry = 'yesPleasImInAHurry';
static const fetchingFeesPleaseWait = 'fetchingFeesPleaseWait';
static const noThanksPhysicalVisit = 'noThanksPhysicalVisit';
static const offline = 'offline';
static const videoCall = 'videoCall';
static const liveVideoCallWithHMGDoctors = 'liveVideoCallWithHMGDoctors';
static const audioCall = 'audioCall';
static const phoneCall = 'phoneCall';
static const livePhoneCallWithHMGDoctors = 'livePhoneCallWithHMGDoctors';
static const reviewLiveCareRequest = 'reviewLiveCareRequest';
static const selectedLiveCareType = 'selectedLiveCareType';
static const selectLiveCareCallType = 'selectLiveCareCallType';
static const confirmingLiveCareRequest = 'confirmingLiveCareRequest';
static const unknownErrorOccurred = 'unknownErrorOccurred';
static const liveCarePermissionsMessage = 'liveCarePermissionsMessage';
static const liveCarePayment = 'liveCarePayment';
static const mada = 'mada';
static const visaOrMastercard = 'visaOrMastercard';
static const tamara = 'tamara';
static const fetchingApplePayDetails = 'fetchingApplePayDetails';
static const liveCarePendingRequest = 'liveCarePendingRequest';
static const callLiveCareSupport = 'callLiveCareSupport';
static const whatIsWaitingAppointment = 'whatIsWaitingAppointment';
static const waitingAppointmentsFeature = 'waitingAppointmentsFeature';
static const appointmentWithDoctorConfirmed = 'appointmentWithDoctorConfirmed';
static const paymentWithinTenMinutes = 'paymentWithinTenMinutes';
static const liveLocation = 'liveLocation';
static const verifyYourLocationAtHospital = 'verifyYourLocationAtHospital';
static const error = 'error';
static const ensureWithinHospitalLocation = 'ensureWithinHospitalLocation';
static const nfcNearFieldCommunication = 'nfcNearFieldCommunication';
static const scanPhoneViaNFC = 'scanPhoneViaNFC';
static const qrCode = 'qrCode';
static const scanQRCodeToCheckIn = 'scanQRCodeToCheckIn';
static const processingCheckIn = 'processingCheckIn';
static const bookingWaitingAppointment = 'bookingWaitingAppointment';
static const enterValidIDorIqama = 'enterValidIDorIqama';
static const selectAppointment = 'selectAppointment';
static const rebookSameDoctor = 'rebookSameDoctor';
static const queueing = 'queueing';
static const inQueue = 'inQueue';
static const yourTurn = 'yourTurn';
static const halaFirstName = 'halaFirstName';
static const thankYouForPatience = 'thankYouForPatience';
static const servingNow = 'servingNow';
static const callForVitalSigns = 'callForVitalSigns';
static const callForDoctor = 'callForDoctor';
static const thingsToAskDoctor = 'thingsToAskDoctor';
static const improveOverallHealth = 'improveOverallHealth';
static const routineScreenings = 'routineScreenings';
static const whatIsThisMedicationFor = 'whatIsThisMedicationFor';
static const sideEffectsToKnow = 'sideEffectsToKnow';
static const whenFollowUp = 'whenFollowUp';
static const goToHomepage = 'goToHomepage';
static const appointmentsList = 'appointmentsList';
static const allAppt = 'allAppt';
static const upcoming = 'upcoming';
static const completed = 'completed';
static const noAppointmentsYet = 'noAppointmentsYet';
static const viewProfile = 'viewProfile';
static const choosePreferredHospitalForService = 'choosePreferredHospitalForService';
static const noHospitalsFound = 'noHospitalsFound';
static const cancelOrderConfirmation = 'cancelOrderConfirmation';
static const orderCancelledSuccessfully = 'orderCancelledSuccessfully';
static const requestID = 'requestID';
static const noCMCOrdersYet = 'noCMCOrdersYet';
static const cmcOrders = 'cmcOrders';
static const summary = 'summary';
static const selectedService = 'selectedService';
static const requestSubmittedSuccessfully = 'requestSubmittedSuccessfully';
static const hereIsYourRequestNumber = 'hereIsYourRequestNumber';
static const pleaseSelectHospitalToContinue = 'pleaseSelectHospitalToContinue';
static const confirmSubmitRequest = 'confirmSubmitRequest';
static const pendingOrderWait = 'pendingOrderWait';
static const noServicesAvailable = 'noServicesAvailable';
static const selectAService = 'selectAService';
static const comprehensiveCheckup = 'comprehensiveCheckup';
static const viewNearestHMGLocations = 'viewNearestHMGLocations';
static const provideFeedbackOnServices = 'provideFeedbackOnServices';
static const liveChatWithHMG = 'liveChatWithHMG';
static const send = 'send';
static const status = 'status';
static const sendingFeedback = 'sendingFeedback';
static const selectFeedbackType = 'selectFeedbackType';
static const loadingAppointmentsList = 'loadingAppointmentsList';
static const noAppointmentsForFeedback = 'noAppointmentsForFeedback';
static const selectedAppointment = 'selectedAppointment';
static const subject = 'subject';
static const enterSubjectHere = 'enterSubjectHere';
static const message = 'message';
static const enterMessageHere = 'enterMessageHere';
static const filesSelected = 'filesSelected';
static const otherDetails = 'otherDetails';
static const medicalReport = 'medicalReport';
static const medicalReportNumber = 'medicalReportNumber';
static const patientIsInsured = 'patientIsInsured';
static const insuranceDocument = 'insuranceDocument';
static const selectBranch = 'selectBranch';
static const patientInformation = 'patientInformation';
static const patientLocation = 'patientLocation';
static const identificationNumber = 'identificationNumber';
static const enterIdentificationNumber = 'enterIdentificationNumber';
static const patientName = 'patientName';
static const referralRequesterInformation = 'referralRequesterInformation';
static const enterReferralRequesterName = 'enterReferralRequesterName';
static const requesterName = 'requesterName';
static const relationship = 'relationship';
static const selectRelation = 'selectRelation';
static const otherName = 'otherName';
static const otherNameHint = 'otherNameHint';
static const requesterNameRequired = 'requesterNameRequired';
static const selectRelationshipRequired = 'selectRelationshipRequired';
static const otherRelationshipNameRequired = 'otherRelationshipNameRequired';
static const identificationNumberRequired = 'identificationNumberRequired';
static const patientNameRequired = 'patientNameRequired';
static const enterPatientPhoneRequired = 'enterPatientPhoneRequired';
static const selectPatientCityRequired = 'selectPatientCityRequired';
static const medicalReportRequired = 'medicalReportRequired';
static const selectBranchRequired = 'selectBranchRequired';
static const insuranceDocumentRequired = 'insuranceDocumentRequired';
static const searchResult = 'searchResult';
static const referralNo = 'referralNo';
static const eReferral = 'eReferral';
static const referralCreatedSuccessfully = 'referralCreatedSuccessfully';
static const hereIsYourReferralNumber = 'hereIsYourReferralNumber';
static const searchEReferral = 'searchEReferral';
static const enterRequiredInfoToSearch = 'enterRequiredInfoToSearch';
static const selectPickupDirection = 'selectPickupDirection';
static const selectDirection = 'selectDirection';
static const toHospital = 'toHospital';
static const fromHospital = 'fromHospital';
static const selectWay = 'selectWay';
static const oneWay = 'oneWay';
static const twoWay = 'twoWay';
static const selectPickupDetails = 'selectPickupDetails';
static const pleaseSelectDetailsOfPickup = 'pleaseSelectDetailsOfPickup';
static const selectDetails = 'selectDetails';
static const work = 'work';
static const pick = 'pick';
static const insideTheHome = 'insideTheHome';
static const haveAnyAppointment = 'haveAnyAppointment';
static const amountPaidAtHospital = 'amountPaidAtHospital';
static const submitRequest = 'submitRequest';
static const enterPickupLocationManually = 'enterPickupLocationManually';
static const enterPickupLocation = 'enterPickupLocation';
static const trackingDetails = 'trackingDetails';
static const cancelRequest = 'cancelRequest';
static const shareLocationWhatsapp = 'shareLocationWhatsapp';
static const pleaseWaitForCall = 'pleaseWaitForCall';
static const toHospitalLower = 'toHospitalLower';
static const contact = 'contact';
static const failed = 'failed';
static const confirmationCall = 'confirmationCall';
static const pickupFromHome = 'pickupFromHome';
static const onTheWayToHospital = 'onTheWayToHospital';
static const arrivedAtHospital = 'arrivedAtHospital';
static const orderCancel = 'orderCancel';
static const emergencyCheckIn = 'emergencyCheckIn';
static const erOnlineCheckInDescription = 'erOnlineCheckInDescription';
static const erOnlineCheckInSuccess = 'erOnlineCheckInSuccess';
static const erOnlineCheckInError = 'erOnlineCheckInError';
static const fetchingHospitalsList = 'fetchingHospitalsList';
static const fetchingPaymentInformation = 'fetchingPaymentInformation';
static const erVisitDetails = 'erVisitDetails';
static const erClinic = 'erClinic';
static const vatWithAmount = 'vatWithAmount';
static const erAppointmentBookedSuccess = 'erAppointmentBookedSuccess';
static const underProcessing = 'underProcessing';
static const canceledByPatient = 'canceledByPatient';
static const rapidResponseTeam = 'rapidResponseTeam';
static const allFacilities = 'allFacilities';
static const selectLocation = 'selectLocation';
static const pleaseSelectTheLocation = 'pleaseSelectTheLocation';
static const viewLocationGoogleMaps = 'viewLocationGoogleMaps';
static const callAmbulance = 'callAmbulance';
static const requestAmbulanceInEmergency = 'requestAmbulanceInEmergency';
static const confirmation = 'confirmation';
static const areYouSureYouWantToCallAmbulance = 'areYouSureYouWantToCallAmbulance';
static const getDetailsOfNearestBranch = 'getDetailsOfNearestBranch';
static const areYouSureYouWantToCallRRT = 'areYouSureYouWantToCallRRT';
static const priorERCheckInToSkipLine = 'priorERCheckInToSkipLine';
static const areYouSureYouWantToMakeERCheckIn = 'areYouSureYouWantToMakeERCheckIn';
static const checkingYourERAppointmentStatus = 'checkingYourERAppointmentStatus';
static const transportOptions = 'transportOptions';
static const selectHospitalForAdvancePayment = 'selectHospitalForAdvancePayment';
static const recharge = 'recharge';
static const activityLevel = 'activityLevel';
static const selectActivityLevel = 'selectActivityLevel';
static const caloriesPerDay = 'caloriesPerDay';
static const dietType = 'dietType';
static const selectDietType = 'selectDietType';
static const bodyFrameSize = 'bodyFrameSize';
static const selectBodyFrameSize = 'selectBodyFrameSize';
static const averageCycleLength = 'averageCycleLength';
static const averageLutealPhase = 'averageLutealPhase';
static const convert = 'convert';
static const calculate = 'calculate';
static const healthCalculators = 'healthCalculators';
static const healthConverters = 'healthConverters';
static const generalHealth = 'generalHealth';
static const relatedToBMICalories = 'relatedToBMICalories';
static const selectCalculator = 'selectCalculator';
static const womensHealth = 'womensHealth';
static const relatedToPeriodsOvulation = 'relatedToPeriodsOvulation';
static const bloodSugar = 'bloodSugar';
static const trackYourGlucoseLevels = 'trackYourGlucoseLevels';
static const bloodCholesterol = 'bloodCholesterol';
static const monitorCholesterolLevels = 'monitorCholesterolLevels';
static const triglyceridesFatBlood = 'triglyceridesFatBlood';
static const understandTriglyceridesImpact = 'understandTriglyceridesImpact';
static const bmiCalculator = 'bmiCalculator';
static const caloriesCalculator = 'caloriesCalculator';
static const bmrCalculator = 'bmrCalculator';
static const idealBodyWeight = 'idealBodyWeight';
static const bodyFatCalculator = 'bodyFatCalculator';
static const carbsProteinFat = 'carbsProteinFat';
static const ovulationPeriod = 'ovulationPeriod';
static const deliveryDueDate = 'deliveryDueDate';
static const low = 'low';
static const preDiabetic = 'preDiabetic';
static const high = 'high';
static const elevated = 'elevated';
static const recorded = 'recorded';
static const noRecordsYet = 'noRecordsYet';
static const lastRecord = 'lastRecord';
static const addBloodSugar = 'addBloodSugar';
static const addBloodPressure = 'addBloodPressure';
static const addWeight = 'addWeight';
static const bloodSugarDataSavedSuccessfully = 'bloodSugarDataSavedSuccessfully';
static const bloodPressureDataSavedSuccessfully = 'bloodPressureDataSavedSuccessfully';
static const weightDataSavedSuccessfully = 'weightDataSavedSuccessfully';
static const pleaseWait = 'pleaseWait';
static const selectUnit = 'selectUnit';
static const selectMeasureTime = 'selectMeasureTime';
static const selectArm = 'selectArm';
static const enterBloodSugar = 'enterBloodSugar';
static const enterSystolicValue = 'enterSystolicValue';
static const enterDiastolicValue = 'enterDiastolicValue';
static const enterWeight = 'enterWeight';
static const selectDuration = 'selectDuration';
static const systolic = 'systolic';
static const diastolic = 'diastolic';
static const sendReportByEmail = 'sendReportByEmail';
static const enterYourEmailToReceiveReport = 'enterYourEmailToReceiveReport';
static const addNewRecord = 'addNewRecord';
static const healthTrackers = 'healthTrackers';
static const monitorBloodPressureLevels = 'monitorBloodPressureLevels';
static const trackWeightProgress = 'trackWeightProgress';
static const bookAppointment = 'bookAppointment';
static const completeCheckup = 'completeCheckup';
static const indoorNavigation = 'indoorNavigation';
static const eReferralServices = 'eReferralServices';
static const dailyWaterMonitor = 'dailyWaterMonitor';
static const fetchingYourWaterIntakeDetails = 'fetchingYourWaterIntakeDetails';
static const healthCalculatorsServices = 'healthCalculatorsServices';
static const healthConvertersServices = 'healthConvertersServices';
static const smartWatchesServices = 'smartWatchesServices';
static const exploreServices = 'exploreServices';
static const medicalAndCareServices = 'medicalAndCareServices';
static const hmgServices = 'hmgServices';
static const personalServices = 'personalServices';
static const habibWallet = 'habibWallet';
static const loginToViewWalletBalance = 'loginToViewWalletBalance';
static const loginToViewMedicalFile = 'loginToViewMedicalFile';
static const addMember = 'addMember';
static const addFamilyMember = 'addFamilyMember';
static const pleaseFillBelowFieldToAddNewFamilyMember = 'pleaseFillBelowFieldToAddNewFamilyMember';
static const healthTools = 'healthTools';
static const supportServices = 'supportServices';
static const virtualTour = 'virtualTour';
static const carParking = 'carParking';
static const latestNews = 'latestNews';
static const hmgContact = 'hmgContact';
static const durationCannotExceed90 = 'durationCannotExceed90';
static const unexpectedError = 'unexpectedError';
static const gettingAmbulanceTransportOption = 'gettingAmbulanceTransportOption';
static const fetchingAppointment = 'fetchingAppointment';
static const doYouWantToCancelTheRequest = 'doYouWantToCancelTheRequest';
static const cancellingRequest = 'cancellingRequest';
static const fetchingTermsAndConditions = 'fetchingTermsAndConditions';
static const selectLocationPrescriptionDelivery = 'selectLocationPrescriptionDelivery';
static const noRadiologyOrders = 'noRadiologyOrders';
static const ageIsRequired = 'ageIsRequired';
static const invalidAge = 'invalidAge';
static const ageMustBeBetween11And120 = 'ageMustBeBetween11And120';
static const heightIsRequired = 'heightIsRequired';
static const invalidHeight = 'invalidHeight';
static const weightIsRequired = 'weightIsRequired';
static const invalidWeight = 'invalidWeight';
static const timeToDrinkWater = 'timeToDrinkWater';
static const stayHydratedDrinkWater = 'stayHydratedDrinkWater';
static const visitPharmacyOnline = 'visitPharmacyOnline';
static const howAreYouFeelingToday = 'howAreYouFeelingToday';
static const checkYourSymptomsWithScale = 'checkYourSymptomsWithScale';
static const checkYourSymptoms = 'checkYourSymptoms';
static const noUpcomingAppointmentPleaseBook = 'noUpcomingAppointmentPleaseBook';
static const youHaveEROnlineCheckInRequest = 'youHaveEROnlineCheckInRequest';
static const quickLinks = 'quickLinks';
static const viewMedicalFileLandingPage = 'viewMedicalFileLandingPage';
static const immediateLiveCareRequest = 'immediateLiveCareRequest';
static const yourTurnIsAfterPatients = 'yourTurnIsAfterPatients';
static const dontHaveHHCOrders = 'dontHaveHHCOrders';
static const hhcOrders = 'hhcOrders';
static const requestedServices = 'requestedServices';
static const selectServices = 'selectServices';
static const selectedServices = 'selectedServices';
static const createNewRequest = 'createNewRequest';
static const youHaveNoPendingRequests = 'youHaveNoPendingRequests';
static const noInsuranceDataFound = 'noInsuranceDataFound';
static const noInsuranceUpdateRequest = 'noInsuranceUpdateRequest';
static const policyNumberInsurancePage = 'policyNumberInsurancePage';
static const insuranceExpired = 'insuranceExpired';
static const insuranceActive = 'insuranceActive';
static const patientCardID = 'patientCardID';
static const noInsuranceApprovals = 'noInsuranceApprovals';
static const noInsuranceWithHMG = 'noInsuranceWithHMG';
static const referenceRange = 'referenceRange';
static const downloadReport = 'downloadReport';
static const generatingReport = 'generatingReport';
static const noLabResults = 'noLabResults';
static const labResultDetails = 'labResultDetails';
static const resultOf = 'resultOf';
static const whatIsThisResult = 'whatIsThisResult';
static const lastTested = 'lastTested';
static const byVisit = 'byVisit';
static const byTest = 'byTest';
static const results = 'results';
static const viewResults = 'viewResults';
static const rebook = 'rebook';
static const noOphthalmologyAppointments = 'noOphthalmologyAppointments';
static const noVitalSignsRecordedYet = 'noVitalSignsRecordedYet';
static const appointmentsAndVisits = 'appointmentsAndVisits';
static const labAndRadiology = 'labAndRadiology';
static const activeMedicationsAndPrescriptions = 'activeMedicationsAndPrescriptions';
static const allPrescriptions = 'allPrescriptions';
static const allMedications = 'allMedications';
static const youDontHaveAnyPrescriptionsYet = 'youDontHaveAnyPrescriptionsYet';
static const youDontHaveAnyCompletedVisitsYet = 'youDontHaveAnyCompletedVisitsYet';
static const others = 'others';
static const allergyInfo = 'allergyInfo';
static const vaccineInfo = 'vaccineInfo';
static const updateInsuranceInfo = 'updateInsuranceInfo';
static const myInvoicesList = 'myInvoicesList';
static const ancillaryOrdersList = 'ancillaryOrdersList';
static const youDontHaveAnySickLeavesYet = 'youDontHaveAnySickLeavesYet';
static const medicalReports = 'medicalReports';
static const sickLeaveReport = 'sickLeaveReport';
static const weightTracker = 'weightTracker';
static const askYourDoctor = 'askYourDoctor';
static const internetPairing = 'internetPairing';
static const requested = 'requested';
static const youDontHaveAnyMedicalReportsYet = 'youDontHaveAnyMedicalReportsYet';
static const requestMedicalReport = 'requestMedicalReport';
static const youDoNotHaveAnyAppointmentsToRequestMedicalReport = 'youDoNotHaveAnyAppointmentsToRequestMedicalReport';
static const areYouSureYouWantToRequestMedicalReport = 'areYouSureYouWantToRequestMedicalReport';
static const yourMedicalReportRequestSubmittedSuccessfully = 'yourMedicalReportRequestSubmittedSuccessfully';
static const monthlyHealthSummaryReportDisclaimer = 'monthlyHealthSummaryReportDisclaimer';
static const updatingMonthlyReportStatus = 'updatingMonthlyReportStatus';
static const monthlyReportStatusUpdatedSuccessfully = 'monthlyReportStatusUpdatedSuccessfully';
static const whoCanViewMyMedicalFile = 'whoCanViewMyMedicalFile';
static const acceptedYourRequestToBeYourFamilyMember = 'acceptedYourRequestToBeYourFamilyMember';
static const canViewYourFile = 'canViewYourFile';
static const hasARequestPendingToBeYourFamilyMember = 'hasARequestPendingToBeYourFamilyMember';
static const wantsToAddYouAsTheirFamilyMember = 'wantsToAddYouAsTheirFamilyMember';
static const rejectedYourRequestToBeYourFamilyMember = 'rejectedYourRequestToBeYourFamilyMember';
static const rejectedYourFamilyMemberRequest = 'rejectedYourFamilyMemberRequest';
static const notAvailable = 'notAvailable';
static const selectAProfile = 'selectAProfile';
static const switchFamilyFile = 'switchFamilyFile';
static const medicalFiles = 'medicalFiles';
static const addANewFamilyMember = 'addANewFamilyMember';
static const viewInvoiceDetails = 'viewInvoiceDetails';
static const outPatient = 'outPatient';
static const invoiceDetails = 'invoiceDetails';
static const sendingEmailPleaseWait = 'sendingEmailPleaseWait';
static const emailSentSuccessfullyMessage = 'emailSentSuccessfullyMessage';
static const discount = 'discount';
static const paid = 'paid';
static const fetchingInvoiceDetails = 'fetchingInvoiceDetails';
static const scanQRCode = 'scanQRCode';
static const parkingSlotDetails = 'parkingSlotDetails';
static const slotNumber = 'slotNumber';
static const basement = 'basement';
static const parkingDate = 'parkingDate';
static const parkedSince = 'parkedSince';
static const resetDirection = 'resetDirection';
static const noPrescriptionOrdersYet = 'noPrescriptionOrdersYet';
static const fetchingPrescriptionPDFPleaseWait = 'fetchingPrescriptionPDFPleaseWait';
static const ratingValue = 'ratingValue';
static const downloadPrescription = 'downloadPrescription';
static const fetchingPrescriptionDetails = 'fetchingPrescriptionDetails';
static const switchBackFamilyFile = 'switchBackFamilyFile';
static const profileAndSettings = 'profileAndSettings';
static const quickActions = 'quickActions';
static const notificationsSettings = 'notificationsSettings';
static const touchIDFaceIDServices = 'touchIDFaceIDServices';
static const personalInformation = 'personalInformation';
static const updateEmailAddress = 'updateEmailAddress';
static const helpAndSupport = 'helpAndSupport';
static const permissionsProfile = 'permissionsProfile';
static const privacyPolicy = 'privacyPolicy';
static const deactivateAccount = 'deactivateAccount';
static const ageYearsOld = 'ageYearsOld';
static const youDontHaveRadiologyOrders = 'youDontHaveRadiologyOrders';
static const radiologyResult = 'radiologyResult';
static const viewRadiologyImage = 'viewRadiologyImage';
static const rateClinic = 'rateClinic';
static const back = 'back';
static const rateDoctor = 'rateDoctor';
static const howWasYourLastVisitWithDoctor = 'howWasYourLastVisitWithDoctor';
static const dateOfBirthSymptoms = 'dateOfBirthSymptoms';
static const genderSymptoms = 'genderSymptoms';
static const heightSymptoms = 'heightSymptoms';
static const weightSymptoms = 'weightSymptoms';
static const femaleGender = 'femaleGender';
static const previous = 'previous';
static const selectedOrgans = 'selectedOrgans';
static const noOrgansSelected = 'noOrgansSelected';
static const organSelector = 'organSelector';
static const noPredictionsAvailable = 'noPredictionsAvailable';
static const areYouSureYouWantToRestartOrganSelection = 'areYouSureYouWantToRestartOrganSelection';
static const possibleConditions = 'possibleConditions';
static const pleaseSelectAtLeastOneRiskBeforeProceeding = 'pleaseSelectAtLeastOneRiskBeforeProceeding';
static const aboveYouSeeCommonRiskFactors = 'aboveYouSeeCommonRiskFactors';
static const readMore = 'readMore';
static const riskFactors = 'riskFactors';
static const noRiskFactorsFound = 'noRiskFactorsFound';
static const basedOnYourSelectedSymptomsNoRiskFactors = 'basedOnYourSelectedSymptomsNoRiskFactors';
static const messageNotification = 'messageNotification';
static const attachedImage = 'attachedImage';
static const failedToLoadImage = 'failedToLoadImage';
static const typeNotification = 'typeNotification';
static const pleaseSelectAtLeastOneOptionBeforeProceeding = 'pleaseSelectAtLeastOneOptionBeforeProceeding';
static const suggestions = 'suggestions';
static const pleaseGoBackAndSelectOrgansFirst = 'pleaseGoBackAndSelectOrgansFirst';
static const symptomsSelector = 'symptomsSelector';
static const emergencyTriage = 'emergencyTriage';
static const emergencyEvidenceDetected = 'emergencyEvidenceDetected';
static const noQuestionItemsAvailable = 'noQuestionItemsAvailable';
static const pleaseAnswerAllQuestionsBeforeProceeding = 'pleaseAnswerAllQuestionsBeforeProceeding';
static const triage = 'triage';
static const areYouSureYouWantToExitProgress = 'areYouSureYouWantToExitProgress';
static const noQuestionAvailable = 'noQuestionAvailable';
static const possibleSymptom = 'possibleSymptom';
static const symptomsCheckerFindingScore = 'symptomsCheckerFindingScore';
static const notSet = 'notSet';
static const years = 'years';
static const symptomsChecker = 'symptomsChecker';
static const helloIsYourInformationUpToDate = 'helloIsYourInformationUpToDate';
static const noEditAll = 'noEditAll';
static const yesItIs = 'yesItIs';
static const age = 'age';
static const youDontHaveAnyAncillaryOrdersYet = 'youDontHaveAnyAncillaryOrdersYet';
static const invoiceWithNumber = 'invoiceWithNumber';
static const queued = 'queued';
static const checkInReady = 'checkInReady';
static const checkIn = 'checkIn';
static const viewDetails = 'viewDetails';
static const selectPaymentMethod = 'selectPaymentMethod';
static const processingPaymentPleaseWait = 'processingPaymentPleaseWait';
static const finalizingPaymentPleaseWait = 'finalizingPaymentPleaseWait';
static const generatingInvoicePleaseWait = 'generatingInvoicePleaseWait';
static const hereIsYourInvoiceNumber = 'hereIsYourInvoiceNumber';
static const paymentCompletedSuccessfully = 'paymentCompletedSuccessfully';
static const failedToInitializeApplePay = 'failedToInitializeApplePay';
static const cash = 'cash';
static const approved = 'approved';
static const approvalRejectedPleaseVisitReceptionist = 'approvalRejectedPleaseVisitReceptionist';
static const sentForApproval = 'sentForApproval';
static const ancillaryOrderDetails = 'ancillaryOrderDetails';
static const noProceduresAvailableForSelectedOrder = 'noProceduresAvailableForSelectedOrder';
static const procedures = 'procedures';
static const totalAmount = 'totalAmount';
static const covered = 'covered';
static const vatPercent = 'vatPercent';
static const proceedToPayment = 'proceedToPayment';
static const supportedSmartWatches = 'supportedSmartWatches';
static const pleaseMakeSureSamsungWatchConnected = 'pleaseMakeSureSamsungWatchConnected';
static const beforeSyncingDataFollowInstructions = 'beforeSyncingDataFollowInstructions';
static const viewWatchInstructions = 'viewWatchInstructions';
static const healthConnectAppNotInstalled = 'healthConnectAppNotInstalled';
static const setTimerOfReminder = 'setTimerOfReminder';
static const youHaveAppointmentWithDr = 'youHaveAppointmentWithDr';
static const hours = 'hours';
static const secs = 'secs';
static const noAllergiesDataFound = 'noAllergiesDataFound';
static const heartRateDescription = 'heartRateDescription';
static const bloodOxygenDescription = 'bloodOxygenDescription';
static const stepsDescription = 'stepsDescription';
static const caloriesDescription = 'caloriesDescription';
static const distanceDescription = 'distanceDescription';
static const overview = 'overview';
static const details = 'details';
static const healthy = 'healthy';
static const warning = 'warning';
static const vitalSignDetails = 'vitalSignDetails';
static const resultOfNoDate = 'resultOfNoDate';
static const referenceRangeBetween = 'referenceRangeBetween';
static const referenceRangeMin = 'referenceRangeMin';
static const referenceRangeMax = 'referenceRangeMax';
static const noHistoryAvailable = 'noHistoryAvailable';
static const bmiDescription = 'bmiDescription';
static const heightDescription = 'heightDescription';
static const weightDescription = 'weightDescription';
static const bloodPressureDescription = 'bloodPressureDescription';
static const temperatureDescription = 'temperatureDescription';
static const heartRateDescriptionVital = 'heartRateDescriptionVital';
static const respiratoryRateDescription = 'respiratoryRateDescription';
static const bmiAdvice = 'bmiAdvice';
static const heightAdvice = 'heightAdvice';
static const weightAdvice = 'weightAdvice';
static const bloodPressureAdvice = 'bloodPressureAdvice';
static const temperatureAdvice = 'temperatureAdvice';
static const heartRateAdvice = 'heartRateAdvice';
static const respiratoryRateAdvice = 'respiratoryRateAdvice';
static const whatShouldIDoNext = 'whatShouldIDoNext';
static const customizeDrinkCup = 'customizeDrinkCup';
static const tipsToStayHydrated = 'tipsToStayHydrated';
static const drinkBeforeYouFeelThirsty = 'drinkBeforeYouFeelThirsty';
static const keepRefillableBottleNextToYou = 'keepRefillableBottleNextToYou';
static const trackYourDailyIntakeToStayMotivated = 'trackYourDailyIntakeToStayMotivated';
static const chooseSparklingWaterInsteadOfSoda = 'chooseSparklingWaterInsteadOfSoda';
static const switchCup = 'switchCup';
static const plainWater = 'plainWater';
static const yourGoal = 'yourGoal';
static const remaining = 'remaining';
static const hydrationStatus = 'hydrationStatus';
static const areYouSureYouWantToCancelAllWaterReminders = 'areYouSureYouWantToCancelAllWaterReminders';
static const remindersSet = 'remindersSet';
static const dailyWaterRemindersScheduledAt = 'dailyWaterRemindersScheduledAt';
static const waterConsumption = 'waterConsumption';
static const selectNumberOfReminders = 'selectNumberOfReminders';
static const h2oSettings = 'h2oSettings';
static const settingsSavedSuccessfully = 'settingsSavedSuccessfully';
static const yourName = 'yourName';
static const ageYears = 'ageYears';
static const numberOfRemindersInADay = 'numberOfRemindersInADay';
static const medications = 'medications';
static const someRemarksAboutPrescription = 'someRemarksAboutPrescription';
static const notifyMeBeforeConsumptionTime = 'notifyMeBeforeConsumptionTime';
static const noMedicationsToday = 'noMedicationsToday';
static const reminders = 'reminders';
static const reminderAddedToCalendar = 'reminderAddedToCalendar';
static const errorWhileSettingCalendar = 'errorWhileSettingCalendar';
static const instructions = 'instructions';
static const requests = 'requests';
static const thisWeek = 'thisWeek';
static const lastMonth = 'lastMonth';
static const lastSixMonths = 'lastSixMonths';
static const selectTime = 'selectTime';
static const pleaseWaitYouWillBeCalledForVitalSigns = 'pleaseWaitYouWillBeCalledForVitalSigns';
static const pleaseVisitRoomForVitalSigns = 'pleaseVisitRoomForVitalSigns';
static const pleaseVisitRoomToTheDoctor = 'pleaseVisitRoomToTheDoctor';
}

@ -10,6 +10,7 @@ import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/active_prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart';
import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart';
@ -27,15 +28,18 @@ import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
import 'package:hmg_patient_app_new/features/qr_parking/qr_parking_view_model.dart';
import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart';
import 'package:hmg_patient_app_new/features/smartwatch_health_data/health_provider.dart';
import 'package:hmg_patient_app_new/features/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/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_trackers/health_trackers_view_model.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -45,6 +49,7 @@ import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart';
import 'core/utils/size_utils.dart';
import 'features/monthly_reports/terms_conditions_view_model.dart';
import 'firebase_options.dart';
@pragma('vm:entry-point')
@ -175,8 +180,23 @@ void main() async {
ChangeNotifierProvider<MyInvoicesViewModel>(
create: (_) => getIt.get<MyInvoicesViewModel>(),
),
ChangeNotifierProvider<HealthTrackersViewModel>(
create: (_) => getIt.get<HealthTrackersViewModel>(),
),
ChangeNotifierProvider<MonthlyReportViewModel>(
create: (_) => getIt.get<MonthlyReportViewModel>(),
),
ChangeNotifierProvider<NotificationsViewModel>(
create: (_) => getIt.get<NotificationsViewModel>(),
),
ChangeNotifierProvider<ActivePrescriptionsViewModel>(
create: (_) => getIt.get<ActivePrescriptionsViewModel>(),
),
ChangeNotifierProvider<QrParkingViewModel>(
create: (_) => getIt.get<QrParkingViewModel>(),
),
ChangeNotifierProvider<TermsConditionsViewModel>(
create: (_) => getIt.get<TermsConditionsViewModel>(),
)
], child: MyApp()),
),
@ -219,3 +239,4 @@ class MyApp extends StatelessWidget {
}
}
// flutter pub run easy_localization:generate -S assets/langs -f keys -o locale_keys.g.dart

@ -123,7 +123,7 @@ class AllergiesListPage extends StatelessWidget {
),
),
)
: Utils.getNoDataWidget(context, noDataText: "No allergies data found...".needTranslation);
: Utils.getNoDataWidget(context, noDataText: LocaleKeys.noAllergiesDataFound.tr());
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -7,16 +7,26 @@ import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/models/blood_group_hospitals_model.dart';
import 'package:hmg_patient_app_new/features/blood_donation/widgets/hospital_selection.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/blood_donation/widgets/select_blood_group_widget.dart';
import 'package:hmg_patient_app_new/presentation/blood_donation/widgets/select_city_widget.dart';
import 'package:hmg_patient_app_new/presentation/blood_donation/widgets/select_gender_widget.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/select_clinic_page.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.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/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:lottie/lottie.dart';
import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart';
class BloodDonationPage extends StatelessWidget {
BloodDonationPage({super.key});
@ -25,7 +35,7 @@ class BloodDonationPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
appState = getIt<AppState>();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Consumer<BloodDonationViewModel>(builder: (context, bloodDonationVM, child) {
@ -34,15 +44,83 @@ class BloodDonationPage extends StatelessWidget {
Expanded(
child: CollapsingListView(
title: LocaleKeys.bloodDonation.tr(),
trailing: CustomButton(
text: "Book",
onPressed: () {
// if (bloodDonationVM.isUserAuthanticated()) {
bloodDonationVM.fetchHospitalsList().then((value) {
showCommonBottomSheetWithoutHeight(context, title: "Select Hospital", isDismissible: false, child: Consumer<BloodDonationViewModel>(builder: (_, data, __) {
return HospitalBottomSheetBodySelection(
onUserHospitalSelection: (BdGetProjectsHaveBdClinic userChoice) {
print("============User Choice===============");
bloodDonationVM.getFreeBloodDonationSlots(request: {"ClinicID": 134, "ProjectID": userChoice.projectId});
},
);
}), callBackFunc: () {});
});
// } else {
// return showCommonBottomSheetWithoutHeight(
// context,
// title: LocaleKeys.notice.tr(context: context),
// child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// crossAxisAlignment: CrossAxisAlignment.center,
// children: [
// Lottie.asset(AppAnimations.errorAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
// SizedBox(height: 8.h),
// (LocaleKeys.loginToUseService.tr()).toText16(color: AppColors.blackColor),
// SizedBox(height: 16.h),
// Row(
// children: [
// Expanded(
// child: CustomButton(
// text: LocaleKeys.cancel.tr(),
// onPressed: () {
// Navigator.of(context).pop();
// },
// backgroundColor: AppColors.secondaryLightRedColor,
// borderColor: AppColors.secondaryLightRedColor,
// textColor: AppColors.primaryRedColor,
// icon: AppAssets.cancel,
// iconColor: AppColors.primaryRedColor,
// ),
// ),
// SizedBox(width: 8.h),
// Expanded(
// child: CustomButton(
// text: LocaleKeys.confirm.tr(),
// onPressed: () async {
// Navigator.of(context).pop();
// // Navigator.pushAndRemoveUntil(context, CustomPageRoute(page: LandingNavigation()), (r) => false);
// await getIt<AuthenticationViewModel>().onLoginPressed();
// },
// backgroundColor: AppColors.bgGreenColor,
// borderColor: AppColors.bgGreenColor,
// textColor: Colors.white,
// icon: AppAssets.confirm,
// ),
// ),
// ],
// ),
// SizedBox(height: 16.h),
// ],
// ).center,
// callBackFunc: () {},
// isFullScreen: false,
// isCloseButtonVisible: true,
// );
// }
},
backgroundColor: AppColors.bgRedLightColor,
borderColor: AppColors.bgRedLightColor,
textColor: AppColors.primaryRedColor,
padding: EdgeInsetsGeometry.symmetric(vertical: 0.h, horizontal: 20.h)),
child: Padding(
padding: EdgeInsets.all(24.w),
child: SingleChildScrollView(
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: false,
),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: false),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
@ -60,8 +138,8 @@ class BloodDonationPage extends StatelessWidget {
children: [
LocaleKeys.city.tr().toText16(color: AppColors.textColor, weight: FontWeight.w500),
(appState.isArabic()
? (bloodDonationVM.selectedCity.descriptionN ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedCity.description ?? LocaleKeys.select.tr(context: context))
? (bloodDonationVM.selectedCity?.descriptionN ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedCity?.description ?? LocaleKeys.select.tr(context: context))
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
@ -71,12 +149,7 @@ class BloodDonationPage extends StatelessWidget {
],
).onPress(() async {
showCommonBottomSheetWithoutHeight(context,
title: LocaleKeys.selectCity.tr(context: context),
isDismissible: true,
child: SelectCityWidget(
bloodDonationViewModel: bloodDonationVM,
),
callBackFunc: () {});
title: LocaleKeys.selectCity.tr(context: context), isDismissible: true, child: SelectCityWidget(bloodDonationViewModel: bloodDonationVM), callBackFunc: () {});
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
@ -86,13 +159,16 @@ class BloodDonationPage extends StatelessWidget {
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.my_account_icon, width: 40.h, height: 40.h),
Utils.buildSvgWithAssets(icon: AppAssets.genderInputIcon, width: 40.h, height: 40.h),
SizedBox(width: 12.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.gender.tr().toText16(color: AppColors.textColor, weight: FontWeight.w500),
"Male".toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
(appState.isArabic()
? (bloodDonationVM.selectedGender?.typeAr ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedGender?.type ?? LocaleKeys.select.tr(context: context))
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
],
@ -103,10 +179,7 @@ class BloodDonationPage extends StatelessWidget {
showCommonBottomSheetWithoutHeight(context,
title: LocaleKeys.selectGender.tr(context: context),
isDismissible: true,
child: SelectGenderWidget(
isArabic: appState.isArabic(),
bloodDonationViewModel: bloodDonationVM,
),
child: SelectGenderWidget(isArabic: appState.isArabic(), bloodDonationViewModel: bloodDonationVM),
callBackFunc: () {});
}),
SizedBox(height: 16.h),
@ -117,13 +190,17 @@ class BloodDonationPage extends StatelessWidget {
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.my_account_icon, width: 40.h, height: 40.h),
Utils.buildSvgWithAssets(icon: AppAssets.bloodType, width: 40.h, height: 40.h),
SizedBox(width: 12.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.bloodType.tr().toText16(color: AppColors.textColor, weight: FontWeight.w500),
bloodDonationVM.selectedBloodType.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
// bloodDonationVM.selectedBloodType?.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
(appState.isArabic()
? (bloodDonationVM.selectedBloodType ?? LocaleKeys.select.tr())
: bloodDonationVM.selectedBloodType ?? LocaleKeys.select.tr(context: context))
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500)
],
),
],
@ -134,10 +211,7 @@ class BloodDonationPage extends StatelessWidget {
showCommonBottomSheetWithoutHeight(context,
title: LocaleKeys.select.tr(context: context),
isDismissible: true,
child: SelectBloodGroupWidget(
isArabic: appState.isArabic(),
bloodDonationViewModel: bloodDonationVM,
),
child: SelectBloodGroupWidget(isArabic: appState.isArabic(), bloodDonationViewModel: bloodDonationVM),
callBackFunc: () {});
}),
],
@ -149,19 +223,73 @@ class BloodDonationPage extends StatelessWidget {
),
),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: true,
),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: SizedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: bloodDonationVM.onTermAccepted,
child: Row(
children: [
Selector<BloodDonationViewModel, bool>(
selector: (_, viewModel) => viewModel.isTermsAccepted,
shouldRebuild: (previous, next) => previous != next,
builder: (context, isTermsAccepted, child) {
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
height: 24.h,
width: 24.h,
decoration: BoxDecoration(
color: isTermsAccepted ? AppColors.primaryRedColor : Colors.transparent,
borderRadius: BorderRadius.circular(6),
border: Border.all(color: isTermsAccepted ? AppColors.primaryRedBorderColor : AppColors.greyColor, width: 2.h),
),
child: isTermsAccepted ? Icon(Icons.check, size: 16.f, color: Colors.white) : null,
);
},
),
SizedBox(width: 12.h),
Row(
children: [
Text(
LocaleKeys.iAcceptThe.tr(),
style: context.dynamicTextStyle(fontSize: 14.f, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)),
),
GestureDetector(
onTap: () {
// Navigate to terms and conditions page
Navigator.of(context).pushNamed('/terms');
},
child: Text(
LocaleKeys.termsConditoins.tr(),
style: context.dynamicTextStyle(
fontSize: 14.f,
fontWeight: FontWeight.w500,
color: AppColors.primaryRedColor,
decoration: TextDecoration.underline,
decorationColor: AppColors.primaryRedBorderColor,
),
),
),
],
),
// Expanded(
// child: Text(
// LocaleKeys.iAcceptTermsConditions.tr().split("the").first,
// style: context.dynamicTextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)),
// ),
// ),
],
),
).paddingOnly(left: 16.h, right: 16.h, top: 24.h),
CustomButton(
text: LocaleKeys.save.tr(),
onPressed: () {
// openDoctorScheduleCalendar();
onPressed: () async {
DialogService dialogService = getIt.get<DialogService>();
if (await bloodDonationVM.validateSelections()) {
bloodDonationVM.updateBloodGroup();
}
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,

@ -26,9 +26,7 @@ class SelectCityWidget extends StatelessWidget {
Navigator.of(context).pop();
});
},
separatorBuilder: (_, __) => SizedBox(
height: 8.h,
),
separatorBuilder: (_, __) => SizedBox(height: 8.h),
itemCount: bloodDonationViewModel.citiesList.length),
)
],

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
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/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@ -8,10 +9,10 @@ import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_
import 'package:hmg_patient_app_new/theme/colors.dart';
class SelectGenderWidget extends StatelessWidget {
SelectGenderWidget({super.key, required this.bloodDonationViewModel, required this.isArabic});
const SelectGenderWidget({super.key, required this.bloodDonationViewModel, required this.isArabic});
BloodDonationViewModel bloodDonationViewModel;
bool isArabic;
final BloodDonationViewModel bloodDonationViewModel;
final bool isArabic;
@override
Widget build(BuildContext context) {
@ -20,46 +21,45 @@ class SelectGenderWidget extends StatelessWidget {
children: [
SizedBox(height: 8.h),
SizedBox(
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
itemBuilder: (_, index) {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [bloodDonationViewModel.genderList[index].name.toText16(color: AppColors.textColor, isBold: true)],
height: MediaQuery.sizeOf(context).height * .4,
child: ListView.separated(
itemBuilder: (_, index) {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: false,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8.h,
children: [GenderTypeEnum.values[index].name.toCamelCase.toText16(color: AppColors.textColor, isBold: true)],
),
),
),
Transform.flip(
flipX: isArabic,
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
iconColor: AppColors.blackColor,
width: 40.h,
height: 40.h,
fit: BoxFit.contain,
Transform.flip(
flipX: isArabic,
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon,
iconColor: AppColors.blackColor,
width: 40.h,
height: 40.h,
fit: BoxFit.contain,
),
),
),
],
).paddingSymmetrical(16.h, 16.h).onPress(() {
// bloodDonationViewModel.setSelectedCity(bloodDonationViewModel.citiesList[index]);
Navigator.of(context).pop();
}));
},
separatorBuilder: (_, __) => SizedBox(
height: 8.h,
),
itemCount: bloodDonationViewModel.genderList.length),
)
],
).paddingSymmetrical(16.h, 16.h).onPress(() {
bloodDonationViewModel.onGenderChange(GenderTypeEnum.values[index].name.toCamelCase);
Navigator.of(context).pop();
}));
},
separatorBuilder: (_, __) => SizedBox(
height: 8.h,
),
itemCount: GenderTypeEnum.values.length))
],
);
}

@ -89,8 +89,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
initialIndex: bookAppointmentsVM.selectedTabIndex,
tabs: [
CustomTabBarModel(null, "General".needTranslation),
CustomTabBarModel(null, "LiveCare".needTranslation),
CustomTabBarModel(null, LocaleKeys.general.tr()),
CustomTabBarModel(null, LocaleKeys.liveCare.tr()),
],
onTabChange: (index) {
bookAppointmentsVM.onTabChanged(index);
@ -112,10 +112,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
fit: BoxFit.cover,
).circle(100).toShimmer2(isShow: true, radius: 50.r),
SizedBox(height: 8.h),
("Dr. John Smith Smith Smith")
.toString()
.toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2)
.toShimmer2(isShow: true),
("Dr. John Smith Smith Smith").toString().toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2).toShimmer2(isShow: true),
],
)
: myAppointmentsVM.patientMyDoctorsList.isEmpty
@ -124,7 +121,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (appState.isAuthenticated) ...[],
"Recent Visits".needTranslation.toText18(isBold: true).paddingSymmetrical(24.w, 0.h),
LocaleKeys.recentVisits.tr().toText18(isBold: true).paddingSymmetrical(24.w, 0.h),
SizedBox(height: 16.h),
SizedBox(
height: 110.h,
@ -235,16 +232,13 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Search By Clinic".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
LocaleKeys.searchByClinic.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500),
LocaleKeys.tapToSelectClinic.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
bookAppointmentsViewModel.setIsClinicsListLoading(true);
@ -270,16 +264,13 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Search By Doctor".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
LocaleKeys.searchByDoctor.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500),
LocaleKeys.tapToSelect.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
bookAppointmentsViewModel.setIsDoctorSearchByNameStarted(false);
@ -303,16 +294,13 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Search By Region".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Central Region".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
LocaleKeys.searchByRegion.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500),
LocaleKeys.centralRegion.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
bookAppointmentsViewModel.setProjectID(null);
@ -332,124 +320,115 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
Column(
children: [
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_clinic_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Immediate Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() async {
//TODO Implement API to check for existing LiveCare Requests
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_clinic_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.immediateConsultation.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500),
LocaleKeys.tapToSelectClinic.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() async {
//TODO Implement API to check for existing LiveCare Requests
LoaderBottomSheet.showLoader();
await immediateLiveCareViewModel.getPatientLiveCareHistory();
LoaderBottomSheet.hideLoader();
LoaderBottomSheet.showLoader();
await immediateLiveCareViewModel.getPatientLiveCareHistory();
LoaderBottomSheet.hideLoader();
if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) {
Navigator.of(context).push(
CustomPageRoute(
page: ImmediateLiveCarePendingRequestPage(),
),
);
} else {
Navigator.of(context).push(
CustomPageRoute(
page: SelectImmediateLiveCareClinicPage(),
),
);
}
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_doctor_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Scheduled Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
bookAppointmentsViewModel.setIsClinicsListLoading(true);
bookAppointmentsViewModel.setIsLiveCareSchedule(true);
Navigator.of(context).push(
CustomPageRoute(
page: SelectClinicPage(),
),
);
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_region_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Pharma LiveCare".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500),
"".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
openRegionListBottomSheet(context, RegionBottomSheetType.FOR_REGION);
}),
],
),
),
),
],
).paddingSymmetrical(24.h, 0.h)
if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) {
Navigator.of(context).push(
CustomPageRoute(
page: ImmediateLiveCarePendingRequestPage(),
),
);
} else {
Navigator.of(context).push(
CustomPageRoute(
page: SelectImmediateLiveCareClinicPage(),
),
);
}
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_doctor_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.scheduledConsultation.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500),
LocaleKeys.tapToSelectClinic.tr().toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
bookAppointmentsViewModel.setIsClinicsListLoading(true);
bookAppointmentsViewModel.setIsLiveCareSchedule(true);
Navigator.of(context).push(
CustomPageRoute(
page: SelectClinicPage(),
),
);
}),
SizedBox(height: 16.h),
Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.search_by_region_icon, width: 40.h, height: 40.h),
SizedBox(width: 12.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.pharmaLiveCare.tr().toText14(color: AppColors.textColor, weight: FontWeight.w500),
"".toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500),
],
),
],
),
Transform.flip(flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)),
],
).onPress(() {
openRegionListBottomSheet(context, RegionBottomSheetType.FOR_REGION);
}),
],
),
),
),
],
).paddingSymmetrical(24.h, 0.h)
// : getLiveCareNotLoggedInUI()
;
default:
@ -468,9 +447,9 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Not sure? help me choose a clinic!".needTranslation.toText16(weight: FontWeight.w600, color: AppColors.textColor),
SizedBox(height: 4.h),
"Mention your symptoms and find the list of doctors accordingly".needTranslation.toText12(
LocaleKeys.notSureHelpMeChooseClinic.tr().toText16(weight: FontWeight.w600, color: AppColors.textColor),
SizedBox(height: 8.h),
LocaleKeys.mentionYourSymptomsAndFindDoctors.tr().toText12(
fontWeight: FontWeight.w500,
color: AppColors.greyTextColor,
),
@ -493,10 +472,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
regionalViewModel.flush();
regionalViewModel.setBottomSheetType(type);
// AppointmentViaRegionViewmodel? viewmodel = null;
showCommonBottomSheetWithoutHeight(context,
title: "",
titleWidget: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) => getTitle(data)),
isDismissible: false, child: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) {
showCommonBottomSheetWithoutHeight(context, title: "", titleWidget: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) => getTitle(data)), isDismissible: false,
child: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) {
return getRegionalSelectionWidget(data);
}), callBackFunc: () {});
}
@ -581,10 +558,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Immediate service".needTranslation.toText18(color: AppColors.textColor, isBold: true),
"No need to wait, you will get medical consultation immediately via video call"
.needTranslation
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
LocaleKeys.immediateService.tr().toText18(color: AppColors.textColor, isBold: true),
LocaleKeys.noNeedToWaitGetMedicalConsultation.tr().toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
),
@ -599,7 +574,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"No visit required".needTranslation.toText18(color: AppColors.textColor, isBold: true),
LocaleKeys.noVisitRequired.tr().toText18(color: AppColors.textColor, isBold: true),
LocaleKeys.livecarePoint5.tr(context: context).toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
@ -615,10 +590,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Doctor will contact".needTranslation.toText18(color: AppColors.textColor, isBold: true),
"A specialised doctor will contact you and will be able to view your medical history"
.needTranslation
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
LocaleKeys.doctorWillContact.tr().toText18(color: AppColors.textColor, isBold: true),
LocaleKeys.specialisedDoctorWillContactYou.tr().toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
),
@ -633,10 +606,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Free medicine delivery".needTranslation.toText18(color: AppColors.textColor, isBold: true),
"Offers free medicine delivery for the LiveCare appointment"
.needTranslation
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
LocaleKeys.freeMedicineDelivery.tr().toText18(color: AppColors.textColor, isBold: true),
LocaleKeys.offersFreeMedicineDelivery.tr().toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
],
),
),
@ -644,7 +615,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
),
SizedBox(height: 36.h),
CustomButton(
text: "Login to use this service".needTranslation,
text: "Login to use this service",
onPressed: () async {
await authVM.onLoginPressed();
},

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

Loading…
Cancel
Save