Merge branch 'refs/heads/master' into faiz_dev
# Conflicts: # lib/presentation/symptoms_checker/user_info_selection.dartfaiz_dev
|
After Width: | Height: | Size: 2.4 MiB |
@ -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="M4 13C4 8.58172 7.58172 5 12 5C16.4183 5 20 8.58172 20 13C20 13.5523 20.4477 14 21 14C21.5523 14 22 13.5523 22 13C22 7.47715 17.5228 3 12 3C6.47715 3 2 7.47715 2 13C2 13.5523 2.44772 14 3 14C3.55228 14 4 13.5523 4 13Z" fill="#D48D05"/>
|
||||
<path d="M12 9C12.5523 9 13 9.44772 13 10L13 15.1707C14.1652 15.5825 15 16.6938 15 18C15 19.6569 13.6569 21 12 21C10.3431 21 9 19.6569 9 18C9 16.6938 9.83481 15.5825 11 15.1707L11 10C11 9.44772 11.4477 9 12 9Z" fill="#D48D05"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 576 B |
|
After Width: | Height: | Size: 6.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="M19.8271 3.35515C16.8461 1.52662 14.1719 2.25537 12.5563 3.46861C12.4618 3.5396 12.3778 3.60261 12.3027 3.6585C12.1487 3.77312 12.0717 3.83043 11.9724 3.83043C11.873 3.83043 11.796 3.77312 11.642 3.6585C11.5669 3.60262 11.4829 3.5396 11.3884 3.46861C9.77284 2.25537 7.09861 1.52662 4.11763 3.35515C2.63347 4.26554 1.61665 5.88968 1.31555 7.86051C1.27161 8.14807 1.24965 8.29185 1.33944 8.39639C1.42923 8.50094 1.58234 8.50092 1.88856 8.50089L5.14448 8.50059C5.55656 8.49886 6.25061 8.49594 6.92509 8.74131C7.18957 8.83753 7.42861 8.9636 7.64109 9.10184C7.94838 9.30175 8.10203 9.40171 8.22623 9.37305C8.35044 9.34439 8.43459 9.20413 8.60289 8.92363L9.32823 7.71474C9.78963 6.94573 10.6276 6.48278 11.5242 6.50152C12.4208 6.52027 13.2387 7.01784 13.6676 7.80546L14.9648 10.1879C15.0479 10.3405 15.0895 10.4168 15.1603 10.4589C15.2311 10.501 15.318 10.501 15.4918 10.501H15.972C17.3527 10.501 18.472 11.6203 18.472 13.001C18.472 14.3817 17.3527 15.501 15.972 15.501L14.8556 15.5031C14.4407 15.5127 13.1951 15.5415 12.106 14.705C12.0741 14.6805 12.0429 14.6555 12.0124 14.6302C11.6751 14.3499 11.5064 14.2097 11.3704 14.2328C11.2345 14.2559 11.1366 14.419 10.9409 14.7453L10.6157 15.2872C10.1827 16.0089 9.41568 16.4642 8.5748 16.4989C7.73393 16.5335 6.93207 16.1427 6.44122 15.4591L5.21484 13.7511C5.12681 13.6285 5.0828 13.5672 5.01833 13.5341C4.95385 13.501 4.87839 13.501 4.72747 13.501L3.23319 13.501C2.80205 13.501 2.58648 13.501 2.49975 13.6503C2.41302 13.7997 2.51637 13.9808 2.72307 14.3432C3.7896 16.2127 5.46319 18.1083 7.86568 19.8865C9.31705 20.9614 10.3823 21.7503 11.9723 21.7503C13.5624 21.7503 14.6276 20.9614 16.079 19.8865C20.2586 16.7929 22.2322 13.3443 22.6412 10.2951C23.0481 7.2606 21.8883 4.61952 19.8271 3.35515Z" fill="#18C273"/>
|
||||
<path d="M12.3509 8.5218C12.1794 8.20675 11.8522 8.00772 11.4936 8.00022C11.1349 7.99272 10.7997 8.1779 10.6152 8.48551L8.39777 12.1812L7.72833 11.2488C7.71432 11.2293 7.69962 11.2103 7.68425 11.1919C7.66865 11.1731 7.65154 11.1522 7.63294 11.1295C7.4192 10.8684 7.00838 10.3666 6.41298 10.15C5.9948 9.99782 5.53719 9.99883 5.08287 9.99984L4.97266 10L2.97266 10C2.42037 10 1.97266 10.4477 1.97266 11C1.97266 11.5523 2.42037 12 2.97266 12H4.97266C5.60991 12 5.68621 12.0141 5.72762 12.0289C5.73136 12.0307 5.76392 12.0476 5.83105 12.1122C5.91437 12.1924 5.9964 12.2905 6.12473 12.4445L7.66036 14.5832C7.8567 14.8567 8.17744 15.013 8.51379 14.9992C8.85014 14.9853 9.15695 14.8032 9.33015 14.5145L11.4306 11.0138L12.2854 12.5838C12.295 12.6013 12.305 12.6186 12.3156 12.6356L12.3573 12.7026C12.5191 12.9635 12.7156 13.2804 13.0204 13.5144C13.6863 14.0259 14.4768 14.0096 14.863 14.0016C14.9044 14.0008 14.9412 14 14.9727 14H15.9727C16.5249 14 16.9727 13.5523 16.9727 13C16.9727 12.4477 16.5249 12 15.9727 12H14.9727C14.9119 12 14.8581 12.0003 14.8096 12.0005C14.6334 12.0015 14.5272 12.002 14.416 11.9872C14.3192 11.9743 14.276 11.9545 14.248 11.9352C14.2434 11.9296 14.2355 11.9197 14.2239 11.9037C14.1807 11.8444 14.1277 11.7611 14.0275 11.601L12.3509 8.5218Z" fill="#18C273"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16.083 8.3418C16.1804 8.26933 16.3034 8.26171 16.4092 8.32129C16.4449 8.34147 16.4818 8.37722 16.5537 8.44922C18.2206 9.92249 19.4021 12.5001 18.3545 14.9922C18.0491 15.7186 17.3429 16.2001 16.5498 16.2002L16.2725 16.1982C16.045 16.1964 15.9309 16.1958 15.8486 16.2598C15.7666 16.3238 15.7397 16.4344 15.6855 16.6553L14.7207 20.5879C14.4117 21.8473 13.2957 22.7461 11.998 22.7461C10.7005 22.746 9.5844 21.8473 9.27539 20.5879L8.31152 16.6553C8.25731 16.4342 8.2297 16.3238 8.14746 16.2598C8.06513 16.1957 7.95135 16.1964 7.72363 16.1982L7.44727 16.2002C6.6541 16.2002 5.94699 15.7187 5.6416 14.9922C4.59407 12.5 5.77638 9.92243 7.44336 8.44922C7.51481 8.37768 7.55044 8.34145 7.58594 8.32129C7.69173 8.26141 7.81555 8.26931 7.91309 8.3418C7.94584 8.36621 7.98081 8.41097 8.0498 8.5C8.14907 8.62808 8.25089 8.75011 8.35254 8.86426C8.78359 9.34823 9.29846 9.79001 9.86914 10.124C10.4188 10.4457 11.1568 10.7461 11.998 10.7461C12.8393 10.7461 13.5773 10.4457 14.127 10.124C14.6976 9.79001 15.2125 9.34823 15.6436 8.86426C15.7452 8.75013 15.847 8.62806 15.9463 8.5C16.0154 8.41081 16.0502 8.36627 16.083 8.3418ZM12 1.25C14.0711 1.25 15.75 2.92893 15.75 5C15.75 6.07361 15.1945 7.1188 14.5254 7.87012C14.1835 8.25405 13.7876 8.58923 13.3711 8.83301C12.9615 9.07273 12.4873 9.25 12 9.25C11.5127 9.25 11.0385 9.07273 10.6289 8.83301C10.2124 8.58923 9.81654 8.25405 9.47461 7.87012C8.80554 7.1188 8.25 6.07361 8.25 5C8.25 2.92893 9.92893 1.25 12 1.25Z" fill="#0B85F7"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.9999 3.125C10.9999 2.57272 11.4476 2.125 11.9999 2.125C12.5522 2.125 12.9999 2.57272 12.9999 3.125V5.25648L13.6002 5.6567C13.6063 5.64329 13.6125 5.62994 13.6188 5.61666C13.7792 5.27762 14.0126 4.95992 14.3466 4.72784C14.6864 4.4917 15.0865 4.375 15.5234 4.375C17.3868 4.375 19.2054 5.74706 20.5136 7.78194C21.844 9.8515 22.75 12.745 22.75 16.125C22.75 18.5571 21.9318 20.0447 20.8453 20.9014C19.7942 21.7302 18.6097 21.875 18.0144 21.875C16.8144 21.875 15.5948 21.6036 14.6787 20.7304C13.7563 19.8512 13.2788 18.4938 13.2788 16.625C13.2842 16.2851 13.3181 15.4637 13.4101 14.8979C13.5229 14.0671 13.7417 12.9986 14.1873 12.0938C13.709 10.979 13.3028 9.33793 13.2548 7.89942C13.254 7.87588 13.2533 7.85231 13.2527 7.82873L11.9999 6.99352L10.7473 7.82858C10.7467 7.85222 10.746 7.87583 10.7452 7.89942C10.6973 9.33793 10.291 10.979 9.81277 12.0938C10.2583 12.9986 10.4772 14.0671 10.5899 14.8979C10.682 15.4637 10.7158 16.2851 10.7213 16.625C10.7213 18.4938 10.2438 19.8512 9.32137 20.7304C8.40522 21.6036 7.18561 21.875 5.98563 21.875C5.39035 21.875 4.20581 21.7302 3.15476 20.9014C2.06825 20.0447 1.25 18.5571 1.25 16.125C1.25 12.745 2.15607 9.8515 3.48648 7.78194C4.79459 5.74706 6.61322 4.375 8.47665 4.375C8.91351 4.375 9.3136 4.4917 9.65343 4.72784C9.98742 4.95992 10.2208 5.27762 10.3812 5.61666C10.3875 5.6299 10.3937 5.64322 10.3997 5.65659L10.9999 5.25648V3.125Z" fill="#18C273"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,6 @@
|
||||
<svg width="67" height="74" viewBox="0 0 67 74" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M66.6078 32.2697C66.1744 30.4738 65.1769 29.2328 63.7991 28.7779C63.3117 28.6169 62.7964 28.5751 62.2712 28.6277C63.2293 24.3157 64.7466 19.7654 64.5501 15.5873C64.1645 7.35177 58.7442 0.579242 41.8415 0.0148163C31.0287 -0.346213 20.1447 5.91597 20.6036 16.0287C20.8633 21.7671 21.9015 25.0884 22.6027 28.1906L22.5955 28.6872C21.9433 28.5588 21.3005 28.5802 20.7048 28.7779C19.3245 29.2328 18.327 30.4738 17.8953 32.2697C17.4945 33.929 17.6233 35.8995 18.2581 37.8187C19.2879 40.9412 21.4426 43.2444 23.6866 43.6967C24.8086 48.1266 26.7007 52.0335 29.1423 55.1157L28.172 72.4976C28.1488 72.947 28.4967 73.3275 28.9447 73.3489C28.9581 73.3504 28.9715 73.3518 28.9853 73.3518C29.4158 73.3518 29.7757 73.0131 29.7974 72.5777L30.6851 56.8736C33.9673 60.2504 37.9975 62.271 42.3673 62.271C46.7608 62.271 50.8119 60.229 54.1046 56.8167L54.9949 72.5777C55.0166 73.0131 55.3771 73.3518 55.8074 73.3518C55.8211 73.3518 55.8345 73.3504 55.848 73.3489C56.296 73.3275 56.6436 72.947 56.6204 72.4976L55.646 55.0476C58.0739 51.9631 59.9511 48.0599 61.0666 43.6372C63.217 43.0688 65.2513 40.8234 66.2445 37.8187C66.8779 35.8995 67.0069 33.9304 66.6078 32.2697ZM19.8023 37.3084C19.2636 35.6723 19.1472 34.0197 19.4762 32.6514C19.7725 31.421 20.3896 30.5942 21.2152 30.3207C21.6323 30.184 22.0894 30.1988 22.5741 30.3493L22.5226 34.373C22.5226 36.9688 22.7961 39.47 23.2684 41.8561C21.862 41.1861 20.5169 39.474 19.8023 37.3084ZM42.3673 60.6429C32.3223 60.6429 24.1495 48.8586 24.1495 34.3838L24.2782 24.4253C24.2957 23.0704 23.6463 18.5731 28.6563 18.5731C35.6019 18.5731 35.2 23.0896 41.772 23.0896C48.4944 23.0896 49.0054 18.4254 55.848 18.4254C61.0748 18.4254 60.4495 23.4953 60.4698 25.083L60.5874 34.373C60.5874 48.8586 52.4154 60.6429 42.3673 60.6429ZM64.6994 37.3084C64.028 39.3398 62.8019 40.9779 61.4919 41.7277C61.9508 39.3764 62.2157 36.9159 62.2157 34.3635L62.1642 30.287C62.5604 30.2003 62.9383 30.2071 63.2873 30.3221C64.1118 30.5942 64.7292 31.421 65.0258 32.6514C65.3557 34.0197 65.2381 35.6723 64.6994 37.3084Z" fill="#2B353E"/>
|
||||
<path d="M14.4426 56.2374C14.4426 59.3856 11.8899 61.9383 8.74195 61.9383C5.59398 61.9383 3.04248 59.3856 3.04248 56.2374C3.04248 53.0909 5.59398 50.5382 8.74195 50.5382C11.8899 50.5382 14.4426 53.0909 14.4426 56.2374Z" fill="#EC1B2A"/>
|
||||
<path d="M8.74187 64.9804C3.92094 64.9804 0 61.058 0 56.2374C0 53.2991 1.50647 50.5382 3.9587 48.9287V19.423C3.9587 16.7865 6.10398 14.6387 8.74187 14.6387C11.3809 14.6387 13.5276 16.7865 13.5276 19.423V48.9302C15.9784 50.5382 17.4849 53.2991 17.4849 56.2374C17.4849 61.058 13.5617 64.9804 8.74187 64.9804ZM8.74187 16.1909C6.95934 16.1909 5.51009 17.6405 5.51009 19.423V49.807L5.1256 50.0307C2.92082 51.3189 1.55138 53.6967 1.55138 56.2374C1.55138 60.2029 4.77773 63.4293 8.74187 63.4293C12.706 63.4293 15.9326 60.2029 15.9326 56.2374C15.9326 53.6982 14.5644 51.3189 12.361 50.0318L11.9751 49.807V19.423C11.9751 17.6405 10.5258 16.1909 8.74187 16.1909Z" fill="#2B353E"/>
|
||||
<path d="M10.4569 51.7886H7.02686V25.6216H10.4569V51.7886Z" fill="#EC1B2A"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.1459 1.27079C12.8412 1.24999 12.47 1.24999 12.0253 1.25C11.5806 1.24999 11.1588 1.24999 10.8541 1.27079C10.5368 1.29245 10.2372 1.33914 9.94665 1.45953C9.27321 1.73863 8.73814 2.2737 8.45905 2.94713C8.33865 3.23764 8.29196 3.53731 8.2703 3.85456C8.2495 4.15932 8.2495 4.53054 8.24951 4.97522L8.24951 12.6414C7.0263 13.6949 6.25 15.2569 6.25 17C6.25 20.1756 8.82436 22.75 12 22.75C15.1756 22.75 17.75 20.1756 17.75 17C17.75 15.2569 16.9737 13.6949 15.7505 12.6414L15.7505 4.97524C15.7505 4.53055 15.7505 4.15933 15.7297 3.85456C15.708 3.53731 15.6614 3.23764 15.541 2.94713C15.2619 2.2737 14.7268 1.73863 14.0534 1.45953C13.7628 1.33914 13.4632 1.29245 13.1459 1.27079ZM12 7C12.5523 7 13 7.44772 13 8L13 14.4375C14.0243 14.8375 14.75 15.834 14.75 17C14.75 18.5188 13.5188 19.75 12 19.75C10.4812 19.75 9.25 18.5188 9.25 17C9.25 15.834 9.97566 14.8375 11 14.4375L11 8C11 7.44772 11.4477 7 12 7Z" fill="#ED1C2B"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.6439 1.25L13.3561 1.25C14.259 1.24997 15.0211 1.24994 15.6249 1.32042C16.255 1.39396 16.8707 1.55847 17.3706 2.00915C17.5958 2.21222 17.7873 2.44899 17.9376 2.71113C18.2326 3.22573 18.2812 3.77334 18.2347 4.31609C19.2103 4.4287 20.0196 4.68604 20.6521 5.31966C21.2538 5.92238 21.5125 6.68113 21.6335 7.58241C21.75 8.4507 21.75 9.55477 21.75 10.9249V16.043C21.75 17.4131 21.75 18.5172 21.6335 19.3855C21.5125 20.2867 21.2538 21.0455 20.6521 21.6482C20.0502 22.2511 19.2923 22.5105 18.3919 22.6318C17.5249 22.7486 16.4225 22.7486 15.055 22.7485L8.94504 22.7485C7.57752 22.7486 6.47513 22.7486 5.60808 22.6318C4.70774 22.5105 3.94976 22.2511 3.3479 21.6482C2.74621 21.0455 2.48747 20.2867 2.3665 19.3855C2.24997 18.5172 2.24998 17.4131 2.25 16.0431L2.25 10.9248C2.24998 9.55478 2.24997 8.45069 2.3665 7.58241C2.48747 6.68113 2.74621 5.92238 3.3479 5.31966C3.98043 4.68604 4.78975 4.4287 5.76534 4.31608C5.71879 3.77334 5.76736 3.22573 6.06239 2.71113C6.21268 2.44899 6.40422 2.21222 6.62944 2.00915C7.1293 1.55847 7.74503 1.39396 8.37506 1.32042C8.97893 1.24994 9.74097 1.24997 10.6439 1.25ZM8.60067 3.2073C8.13641 3.26149 7.99252 3.35241 7.92575 3.4126C7.8493 3.48154 7.78534 3.56095 7.73568 3.64756C7.69637 3.71613 7.64027 3.8608 7.69746 4.30137C7.75673 4.75797 7.91092 5.36081 8.14823 6.27796C8.33725 7.00848 8.46246 7.48783 8.59555 7.84684C8.72171 8.18716 8.82647 8.33584 8.9287 8.43308C9.00978 8.51021 9.10016 8.57847 9.1982 8.63631C9.32461 8.71091 9.5056 8.77465 9.88389 8.81094C10.1378 8.83531 10.4406 8.84448 10.8301 8.84793L11.5514 6.68404C11.726 6.1601 12.2924 5.87694 12.8163 6.05159C13.3402 6.22624 13.6234 6.79256 13.4488 7.3165L12.9378 8.84935C13.4424 8.84743 13.8138 8.83994 14.1161 8.81094C14.4944 8.77465 14.6754 8.71091 14.8018 8.63631C14.8998 8.57847 14.9902 8.51021 15.0713 8.43308C15.1735 8.33584 15.2783 8.18716 15.4045 7.84684C15.5375 7.48783 15.6628 7.00848 15.8518 6.27796C16.0891 5.36081 16.2433 4.75797 16.3025 4.30137C16.3597 3.8608 16.3036 3.71613 16.2643 3.64756C16.2147 3.56095 16.1507 3.48153 16.0742 3.4126C16.0075 3.35241 15.8636 3.26149 15.3993 3.2073C14.9218 3.15157 14.2747 3.15 13.2979 3.15L10.7021 3.15C9.72532 3.15 9.07816 3.15157 8.60067 3.2073ZM10 17C9.44772 17 9 17.4477 9 18C9 18.5523 9.44772 19 10 19H14C14.5523 19 15 18.5523 15 18C15 17.4477 14.5523 17 14 17L10 17Z" fill="#18C273"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@ -0,0 +1,102 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
|
||||
/// UI-only helper model for Vital Sign cards.
|
||||
///
|
||||
/// Keeps presentation logic (chip colors, icon colors, simple status rules)
|
||||
/// in one place so it can be reused across multiple pages.
|
||||
class VitalSignUiModel {
|
||||
final Color iconBg;
|
||||
final Color iconFg;
|
||||
final Color chipBg;
|
||||
final Color chipFg;
|
||||
|
||||
const VitalSignUiModel({
|
||||
required this.iconBg,
|
||||
required this.iconFg,
|
||||
required this.chipBg,
|
||||
required this.chipFg,
|
||||
});
|
||||
|
||||
/// Returns a color scheme for a card based on its [status] and [label].
|
||||
///
|
||||
/// Rules (mirrors existing behavior in Medical File page):
|
||||
/// - Height is always blue.
|
||||
/// - High => red scheme.
|
||||
/// - Low => yellow scheme.
|
||||
/// - Otherwise => green scheme (Normal).
|
||||
static VitalSignUiModel scheme({required String? status, required String label}) {
|
||||
final s = (status ?? '').toLowerCase();
|
||||
final l = label.toLowerCase();
|
||||
|
||||
// Height should always be blue.
|
||||
if (l.contains('height')) {
|
||||
return VitalSignUiModel(
|
||||
iconBg: AppColors.infoColor.withValues(alpha: 0.12),
|
||||
iconFg: AppColors.infoColor,
|
||||
chipBg: AppColors.infoColor.withValues(alpha: 0.12),
|
||||
chipFg: AppColors.infoColor,
|
||||
);
|
||||
}
|
||||
|
||||
if (s.contains('high')) {
|
||||
return const VitalSignUiModel(
|
||||
iconBg: AppColors.chipSecondaryLightRedColor,
|
||||
iconFg: AppColors.primaryRedColor,
|
||||
chipBg: AppColors.chipSecondaryLightRedColor,
|
||||
chipFg: AppColors.primaryRedColor,
|
||||
);
|
||||
}
|
||||
|
||||
if (s.contains('low')) {
|
||||
final Color yellowBg = AppColors.warningColor.withValues(alpha: 0.12);
|
||||
return VitalSignUiModel(
|
||||
iconBg: yellowBg,
|
||||
iconFg: AppColors.warningColor,
|
||||
chipBg: yellowBg,
|
||||
chipFg: AppColors.warningColor,
|
||||
);
|
||||
}
|
||||
|
||||
// Normal (green)
|
||||
final Color greenBg = AppColors.lightGreenColor;
|
||||
return VitalSignUiModel(
|
||||
iconBg: greenBg,
|
||||
iconFg: AppColors.bgGreenColor,
|
||||
chipBg: greenBg,
|
||||
chipFg: AppColors.bgGreenColor,
|
||||
);
|
||||
}
|
||||
|
||||
/// Simple, user-friendly classification:
|
||||
/// - Low: systolic < 90 OR diastolic < 60
|
||||
/// - High: systolic >= 140 OR diastolic >= 90
|
||||
/// - Normal: otherwise
|
||||
/// Returns null if values are missing/unparseable.
|
||||
static String? bloodPressureStatus({dynamic systolic, dynamic diastolic}) {
|
||||
final int? s = toIntOrNull(systolic);
|
||||
final int? d = toIntOrNull(diastolic);
|
||||
if (s == null || d == null) return null;
|
||||
|
||||
if (s < 90 || d < 60) return 'Low';
|
||||
if (s >= 140 || d >= 90) return 'High';
|
||||
return 'Normal';
|
||||
}
|
||||
|
||||
static int? toIntOrNull(dynamic v) {
|
||||
if (v == null) return null;
|
||||
if (v is int) return v;
|
||||
if (v is double) return v.round();
|
||||
return int.tryParse(v.toString());
|
||||
}
|
||||
|
||||
static String bmiStatus(dynamic bmi) {
|
||||
if (bmi == null) return 'N/A';
|
||||
final double bmiValue = double.tryParse(bmi.toString()) ?? 0;
|
||||
if (bmiValue < 18.5) return 'Underweight';
|
||||
if (bmiValue < 25) return 'Normal';
|
||||
if (bmiValue < 30) return 'Overweight';
|
||||
return 'High';
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,489 @@
|
||||
class GetInvoiceDetailsResponseModel {
|
||||
int? projectID;
|
||||
int? doctorID;
|
||||
num? grandTotal;
|
||||
num? quantity;
|
||||
num? total;
|
||||
num? discount;
|
||||
num? subTotal;
|
||||
int? invoiceNo;
|
||||
String? createdOn;
|
||||
String? procedureID;
|
||||
String? procedureName;
|
||||
String? procedureNameN;
|
||||
num? procedurePrice;
|
||||
num? patientShare;
|
||||
num? companyShare;
|
||||
num? totalPatientShare;
|
||||
num? totalCompanyShare;
|
||||
num? totalShare;
|
||||
num? discountAmount;
|
||||
num? vATPercentage;
|
||||
num? patientVATAmount;
|
||||
num? companyVATAmount;
|
||||
num? totalVATAmount;
|
||||
num? price;
|
||||
int? patientID;
|
||||
String? patientIdentificationNo;
|
||||
String? patientName;
|
||||
String? patientNameN;
|
||||
String? nationalityID;
|
||||
String? doctorName;
|
||||
String? doctorNameN;
|
||||
int? clinicID;
|
||||
String? clinicDescription;
|
||||
String? clinicDescriptionN;
|
||||
String? appointmentDate;
|
||||
int? appointmentNo;
|
||||
String? insuranceID;
|
||||
int? companyID;
|
||||
String? companyName;
|
||||
String? companyNameN;
|
||||
String? companyAddress;
|
||||
String? companyAddressN;
|
||||
String? companyGroupAddress;
|
||||
String? groupName;
|
||||
String? groupNameN;
|
||||
String? patientAddress;
|
||||
String? vATNo;
|
||||
String? paymentDate;
|
||||
String? projectName;
|
||||
num? totalDiscount;
|
||||
num? totalPatientShareWithQuantity;
|
||||
String? legalName;
|
||||
String? legalNameN;
|
||||
num? advanceAdjustment;
|
||||
String? patientCityName;
|
||||
String? patientCityNameN;
|
||||
String? doctorImageURL;
|
||||
List<ListConsultation>? listConsultation;
|
||||
|
||||
GetInvoiceDetailsResponseModel(
|
||||
{this.projectID,
|
||||
this.doctorID,
|
||||
this.grandTotal,
|
||||
this.quantity,
|
||||
this.total,
|
||||
this.discount,
|
||||
this.subTotal,
|
||||
this.invoiceNo,
|
||||
this.createdOn,
|
||||
this.procedureID,
|
||||
this.procedureName,
|
||||
this.procedureNameN,
|
||||
this.procedurePrice,
|
||||
this.patientShare,
|
||||
this.companyShare,
|
||||
this.totalPatientShare,
|
||||
this.totalCompanyShare,
|
||||
this.totalShare,
|
||||
this.discountAmount,
|
||||
this.vATPercentage,
|
||||
this.patientVATAmount,
|
||||
this.companyVATAmount,
|
||||
this.totalVATAmount,
|
||||
this.price,
|
||||
this.patientID,
|
||||
this.patientIdentificationNo,
|
||||
this.patientName,
|
||||
this.patientNameN,
|
||||
this.nationalityID,
|
||||
this.doctorName,
|
||||
this.doctorNameN,
|
||||
this.clinicID,
|
||||
this.clinicDescription,
|
||||
this.clinicDescriptionN,
|
||||
this.appointmentDate,
|
||||
this.appointmentNo,
|
||||
this.insuranceID,
|
||||
this.companyID,
|
||||
this.companyName,
|
||||
this.companyNameN,
|
||||
this.companyAddress,
|
||||
this.companyAddressN,
|
||||
this.companyGroupAddress,
|
||||
this.groupName,
|
||||
this.groupNameN,
|
||||
this.patientAddress,
|
||||
this.vATNo,
|
||||
this.paymentDate,
|
||||
this.projectName,
|
||||
this.totalDiscount,
|
||||
this.totalPatientShareWithQuantity,
|
||||
this.legalName,
|
||||
this.legalNameN,
|
||||
this.advanceAdjustment,
|
||||
this.patientCityName,
|
||||
this.patientCityNameN,
|
||||
this.doctorImageURL,
|
||||
this.listConsultation});
|
||||
|
||||
GetInvoiceDetailsResponseModel.fromJson(Map<String, dynamic> json) {
|
||||
projectID = json['ProjectID'];
|
||||
doctorID = json['DoctorID'];
|
||||
grandTotal = json['GrandTotal'];
|
||||
quantity = json['Quantity'];
|
||||
total = json['Total'];
|
||||
discount = json['Discount'];
|
||||
subTotal = json['SubTotal'];
|
||||
invoiceNo = json['InvoiceNo'];
|
||||
createdOn = json['CreatedOn'];
|
||||
procedureID = json['ProcedureID'];
|
||||
procedureName = json['ProcedureName'];
|
||||
procedureNameN = json['ProcedureNameN'];
|
||||
procedurePrice = json['ProcedurePrice'];
|
||||
patientShare = json['PatientShare'];
|
||||
companyShare = json['CompanyShare'];
|
||||
totalPatientShare = json['TotalPatientShare'];
|
||||
totalCompanyShare = json['TotalCompanyShare'];
|
||||
totalShare = json['TotalShare'];
|
||||
discountAmount = json['DiscountAmount'];
|
||||
vATPercentage = json['VATPercentage'];
|
||||
patientVATAmount = json['PatientVATAmount'];
|
||||
companyVATAmount = json['CompanyVATAmount'];
|
||||
totalVATAmount = json['TotalVATAmount'];
|
||||
price = json['Price'];
|
||||
patientID = json['PatientID'];
|
||||
patientIdentificationNo = json['PatientIdentificationNo'];
|
||||
patientName = json['PatientName'];
|
||||
patientNameN = json['PatientNameN'];
|
||||
nationalityID = json['NationalityID'];
|
||||
doctorName = json['DoctorName'];
|
||||
doctorNameN = json['DoctorNameN'];
|
||||
clinicID = json['ClinicID'];
|
||||
clinicDescription = json['ClinicDescription'];
|
||||
clinicDescriptionN = json['ClinicDescriptionN'];
|
||||
appointmentDate = json['AppointmentDate'];
|
||||
appointmentNo = json['AppointmentNo'];
|
||||
insuranceID = json['InsuranceID'];
|
||||
companyID = json['CompanyID'];
|
||||
companyName = json['CompanyName'];
|
||||
companyNameN = json['CompanyNameN'];
|
||||
companyAddress = json['CompanyAddress'];
|
||||
companyAddressN = json['CompanyAddressN'];
|
||||
companyGroupAddress = json['CompanyGroupAddress'];
|
||||
groupName = json['GroupName'];
|
||||
groupNameN = json['GroupNameN'];
|
||||
patientAddress = json['PatientAddress'];
|
||||
vATNo = json['VATNo'];
|
||||
paymentDate = json['PaymentDate'];
|
||||
projectName = json['ProjectName'];
|
||||
totalDiscount = json['TotalDiscount'];
|
||||
totalPatientShareWithQuantity = json['TotalPatientShareWithQuantity'];
|
||||
legalName = json['LegalName'];
|
||||
legalNameN = json['LegalNameN'];
|
||||
advanceAdjustment = json['AdvanceAdjustment'];
|
||||
patientCityName = json['PatientCityName'];
|
||||
patientCityNameN = json['PatientCityNameN'];
|
||||
doctorImageURL = json['DoctorImageURL'];
|
||||
if (json['listConsultation'] != null) {
|
||||
listConsultation = <ListConsultation>[];
|
||||
json['listConsultation'].forEach((v) {
|
||||
listConsultation!.add(new ListConsultation.fromJson(v));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['ProjectID'] = this.projectID;
|
||||
data['DoctorID'] = this.doctorID;
|
||||
data['GrandTotal'] = this.grandTotal;
|
||||
data['Quantity'] = this.quantity;
|
||||
data['Total'] = this.total;
|
||||
data['Discount'] = this.discount;
|
||||
data['SubTotal'] = this.subTotal;
|
||||
data['InvoiceNo'] = this.invoiceNo;
|
||||
data['CreatedOn'] = this.createdOn;
|
||||
data['ProcedureID'] = this.procedureID;
|
||||
data['ProcedureName'] = this.procedureName;
|
||||
data['ProcedureNameN'] = this.procedureNameN;
|
||||
data['ProcedurePrice'] = this.procedurePrice;
|
||||
data['PatientShare'] = this.patientShare;
|
||||
data['CompanyShare'] = this.companyShare;
|
||||
data['TotalPatientShare'] = this.totalPatientShare;
|
||||
data['TotalCompanyShare'] = this.totalCompanyShare;
|
||||
data['TotalShare'] = this.totalShare;
|
||||
data['DiscountAmount'] = this.discountAmount;
|
||||
data['VATPercentage'] = this.vATPercentage;
|
||||
data['PatientVATAmount'] = this.patientVATAmount;
|
||||
data['CompanyVATAmount'] = this.companyVATAmount;
|
||||
data['TotalVATAmount'] = this.totalVATAmount;
|
||||
data['Price'] = this.price;
|
||||
data['PatientID'] = this.patientID;
|
||||
data['PatientIdentificationNo'] = this.patientIdentificationNo;
|
||||
data['PatientName'] = this.patientName;
|
||||
data['PatientNameN'] = this.patientNameN;
|
||||
data['NationalityID'] = this.nationalityID;
|
||||
data['DoctorName'] = this.doctorName;
|
||||
data['DoctorNameN'] = this.doctorNameN;
|
||||
data['ClinicID'] = this.clinicID;
|
||||
data['ClinicDescription'] = this.clinicDescription;
|
||||
data['ClinicDescriptionN'] = this.clinicDescriptionN;
|
||||
data['AppointmentDate'] = this.appointmentDate;
|
||||
data['AppointmentNo'] = this.appointmentNo;
|
||||
data['InsuranceID'] = this.insuranceID;
|
||||
data['CompanyID'] = this.companyID;
|
||||
data['CompanyName'] = this.companyName;
|
||||
data['CompanyNameN'] = this.companyNameN;
|
||||
data['CompanyAddress'] = this.companyAddress;
|
||||
data['CompanyAddressN'] = this.companyAddressN;
|
||||
data['CompanyGroupAddress'] = this.companyGroupAddress;
|
||||
data['GroupName'] = this.groupName;
|
||||
data['GroupNameN'] = this.groupNameN;
|
||||
data['PatientAddress'] = this.patientAddress;
|
||||
data['VATNo'] = this.vATNo;
|
||||
data['PaymentDate'] = this.paymentDate;
|
||||
data['ProjectName'] = this.projectName;
|
||||
data['TotalDiscount'] = this.totalDiscount;
|
||||
data['TotalPatientShareWithQuantity'] = this.totalPatientShareWithQuantity;
|
||||
data['LegalName'] = this.legalName;
|
||||
data['LegalNameN'] = this.legalNameN;
|
||||
data['AdvanceAdjustment'] = this.advanceAdjustment;
|
||||
data['PatientCityName'] = this.patientCityName;
|
||||
data['PatientCityNameN'] = this.patientCityNameN;
|
||||
data['DoctorImageURL'] = this.doctorImageURL;
|
||||
if (this.listConsultation != null) {
|
||||
data['listConsultation'] =
|
||||
this.listConsultation!.map((v) => v.toJson()).toList();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class ListConsultation {
|
||||
int? projectID;
|
||||
int? doctorID;
|
||||
num? grandTotal;
|
||||
int? quantity;
|
||||
num? total;
|
||||
num? discount;
|
||||
num? subTotal;
|
||||
int? invoiceNo;
|
||||
String? createdOn;
|
||||
String? procedureID;
|
||||
String? procedureName;
|
||||
String? procedureNameN;
|
||||
num? procedurePrice;
|
||||
num? patientShare;
|
||||
num? companyShare;
|
||||
num? totalPatientShare;
|
||||
num? totalCompanyShare;
|
||||
num? totalShare;
|
||||
num? discountAmount;
|
||||
num? vATPercentage;
|
||||
num? patientVATAmount;
|
||||
num? companyVATAmount;
|
||||
num? totalVATAmount;
|
||||
num? price;
|
||||
int? patientID;
|
||||
int? patientIdentificationNo;
|
||||
String? patientName;
|
||||
String? patientNameN;
|
||||
String? nationalityID;
|
||||
String? doctorName;
|
||||
String? doctorNameN;
|
||||
int? clinicID;
|
||||
String? clinicDescription;
|
||||
String? clinicDescriptionN;
|
||||
String? appointmentDate;
|
||||
dynamic appointmentNo;
|
||||
dynamic insuranceID;
|
||||
dynamic companyID;
|
||||
String? companyName;
|
||||
String? companyNameN;
|
||||
String? companyAddress;
|
||||
String? companyAddressN;
|
||||
String? companyGroupAddress;
|
||||
String? groupName;
|
||||
String? groupNameN;
|
||||
String? patientAddress;
|
||||
String? vATNo;
|
||||
String? paymentDate;
|
||||
String? projectName;
|
||||
num? totalDiscount;
|
||||
num? totalPatientShareWithQuantity;
|
||||
String? legalName;
|
||||
String? legalNameN;
|
||||
num? advanceAdjustment;
|
||||
String? patientCityName;
|
||||
String? patientCityNameN;
|
||||
|
||||
ListConsultation(
|
||||
{this.projectID,
|
||||
this.doctorID,
|
||||
this.grandTotal,
|
||||
this.quantity,
|
||||
this.total,
|
||||
this.discount,
|
||||
this.subTotal,
|
||||
this.invoiceNo,
|
||||
this.createdOn,
|
||||
this.procedureID,
|
||||
this.procedureName,
|
||||
this.procedureNameN,
|
||||
this.procedurePrice,
|
||||
this.patientShare,
|
||||
this.companyShare,
|
||||
this.totalPatientShare,
|
||||
this.totalCompanyShare,
|
||||
this.totalShare,
|
||||
this.discountAmount,
|
||||
this.vATPercentage,
|
||||
this.patientVATAmount,
|
||||
this.companyVATAmount,
|
||||
this.totalVATAmount,
|
||||
this.price,
|
||||
this.patientID,
|
||||
this.patientIdentificationNo,
|
||||
this.patientName,
|
||||
this.patientNameN,
|
||||
this.nationalityID,
|
||||
this.doctorName,
|
||||
this.doctorNameN,
|
||||
this.clinicID,
|
||||
this.clinicDescription,
|
||||
this.clinicDescriptionN,
|
||||
this.appointmentDate,
|
||||
this.appointmentNo,
|
||||
this.insuranceID,
|
||||
this.companyID,
|
||||
this.companyName,
|
||||
this.companyNameN,
|
||||
this.companyAddress,
|
||||
this.companyAddressN,
|
||||
this.companyGroupAddress,
|
||||
this.groupName,
|
||||
this.groupNameN,
|
||||
this.patientAddress,
|
||||
this.vATNo,
|
||||
this.paymentDate,
|
||||
this.projectName,
|
||||
this.totalDiscount,
|
||||
this.totalPatientShareWithQuantity,
|
||||
this.legalName,
|
||||
this.legalNameN,
|
||||
this.advanceAdjustment,
|
||||
this.patientCityName,
|
||||
this.patientCityNameN});
|
||||
|
||||
ListConsultation.fromJson(Map<String, dynamic> json) {
|
||||
projectID = json['ProjectID'];
|
||||
doctorID = json['DoctorID'];
|
||||
grandTotal = json['GrandTotal'];
|
||||
quantity = json['Quantity'];
|
||||
total = json['Total'];
|
||||
discount = json['Discount'];
|
||||
subTotal = json['SubTotal'];
|
||||
invoiceNo = json['InvoiceNo'];
|
||||
createdOn = json['CreatedOn'];
|
||||
procedureID = json['ProcedureID'];
|
||||
procedureName = json['ProcedureName'];
|
||||
procedureNameN = json['ProcedureNameN'];
|
||||
procedurePrice = json['ProcedurePrice'];
|
||||
patientShare = json['PatientShare'];
|
||||
companyShare = json['CompanyShare'];
|
||||
totalPatientShare = json['TotalPatientShare'];
|
||||
totalCompanyShare = json['TotalCompanyShare'];
|
||||
totalShare = json['TotalShare'];
|
||||
discountAmount = json['DiscountAmount'];
|
||||
vATPercentage = json['VATPercentage'];
|
||||
patientVATAmount = json['PatientVATAmount'];
|
||||
companyVATAmount = json['CompanyVATAmount'];
|
||||
totalVATAmount = json['TotalVATAmount'];
|
||||
price = json['Price'];
|
||||
patientID = json['PatientID'];
|
||||
patientIdentificationNo = json['PatientIdentificationNo'];
|
||||
patientName = json['PatientName'];
|
||||
patientNameN = json['PatientNameN'];
|
||||
nationalityID = json['NationalityID'];
|
||||
doctorName = json['DoctorName'];
|
||||
doctorNameN = json['DoctorNameN'];
|
||||
clinicID = json['ClinicID'];
|
||||
clinicDescription = json['ClinicDescription'];
|
||||
clinicDescriptionN = json['ClinicDescriptionN'];
|
||||
appointmentDate = json['AppointmentDate'];
|
||||
appointmentNo = json['AppointmentNo'];
|
||||
insuranceID = json['InsuranceID'];
|
||||
companyID = json['CompanyID'];
|
||||
companyName = json['CompanyName'];
|
||||
companyNameN = json['CompanyNameN'];
|
||||
companyAddress = json['CompanyAddress'];
|
||||
companyAddressN = json['CompanyAddressN'];
|
||||
companyGroupAddress = json['CompanyGroupAddress'];
|
||||
groupName = json['GroupName'];
|
||||
groupNameN = json['GroupNameN'];
|
||||
patientAddress = json['PatientAddress'];
|
||||
vATNo = json['VATNo'];
|
||||
paymentDate = json['PaymentDate'];
|
||||
projectName = json['ProjectName'];
|
||||
totalDiscount = json['TotalDiscount'];
|
||||
totalPatientShareWithQuantity = json['TotalPatientShareWithQuantity'];
|
||||
legalName = json['LegalName'];
|
||||
legalNameN = json['LegalNameN'];
|
||||
advanceAdjustment = json['AdvanceAdjustment'];
|
||||
patientCityName = json['PatientCityName'];
|
||||
patientCityNameN = json['PatientCityNameN'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['ProjectID'] = this.projectID;
|
||||
data['DoctorID'] = this.doctorID;
|
||||
data['GrandTotal'] = this.grandTotal;
|
||||
data['Quantity'] = this.quantity;
|
||||
data['Total'] = this.total;
|
||||
data['Discount'] = this.discount;
|
||||
data['SubTotal'] = this.subTotal;
|
||||
data['InvoiceNo'] = this.invoiceNo;
|
||||
data['CreatedOn'] = this.createdOn;
|
||||
data['ProcedureID'] = this.procedureID;
|
||||
data['ProcedureName'] = this.procedureName;
|
||||
data['ProcedureNameN'] = this.procedureNameN;
|
||||
data['ProcedurePrice'] = this.procedurePrice;
|
||||
data['PatientShare'] = this.patientShare;
|
||||
data['CompanyShare'] = this.companyShare;
|
||||
data['TotalPatientShare'] = this.totalPatientShare;
|
||||
data['TotalCompanyShare'] = this.totalCompanyShare;
|
||||
data['TotalShare'] = this.totalShare;
|
||||
data['DiscountAmount'] = this.discountAmount;
|
||||
data['VATPercentage'] = this.vATPercentage;
|
||||
data['PatientVATAmount'] = this.patientVATAmount;
|
||||
data['CompanyVATAmount'] = this.companyVATAmount;
|
||||
data['TotalVATAmount'] = this.totalVATAmount;
|
||||
data['Price'] = this.price;
|
||||
data['PatientID'] = this.patientID;
|
||||
data['PatientIdentificationNo'] = this.patientIdentificationNo;
|
||||
data['PatientName'] = this.patientName;
|
||||
data['PatientNameN'] = this.patientNameN;
|
||||
data['NationalityID'] = this.nationalityID;
|
||||
data['DoctorName'] = this.doctorName;
|
||||
data['DoctorNameN'] = this.doctorNameN;
|
||||
data['ClinicID'] = this.clinicID;
|
||||
data['ClinicDescription'] = this.clinicDescription;
|
||||
data['ClinicDescriptionN'] = this.clinicDescriptionN;
|
||||
data['AppointmentDate'] = this.appointmentDate;
|
||||
data['AppointmentNo'] = this.appointmentNo;
|
||||
data['InsuranceID'] = this.insuranceID;
|
||||
data['CompanyID'] = this.companyID;
|
||||
data['CompanyName'] = this.companyName;
|
||||
data['CompanyNameN'] = this.companyNameN;
|
||||
data['CompanyAddress'] = this.companyAddress;
|
||||
data['CompanyAddressN'] = this.companyAddressN;
|
||||
data['CompanyGroupAddress'] = this.companyGroupAddress;
|
||||
data['GroupName'] = this.groupName;
|
||||
data['GroupNameN'] = this.groupNameN;
|
||||
data['PatientAddress'] = this.patientAddress;
|
||||
data['VATNo'] = this.vATNo;
|
||||
data['PaymentDate'] = this.paymentDate;
|
||||
data['ProjectName'] = this.projectName;
|
||||
data['TotalDiscount'] = this.totalDiscount;
|
||||
data['TotalPatientShareWithQuantity'] = this.totalPatientShareWithQuantity;
|
||||
data['LegalName'] = this.legalName;
|
||||
data['LegalNameN'] = this.legalNameN;
|
||||
data['AdvanceAdjustment'] = this.advanceAdjustment;
|
||||
data['PatientCityName'] = this.patientCityName;
|
||||
data['PatientCityNameN'] = this.patientCityNameN;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
class GetInvoicesListResponseModel {
|
||||
String? setupId;
|
||||
int? projectID;
|
||||
int? patientID;
|
||||
int? appointmentNo;
|
||||
String? appointmentDate;
|
||||
String? appointmentDateN;
|
||||
int? clinicID;
|
||||
int? doctorID;
|
||||
int? invoiceNo;
|
||||
int? status;
|
||||
String? arrivedOn;
|
||||
String? doctorName;
|
||||
String? doctorNameN;
|
||||
String? clinicName;
|
||||
double? decimalDoctorRate;
|
||||
String? doctorImageURL;
|
||||
int? doctorRate;
|
||||
int? patientNumber;
|
||||
String? projectName;
|
||||
|
||||
GetInvoicesListResponseModel(
|
||||
{this.setupId,
|
||||
this.projectID,
|
||||
this.patientID,
|
||||
this.appointmentNo,
|
||||
this.appointmentDate,
|
||||
this.appointmentDateN,
|
||||
this.clinicID,
|
||||
this.doctorID,
|
||||
this.invoiceNo,
|
||||
this.status,
|
||||
this.arrivedOn,
|
||||
this.doctorName,
|
||||
this.doctorNameN,
|
||||
this.clinicName,
|
||||
this.decimalDoctorRate,
|
||||
this.doctorImageURL,
|
||||
this.doctorRate,
|
||||
this.patientNumber,
|
||||
this.projectName});
|
||||
|
||||
GetInvoicesListResponseModel.fromJson(Map<String, dynamic> json) {
|
||||
setupId = json['SetupId'];
|
||||
projectID = json['ProjectID'];
|
||||
patientID = json['PatientID'];
|
||||
appointmentNo = json['AppointmentNo'];
|
||||
appointmentDate = json['AppointmentDate'];
|
||||
appointmentDateN = json['AppointmentDateN'];
|
||||
clinicID = json['ClinicID'];
|
||||
doctorID = json['DoctorID'];
|
||||
invoiceNo = json['InvoiceNo'];
|
||||
status = json['Status'];
|
||||
arrivedOn = json['ArrivedOn'];
|
||||
doctorName = json['DoctorName'];
|
||||
doctorNameN = json['DoctorNameN'];
|
||||
clinicName = json['ClinicName'];
|
||||
decimalDoctorRate = json['DecimalDoctorRate'];
|
||||
doctorImageURL = json['DoctorImageURL'];
|
||||
doctorRate = json['DoctorRate'];
|
||||
patientNumber = json['PatientNumber'];
|
||||
projectName = json['ProjectName'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['SetupId'] = this.setupId;
|
||||
data['ProjectID'] = this.projectID;
|
||||
data['PatientID'] = this.patientID;
|
||||
data['AppointmentNo'] = this.appointmentNo;
|
||||
data['AppointmentDate'] = this.appointmentDate;
|
||||
data['AppointmentDateN'] = this.appointmentDateN;
|
||||
data['ClinicID'] = this.clinicID;
|
||||
data['DoctorID'] = this.doctorID;
|
||||
data['InvoiceNo'] = this.invoiceNo;
|
||||
data['Status'] = this.status;
|
||||
data['ArrivedOn'] = this.arrivedOn;
|
||||
data['DoctorName'] = this.doctorName;
|
||||
data['DoctorNameN'] = this.doctorNameN;
|
||||
data['ClinicName'] = this.clinicName;
|
||||
data['DecimalDoctorRate'] = this.decimalDoctorRate;
|
||||
data['DoctorImageURL'] = this.doctorImageURL;
|
||||
data['DoctorRate'] = this.doctorRate;
|
||||
data['PatientNumber'] = this.patientNumber;
|
||||
data['ProjectName'] = this.projectName;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,141 @@
|
||||
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/my_invoices/models/get_invoice_details_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoices_list_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/services/logger_service.dart';
|
||||
|
||||
abstract class MyInvoicesRepo {
|
||||
Future<Either<Failure, GenericApiModel<List<GetInvoicesListResponseModel>>>> getAllInvoicesList();
|
||||
|
||||
Future<Either<Failure, GenericApiModel<GetInvoiceDetailsResponseModel>>> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID});
|
||||
|
||||
Future<Either<Failure, GenericApiModel<dynamic>>> sendInvoiceEmail({required num appointmentNo, required int projectID});
|
||||
}
|
||||
|
||||
class MyInvoicesRepoImp implements MyInvoicesRepo {
|
||||
final ApiClient apiClient;
|
||||
final LoggerService loggerService;
|
||||
|
||||
MyInvoicesRepoImp({required this.loggerService, required this.apiClient});
|
||||
|
||||
@override
|
||||
Future<Either<Failure, GenericApiModel<List<GetInvoicesListResponseModel>>>> getAllInvoicesList() async {
|
||||
Map<String, dynamic> mapDevice = {};
|
||||
|
||||
try {
|
||||
GenericApiModel<List<GetInvoicesListResponseModel>>? apiResponse;
|
||||
Failure? failure;
|
||||
await apiClient.post(
|
||||
GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC,
|
||||
body: mapDevice,
|
||||
onFailure: (error, statusCode, {messageStatus, failureType}) {
|
||||
failure = failureType;
|
||||
},
|
||||
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
|
||||
try {
|
||||
final list = response['List_DentalAppointments'];
|
||||
|
||||
final invoicesList = list.map((item) => GetInvoicesListResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<GetInvoicesListResponseModel>();
|
||||
|
||||
apiResponse = GenericApiModel<List<GetInvoicesListResponseModel>>(
|
||||
messageStatus: messageStatus,
|
||||
statusCode: statusCode,
|
||||
errorMessage: null,
|
||||
data: invoicesList,
|
||||
);
|
||||
} 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<GetInvoiceDetailsResponseModel>>> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID}) async {
|
||||
Map<String, dynamic> mapDevice = {
|
||||
"AppointmentNo": appointmentNo,
|
||||
"InvoiceNo": invoiceNo,
|
||||
"IsRegistered": true,
|
||||
"ProjectID": projectID,
|
||||
};
|
||||
|
||||
try {
|
||||
GenericApiModel<GetInvoiceDetailsResponseModel>? apiResponse;
|
||||
Failure? failure;
|
||||
await apiClient.post(
|
||||
GET_DENTAL_APPOINTMENT_INVOICE,
|
||||
body: mapDevice,
|
||||
onFailure: (error, statusCode, {messageStatus, failureType}) {
|
||||
failure = failureType;
|
||||
},
|
||||
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
|
||||
try {
|
||||
final list = response['List_eInvoiceForDental'];
|
||||
final invoicesList = GetInvoiceDetailsResponseModel.fromJson(list[0]);
|
||||
|
||||
apiResponse = GenericApiModel<GetInvoiceDetailsResponseModel>(
|
||||
messageStatus: messageStatus,
|
||||
statusCode: statusCode,
|
||||
errorMessage: null,
|
||||
data: invoicesList,
|
||||
);
|
||||
} 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>> sendInvoiceEmail({required num appointmentNo, required int projectID}) async {
|
||||
Map<String, dynamic> mapDevice = {
|
||||
"AppointmentNo": appointmentNo,
|
||||
"IsRegistered": true,
|
||||
"ProjectID": projectID,
|
||||
};
|
||||
|
||||
try {
|
||||
GenericApiModel<GetInvoiceDetailsResponseModel>? apiResponse;
|
||||
Failure? failure;
|
||||
await apiClient.post(
|
||||
SEND_DENTAL_APPOINTMENT_INVOICE_EMAIL,
|
||||
body: mapDevice,
|
||||
onFailure: (error, statusCode, {messageStatus, failureType}) {
|
||||
failure = failureType;
|
||||
},
|
||||
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
|
||||
try {
|
||||
apiResponse = GenericApiModel(
|
||||
messageStatus: messageStatus,
|
||||
statusCode: statusCode,
|
||||
errorMessage: null,
|
||||
data: response,
|
||||
);
|
||||
} 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,99 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoice_details_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoices_list_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_repo.dart';
|
||||
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
|
||||
import 'package:hmg_patient_app_new/services/navigation_service.dart';
|
||||
|
||||
class MyInvoicesViewModel extends ChangeNotifier {
|
||||
bool isInvoicesListLoading = false;
|
||||
bool isInvoiceDetailsLoading = false;
|
||||
|
||||
MyInvoicesRepo myInvoicesRepo;
|
||||
ErrorHandlerService errorHandlerService;
|
||||
NavigationService navServices;
|
||||
|
||||
List<GetInvoicesListResponseModel> allInvoicesList = [];
|
||||
late GetInvoiceDetailsResponseModel invoiceDetailsResponseModel;
|
||||
|
||||
MyInvoicesViewModel({required this.myInvoicesRepo, required this.errorHandlerService, required this.navServices});
|
||||
|
||||
setInvoicesListLoading() {
|
||||
isInvoicesListLoading = true;
|
||||
allInvoicesList.clear();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
setInvoiceDetailLoading() {
|
||||
isInvoiceDetailsLoading = true;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> getAllInvoicesList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
||||
final result = await myInvoicesRepo.getAllInvoicesList();
|
||||
|
||||
result.fold(
|
||||
(failure) async {
|
||||
isInvoicesListLoading = false;
|
||||
notifyListeners();
|
||||
},
|
||||
(apiResponse) {
|
||||
if (apiResponse.messageStatus == 2) {
|
||||
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
|
||||
} else if (apiResponse.messageStatus == 1) {
|
||||
allInvoicesList = apiResponse.data!;
|
||||
isInvoicesListLoading = false;
|
||||
|
||||
notifyListeners();
|
||||
if (onSuccess != null) {
|
||||
onSuccess(apiResponse);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
||||
final result = await myInvoicesRepo.getInvoiceDetails(appointmentNo: appointmentNo, invoiceNo: invoiceNo, projectID: projectID);
|
||||
|
||||
result.fold(
|
||||
(failure) async {
|
||||
isInvoiceDetailsLoading = false;
|
||||
notifyListeners();
|
||||
},
|
||||
(apiResponse) {
|
||||
if (apiResponse.messageStatus == 2) {
|
||||
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
|
||||
} else if (apiResponse.messageStatus == 1) {
|
||||
invoiceDetailsResponseModel = apiResponse.data!;
|
||||
isInvoiceDetailsLoading = false;
|
||||
|
||||
notifyListeners();
|
||||
if (onSuccess != null) {
|
||||
onSuccess(apiResponse);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> sendInvoiceEmail({required num appointmentNo, required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
||||
final result = await myInvoicesRepo.sendInvoiceEmail(appointmentNo: appointmentNo, projectID: projectID);
|
||||
|
||||
result.fold(
|
||||
(failure) async {
|
||||
notifyListeners();
|
||||
},
|
||||
(apiResponse) {
|
||||
if (apiResponse.messageStatus == 2) {
|
||||
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
|
||||
} else if (apiResponse.messageStatus == 1) {
|
||||
notifyListeners();
|
||||
if (onSuccess != null) {
|
||||
onSuccess(apiResponse);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,272 @@
|
||||
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/date_util.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/my_invoices/models/get_invoice_details_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class MyInvoicesDetailsPage extends StatefulWidget {
|
||||
GetInvoiceDetailsResponseModel getInvoiceDetailsResponseModel;
|
||||
|
||||
MyInvoicesDetailsPage({super.key, required this.getInvoiceDetailsResponseModel});
|
||||
|
||||
@override
|
||||
State<MyInvoicesDetailsPage> createState() => _MyInvoicesDetailsPageState();
|
||||
}
|
||||
|
||||
class _MyInvoicesDetailsPageState extends State<MyInvoicesDetailsPage> {
|
||||
late MyInvoicesViewModel myInvoicesViewModel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
myInvoicesViewModel = Provider.of<MyInvoicesViewModel>(context, listen: false);
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.bgScaffoldColor,
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CollapsingListView(
|
||||
title: "Invoice Details".needTranslation,
|
||||
sendEmail: () async {
|
||||
LoaderBottomSheet.showLoader(loadingText: "Sending email, Please wait...".needTranslation);
|
||||
await myInvoicesViewModel.sendInvoiceEmail(
|
||||
appointmentNo: widget.getInvoiceDetailsResponseModel.appointmentNo!,
|
||||
projectID: widget.getInvoiceDetailsResponseModel.projectID!,
|
||||
onSuccess: (val) {
|
||||
LoaderBottomSheet.hideLoader();
|
||||
showCommonBottomSheetWithoutHeight(
|
||||
context,
|
||||
child: Utils.getSuccessWidget(loadingText: "Email sent successfully.".needTranslation),
|
||||
callBackFunc: () {},
|
||||
isFullScreen: false,
|
||||
isCloseButtonVisible: true,
|
||||
);
|
||||
},
|
||||
onError: (err) {
|
||||
LoaderBottomSheet.hideLoader();
|
||||
showCommonBottomSheetWithoutHeight(
|
||||
context,
|
||||
child: Utils.getErrorWidget(loadingText: err),
|
||||
callBackFunc: () {},
|
||||
isFullScreen: false,
|
||||
isCloseButtonVisible: true,
|
||||
);
|
||||
});
|
||||
},
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(24.h),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: 20.h,
|
||||
hasShadow: true,
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(14.h),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
Image.network(
|
||||
widget.getInvoiceDetailsResponseModel.doctorImageURL!,
|
||||
width: 63.h,
|
||||
height: 63.h,
|
||||
fit: BoxFit.cover,
|
||||
).circle(100.r),
|
||||
],
|
||||
),
|
||||
SizedBox(width: 16.w),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
(getIt<AppState>().isArabic() ? widget.getInvoiceDetailsResponseModel.doctorNameN! : widget.getInvoiceDetailsResponseModel.doctorName!).toText16(isBold: true),
|
||||
SizedBox(height: 8.h),
|
||||
Wrap(
|
||||
direction: Axis.horizontal,
|
||||
spacing: 6.w,
|
||||
runSpacing: 6.h,
|
||||
children: [
|
||||
AppCustomChipWidget(
|
||||
labelText: "${LocaleKeys.invoiceNo}: ${widget.getInvoiceDetailsResponseModel.invoiceNo!}",
|
||||
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
|
||||
),
|
||||
AppCustomChipWidget(
|
||||
labelText: (widget.getInvoiceDetailsResponseModel.clinicDescription!.length > 15
|
||||
? '${widget.getInvoiceDetailsResponseModel.clinicDescription!.substring(0, 12)}...'
|
||||
: widget.getInvoiceDetailsResponseModel.clinicDescription!),
|
||||
labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w),
|
||||
),
|
||||
AppCustomChipWidget(
|
||||
labelText: widget.getInvoiceDetailsResponseModel.projectName!,
|
||||
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
|
||||
),
|
||||
AppCustomChipWidget(
|
||||
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
|
||||
icon: AppAssets.doctor_calendar_icon,
|
||||
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.getInvoiceDetailsResponseModel.appointmentDate), false),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
Container(
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: 20.h,
|
||||
hasShadow: true,
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(14.h),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
widget.getInvoiceDetailsResponseModel.listConsultation!.first.procedureName!.toText16(isBold: true),
|
||||
SizedBox(height: 16.h),
|
||||
Wrap(
|
||||
direction: Axis.horizontal,
|
||||
spacing: 6.w,
|
||||
runSpacing: 6.h,
|
||||
children: [
|
||||
AppCustomChipWidget(
|
||||
labelText: "${LocaleKeys.quantity.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.quantity!}",
|
||||
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
|
||||
),
|
||||
AppCustomChipWidget(
|
||||
labelText: "${LocaleKeys.price.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.price!} ${LocaleKeys.sar.tr()}",
|
||||
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
|
||||
),
|
||||
AppCustomChipWidget(
|
||||
labelText: "${LocaleKeys.total.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.total!} ${LocaleKeys.sar.tr()}",
|
||||
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
Container(
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: 20.h,
|
||||
hasShadow: true,
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(14.h),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
"Insurance Details".toText16(isBold: true),
|
||||
SizedBox(height: 16.h),
|
||||
widget.getInvoiceDetailsResponseModel.groupName!.toText14(isBold: true),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: widget.getInvoiceDetailsResponseModel.companyName!.toText14(isBold: true)),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 12.h),
|
||||
Row(
|
||||
children: [
|
||||
AppCustomChipWidget(
|
||||
labelText: "Insurance ID: ${widget.getInvoiceDetailsResponseModel.insuranceID ?? "-"}",
|
||||
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: 24.h,
|
||||
hasShadow: false,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 24.h),
|
||||
"Total Balance".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
|
||||
SizedBox(height: 17.h),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
"Amount before tax".needTranslation.toText14(isBold: true),
|
||||
Utils.getPaymentAmountWithSymbol(widget.getInvoiceDetailsResponseModel.listConsultation!.first.totalShare.toString().toText16(isBold: true), AppColors.blackColor, 13,
|
||||
isSaudiCurrency: true),
|
||||
],
|
||||
).paddingSymmetrical(24.h, 0.h),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor),
|
||||
Utils.getPaymentAmountWithSymbol(
|
||||
widget.getInvoiceDetailsResponseModel.listConsultation!.first.totalVATAmount!.toString().toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13,
|
||||
isSaudiCurrency: true),
|
||||
],
|
||||
).paddingSymmetrical(24.h, 0.h),
|
||||
SizedBox(height: 16.h),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
"Discount".needTranslation.toText14(isBold: true),
|
||||
Utils.getPaymentAmountWithSymbol(widget.getInvoiceDetailsResponseModel.listConsultation!.first.discountAmount!.toString().toText14(isBold: true, color: AppColors.primaryRedColor),
|
||||
AppColors.primaryRedColor, 13,
|
||||
isSaudiCurrency: true),
|
||||
],
|
||||
).paddingSymmetrical(24.h, 0.h),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
"Paid".needTranslation.toText14(isBold: true),
|
||||
Utils.getPaymentAmountWithSymbol(
|
||||
widget.getInvoiceDetailsResponseModel.listConsultation!.first.grandTotal!.toString().toText14(isBold: true, color: AppColors.textColor), AppColors.textColor, 13,
|
||||
isSaudiCurrency: true),
|
||||
],
|
||||
).paddingSymmetrical(24.h, 0.h),
|
||||
SizedBox(height: 24.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_staggered_animations/flutter_staggered_animations.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/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/my_invoices/my_invoices_details_page.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/my_invoices/widgets/invoice_list_card.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/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:provider/provider.dart';
|
||||
|
||||
class MyInvoicesList extends StatefulWidget {
|
||||
const MyInvoicesList({super.key});
|
||||
|
||||
@override
|
||||
State<MyInvoicesList> createState() => _MyInvoicesListState();
|
||||
}
|
||||
|
||||
class _MyInvoicesListState extends State<MyInvoicesList> {
|
||||
late MyInvoicesViewModel myInvoicesViewModel;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
scheduleMicrotask(() {
|
||||
myInvoicesViewModel.setInvoicesListLoading();
|
||||
myInvoicesViewModel.getAllInvoicesList();
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
myInvoicesViewModel = Provider.of<MyInvoicesViewModel>(context, listen: false);
|
||||
return CollapsingListView(
|
||||
title: LocaleKeys.invoiceList.tr(context: context),
|
||||
child: SingleChildScrollView(
|
||||
child: Consumer<MyInvoicesViewModel>(builder: (context, myInvoicesVM, child) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 24.h),
|
||||
ListView.builder(
|
||||
itemCount: myInvoicesVM.isInvoicesListLoading ? 4 : myInvoicesVM.allInvoicesList.length,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsetsGeometry.zero,
|
||||
itemBuilder: (context, index) {
|
||||
return myInvoicesVM.isInvoicesListLoading
|
||||
? LabResultItemView(
|
||||
onTap: () {},
|
||||
labOrder: null,
|
||||
index: index,
|
||||
isLoading: true,
|
||||
)
|
||||
: AnimationConfiguration.staggeredList(
|
||||
position: index,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
child: SlideAnimation(
|
||||
verticalOffset: 100.0,
|
||||
child: FadeInAnimation(
|
||||
child: AnimatedContainer(
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
child: InvoiceListCard(
|
||||
getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index],
|
||||
onTap: () async {
|
||||
myInvoicesVM.setInvoiceDetailLoading();
|
||||
LoaderBottomSheet.showLoader(loadingText: "Fetching invoice details, Please wait...".needTranslation);
|
||||
await myInvoicesVM.getInvoiceDetails(
|
||||
appointmentNo: myInvoicesVM.allInvoicesList[index].appointmentNo!,
|
||||
invoiceNo: myInvoicesVM.allInvoicesList[index].invoiceNo!,
|
||||
projectID: myInvoicesVM.allInvoicesList[index].projectID!,
|
||||
onSuccess: (val) {
|
||||
LoaderBottomSheet.hideLoader();
|
||||
Navigator.of(context).push(
|
||||
CustomPageRoute(
|
||||
page: MyInvoicesDetailsPage(getInvoiceDetailsResponseModel: myInvoicesVM.invoiceDetailsResponseModel),
|
||||
),
|
||||
);
|
||||
},
|
||||
onError: (err) {
|
||||
LoaderBottomSheet.hideLoader();
|
||||
showCommonBottomSheetWithoutHeight(
|
||||
context,
|
||||
child: Utils.getErrorWidget(loadingText: err),
|
||||
callBackFunc: () {},
|
||||
isFullScreen: false,
|
||||
isCloseButtonVisible: true,
|
||||
);
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).paddingSymmetrical(24.w, 0.h),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,151 @@
|
||||
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/date_util.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/my_invoices/models/get_invoices_list_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
|
||||
|
||||
class InvoiceListCard extends StatelessWidget {
|
||||
final GetInvoicesListResponseModel getInvoicesListResponseModel;
|
||||
Function? onTap;
|
||||
|
||||
InvoiceListCard({super.key, required this.getInvoicesListResponseModel, required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: 20.h,
|
||||
hasShadow: true,
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(14.h),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Wrap(
|
||||
alignment: WrapAlignment.start,
|
||||
direction: Axis.horizontal,
|
||||
spacing: 6.w,
|
||||
runSpacing: 6.h,
|
||||
children: [
|
||||
AppCustomChipWidget(
|
||||
icon: AppAssets.walkin_appointment_icon,
|
||||
iconColor: AppColors.textColor,
|
||||
labelText: 'Walk In'.needTranslation,
|
||||
textColor: AppColors.textColor,
|
||||
),
|
||||
AppCustomChipWidget(
|
||||
labelText: 'OutPatient'.needTranslation,
|
||||
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1),
|
||||
textColor: AppColors.primaryRedColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
Image.network(
|
||||
getInvoicesListResponseModel.doctorImageURL!,
|
||||
width: 63.h,
|
||||
height: 63.h,
|
||||
fit: BoxFit.cover,
|
||||
).circle(100.r),
|
||||
Transform.translate(
|
||||
offset: Offset(0.0, -20.h),
|
||||
child: Container(
|
||||
width: 40.w,
|
||||
height: 40.h,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
shape: BoxShape.circle, // Makes the container circular
|
||||
border: Border.all(
|
||||
color: AppColors.scaffoldBgColor, // Color of the border
|
||||
width: 1.5.w, // Width of the border
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h),
|
||||
SizedBox(height: 2.h),
|
||||
"${getInvoicesListResponseModel.decimalDoctorRate}".toText11(isBold: true, color: AppColors.textColor),
|
||||
],
|
||||
),
|
||||
).circle(100),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(width: 16.w),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
(getIt<AppState>().isArabic() ? getInvoicesListResponseModel.doctorNameN! : getInvoicesListResponseModel.doctorName!).toText16(isBold: true),
|
||||
SizedBox(height: 8.h),
|
||||
Wrap(
|
||||
direction: Axis.horizontal,
|
||||
spacing: 6.w,
|
||||
runSpacing: 6.h,
|
||||
children: [
|
||||
AppCustomChipWidget(
|
||||
labelText: "${LocaleKeys.invoiceNo}: ${getInvoicesListResponseModel.invoiceNo!}",
|
||||
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
|
||||
),
|
||||
AppCustomChipWidget(
|
||||
labelText:
|
||||
(getInvoicesListResponseModel.clinicName!.length > 15 ? '${getInvoicesListResponseModel.clinicName!.substring(0, 12)}...' : getInvoicesListResponseModel.clinicName!),
|
||||
labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w),
|
||||
),
|
||||
AppCustomChipWidget(
|
||||
labelText: getInvoicesListResponseModel.projectName!,
|
||||
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
|
||||
),
|
||||
AppCustomChipWidget(
|
||||
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
|
||||
icon: AppAssets.doctor_calendar_icon,
|
||||
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(getInvoicesListResponseModel.appointmentDate), false),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
CustomButton(
|
||||
text: "View invoice details".needTranslation,
|
||||
onPressed: () {
|
||||
if (onTap != null) {
|
||||
onTap!();
|
||||
}
|
||||
},
|
||||
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1),
|
||||
borderColor: AppColors.primaryRedColor.withValues(alpha: 0.01),
|
||||
textColor: AppColors.primaryRedColor,
|
||||
fontSize: 14.f,
|
||||
fontWeight: FontWeight.w500,
|
||||
borderRadius: 12.r,
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
height: 40.h,
|
||||
iconSize: 14.h,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
).paddingOnly(bottom: 16.h);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
|
||||
class VitalSignShimmerWidget extends StatelessWidget {
|
||||
const VitalSignShimmerWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
// BMI Card Shimmer
|
||||
Expanded(child: _buildShimmerCard()),
|
||||
SizedBox(width: 8.w),
|
||||
// Height Card Shimmer
|
||||
Expanded(child: _buildShimmerCard()),
|
||||
SizedBox(width: 8.w),
|
||||
// Weight Card Shimmer
|
||||
Expanded(child: _buildShimmerCard()),
|
||||
SizedBox(width: 8.w),
|
||||
// Blood Pressure Card Shimmer
|
||||
Expanded(child: _buildShimmerCard()),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildShimmerCard() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: BorderRadius.circular(12.r),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Icon shimmer
|
||||
Container(
|
||||
width: 32.w,
|
||||
height: 32.h,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8.r),
|
||||
),
|
||||
).toShimmer(),
|
||||
SizedBox(height: 8.h),
|
||||
// Label shimmer
|
||||
Container(
|
||||
width: 50.w,
|
||||
height: 10.h,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4.r),
|
||||
),
|
||||
).toShimmer(),
|
||||
SizedBox(height: 4.h),
|
||||
// Value shimmer
|
||||
Container(
|
||||
width: 40.w,
|
||||
height: 16.h,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4.r),
|
||||
),
|
||||
).toShimmer(),
|
||||
SizedBox(height: 4.h),
|
||||
// Chip shimmer
|
||||
Container(
|
||||
width: 45.w,
|
||||
height: 18.h,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12.r),
|
||||
),
|
||||
).toShimmer(),
|
||||
SizedBox(height: 4.h),
|
||||
// Arrow shimmer
|
||||
Align(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
child: Container(
|
||||
width: 10.w,
|
||||
height: 10.h,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(2.r),
|
||||
),
|
||||
).toShimmer(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||