diff --git a/assets/images/svg/book_appo_bottom.svg b/assets/images/svg/book_appo_bottom.svg
new file mode 100644
index 0000000..d09107e
--- /dev/null
+++ b/assets/images/svg/book_appo_bottom.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/svg/doctor_calendar_icon.svg b/assets/images/svg/doctor_calendar_icon.svg
new file mode 100644
index 0000000..f76c49f
--- /dev/null
+++ b/assets/images/svg/doctor_calendar_icon.svg
@@ -0,0 +1,8 @@
+
diff --git a/assets/images/svg/eye_results_icon.svg b/assets/images/svg/eye_results_icon.svg
new file mode 100644
index 0000000..fd9c754
--- /dev/null
+++ b/assets/images/svg/eye_results_icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/images/svg/forward_arrow_icon.svg b/assets/images/svg/forward_arrow_icon.svg
new file mode 100644
index 0000000..d8a3d51
--- /dev/null
+++ b/assets/images/svg/forward_arrow_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/svg/home_bottom.svg b/assets/images/svg/home_bottom.svg
new file mode 100644
index 0000000..1bf82f9
--- /dev/null
+++ b/assets/images/svg/home_bottom.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/svg/my_files_bottom.svg b/assets/images/svg/my_files_bottom.svg
new file mode 100644
index 0000000..813805e
--- /dev/null
+++ b/assets/images/svg/my_files_bottom.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/images/svg/prescription_refill_icon.svg b/assets/images/svg/prescription_refill_icon.svg
new file mode 100644
index 0000000..7a9706b
--- /dev/null
+++ b/assets/images/svg/prescription_refill_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/svg/prescription_remarks_icon.svg b/assets/images/svg/prescription_remarks_icon.svg
new file mode 100644
index 0000000..a8d7adb
--- /dev/null
+++ b/assets/images/svg/prescription_remarks_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/svg/rating_icon.svg b/assets/images/svg/rating_icon.svg
new file mode 100644
index 0000000..dee25d4
--- /dev/null
+++ b/assets/images/svg/rating_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/svg/search_icon.svg b/assets/images/svg/search_icon.svg
new file mode 100644
index 0000000..1a64ce5
--- /dev/null
+++ b/assets/images/svg/search_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/svg/services_bottom.svg b/assets/images/svg/services_bottom.svg
new file mode 100644
index 0000000..baa3d6b
--- /dev/null
+++ b/assets/images/svg/services_bottom.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/images/svg/todo_bottom.svg b/assets/images/svg/todo_bottom.svg
new file mode 100644
index 0000000..ab49757
--- /dev/null
+++ b/assets/images/svg/todo_bottom.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/svg/view_report_icon.svg b/assets/images/svg/view_report_icon.svg
new file mode 100644
index 0000000..0f7d866
--- /dev/null
+++ b/assets/images/svg/view_report_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/json/countriesList.json b/assets/json/countriesList.json
new file mode 100644
index 0000000..25a65b3
--- /dev/null
+++ b/assets/json/countriesList.json
@@ -0,0 +1,1212 @@
+[
+ {
+ "ID": "AFG",
+ "Name": "Afghan",
+ "NameN": "أفغاني"
+ },
+ {
+ "ID": "CAF",
+ "Name": "African",
+ "NameN": "أفريقي"
+ },
+ {
+ "ID": "ALB",
+ "Name": "Albanian",
+ "NameN": "ألباني"
+ },
+ {
+ "ID": "DZA",
+ "Name": "Algerian",
+ "NameN": "جزائري"
+ },
+ {
+ "ID": "USA",
+ "Name": "American",
+ "NameN": "أمريكي"
+ },
+ {
+ "ID": "UMI",
+ "Name": "American (Minor Outlying Islands)",
+ "NameN": "أمريكي (الجزر الصغرى النائية)"
+ },
+ {
+ "ID": "ASM",
+ "Name": "American Samoa",
+ "NameN": "ساموا الأمريكية"
+ },
+ {
+ "ID": "AND",
+ "Name": "Andorrian",
+ "NameN": "أندوري"
+ },
+ {
+ "ID": "AGO",
+ "Name": "Angolan",
+ "NameN": "أنغولي"
+ },
+ {
+ "ID": "AIA",
+ "Name": "Anguillan",
+ "NameN": "أنغيلي"
+ },
+ {
+ "ID": "ATA",
+ "Name": "Antarctica",
+ "NameN": "أنتاركتيكا"
+ },
+ {
+ "ID": "ATG",
+ "Name": "Antiguans, Barbudans",
+ "NameN": "أنتيغوي، باربودي"
+ },
+ {
+ "ID": "ARG",
+ "Name": "Argentine",
+ "NameN": "أرجنتيني"
+ },
+ {
+ "ID": "ARM",
+ "Name": "Armenian",
+ "NameN": "أرمني"
+ },
+ {
+ "ID": "ABW",
+ "Name": "Arubian",
+ "NameN": "أروبي"
+ },
+ {
+ "ID": "AUS",
+ "Name": "Australian",
+ "NameN": "أسترالي"
+ },
+ {
+ "ID": "AUT",
+ "Name": "Austrian",
+ "NameN": "نمساوي"
+ },
+ {
+ "ID": "AZE",
+ "Name": "Azeri",
+ "NameN": "أذربيجاني"
+ },
+ {
+ "ID": "BHS",
+ "Name": "Bahamian",
+ "NameN": "باهامي"
+ },
+ {
+ "ID": "BHR",
+ "Name": "Bahraini",
+ "NameN": "بحريني"
+ },
+ {
+ "ID": "BRB",
+ "Name": "Barbadian or Bajuns",
+ "NameN": "باربادوسي"
+ },
+ {
+ "ID": "BLR",
+ "Name": "Belarusian",
+ "NameN": "بيلاروسي"
+ },
+ {
+ "ID": "BEL",
+ "Name": "Belgian",
+ "NameN": "بلجيكي"
+ },
+ {
+ "ID": "BLZ",
+ "Name": "Belizean",
+ "NameN": "بليزي"
+ },
+ {
+ "ID": "BGD",
+ "Name": "Bengali",
+ "NameN": "بنغلاديشي"
+ },
+ {
+ "ID": "BEN",
+ "Name": "Beninese",
+ "NameN": "بنيني"
+ },
+ {
+ "ID": "BMU",
+ "Name": "Bermudian",
+ "NameN": "برمودي"
+ },
+ {
+ "ID": "BTN",
+ "Name": "Bhutanese",
+ "NameN": "بوتاني"
+ },
+ {
+ "ID": "BOL",
+ "Name": "Bolivian",
+ "NameN": "بوليفي"
+ },
+ {
+ "ID": "BIH",
+ "Name": "Bosnian And Herzegovinian",
+ "NameN": "بوسني وهرسكي"
+ },
+ {
+ "ID": "BWA",
+ "Name": "Botswanian",
+ "NameN": "بوتسواني"
+ },
+ {
+ "ID": "BVT",
+ "Name": "Bouvet Island (Bouvetoya)",
+ "NameN": "جزيرة بوفيه"
+ },
+ {
+ "ID": "BRA",
+ "Name": "Brazilian",
+ "NameN": "برازيلي"
+ },
+ {
+ "ID": "GBR",
+ "Name": "British",
+ "NameN": "بريطاني"
+ },
+ {
+ "ID": "IOT",
+ "Name": "British (Chagos Archipelago)",
+ "NameN": "بريطاني (أرخبيل شاغوس)"
+ },
+ {
+ "ID": "VGB",
+ "Name": "British (Virgin Islands)",
+ "NameN": "بريطاني (الجزر العذراء)"
+ },
+ {
+ "ID": "BRN",
+ "Name": "Bruneian",
+ "NameN": "بروني"
+ },
+ {
+ "ID": "BGR",
+ "Name": "Bulgarian",
+ "NameN": "بلغاري"
+ },
+ {
+ "ID": "MMR",
+ "Name": "Burmese or Myanmarese",
+ "NameN": "بورمي أو ميانماري"
+ },
+ {
+ "ID": "BFA",
+ "Name": "Burnikabe",
+ "NameN": "بوركيني"
+ },
+ {
+ "ID": "BDI",
+ "Name": "Burundi",
+ "NameN": "بوروندي"
+ },
+ {
+ "ID": "KHM",
+ "Name": "Cambodian",
+ "NameN": "كمبودي"
+ },
+ {
+ "ID": "CMR",
+ "Name": "Cameroonian",
+ "NameN": "كاميروني"
+ },
+ {
+ "ID": "CAN",
+ "Name": "Canadian",
+ "NameN": "كندي"
+ },
+ {
+ "ID": "CPV",
+ "Name": "Cape Verdian or Cape Verdean",
+ "NameN": "رأس أخضري"
+ },
+ {
+ "ID": "CYM",
+ "Name": "Cayman Islander",
+ "NameN": "جزر كايماني"
+ },
+ {
+ "ID": "TCD",
+ "Name": "Chadian",
+ "NameN": "تشادي"
+ },
+ {
+ "ID": "CHL",
+ "Name": "Chilean",
+ "NameN": "تشيلي"
+ },
+ {
+ "ID": "HKG",
+ "Name": "Chinese (Hong Kong)",
+ "NameN": "صيني (هونغ كونغ)"
+ },
+ {
+ "ID": "MAC",
+ "Name": "Chinese (Macao)",
+ "NameN": "صيني (ماكاو)"
+ },
+ {
+ "ID": "CHN",
+ "Name": "Chinese",
+ "NameN": "صيني"
+ },
+ {
+ "ID": "CXR",
+ "Name": "Christmas Island",
+ "NameN": "جزيرة الكريسماس"
+ },
+ {
+ "ID": "CCK",
+ "Name": "Cocos (Keeling) Islands",
+ "NameN": "جزر كوكوس (كيلنغ)"
+ },
+ {
+ "ID": "COL",
+ "Name": "Colombian",
+ "NameN": "كولومبي"
+ },
+ {
+ "ID": "COM",
+ "Name": "Comoran",
+ "NameN": "قمري"
+ },
+ {
+ "ID": "COG",
+ "Name": "Congolese",
+ "NameN": "كونغولي"
+ },
+ {
+ "ID": "COD",
+ "Name": "Congolese (Zaire)",
+ "NameN": "كونغولي (زائير)"
+ },
+ {
+ "ID": "COK",
+ "Name": "Cook Islander",
+ "NameN": "جزر كوك"
+ },
+ {
+ "ID": "CRI",
+ "Name": "Costa Rican",
+ "NameN": "كوستاريكي"
+ },
+ {
+ "ID": "HRV",
+ "Name": "Croat",
+ "NameN": "كرواتي"
+ },
+ {
+ "ID": "CUB",
+ "Name": "Cuban",
+ "NameN": "كوبي"
+ },
+ {
+ "ID": "CYP",
+ "Name": "Cypriot, Greek",
+ "NameN": "قبرصي، يوناني"
+ },
+ {
+ "ID": "CZE",
+ "Name": "Czech",
+ "NameN": "تشيكي"
+ },
+ {
+ "ID": "DNK",
+ "Name": "Danish",
+ "NameN": "دنماركي"
+ },
+ {
+ "ID": "DJI",
+ "Name": "Djibouti",
+ "NameN": "جيبوتي"
+ },
+ {
+ "ID": "DOM",
+ "Name": "Dominican",
+ "NameN": "دومينيكاني"
+ },
+ {
+ "ID": "DMA",
+ "Name": "Dominican (Commonwealth)",
+ "NameN": "دومينيكي (الكومنولث)"
+ },
+ {
+ "ID": "ANT",
+ "Name": "Dutch (Antilles)",
+ "NameN": "هولندي (الأنتيل)"
+ },
+ {
+ "ID": "NLD",
+ "Name": "Dutch (Netherlands)",
+ "NameN": "هولندي (هولندا)"
+ },
+ {
+ "ID": "ECU",
+ "Name": "Ecuadorean",
+ "NameN": "إكوادوري"
+ },
+ {
+ "ID": "EGY",
+ "Name": "Egyptians",
+ "NameN": "مصري"
+ },
+ {
+ "ID": "ARE",
+ "Name": "Emirati",
+ "NameN": "إماراتي"
+ },
+ {
+ "ID": "GNQ",
+ "Name": "Equatorial Guinean or Equatoguinean",
+ "NameN": "غيني استوائي"
+ },
+ {
+ "ID": "ERI",
+ "Name": "Eritrean",
+ "NameN": "إريتري"
+ },
+ {
+ "ID": "EST",
+ "Name": "Estonian",
+ "NameN": "إستوني"
+ },
+ {
+ "ID": "ETH",
+ "Name": "Ethiopian",
+ "NameN": "إثيوبي"
+ },
+ {
+ "ID": "FRO",
+ "Name": "Faeroe Islander",
+ "NameN": "جزر فارو"
+ },
+ {
+ "ID": "FLK",
+ "Name": "Falkland Islander",
+ "NameN": "جزر فوكلاند"
+ },
+ {
+ "ID": "FJI",
+ "Name": "Fijian",
+ "NameN": "فيجي"
+ },
+ {
+ "ID": "PHL",
+ "Name": "Filipino",
+ "NameN": "فلبيني"
+ },
+ {
+ "ID": "FIN",
+ "Name": "Finnish",
+ "NameN": "فنلندي"
+ },
+ {
+ "ID": "FRA",
+ "Name": "French",
+ "NameN": "فرنسي"
+ },
+ {
+ "ID": "GUF",
+ "Name": "French Guianian",
+ "NameN": "غويانا الفرنسية"
+ },
+ {
+ "ID": "PYF",
+ "Name": "French Polynesian",
+ "NameN": "بولينيزيا الفرنسية"
+ },
+ {
+ "ID": "ATF",
+ "Name": "French Southern Territories",
+ "NameN": "الأقاليم الجنوبية الفرنسية"
+ },
+ {
+ "ID": "GAB",
+ "Name": "Gabonese",
+ "NameN": "غابوني"
+ },
+ {
+ "ID": "GMB",
+ "Name": "Gambian",
+ "NameN": "غامبي"
+ },
+ {
+ "ID": "GEO",
+ "Name": "Georgian",
+ "NameN": "جورجي"
+ },
+ {
+ "ID": "SGS",
+ "Name": "Georgian (South)",
+ "NameN": "جورجي (جنوبي)"
+ },
+ {
+ "ID": "DEU",
+ "Name": "German",
+ "NameN": "ألماني"
+ },
+ {
+ "ID": "GHA",
+ "Name": "Ghanaian",
+ "NameN": "غاني"
+ },
+ {
+ "ID": "GIB",
+ "Name": "Gibraltarian",
+ "NameN": "جبل طارقي"
+ },
+ {
+ "ID": "GRC",
+ "Name": "Greek",
+ "NameN": "يوناني"
+ },
+ {
+ "ID": "GRL",
+ "Name": "Greenlander",
+ "NameN": "غرينلاندي"
+ },
+ {
+ "ID": "GRD",
+ "Name": "Grenadian or Grenadan",
+ "NameN": "غرينادي"
+ },
+ {
+ "ID": "GLP",
+ "Name": "Guadeloupian",
+ "NameN": "غوادلوبي"
+ },
+ {
+ "ID": "GUM",
+ "Name": "Guamanian",
+ "NameN": "غوامي"
+ },
+ {
+ "ID": "GTM",
+ "Name": "Guatemalan",
+ "NameN": "غواتيمالي"
+ },
+ {
+ "ID": "GNB",
+ "Name": "Guinea-Bissauan",
+ "NameN": "غيني بيساوي"
+ },
+ {
+ "ID": "GIN",
+ "Name": "Guinean",
+ "NameN": "غيني"
+ },
+ {
+ "ID": "GUY",
+ "Name": "Guyanese",
+ "NameN": "غيانيزي"
+ },
+ {
+ "ID": "HTI",
+ "Name": "Haitian",
+ "NameN": "هايتيني"
+ },
+ {
+ "ID": "HMD",
+ "Name": "Heard and McDonald Islands",
+ "NameN": "جزر هيرد وماكدونالد"
+ },
+ {
+ "ID": "HND",
+ "Name": "Honduran",
+ "NameN": "هندوراسي"
+ },
+ {
+ "ID": "HUN",
+ "Name": "Hungarian",
+ "NameN": "مجري"
+ },
+ {
+ "ID": "ISL",
+ "Name": "Icelander",
+ "NameN": "آيسلندي"
+ },
+ {
+ "ID": "KIR",
+ "Name": "I-Kiribati",
+ "NameN": "كيريباتي"
+ },
+ {
+ "ID": "IND",
+ "Name": "Indian",
+ "NameN": "هندي"
+ },
+ {
+ "ID": "IDN",
+ "Name": "Indonesian",
+ "NameN": "إندونيسي"
+ },
+ {
+ "ID": "IRN",
+ "Name": "Iranian",
+ "NameN": "إيراني"
+ },
+ {
+ "ID": "IRQ",
+ "Name": "Iraqi",
+ "NameN": "عراقي"
+ },
+ {
+ "ID": "IRL",
+ "Name": "Irish",
+ "NameN": "إيرلندي"
+ },
+ {
+ "ID": "ITA",
+ "Name": "Italian",
+ "NameN": "إيطالي"
+ },
+ {
+ "ID": "CIV",
+ "Name": "Ivoirian",
+ "NameN": "إيفواري"
+ },
+ {
+ "ID": "JAM",
+ "Name": "Jamaican",
+ "NameN": "جامايكي"
+ },
+ {
+ "ID": "JPN",
+ "Name": "Japanese",
+ "NameN": "ياباني"
+ },
+ {
+ "ID": "JOR",
+ "Name": "Jordanian",
+ "NameN": "أردني"
+ },
+ {
+ "ID": "KAZ",
+ "Name": "Kazakhstani",
+ "NameN": "كازاخستاني"
+ },
+ {
+ "ID": "KEN",
+ "Name": "Kenyan",
+ "NameN": "كيني"
+ },
+ {
+ "ID": "KGZ",
+ "Name": "Kirghiz",
+ "NameN": "قيرغيزي"
+ },
+ {
+ "ID": "KOR",
+ "Name": "Korean",
+ "NameN": "كوري"
+ },
+ {
+ "ID": "PRK",
+ "Name": "Korean",
+ "NameN": "كوري"
+ },
+ {
+ "ID": "KWT",
+ "Name": "Kuwaiti",
+ "NameN": "كويتي"
+ },
+ {
+ "ID": "LAO",
+ "Name": "Laotian",
+ "NameN": "لاوسي"
+ },
+ {
+ "ID": "LVA",
+ "Name": "Latvian",
+ "NameN": "لاتفي"
+ },
+ {
+ "ID": "LBN",
+ "Name": "Lebanese",
+ "NameN": "لبناني"
+ },
+ {
+ "ID": "LBR",
+ "Name": "Liberian",
+ "NameN": "ليبيري"
+ },
+ {
+ "ID": "LBY",
+ "Name": "Libyan",
+ "NameN": "ليبي"
+ },
+ {
+ "ID": "LIE",
+ "Name": "Liechtensteiner",
+ "NameN": "ليختنشتايني"
+ },
+ {
+ "ID": "LTU",
+ "Name": "Lithuanian",
+ "NameN": "ليتواني"
+ },
+ {
+ "ID": "LUX",
+ "Name": "Luxembourger",
+ "NameN": "لوكسمبورغي"
+ },
+ {
+ "ID": "MKD",
+ "Name": "Macedonia, the former Yugoslav Republic of",
+ "NameN": "مقدوني، جمهورية يوغوسلافيا السابقة"
+ },
+ {
+ "ID": "MYT",
+ "Name": "Mahorais",
+ "NameN": "مايوتي"
+ },
+ {
+ "ID": "MDG",
+ "Name": "Malagasy",
+ "NameN": "مدغشقري"
+ },
+ {
+ "ID": "MWI",
+ "Name": "Malawian",
+ "NameN": "مالاوي"
+ },
+ {
+ "ID": "MYS",
+ "Name": "Malaysian",
+ "NameN": "ماليزي"
+ },
+ {
+ "ID": "MDV",
+ "Name": "Maldivan",
+ "NameN": "مالديفي"
+ },
+ {
+ "ID": "MLI",
+ "Name": "Malian",
+ "NameN": "مالي"
+ },
+ {
+ "ID": "MLT",
+ "Name": "Maltese",
+ "NameN": "مالطي"
+ },
+ {
+ "ID": "MHL",
+ "Name": "Marshallese",
+ "NameN": "مارشالي"
+ },
+ {
+ "ID": "MTQ",
+ "Name": "Martiniquais",
+ "NameN": "مارتينيكي"
+ },
+ {
+ "ID": "MRT",
+ "Name": "Mauritanian",
+ "NameN": "موريتاني"
+ },
+ {
+ "ID": "MUS",
+ "Name": "Mauritian",
+ "NameN": "موريشيوسي"
+ },
+ {
+ "ID": "MEX",
+ "Name": "Mexican",
+ "NameN": "مكسيكي"
+ },
+ {
+ "ID": "FSM",
+ "Name": "Micronesian",
+ "NameN": "ميكرونيزي"
+ },
+ {
+ "ID": "MDA",
+ "Name": "Moldovian",
+ "NameN": "مولدوفي"
+ },
+ {
+ "ID": "MCO",
+ "Name": "Monegasque or Monacan",
+ "NameN": "موناكي"
+ },
+ {
+ "ID": "MNG",
+ "Name": "Mongolian",
+ "NameN": "منغولي"
+ },
+ {
+ "ID": "MNE",
+ "Name": "Montenegrin",
+ "NameN": "جبل أسودي"
+ },
+ {
+ "ID": "MSR",
+ "Name": "Montserratian",
+ "NameN": "مونتسيراتي"
+ },
+ {
+ "ID": "MAR",
+ "Name": "Moroccan",
+ "NameN": "مغربي"
+ },
+ {
+ "ID": "LSO",
+ "Name": "Mosotho",
+ "NameN": "ليسوتي"
+ },
+ {
+ "ID": "MOZ",
+ "Name": "Mozambican",
+ "NameN": "موزمبيقي"
+ },
+ {
+ "ID": "NAM",
+ "Name": "Namibian",
+ "NameN": "ناميبي"
+ },
+ {
+ "ID": "NRU",
+ "Name": "Nauruan",
+ "NameN": "ناوروي"
+ },
+ {
+ "ID": "NPL",
+ "Name": "Nepalese",
+ "NameN": "نيبالي"
+ },
+ {
+ "ID": "NCL",
+ "Name": "New Caledonian",
+ "NameN": "كاليدوني جديد"
+ },
+ {
+ "ID": "NZL",
+ "Name": "New Zealand",
+ "NameN": "نيوزيلندي"
+ },
+ {
+ "ID": "VUT",
+ "Name": "Ni- Vanuatu",
+ "NameN": "فانواتي"
+ },
+ {
+ "ID": "NIC",
+ "Name": "Nicaraguan",
+ "NameN": "نيكاراغوي"
+ },
+ {
+ "ID": "NGA",
+ "Name": "Nigerian",
+ "NameN": "نيجيري"
+ },
+ {
+ "ID": "NER",
+ "Name": "Nigerien",
+ "NameN": "نيجري"
+ },
+ {
+ "ID": "NIU",
+ "Name": "Niuean",
+ "NameN": "نيوي"
+ },
+ {
+ "ID": "VAT",
+ "Name": "None (Vatican City)",
+ "NameN": "لا شيء (مدينة الفاتيكان)"
+ },
+ {
+ "ID": "NFK",
+ "Name": "Norfolk Islander",
+ "NameN": "جزيرة نورفولك"
+ },
+ {
+ "ID": "MNP",
+ "Name": "Northern Mariana Islander",
+ "NameN": "جزر ماريانا الشمالية"
+ },
+ {
+ "ID": "NOR",
+ "Name": "Norwegean",
+ "NameN": "نرويجي"
+ },
+ {
+ "ID": "OMN",
+ "Name": "Omani",
+ "NameN": "عماني"
+ },
+ {
+ "ID": "OTH",
+ "Name": "OTHERS",
+ "NameN": "آخرون"
+ },
+ {
+ "ID": "PAK",
+ "Name": "Pakistani",
+ "NameN": "باكستاني"
+ },
+ {
+ "ID": "PLW",
+ "Name": "Palauan",
+ "NameN": "بالاوي"
+ },
+ {
+ "ID": "PSE",
+ "Name": "Palestinian",
+ "NameN": "فلسطيني"
+ },
+ {
+ "ID": "PAN",
+ "Name": "Panamanian",
+ "NameN": "بنمي"
+ },
+ {
+ "ID": "PNG",
+ "Name": "Papua New Guinean",
+ "NameN": "بابوا غيني جديد"
+ },
+ {
+ "ID": "PRY",
+ "Name": "Paraguayan",
+ "NameN": "باراغوايي"
+ },
+ {
+ "ID": "PER",
+ "Name": "Peruvian",
+ "NameN": "بيروفي"
+ },
+ {
+ "ID": "PCN",
+ "Name": "Pitcairn Islander",
+ "NameN": "جزر بيتكايرن"
+ },
+ {
+ "ID": "POL",
+ "Name": "Polish",
+ "NameN": "بولندي"
+ },
+ {
+ "ID": "PRT",
+ "Name": "Portuguese",
+ "NameN": "برتغالي"
+ },
+ {
+ "ID": "PRI",
+ "Name": "Puerto Rican",
+ "NameN": "بورتوريكي"
+ },
+ {
+ "ID": "QAT",
+ "Name": "Qatari",
+ "NameN": "قطري"
+ },
+ {
+ "ID": "RKS",
+ "Name": "Republic of Kosovo",
+ "NameN": "جمهورية كوسوفو"
+ },
+ {
+ "ID": "REU",
+ "Name": "Reunionese",
+ "NameN": "ريونيوني"
+ },
+ {
+ "ID": "ROU",
+ "Name": "Romanian",
+ "NameN": "روماني"
+ },
+ {
+ "ID": "RUS",
+ "Name": "Russian",
+ "NameN": "روسي"
+ },
+ {
+ "ID": "RWA",
+ "Name": "Rwandan",
+ "NameN": "رواندي"
+ },
+ {
+ "ID": "ESH",
+ "Name": "Sahrawi",
+ "NameN": "صحراوي"
+ },
+ {
+ "ID": "SLV",
+ "Name": "Salvadoran",
+ "NameN": "سلفادوري"
+ },
+ {
+ "ID": "SMR",
+ "Name": "Sammarinese",
+ "NameN": "سان مارينو"
+ },
+ {
+ "ID": "WSM",
+ "Name": "Samoan",
+ "NameN": "ساموي"
+ },
+ {
+ "ID": "STP",
+ "Name": "Sao Tomean",
+ "NameN": "ساو تومي"
+ },
+ {
+ "ID": "SAU",
+ "Name": "Saudi",
+ "NameN": "سعودي"
+ },
+ {
+ "ID": "SCT",
+ "Name": "Scottish",
+ "NameN": "اسكتلندي"
+ },
+ {
+ "ID": "SEN",
+ "Name": "Senegalese",
+ "NameN": "سنغالي"
+ },
+ {
+ "ID": "SRB",
+ "Name": "Serbian",
+ "NameN": "صربي"
+ },
+ {
+ "ID": "SYC",
+ "Name": "Seychellois",
+ "NameN": "سيشيلي"
+ },
+ {
+ "ID": "SLE",
+ "Name": "Sierra Leonean",
+ "NameN": "سيراليوني"
+ },
+ {
+ "ID": "SGP",
+ "Name": "Singaporian",
+ "NameN": "سنغافوري"
+ },
+ {
+ "ID": "SVK",
+ "Name": "Slovak",
+ "NameN": "سلوفاكي"
+ },
+ {
+ "ID": "SVN",
+ "Name": "Slovene",
+ "NameN": "سلوفيني"
+ },
+ {
+ "ID": "SLB",
+ "Name": "Solomon Islander",
+ "NameN": "جزر سليمان"
+ },
+ {
+ "ID": "SOM",
+ "Name": "Somalian",
+ "NameN": "صومالي"
+ },
+ {
+ "ID": "ZAF",
+ "Name": "South African",
+ "NameN": "جنوب أفريقي"
+ },
+ {
+ "ID": "ESP",
+ "Name": "Spanish",
+ "NameN": "إسباني"
+ },
+ {
+ "ID": "LKA",
+ "Name": "Sri Lankan",
+ "NameN": "سريلانكي"
+ },
+ {
+ "ID": "SHN",
+ "Name": "St. Helena",
+ "NameN": "سانت هيلينا"
+ },
+ {
+ "ID": "KNA",
+ "Name": "St. Kitts and Nevis",
+ "NameN": "سانت كيتس ونيفيس"
+ },
+ {
+ "ID": "LCA",
+ "Name": "St. Lucia",
+ "NameN": "سانت لوسيا"
+ },
+ {
+ "ID": "SPM",
+ "Name": "St. Pierre and Miquelon",
+ "NameN": "سانت بيير وميكيلون"
+ },
+ {
+ "ID": "VCT",
+ "Name": "St. Vincent and the Grenadines",
+ "NameN": "سانت فنسنت والغرينادين"
+ },
+ {
+ "ID": "SDN",
+ "Name": "Sudanese",
+ "NameN": "سوداني"
+ },
+ {
+ "ID": "SUR",
+ "Name": "Surinamer",
+ "NameN": "سورينامي"
+ },
+ {
+ "ID": "SJM",
+ "Name": "Svalbard and Jan Mayen islander",
+ "NameN": "سفالبارد وجان ماين"
+ },
+ {
+ "ID": "SWZ",
+ "Name": "Swazi",
+ "NameN": "سوازي"
+ },
+ {
+ "ID": "SWE",
+ "Name": "Swedish",
+ "NameN": "سويدي"
+ },
+ {
+ "ID": "CHE",
+ "Name": "Swiss",
+ "NameN": "سويسري"
+ },
+ {
+ "ID": "SYR",
+ "Name": "Syrian",
+ "NameN": "سوري"
+ },
+ {
+ "ID": "TWN",
+ "Name": "Taiwan, Province of China",
+ "NameN": "تايوان، مقاطعة الصين"
+ },
+ {
+ "ID": "TJK",
+ "Name": "Tajik",
+ "NameN": "طاجيكي"
+ },
+ {
+ "ID": "TZA",
+ "Name": "Tanzania, United Republic o",
+ "NameN": "تنزاني، الجمهورية المتحدة"
+ },
+ {
+ "ID": "THA",
+ "Name": "Thai",
+ "NameN": "تايلندي"
+ },
+ {
+ "ID": "TLS",
+ "Name": "Timorese",
+ "NameN": "تيموري"
+ },
+ {
+ "ID": "TGO",
+ "Name": "Togolese",
+ "NameN": "توغولي"
+ },
+ {
+ "ID": "TKL",
+ "Name": "Tokelauan",
+ "NameN": "توكيلاوي"
+ },
+ {
+ "ID": "TON",
+ "Name": "Tongan",
+ "NameN": "تونغي"
+ },
+ {
+ "ID": "TTO",
+ "Name": "Trinidadian",
+ "NameN": "ترينيدادي"
+ },
+ {
+ "ID": "TUN",
+ "Name": "Tunisian",
+ "NameN": "تونسي"
+ },
+ {
+ "ID": "TCA",
+ "Name": "Turk",
+ "NameN": "تركي"
+ },
+ {
+ "ID": "TUR",
+ "Name": "Turkish",
+ "NameN": "تركي"
+ },
+ {
+ "ID": "TKM",
+ "Name": "Turkmen",
+ "NameN": "تركماني"
+ },
+ {
+ "ID": "TUV",
+ "Name": "Tuvaluan",
+ "NameN": "توفالوي"
+ },
+ {
+ "ID": "UGA",
+ "Name": "Ugandan",
+ "NameN": "أوغندي"
+ },
+ {
+ "ID": "UKR",
+ "Name": "Ukrainian",
+ "NameN": "أوكراني"
+ },
+ {
+ "ID": "URY",
+ "Name": "Uruguayan",
+ "NameN": "أوروغوايي"
+ },
+ {
+ "ID": "UZB",
+ "Name": "Uzbek",
+ "NameN": "أوزبكي"
+ },
+ {
+ "ID": "VEN",
+ "Name": "Venenzuelan",
+ "NameN": "فنزويلي"
+ },
+ {
+ "ID": "VNM",
+ "Name": "Vietnamese",
+ "NameN": "فيتنامي"
+ },
+ {
+ "ID": "VIR",
+ "Name": "Virgin Islander",
+ "NameN": "جزر عذراء"
+ },
+ {
+ "ID": "WLF",
+ "Name": "Wallis and Futuna Islander",
+ "NameN": "واليس وفوتونا"
+ },
+ {
+ "ID": "YEM",
+ "Name": "Yemeni",
+ "NameN": "يمني"
+ },
+ {
+ "ID": "ZMB",
+ "Name": "Zambian",
+ "NameN": "زامبي"
+ },
+ {
+ "ID": "ZWE",
+ "Name": "Zimbabwean",
+ "NameN": "زيمبابوي"
+ }
+]
\ No newline at end of file
diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json
index 64477a3..2c7ac9b 100644
--- a/assets/langs/ar-SA.json
+++ b/assets/langs/ar-SA.json
@@ -776,8 +776,13 @@
"validPassportNumber": "يرجى إدخال رقم جواز سفر صالح",
"continuePlan": "متابعة خطة العلاج؟",
"aboutApp": "حول التطبيق",
- "loginOrRegister": "تسجيل الدخول أو التسجيل",
"dontHaveAccount": "ليس لديك حساب؟",
+ "loginOrRegister": "تسجيل الدخول أو التسجيل",
+ "myFiles" : "ملفاتي",
+ "resultsPending": "النتائج معلقة",
+ "resultsAvailable": "النتائج متاحة",
+ "viewReport": "عرض التقرير",
+ "prescriptionDeliveryError": "هذه العيادة لا تدعم إعادة التعبئة والتسليم.",
"receiveOtpToast": "أين تود تلقي رمز التحقق OTP؟",
"enterPhoneNumber": "أدخل رقم الهاتف",
"enterEmailDesc": "أدخل عنوان بريدك الإلكتروني لإكمال عملية إنشاء ملف طبي",
@@ -790,5 +795,13 @@
"notice": "إشعار",
"oR": "أو",
"sendOTPWHATSAPP": "أرسل لي OTP عبر واتساب",
- "sendOTPSMS": "أرسل لي OTP عبر الرسائل القصيرة"
+ "sendOTPSMS": "أرسل لي OTP عبر الرسائل القصيرة",
+ "fullName": "الاسم الكامل",
+ "married": "متزوج",
+ "uae": "الإمارات العربية المتحدة",
+ "malE": "ذكر",
+ "loginBy": "تسجيل الدخول بواسطة",
+ "loginByOTP": "تسجيل الدخول بواسطة OTP",
+ "guest": "زائر",
+ "switchAccount": "تبديل الحساب"
}
\ No newline at end of file
diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json
index cd15a5a..d01d9f6 100644
--- a/assets/langs/en-US.json
+++ b/assets/langs/en-US.json
@@ -665,7 +665,7 @@
"healthWeatherIndicators": "Health Weather Indicators",
"healthTipsBasedOnCurrentWeather": "Health Tips Based On Current Weather",
"moreDetails": "More details",
- "resendOrder": "Refill & Delivery",
+ "resendOrder": "Refill and Delivery",
"ports": "Ports",
"way": "Way",
"dailyDoses": "Daily Doses",
@@ -779,6 +779,11 @@
"pleaseChooseOption": "Please select from the below options to receive OTP",
"dontHaveAccount": "Don't have an account?",
"loginOrRegister": "Login or Register",
+ "myFiles": "My Files",
+ "resultsPending": "Results Pending",
+ "resultsAvailable": "Results Available",
+ "viewReport": "View Report",
+ "prescriptionDeliveryError": "This clinic doesn't support refill",
"prepareToElevate": "Prepared to elevate your health and well-being?",
"iAcceptTermsConditions": "I Accept the Terms and Conditions",
"alreadyHaveAccount": "Already have an account?",
@@ -786,5 +791,13 @@
"notice": "Notice",
"oR": "OR",
"sendOTPWHATSAPP": "Send me OTP on Whatsapp",
- "sendOTPSMS": "Send me OTP on SMS"
+ "sendOTPSMS": "Send me OTP on SMS",
+ "fullName": "Full Name",
+ "married": "Married",
+ "uae" : "United Arab Emirates",
+ "malE": "Male",
+ "loginBy": "Login By",
+ "loginByOTP": "Login By OTP",
+ "guest": "Guest",
+ "switchAccount": "Switch Account"
}
\ No newline at end of file
diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart
index a7835f4..6e64543 100644
--- a/lib/core/api/api_client.dart
+++ b/lib/core/api/api_client.dart
@@ -177,7 +177,7 @@ class ApiClientImp implements ApiClient {
// TODO : we will use all these from appState
body['LanguageID'] = body['LanguageID'] ?? "2";
- body['VersionID'] = body['VersionID'] ?? "18.7";
+ body['VersionID'] = body['VersionID'] ?? "50.0";
body['Channel'] = body['Channel'] ?? "3";
body['IPAdress'] = body['IPAdress'] ?? "10.20.10.20";
body['generalid'] = body['generalid'] ?? "Cs2020@2016\$2958";
@@ -189,6 +189,7 @@ class ApiClientImp implements ApiClient {
: await Utils.isGoogleServicesAvailable()
? "2"
: "3");
+ body['TokenID'] = "@dm!n";
body.removeWhere((key, value) => value == null);
log("body: ${json.encode(body)}");
log("uri: ${Uri.parse(url.trim())}");
diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart
index 1522174..ef7656c 100644
--- a/lib/core/api_consts.dart
+++ b/lib/core/api_consts.dart
@@ -17,8 +17,8 @@ var PACKAGES_ORDERS = '/api/orders';
var PACKAGES_ORDER_HISTORY = '/api/orders/items';
var PACKAGES_TAMARA_OPT = '/api/orders/paymentoptions/tamara';
// var BASE_URL = 'http://10.50.100.198:2018/';
-var BASE_URL = 'https://uat.hmgwebservices.com/';
-// var BASE_URL = 'https://hmgwebservices.com/';
+// var BASE_URL = 'https://uat.hmgwebservices.com/';
+var BASE_URL = 'https://hmgwebservices.com/';
// var BASE_URL = 'http://10.201.204.103/';
// var BASE_URL = 'https://orash.cloudsolutions.com.sa/';
// var BASE_URL = 'https://vidauat.cloudsolutions.com.sa/';
diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart
index 0e7d944..bd3e541 100644
--- a/lib/core/app_assets.dart
+++ b/lib/core/app_assets.dart
@@ -59,6 +59,22 @@ class AppAssets {
static const String habib_background_icon = '$svgBasePath/habib_logo_background.svg';
static const String show_icon = '$svgBasePath/show_icon.svg';
static const String recharge_icon = '$svgBasePath/recharge_icon.svg';
+ static const String eye_result_icon = '$svgBasePath/eye_results_icon.svg';
+ static const String search_icon = '$svgBasePath/search_icon.svg';
+ static const String view_report_icon = '$svgBasePath/view_report_icon.svg';
+ static const String forward_arrow_icon = '$svgBasePath/forward_arrow_icon.svg';
+ static const String prescription_refill_icon = '$svgBasePath/prescription_refill_icon.svg';
+ static const String rating_icon = '$svgBasePath/rating_icon.svg';
+ static const String doctor_calendar_icon = '$svgBasePath/doctor_calendar_icon.svg';
+ static const String prescription_remarks_icon = '$svgBasePath/prescription_remarks_icon.svg';
+
+ //bottom navigation//
+
+ static const String homeBottom = '$svgBasePath/home_bottom.svg';
+ static const String bookAppoBottom = '$svgBasePath/book_appo_bottom.svg';
+ static const String myFilesBottom = '$svgBasePath/my_files_bottom.svg';
+ static const String toDoBottom = '$svgBasePath/todo_bottom.svg';
+ static const String servicesBottom = '$svgBasePath/services_bottom.svg';
// PNGS //
static const String hmg_logo = '$pngBasePath/hmg_logo.png';
diff --git a/lib/core/common_models/nationality_country_model.dart b/lib/core/common_models/nationality_country_model.dart
new file mode 100644
index 0000000..fb3961b
--- /dev/null
+++ b/lib/core/common_models/nationality_country_model.dart
@@ -0,0 +1,29 @@
+import 'dart:convert';
+
+class NationalityCountries {
+ String? id;
+ String? name;
+ String? nameN;
+
+ NationalityCountries({
+ this.id,
+ this.name,
+ this.nameN,
+ });
+
+ factory NationalityCountries.fromRawJson(String str) => NationalityCountries.fromJson(json.decode(str));
+
+ String toRawJson() => json.encode(toJson());
+
+ factory NationalityCountries.fromJson(Map json) => NationalityCountries(
+ id: json["ID"],
+ name: json["Name"],
+ nameN: json["NameN"],
+ );
+
+ Map toJson() => {
+ "ID": id,
+ "Name": name,
+ "NameN": nameN,
+ };
+}
diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart
index ee20a60..721d01d 100644
--- a/lib/core/dependencies.dart
+++ b/lib/core/dependencies.dart
@@ -7,7 +7,13 @@ import 'package:hmg_patient_app_new/features/authentication/authentication_repo.
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/common/common_repo.dart';
+import 'package:hmg_patient_app_new/features/lab/lab_repo.dart';
+import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
+import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
+import 'package:hmg_patient_app_new/features/radiology/radiology_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';
@@ -64,9 +70,34 @@ class AppDependencies {
getIt.registerLazySingleton(() => AuthenticationRepoImp(loggerService: getIt(), apiClient: getIt()));
getIt.registerLazySingleton(() => BookAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt()));
getIt.registerLazySingleton(() => MyAppointmentsRepoImp(loggerService: getIt(), apiClient: getIt()));
+ getIt.registerLazySingleton(() => LabRepoImp(loggerService: getIt(), apiClient: getIt()));
+ getIt.registerLazySingleton(() => RadiologyRepoImp(loggerService: getIt(), apiClient: getIt()));
+ getIt.registerLazySingleton(() => PrescriptionsRepoImp(loggerService: getIt(), apiClient: getIt()));
// ViewModels
// Global/shared VMs → LazySingleton
+
+ getIt.registerLazySingleton(
+ () => LabViewModel(
+ labRepo: getIt(),
+ errorHandlerService: getIt(),
+ ),
+ );
+
+ getIt.registerLazySingleton(
+ () => RadiologyViewModel(
+ radiologyRepo: getIt(),
+ errorHandlerService: getIt(),
+ ),
+ );
+
+ getIt.registerLazySingleton(
+ () => PrescriptionsViewModel(
+ prescriptionsRepo: getIt(),
+ errorHandlerService: getIt(),
+ ),
+ );
+
getIt.registerLazySingleton(
() => AuthenticationViewModel(
authenticationRepo: getIt(),
diff --git a/lib/core/enums.dart b/lib/core/enums.dart
index 77a17bc..874dff4 100644
--- a/lib/core/enums.dart
+++ b/lib/core/enums.dart
@@ -41,6 +41,51 @@ enum ChipTypeEnum { success, error, alert, info, warning }
enum OTPTypeEnum { sms, whatsapp }
+enum LoginTypeEnum { sms, whatsapp, face, fingerprint }
+
+extension LoginTypeExtension on LoginTypeEnum {
+ int get toInt {
+ switch (this) {
+ case LoginTypeEnum.sms:
+ return 1;
+ case LoginTypeEnum.whatsapp:
+ return 4;
+ case LoginTypeEnum.face:
+ return 3;
+ case LoginTypeEnum.fingerprint:
+ return 2;
+ }
+ }
+
+ String get displayName {
+ switch (this) {
+ case LoginTypeEnum.sms:
+ return 'SMS';
+ case LoginTypeEnum.whatsapp:
+ return 'WhatsApp';
+ case LoginTypeEnum.face:
+ return 'Face Recognition';
+ case LoginTypeEnum.fingerprint:
+ return 'Fingerprint';
+ }
+ }
+
+ static LoginTypeEnum? fromValue(int value) {
+ switch (value) {
+ case 1:
+ return LoginTypeEnum.sms;
+ case 2:
+ return LoginTypeEnum.fingerprint;
+ case 3:
+ return LoginTypeEnum.face;
+ case 4:
+ return LoginTypeEnum.whatsapp;
+ default:
+ return null;
+ }
+ }
+}
+
extension OTPTypeEnumExtension on OTPTypeEnum {
/// Convert enum to int
int toInt() {
diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart
index cbfac11..4d813f0 100644
--- a/lib/extensions/string_extensions.dart
+++ b/lib/extensions/string_extensions.dart
@@ -206,19 +206,25 @@ extension EmailValidator on String {
Widget toText21({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text(
this,
maxLines: maxlines,
- style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 21.fSize, letterSpacing: -0.4, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
+ style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 21.fSize, letterSpacing: -0.4, fontWeight: weight ?? (isBold ? FontWeight.w600 : FontWeight.normal)),
);
Widget toText22({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
- style: TextStyle(height: 1, color: color ?? AppColors.blackColor, fontSize: 22.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(height: 1, color: color ?? AppColors.blackColor, fontSize: 22.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.w600 : FontWeight.normal),
);
Widget toText24({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
- style: TextStyle(height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.w600 : FontWeight.normal),
+ );
+
+ Widget toText26({Color? color, bool isBold = false, bool isCenter = false, double height = 23/26}) => Text(
+ this,
+ textAlign: isCenter ? TextAlign.center : null,
+ style: TextStyle(height: height, color: color ?? AppColors.blackColor, fontSize: 26.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.w600 : FontWeight.normal),
);
Widget toText28({Color? color, bool isBold = false, bool isCenter = false, TextScaler? textScaler}) => Text(
@@ -231,20 +237,18 @@ extension EmailValidator on String {
Widget toText32({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
- style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.w600 : FontWeight.normal),
);
Widget toText36({Color? color, bool isBold = false, bool isCenter = false}) => Text(
- this,
- textAlign: isCenter ? TextAlign.center : null,
- style: TextStyle(height: 47 / 36, color: color ?? AppColors.blackColor, fontSize: 36.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.w600 : FontWeight.normal),
- );
-
-
+ this,
+ textAlign: isCenter ? TextAlign.center : null,
+ style: TextStyle(height: 47 / 36, color: color ?? AppColors.blackColor, fontSize: 36.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.w600 : FontWeight.normal),
+ );
Widget toText44({Color? color, bool isBold = false}) => Text(
this,
- style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
+ style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.w600 : FontWeight.normal),
);
Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) {
@@ -383,7 +387,6 @@ class FontUtils {
}
}
-
extension CountryExtension on CountryEnum {
String get displayName {
switch (this) {
@@ -435,3 +438,103 @@ extension CountryExtension on CountryEnum {
}
}
+extension GenderTypeExtension on GenderTypeEnum {
+ String get value => this == GenderTypeEnum.male ? "M" : "F";
+
+ String get type => this == GenderTypeEnum.male ? "Male" : "Female";
+
+ String get typeAr => this == GenderTypeEnum.male ? "ذكر" : "أنثى";
+
+ static GenderTypeEnum? fromValue(String? value) {
+ switch (value) {
+ case "M":
+ return GenderTypeEnum.male;
+ case "F":
+ return GenderTypeEnum.female;
+ default:
+ return null;
+ }
+ }
+
+ static GenderTypeEnum? fromType(String? type) {
+ switch (type) {
+ case "Male":
+ return GenderTypeEnum.male;
+ case "Female":
+ return GenderTypeEnum.female;
+ default:
+ return null;
+ }
+ }
+}
+
+extension MaritalStatusTypeExtension on MaritalStatusTypeEnum {
+ String get value {
+ switch (this) {
+ case MaritalStatusTypeEnum.single:
+ return "U";
+ case MaritalStatusTypeEnum.married:
+ return "M";
+ case MaritalStatusTypeEnum.divorced:
+ return "D";
+ case MaritalStatusTypeEnum.widowed:
+ return "W";
+ }
+ }
+
+ String get type {
+ switch (this) {
+ case MaritalStatusTypeEnum.single:
+ return "Single";
+ case MaritalStatusTypeEnum.married:
+ return "Married";
+ case MaritalStatusTypeEnum.divorced:
+ return "Divorced";
+ case MaritalStatusTypeEnum.widowed:
+ return "Widowed";
+ }
+ }
+
+ String get typeAr {
+ switch (this) {
+ case MaritalStatusTypeEnum.single:
+ return "أعزب";
+ case MaritalStatusTypeEnum.married:
+ return "متزوج";
+ case MaritalStatusTypeEnum.divorced:
+ return "مطلق";
+ case MaritalStatusTypeEnum.widowed:
+ return "أرمل";
+ }
+ }
+
+ static MaritalStatusTypeEnum? fromValue(String? value) {
+ switch (value) {
+ case "U":
+ return MaritalStatusTypeEnum.single;
+ case "M":
+ return MaritalStatusTypeEnum.married;
+ case "D":
+ return MaritalStatusTypeEnum.divorced;
+ case "W":
+ return MaritalStatusTypeEnum.widowed;
+ default:
+ return null;
+ }
+ }
+
+ static MaritalStatusTypeEnum? fromType(String? type) {
+ switch (type) {
+ case "Single":
+ return MaritalStatusTypeEnum.single;
+ case "Married":
+ return MaritalStatusTypeEnum.married;
+ case "Divorced":
+ return MaritalStatusTypeEnum.divorced;
+ case "Widowed":
+ return MaritalStatusTypeEnum.widowed;
+ default:
+ return null;
+ }
+ }
+}
diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart
index e6913d2..d1a3db4 100644
--- a/lib/extensions/widget_extensions.dart
+++ b/lib/extensions/widget_extensions.dart
@@ -78,7 +78,14 @@ extension WidgetExtensions on Widget {
}
Widget objectContainerBorderView(
- {String title = "", String note = "", bool disablePadding = false, double radius = 20, Color? color, Color borderColor = AppColors.buttonColor, bool disableWidth = false, bool isAlignment = false}) {
+ {String title = "",
+ String note = "",
+ bool disablePadding = false,
+ double radius = 20,
+ Color? color,
+ Color borderColor = AppColors.buttonColor,
+ bool disableWidth = false,
+ bool isAlignment = false}) {
return Container(
padding: disablePadding ? EdgeInsets.zero : const EdgeInsets.only(top: 15, bottom: 15, left: 14, right: 14),
decoration: BoxDecoration(
@@ -127,6 +134,7 @@ extension SmoothContainerExtension on ShapeBorder {
bool isDisabled = false,
Color? backgroundColor,
BorderSide? side,
+ bool hasShadow = false,
}) {
final bgColor = backgroundColor ?? color;
return ShapeDecoration(
@@ -136,15 +144,19 @@ extension SmoothContainerExtension on ShapeBorder {
smoothness: 1,
side: side ?? BorderSide.none,
),
+ shadows: hasShadow
+ ? [
+ BoxShadow(
+ color: const Color(0xff000000).withOpacity(.05),
+ blurRadius: 32,
+ offset: const Offset(0, 0),
+ )
+ ]
+ : [],
);
}
}
-
-
-
-
-
//Height Spacers in percentages
Widget heightSpacer02per() => SizedBox(height: 0.2.h);
@@ -191,8 +203,6 @@ Widget widthSpacer4per() => SizedBox(height: 4.w);
Widget widthSpacer5per() => SizedBox(height: 5.w);
-
-
extension ChipTypeEnumExtension on ChipTypeEnum {
Color get color {
switch (this) {
@@ -223,4 +233,4 @@ extension ChipTypeEnumExtension on ChipTypeEnum {
return AppColors.warningLightColor; // Replace with your actual color
}
}
-}
\ No newline at end of file
+}
diff --git a/lib/features/authentication/widgets/otp_verification_screen.dart b/lib/features/authentication/widgets/otp_verification_screen.dart
index 5ff4fdf..9ea1b9e 100644
--- a/lib/features/authentication/widgets/otp_verification_screen.dart
+++ b/lib/features/authentication/widgets/otp_verification_screen.dart
@@ -3,6 +3,7 @@ import 'dart:async';
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/presentation/authentication/register_step2.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
@@ -220,6 +221,8 @@ class _OTPVerificationScreenState extends State {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Verifying OTP: $otp')),
);
+
+ Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => RegisterNewStep2(null, {"nationalID": "12345678654321"})));
}
/// Auto fill OTP into text fields
diff --git a/lib/features/lab/lab_repo.dart b/lib/features/lab/lab_repo.dart
new file mode 100644
index 0000000..326379c
--- /dev/null
+++ b/lib/features/lab/lab_repo.dart
@@ -0,0 +1,78 @@
+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/exceptions/api_failure.dart';
+import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
+import 'package:dartz/dartz.dart';
+import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart';
+import 'package:hmg_patient_app_new/services/logger_service.dart';
+
+abstract class LabRepo {
+ Future>>> getPatientLabOrders({required String patientId});
+}
+
+class LabRepoImp implements LabRepo {
+ final ApiClient apiClient;
+ final LoggerService loggerService;
+
+ LabRepoImp({required this.loggerService, required this.apiClient});
+
+ @override
+ Future>>> getPatientLabOrders({required String patientId}) async {
+ final mapDevice = {
+ "isDentalAllowedBackend": false,
+ "VersionID": 50.0,
+ "Channel": 3,
+ "LanguageID": 2,
+ "IPAdress": "10.20.10.20",
+ "generalid": "Cs2020@2016\$2958",
+ "Latitude": 0.0,
+ "Longitude": 0.0,
+ "DeviceTypeID": 1,
+ "PatientType": 1,
+ "PatientTypeID": 1,
+ "TokenID": "@dm!n",
+ "PatientID": "1018977",
+ "PatientOutSA": "0",
+ "SessionID": "03478TYC02N80874CTYN04883475!?"
+ };
+
+ try {
+ GenericApiModel>? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ GET_Patient_LAB_ORDERS,
+ body: mapDevice,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus}) {
+ try {
+ final list = response['ListPLO'];
+ if (list == null || list.isEmpty) {
+ throw Exception("lab list is empty");
+ }
+
+ final labOrders = list
+ .map((item) => PatientLabOrdersResponseModel.fromJson(item as Map))
+ .toList()
+ .cast();
+
+ apiResponse = GenericApiModel>(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: labOrders,
+ );
+ } 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()));
+ }
+ }
+}
diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart
new file mode 100644
index 0000000..acd87eb
--- /dev/null
+++ b/lib/features/lab/lab_view_model.dart
@@ -0,0 +1,45 @@
+import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/features/lab/lab_repo.dart';
+import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart';
+import 'package:hmg_patient_app_new/services/error_handler_service.dart';
+
+class LabViewModel extends ChangeNotifier {
+ bool isLabOrdersLoading = false;
+ bool isLabResultsLoading = false;
+
+ LabRepo labRepo;
+ ErrorHandlerService errorHandlerService;
+
+ List patientLabOrders = [];
+
+ LabViewModel({required this.labRepo, required this.errorHandlerService});
+
+ initLabProvider() {
+ patientLabOrders.clear();
+ isLabOrdersLoading = true;
+ isLabResultsLoading = true;
+ getPatientLabOrders();
+ notifyListeners();
+ }
+
+ Future getPatientLabOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async {
+ final result = await labRepo.getPatientLabOrders(patientId: "1231755");
+
+ 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) {
+ patientLabOrders = apiResponse.data!;
+ isLabOrdersLoading = false;
+ isLabResultsLoading = false;
+ notifyListeners();
+ if (onSuccess != null) {
+ onSuccess(apiResponse);
+ }
+ }
+ },
+ );
+ }
+}
diff --git a/lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart b/lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart
new file mode 100644
index 0000000..11bf573
--- /dev/null
+++ b/lib/features/lab/models/resp_models/patient_lab_orders_response_model.dart
@@ -0,0 +1,245 @@
+class PatientLabOrdersResponseModel {
+ int? actualDoctorRate;
+ dynamic? admissionDate;
+ dynamic? admissionNumber;
+ dynamic? appointmentDate;
+ dynamic? appointmentNo;
+ dynamic? appointmentTime;
+ String? clinicDescription;
+ String? clinicDescriptionEnglish;
+ dynamic? clinicDescriptionN;
+ int? clinicID;
+ String? createdOn;
+ num? decimalDoctorRate;
+ int? doctorID;
+ String? doctorImageURL;
+ String? doctorName;
+ String? doctorNameEnglish;
+ dynamic? doctorNameN;
+ int? doctorRate;
+ num? doctorStarsRate;
+ String? doctorTitle;
+ int? gender;
+ String? genderDescription;
+ String? invoiceNo;
+ dynamic? invoiceNoVP;
+ String? invoiceType;
+ bool? isActiveDoctorProfile;
+ bool? isDoctorAllowVedioCall;
+ bool? isDrReviewReq;
+ bool? isExecludeDoctor;
+ bool? isInOutPatient;
+ String? isInOutPatientDescription;
+ String? isInOutPatientDescriptionN;
+ bool? isLiveCareAppointment;
+ bool? isRead;
+ bool? isSendEmail;
+ String? nationalityFlagURL;
+ int? noOfPatientsRate;
+ String? orderDate;
+ String? orderNo;
+ dynamic? orderProjectID;
+ String? patientID;
+ String? projectID;
+ String? projectName;
+ dynamic? projectNameN;
+ String? qR;
+ String? setupID;
+ // List? speciality;
+ int? status;
+ String? statusDesc;
+ String? strOrderDate;
+ List? testDetails;
+
+ PatientLabOrdersResponseModel(
+ {this.actualDoctorRate,
+ this.admissionDate,
+ this.admissionNumber,
+ this.appointmentDate,
+ this.appointmentNo,
+ this.appointmentTime,
+ this.clinicDescription,
+ this.clinicDescriptionEnglish,
+ this.clinicDescriptionN,
+ this.clinicID,
+ this.createdOn,
+ this.decimalDoctorRate,
+ this.doctorID,
+ this.doctorImageURL,
+ this.doctorName,
+ this.doctorNameEnglish,
+ this.doctorNameN,
+ this.doctorRate,
+ this.doctorStarsRate,
+ this.doctorTitle,
+ this.gender,
+ this.genderDescription,
+ this.invoiceNo,
+ this.invoiceNoVP,
+ this.invoiceType,
+ this.isActiveDoctorProfile,
+ this.isDoctorAllowVedioCall,
+ this.isDrReviewReq,
+ this.isExecludeDoctor,
+ this.isInOutPatient,
+ this.isInOutPatientDescription,
+ this.isInOutPatientDescriptionN,
+ this.isLiveCareAppointment,
+ this.isRead,
+ this.isSendEmail,
+ this.nationalityFlagURL,
+ this.noOfPatientsRate,
+ this.orderDate,
+ this.orderNo,
+ this.orderProjectID,
+ this.patientID,
+ this.projectID,
+ this.projectName,
+ this.projectNameN,
+ this.qR,
+ this.setupID,
+ // this.speciality,
+ this.status,
+ this.statusDesc,
+ this.strOrderDate,
+ this.testDetails});
+
+ PatientLabOrdersResponseModel.fromJson(Map json) {
+ actualDoctorRate = json['ActualDoctorRate'];
+ admissionDate = json['AdmissionDate'];
+ admissionNumber = json['AdmissionNumber'];
+ appointmentDate = json['AppointmentDate'];
+ appointmentNo = json['AppointmentNo'];
+ appointmentTime = json['AppointmentTime'];
+ clinicDescription = json['ClinicDescription'];
+ clinicDescriptionEnglish = json['ClinicDescriptionEnglish'];
+ clinicDescriptionN = json['ClinicDescriptionN'];
+ clinicID = json['ClinicID'];
+ createdOn = json['CreatedOn'];
+ decimalDoctorRate = json['DecimalDoctorRate'];
+ doctorID = json['DoctorID'];
+ doctorImageURL = json['DoctorImageURL'];
+ doctorName = json['DoctorName'];
+ doctorNameEnglish = json['DoctorNameEnglish'];
+ doctorNameN = json['DoctorNameN'];
+ doctorRate = json['DoctorRate'];
+ doctorStarsRate = json['DoctorStarsRate'];
+ doctorTitle = json['DoctorTitle'];
+ gender = json['Gender'];
+ genderDescription = json['GenderDescription'];
+ invoiceNo = json['InvoiceNo'];
+ invoiceNoVP = json['InvoiceNo_VP'];
+ invoiceType = json['InvoiceType'];
+ isActiveDoctorProfile = json['IsActiveDoctorProfile'];
+ isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall'];
+ isDrReviewReq = json['IsDrReviewReq'];
+ isExecludeDoctor = json['IsExecludeDoctor'];
+ isInOutPatient = json['IsInOutPatient'];
+ isInOutPatientDescription = json['IsInOutPatientDescription'];
+ isInOutPatientDescriptionN = json['IsInOutPatientDescriptionN'];
+ isLiveCareAppointment = json['IsLiveCareAppointment'];
+ isRead = json['IsRead'];
+ isSendEmail = json['IsSendEmail'];
+ nationalityFlagURL = json['NationalityFlagURL'];
+ noOfPatientsRate = json['NoOfPatientsRate'];
+ orderDate = json['OrderDate'];
+ orderNo = json['OrderNo'];
+ orderProjectID = json['OrderProjectID'];
+ patientID = json['PatientID'];
+ projectID = json['ProjectID'];
+ projectName = json['ProjectName'];
+ projectNameN = json['ProjectNameN'];
+ qR = json['QR'];
+ setupID = json['SetupID'];
+ // speciality = json['Speciality'].cast();
+ status = json['Status'];
+ statusDesc = json['StatusDesc'];
+ strOrderDate = json['StrOrderDate'];
+ if (json['TestDetails'] != dynamic) {
+ testDetails = [];
+ json['TestDetails'].forEach((v) {
+ testDetails!.add(new TestDetails.fromJson(v));
+ });
+ }
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['ActualDoctorRate'] = this.actualDoctorRate;
+ data['AdmissionDate'] = this.admissionDate;
+ data['AdmissionNumber'] = this.admissionNumber;
+ data['AppointmentDate'] = this.appointmentDate;
+ data['AppointmentNo'] = this.appointmentNo;
+ data['AppointmentTime'] = this.appointmentTime;
+ data['ClinicDescription'] = this.clinicDescription;
+ data['ClinicDescriptionEnglish'] = this.clinicDescriptionEnglish;
+ data['ClinicDescriptionN'] = this.clinicDescriptionN;
+ data['ClinicID'] = this.clinicID;
+ data['CreatedOn'] = this.createdOn;
+ data['DecimalDoctorRate'] = this.decimalDoctorRate;
+ data['DoctorID'] = this.doctorID;
+ data['DoctorImageURL'] = this.doctorImageURL;
+ data['DoctorName'] = this.doctorName;
+ data['DoctorNameEnglish'] = this.doctorNameEnglish;
+ data['DoctorNameN'] = this.doctorNameN;
+ data['DoctorRate'] = this.doctorRate;
+ data['DoctorStarsRate'] = this.doctorStarsRate;
+ data['DoctorTitle'] = this.doctorTitle;
+ data['Gender'] = this.gender;
+ data['GenderDescription'] = this.genderDescription;
+ data['InvoiceNo'] = this.invoiceNo;
+ data['InvoiceNo_VP'] = this.invoiceNoVP;
+ data['InvoiceType'] = this.invoiceType;
+ data['IsActiveDoctorProfile'] = this.isActiveDoctorProfile;
+ data['IsDoctorAllowVedioCall'] = this.isDoctorAllowVedioCall;
+ data['IsDrReviewReq'] = this.isDrReviewReq;
+ data['IsExecludeDoctor'] = this.isExecludeDoctor;
+ data['IsInOutPatient'] = this.isInOutPatient;
+ data['IsInOutPatientDescription'] = this.isInOutPatientDescription;
+ data['IsInOutPatientDescriptionN'] = this.isInOutPatientDescriptionN;
+ data['IsLiveCareAppointment'] = this.isLiveCareAppointment;
+ data['IsRead'] = this.isRead;
+ data['IsSendEmail'] = this.isSendEmail;
+ data['NationalityFlagURL'] = this.nationalityFlagURL;
+ data['NoOfPatientsRate'] = this.noOfPatientsRate;
+ data['OrderDate'] = this.orderDate;
+ data['OrderNo'] = this.orderNo;
+ data['OrderProjectID'] = this.orderProjectID;
+ data['PatientID'] = this.patientID;
+ data['ProjectID'] = this.projectID;
+ data['ProjectName'] = this.projectName;
+ data['ProjectNameN'] = this.projectNameN;
+ data['QR'] = this.qR;
+ data['SetupID'] = this.setupID;
+ // data['Speciality'] = this.speciality;
+ data['Status'] = this.status;
+ data['StatusDesc'] = this.statusDesc;
+ data['StrOrderDate'] = this.strOrderDate;
+ if (this.testDetails != dynamic) {
+ data['TestDetails'] = this.testDetails!.map((v) => v.toJson()).toList();
+ }
+ return data;
+ }
+}
+
+class TestDetails {
+ String? description;
+ String? testCode;
+ String? testID;
+
+ TestDetails({this.description, this.testCode, this.testID});
+
+ TestDetails.fromJson(Map json) {
+ description = json['Description'];
+ testCode = json['TestCode'];
+ testID = json['TestID'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['Description'] = this.description;
+ data['TestCode'] = this.testCode;
+ data['TestID'] = this.testID;
+ return data;
+ }
+}
diff --git a/lib/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart b/lib/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart
new file mode 100644
index 0000000..7b1d879
--- /dev/null
+++ b/lib/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart
@@ -0,0 +1,174 @@
+class PatientPrescriptionsResponseModel {
+ String? setupID;
+ int? projectID;
+ int? patientID;
+ int? appointmentNo;
+ String? appointmentDate;
+ String? doctorName;
+ String? clinicDescription;
+ String? name;
+ int? episodeID;
+ num? actualDoctorRate;
+ int? admission;
+ int? clinicID;
+ String? companyName;
+ num? decimalDoctorRate;
+ String? despensedStatus;
+ String? dischargeDate;
+ int? dischargeNo;
+ int? doctorID;
+ String? doctorImageURL;
+ num? doctorRate;
+ num? doctorStarsRate;
+ String? doctorTitle;
+ int? gender;
+ String? genderDescription;
+ bool? isActiveDoctorProfile;
+ bool? isDoctorAllowVedioCall;
+ bool? isExecludeDoctor;
+ bool? isHomeMedicineDeliverySupported;
+ bool? isInOutPatient;
+ String? isInOutPatientDescription;
+ String? isInOutPatientDescriptionN;
+ bool? isInsurancePatient;
+ bool? isLiveCareAppointment;
+ String? nationalityFlagURL;
+ int? noOfPatientsRate;
+ String? qR;
+
+ // List? speciality;
+ String? strAppointmentDate;
+
+ PatientPrescriptionsResponseModel(
+ {this.setupID,
+ this.projectID,
+ this.patientID,
+ this.appointmentNo,
+ this.appointmentDate,
+ this.doctorName,
+ this.clinicDescription,
+ this.name,
+ this.episodeID,
+ this.actualDoctorRate,
+ this.admission,
+ this.clinicID,
+ this.companyName,
+ this.decimalDoctorRate,
+ this.despensedStatus,
+ this.dischargeDate,
+ this.dischargeNo,
+ this.doctorID,
+ this.doctorImageURL,
+ this.doctorRate,
+ this.doctorStarsRate,
+ this.doctorTitle,
+ this.gender,
+ this.genderDescription,
+ this.isActiveDoctorProfile,
+ this.isDoctorAllowVedioCall,
+ this.isExecludeDoctor,
+ this.isHomeMedicineDeliverySupported,
+ this.isInOutPatient,
+ this.isInOutPatientDescription,
+ this.isInOutPatientDescriptionN,
+ this.isInsurancePatient,
+ this.isLiveCareAppointment,
+ this.nationalityFlagURL,
+ this.noOfPatientsRate,
+ this.qR,
+ // this.speciality,
+ this.strAppointmentDate});
+
+ PatientPrescriptionsResponseModel.fromJson(Map json) {
+ setupID = json['SetupID'];
+ projectID = json['ProjectID'];
+ patientID = json['PatientID'];
+ appointmentNo = json['AppointmentNo'];
+ appointmentDate = json['AppointmentDate'];
+ doctorName = json['DoctorName'];
+ clinicDescription = json['ClinicDescription'];
+ name = json['Name'];
+ episodeID = json['EpisodeID'];
+ actualDoctorRate = json['ActualDoctorRate'];
+ admission = json['Admission'];
+ clinicID = json['ClinicID'];
+ companyName = json['CompanyName'];
+ decimalDoctorRate = json['DecimalDoctorRate'];
+ despensedStatus = json['Despensed_Status'];
+ dischargeDate = json['DischargeDate'];
+ dischargeNo = json['DischargeNo'];
+ doctorID = json['DoctorID'];
+ doctorImageURL = json['DoctorImageURL'];
+ doctorRate = json['DoctorRate'];
+ doctorStarsRate = json['DoctorStarsRate'];
+ doctorTitle = json['DoctorTitle'];
+ gender = json['Gender'];
+ genderDescription = json['GenderDescription'];
+ isActiveDoctorProfile = json['IsActiveDoctorProfile'];
+ isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall'];
+ isExecludeDoctor = json['IsExecludeDoctor'];
+ isHomeMedicineDeliverySupported = json['IsHomeMedicineDeliverySupported'];
+ isInOutPatient = json['IsInOutPatient'];
+ isInOutPatientDescription = json['IsInOutPatientDescription'];
+ isInOutPatientDescriptionN = json['IsInOutPatientDescriptionN'];
+ isInsurancePatient = json['IsInsurancePatient'];
+ isLiveCareAppointment = json['IsLiveCareAppointment'];
+ nationalityFlagURL = json['NationalityFlagURL'];
+ noOfPatientsRate = json['NoOfPatientsRate'];
+ qR = json['QR'];
+ // speciality = json['Speciality'].cast();
+ strAppointmentDate = json['StrAppointmentDate'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['SetupID'] = this.setupID;
+ data['ProjectID'] = this.projectID;
+ data['PatientID'] = this.patientID;
+ data['AppointmentNo'] = this.appointmentNo;
+ data['AppointmentDate'] = this.appointmentDate;
+ data['DoctorName'] = this.doctorName;
+ data['ClinicDescription'] = this.clinicDescription;
+ data['Name'] = this.name;
+ data['EpisodeID'] = this.episodeID;
+ data['ActualDoctorRate'] = this.actualDoctorRate;
+ data['Admission'] = this.admission;
+ data['ClinicID'] = this.clinicID;
+ data['CompanyName'] = this.companyName;
+ data['DecimalDoctorRate'] = this.decimalDoctorRate;
+ data['Despensed_Status'] = this.despensedStatus;
+ data['DischargeDate'] = this.dischargeDate;
+ data['DischargeNo'] = this.dischargeNo;
+ data['DoctorID'] = this.doctorID;
+ data['DoctorImageURL'] = this.doctorImageURL;
+ data['DoctorRate'] = this.doctorRate;
+ data['DoctorStarsRate'] = this.doctorStarsRate;
+ data['DoctorTitle'] = this.doctorTitle;
+ data['Gender'] = this.gender;
+ data['GenderDescription'] = this.genderDescription;
+ data['IsActiveDoctorProfile'] = this.isActiveDoctorProfile;
+ data['IsDoctorAllowVedioCall'] = this.isDoctorAllowVedioCall;
+ data['IsExecludeDoctor'] = this.isExecludeDoctor;
+ data['IsHomeMedicineDeliverySupported'] = this.isHomeMedicineDeliverySupported;
+ data['IsInOutPatient'] = this.isInOutPatient;
+ data['IsInOutPatientDescription'] = this.isInOutPatientDescription;
+ data['IsInOutPatientDescriptionN'] = this.isInOutPatientDescriptionN;
+ data['IsInsurancePatient'] = this.isInsurancePatient;
+ data['IsLiveCareAppointment'] = this.isLiveCareAppointment;
+ data['NationalityFlagURL'] = this.nationalityFlagURL;
+ data['NoOfPatientsRate'] = this.noOfPatientsRate;
+ data['QR'] = this.qR;
+ // data['Speciality'] = this.speciality;
+ data['StrAppointmentDate'] = this.strAppointmentDate;
+ return data;
+ }
+}
+
+class PrescriptionsList {
+ String? filterName = "";
+ List? prescriptionsList = [];
+
+ PrescriptionsList({this.filterName, PatientPrescriptionsResponseModel? prescriptions}) {
+ prescriptionsList!.add(prescriptions!);
+ }
+}
diff --git a/lib/features/prescriptions/models/resp_models/prescription_detail_response_model.dart b/lib/features/prescriptions/models/resp_models/prescription_detail_response_model.dart
new file mode 100644
index 0000000..3ca8396
--- /dev/null
+++ b/lib/features/prescriptions/models/resp_models/prescription_detail_response_model.dart
@@ -0,0 +1,144 @@
+class PrescriptionDetailResponseModel {
+ String? address;
+ num? appointmentNo;
+ String? clinic;
+ dynamic companyName;
+ num? days;
+ String? doctorName;
+ num? doseDailyQuantity;
+ String? frequency;
+ num? frequencyNumber;
+ dynamic image;
+ dynamic imageExtension;
+ String? imageSRCUrl;
+ dynamic imageString;
+ String? imageThumbUrl;
+ String? isCovered;
+ String? itemDescription;
+ num? itemID;
+ String? orderDate;
+ num? patientID;
+ String? patientName;
+ String? phoneOffice1;
+ dynamic prescriptionQR;
+ num? prescriptionTimes;
+ dynamic productImage;
+ dynamic productImageBase64;
+ String? productImageString;
+ num? projectID;
+ String? projectName;
+ String? remarks;
+ String? route;
+ String? sKU;
+ num? scaleOffset;
+ String? startDate;
+
+ PrescriptionDetailResponseModel(
+ {this.address,
+ this.appointmentNo,
+ this.clinic,
+ this.companyName,
+ this.days,
+ this.doctorName,
+ this.doseDailyQuantity,
+ this.frequency,
+ this.frequencyNumber,
+ this.image,
+ this.imageExtension,
+ this.imageSRCUrl,
+ this.imageString,
+ this.imageThumbUrl,
+ this.isCovered,
+ this.itemDescription,
+ this.itemID,
+ this.orderDate,
+ this.patientID,
+ this.patientName,
+ this.phoneOffice1,
+ this.prescriptionQR,
+ this.prescriptionTimes,
+ this.productImage,
+ this.productImageBase64,
+ this.productImageString,
+ this.projectID,
+ this.projectName,
+ this.remarks,
+ this.route,
+ this.sKU,
+ this.scaleOffset,
+ this.startDate});
+
+ PrescriptionDetailResponseModel.fromJson(Map json) {
+ address = json['Address'];
+ appointmentNo = json['AppointmentNo'];
+ clinic = json['Clinic'];
+ companyName = json['CompanyName'];
+ days = json['Days'];
+ doctorName = json['DoctorName'];
+ doseDailyQuantity = json['DoseDailyQuantity'];
+ frequency = json['Frequency'];
+ frequencyNumber = json['FrequencyNumber'];
+ image = json['Image'];
+ imageExtension = json['ImageExtension'];
+ imageSRCUrl = json['ImageSRCUrl'];
+ imageString = json['ImageString'];
+ imageThumbUrl = json['ImageThumbUrl'];
+ isCovered = json['IsCovered'];
+ itemDescription = json['ItemDescription'];
+ itemID = json['ItemID'];
+ orderDate = json['OrderDate'];
+ patientID = json['PatientID'];
+ patientName = json['PatientName'];
+ phoneOffice1 = json['PhoneOffice1'];
+ prescriptionQR = json['PrescriptionQR'];
+ prescriptionTimes = json['PrescriptionTimes'];
+ productImage = json['ProductImage'];
+ productImageBase64 = json['ProductImageBase64'];
+ productImageString = json['ProductImageString'];
+ projectID = json['ProjectID'];
+ projectName = json['ProjectName'];
+ remarks = json['Remarks'];
+ route = json['Route'];
+ sKU = json['SKU'];
+ scaleOffset = json['ScaleOffset'];
+ startDate = json['StartDate'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['Address'] = address;
+ data['AppointmentNo'] = appointmentNo;
+ data['Clinic'] = clinic;
+ data['CompanyName'] = companyName;
+ data['Days'] = days;
+ data['DoctorName'] = doctorName;
+ data['DoseDailyQuantity'] = doseDailyQuantity;
+ data['Frequency'] = frequency;
+ data['FrequencyNumber'] = frequencyNumber;
+ data['Image'] = image;
+ data['ImageExtension'] = imageExtension;
+ data['ImageSRCUrl'] = imageSRCUrl;
+ data['ImageString'] = imageString;
+ data['ImageThumbUrl'] = imageThumbUrl;
+ data['IsCovered'] = isCovered;
+ data['ItemDescription'] = itemDescription;
+ data['ItemID'] = itemID;
+ data['OrderDate'] = orderDate;
+ data['PatientID'] = patientID;
+ data['PatientName'] = patientName;
+ data['PhoneOffice1'] = phoneOffice1;
+ data['PrescriptionQR'] = prescriptionQR;
+ data['PrescriptionTimes'] = prescriptionTimes;
+ data['ProductImage'] = productImage;
+ data['ProductImageBase64'] = productImageBase64;
+ data['ProductImageString'] = productImageString;
+ data['ProjectID'] = projectID;
+ data['ProjectName'] = projectName;
+ data['Remarks'] = remarks;
+ data['Route'] = route;
+ data['SKU'] = sKU;
+ data['ScaleOffset'] = scaleOffset;
+ data['StartDate'] = startDate;
+ return data;
+ }
+}
diff --git a/lib/features/prescriptions/prescriptions_repo.dart b/lib/features/prescriptions/prescriptions_repo.dart
new file mode 100644
index 0000000..de7bc4b
--- /dev/null
+++ b/lib/features/prescriptions/prescriptions_repo.dart
@@ -0,0 +1,141 @@
+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/exceptions/api_failure.dart';
+import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
+import 'package:dartz/dartz.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_detail_response_model.dart';
+import 'package:hmg_patient_app_new/services/logger_service.dart';
+
+abstract class PrescriptionsRepo {
+ Future>>> getPatientPrescriptionOrders({required String patientId});
+
+ Future>>> getPatientPrescriptionDetails({required PatientPrescriptionsResponseModel prescriptionsResponseModel});
+}
+
+class PrescriptionsRepoImp implements PrescriptionsRepo {
+ final ApiClient apiClient;
+ final LoggerService loggerService;
+
+ PrescriptionsRepoImp({required this.loggerService, required this.apiClient});
+
+ @override
+ Future>>> getPatientPrescriptionOrders({required String patientId}) async {
+ final mapDevice = {
+ "isDentalAllowedBackend": false,
+ "VersionID": 50.0,
+ "Channel": 3,
+ "LanguageID": 2,
+ "IPAdress": "10.20.10.20",
+ "generalid": "Cs2020@2016\$2958",
+ "Latitude": 0.0,
+ "Longitude": 0.0,
+ "DeviceTypeID": 1,
+ "PatientType": 1,
+ "PatientTypeID": 1,
+ "TokenID": "@dm!n",
+ "PatientID": "1018977",
+ "PatientOutSA": "0",
+ "SessionID": "03478TYC02N80874CTYN04883475!?"
+ };
+
+ try {
+ GenericApiModel>? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ PRESCRIPTIONS,
+ body: mapDevice,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus}) {
+ try {
+ final list = response['PatientPrescriptionList'];
+ if (list == null || list.isEmpty) {
+ throw Exception("lab list is empty");
+ }
+
+ final prescriptionOrders = list.map((item) => PatientPrescriptionsResponseModel.fromJson(item as Map)).toList().cast();
+
+ apiResponse = GenericApiModel>(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: prescriptionOrders,
+ );
+ } 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>>> getPatientPrescriptionDetails({required PatientPrescriptionsResponseModel prescriptionsResponseModel}) async {
+ final mapDevice = {
+ "AppointmentNo": prescriptionsResponseModel.appointmentNo.toString(),
+ "SetupID": prescriptionsResponseModel.setupID,
+ "EpisodeID": prescriptionsResponseModel.episodeID.toString(),
+ "ClinicID": prescriptionsResponseModel.clinicID.toString(),
+ "ProjectID": prescriptionsResponseModel.projectID.toString(),
+ "DischargeNo": prescriptionsResponseModel.dischargeNo.toString(),
+ "isDentalAllowedBackend": false,
+ "VersionID": 50.0,
+ "Channel": 3,
+ "LanguageID": 2,
+ "IPAdress": "10.20.10.20",
+ "generalid": "Cs2020@2016\$2958",
+ "Latitude": 0.0,
+ "Longitude": 0.0,
+ "DeviceTypeID": 1,
+ "PatientType": 1,
+ "PatientTypeID": 1,
+ "TokenID": "@dm!n",
+ "PatientID": "1018977",
+ "PatientOutSA": "0",
+ "SessionID": "03478TYC02N80874CTYN04883475!?"
+ };
+
+ try {
+ GenericApiModel>? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ prescriptionsResponseModel.isInOutPatient! ? GET_PRESCRIPTION_REPORT_ENH : GET_PRESCRIPTION_REPORT,
+ body: mapDevice,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus}) {
+ try {
+ final list = prescriptionsResponseModel.isInOutPatient! ? response['ListPRM'] : response['INP_GetPrescriptionReport_List'];
+ if (list == null || list.isEmpty) {
+ throw Exception("prescription list is empty");
+ }
+
+ final prescriptionOrders = list.map((item) => PrescriptionDetailResponseModel.fromJson(item as Map)).toList().cast();
+
+ apiResponse = GenericApiModel>(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: prescriptionOrders,
+ );
+ } 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()));
+ }
+ }
+}
diff --git a/lib/features/prescriptions/prescriptions_view_model.dart b/lib/features/prescriptions/prescriptions_view_model.dart
new file mode 100644
index 0000000..23a818e
--- /dev/null
+++ b/lib/features/prescriptions/prescriptions_view_model.dart
@@ -0,0 +1,114 @@
+import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_detail_response_model.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
+import 'package:hmg_patient_app_new/services/error_handler_service.dart';
+
+class PrescriptionsViewModel extends ChangeNotifier {
+ bool isPrescriptionsOrdersLoading = false;
+ bool isPrescriptionsDetailsLoading = false;
+
+ PrescriptionsRepo prescriptionsRepo;
+ ErrorHandlerService errorHandlerService;
+
+ // Prescription Orders Lists
+ List patientPrescriptionOrders = [];
+
+ List patientPrescriptionOrdersByClinic = [];
+ List patientPrescriptionOrdersByHospital = [];
+ List patientPrescriptionOrdersViewList = [];
+
+ // Prescription Details List
+ List prescriptionDetailsList = [];
+
+ bool isSortByClinic = true;
+
+ PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService});
+
+ initPrescriptionsViewModel() {
+ patientPrescriptionOrders.clear();
+ patientPrescriptionOrdersByClinic.clear();
+ patientPrescriptionOrdersByHospital.clear();
+ patientPrescriptionOrdersViewList.clear();
+ isPrescriptionsOrdersLoading = true;
+ isPrescriptionsDetailsLoading = true;
+ isSortByClinic = true;
+ getPatientPrescriptionOrders();
+ notifyListeners();
+ }
+
+ setPrescriptionsDetailsLoading() {
+ isPrescriptionsDetailsLoading = true;
+ prescriptionDetailsList.clear();
+ notifyListeners();
+ }
+
+ setIsSortByClinic(bool value) {
+ isSortByClinic = value;
+ if (isSortByClinic) {
+ patientPrescriptionOrdersViewList = patientPrescriptionOrdersByClinic;
+ } else {
+ patientPrescriptionOrdersViewList = patientPrescriptionOrdersByHospital;
+ }
+ notifyListeners();
+ }
+
+ Future getPatientPrescriptionOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async {
+ final result = await prescriptionsRepo.getPatientPrescriptionOrders(patientId: "1231755");
+
+ 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) {
+ patientPrescriptionOrders = apiResponse.data!;
+ isPrescriptionsOrdersLoading = false;
+
+ for (var element in patientPrescriptionOrders) {
+ List prescriptionsByClinic = patientPrescriptionOrdersByClinic.where((elementClinic) => elementClinic.filterName == element.clinicDescription).toList();
+
+ if (prescriptionsByClinic.isNotEmpty) {
+ patientPrescriptionOrdersByClinic[patientPrescriptionOrdersByClinic.indexOf(prescriptionsByClinic[0])].prescriptionsList!.add(element);
+ } else {
+ patientPrescriptionOrdersByClinic.add(PrescriptionsList(filterName: element.clinicDescription, prescriptions: element));
+ }
+
+ List prescriptionsByHospital = patientPrescriptionOrdersByHospital.where((elementClinic) => elementClinic.filterName == element.name).toList();
+
+ if (prescriptionsByHospital.isNotEmpty) {
+ patientPrescriptionOrdersByHospital[patientPrescriptionOrdersByHospital.indexOf(prescriptionsByHospital[0])].prescriptionsList!.add(element);
+ } else {
+ patientPrescriptionOrdersByHospital.add(PrescriptionsList(filterName: element.name, prescriptions: element));
+ }
+ }
+ patientPrescriptionOrdersViewList = patientPrescriptionOrdersByClinic;
+ notifyListeners();
+ if (onSuccess != null) {
+ onSuccess(apiResponse);
+ }
+ }
+ },
+ );
+ }
+
+ Future getPrescriptionDetails(PatientPrescriptionsResponseModel prescriptionsResponseModel, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
+ final result = await prescriptionsRepo.getPatientPrescriptionDetails(prescriptionsResponseModel: prescriptionsResponseModel);
+
+ 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) {
+ prescriptionDetailsList = apiResponse.data!;
+ isPrescriptionsDetailsLoading = false;
+ notifyListeners();
+ if (onSuccess != null) {
+ onSuccess(apiResponse);
+ }
+ }
+ },
+ );
+ }
+}
diff --git a/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart b/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart
new file mode 100644
index 0000000..b5568bf
--- /dev/null
+++ b/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart
@@ -0,0 +1,232 @@
+class PatientRadiologyResponseModel {
+ String? setupID;
+ int? projectID;
+ dynamic patientID;
+ int? invoiceLineItemNo;
+ int? invoiceNo;
+ int? doctorID;
+ int? clinicID;
+ String? orderDate;
+ String? reportData;
+ String? imageURL;
+ String? procedureID;
+ int? appointmentNo;
+ dynamic dIAPacsURL;
+ bool? isRead;
+ String? readOn;
+ dynamic admissionNo;
+ bool? isInOutPatient;
+ int? actualDoctorRate;
+ dynamic admissionDate;
+ dynamic admissionNumber;
+ dynamic appointmentDate;
+ dynamic appointmentNumber;
+ dynamic appointmentTime;
+ String? clinicDescription;
+ String? dIAPACSURL;
+ dynamic decimalDoctorRate;
+ String? description;
+ String? doctorImageURL;
+ String? doctorName;
+ num? doctorRate;
+ num? doctorStarsRate;
+ String? doctorTitle;
+ String? examId;
+ int? gender;
+ dynamic genderDescription;
+ int? invoiceNoVP;
+ String? invoiceType;
+ bool? isActiveDoctorProfile;
+ bool? isExecludeDoctor;
+ String? isInOutPatientDescription;
+ String? isInOutPatientDescriptionN;
+ bool? isLiveCareAppointment;
+ dynamic nationalityFlagURL;
+ int? noOfPatientsRate;
+ int? orderNo;
+ dynamic procedureName;
+ String? projectName;
+ String? qR;
+ String? reportDataHTML;
+ String? reportDataTextString;
+ dynamic strAppointmentDate;
+ dynamic strOrderDate;
+ bool? isCVI;
+ bool? isRadMedicalReport;
+ dynamic vida3Id;
+
+ PatientRadiologyResponseModel(
+ {this.setupID,
+ this.projectID,
+ this.patientID,
+ this.invoiceLineItemNo,
+ this.invoiceNo,
+ this.doctorID,
+ this.clinicID,
+ this.orderDate,
+ this.reportData,
+ this.imageURL,
+ this.procedureID,
+ this.appointmentNo,
+ this.dIAPacsURL,
+ this.isRead,
+ this.readOn,
+ this.admissionNo,
+ this.isInOutPatient,
+ this.actualDoctorRate,
+ this.admissionDate,
+ this.admissionNumber,
+ this.appointmentDate,
+ this.appointmentNumber,
+ this.appointmentTime,
+ this.clinicDescription,
+ this.dIAPACSURL,
+ this.decimalDoctorRate,
+ this.description,
+ this.doctorImageURL,
+ this.doctorName,
+ this.doctorRate,
+ this.doctorStarsRate,
+ this.doctorTitle,
+ this.examId,
+ this.gender,
+ this.genderDescription,
+ this.invoiceNoVP,
+ this.invoiceType,
+ this.isActiveDoctorProfile,
+ this.isExecludeDoctor,
+ this.isInOutPatientDescription,
+ this.isInOutPatientDescriptionN,
+ this.isLiveCareAppointment,
+ this.nationalityFlagURL,
+ this.noOfPatientsRate,
+ this.orderNo,
+ this.procedureName,
+ this.projectName,
+ this.qR,
+ this.reportDataHTML,
+ this.reportDataTextString,
+ this.strAppointmentDate,
+ this.strOrderDate,
+ this.isCVI,
+ this.isRadMedicalReport,
+ this.vida3Id});
+
+ PatientRadiologyResponseModel.fromJson(Map json) {
+ setupID = json['SetupID'];
+ projectID = json['ProjectID'];
+ patientID = json['PatientID'];
+ invoiceLineItemNo = json['InvoiceLineItemNo'];
+ invoiceNo = json['InvoiceNo'];
+ doctorID = json['DoctorID'];
+ clinicID = json['ClinicID'];
+ orderDate = json['OrderDate'];
+ reportData = json['ReportData'];
+ imageURL = json['ImageURL'];
+ procedureID = json['ProcedureID'];
+ appointmentNo = json['AppointmentNo'];
+ dIAPacsURL = json['DIAPacsURL'];
+ isRead = json['IsRead'];
+ readOn = json['ReadOn'];
+ admissionNo = json['AdmissionNo'];
+ isInOutPatient = json['IsInOutPatient'];
+ actualDoctorRate = json['ActualDoctorRate'];
+ admissionDate = json['AdmissionDate'];
+ admissionNumber = json['AdmissionNumber'];
+ appointmentDate = json['AppointmentDate'];
+ appointmentNumber = json['AppointmentNumber'];
+ appointmentTime = json['AppointmentTime'];
+ clinicDescription = json['ClinicDescription'];
+ dIAPACSURL = json['DIA_PACS_URL'];
+ decimalDoctorRate = json['DecimalDoctorRate'];
+ description = json['Description'];
+ doctorImageURL = json['DoctorImageURL'];
+ doctorName = json['DoctorName'];
+ doctorRate = json['DoctorRate'];
+ doctorStarsRate = json['DoctorStarsRate'];
+ doctorTitle = json['DoctorTitle'];
+ examId = json['Exam_id'];
+ gender = json['Gender'];
+ genderDescription = json['GenderDescription'];
+ invoiceNoVP = json['InvoiceNo_VP'];
+ invoiceType = json['InvoiceType'];
+ isActiveDoctorProfile = json['IsActiveDoctorProfile'];
+ isExecludeDoctor = json['IsExecludeDoctor'];
+ isInOutPatientDescription = json['IsInOutPatientDescription'];
+ isInOutPatientDescriptionN = json['IsInOutPatientDescriptionN'];
+ isLiveCareAppointment = json['IsLiveCareAppointment'];
+ nationalityFlagURL = json['NationalityFlagURL'];
+ noOfPatientsRate = json['NoOfPatientsRate'];
+ orderNo = json['OrderNo'];
+ procedureName = json['ProcedureName'];
+ projectName = json['ProjectName'];
+ qR = json['QR'];
+ reportDataHTML = json['ReportDataHTML'];
+ reportDataTextString = json['ReportDataTextString'];
+ strAppointmentDate = json['StrAppointmentDate'];
+ strOrderDate = json['StrOrderDate'];
+ isCVI = json['isCVI'];
+ isRadMedicalReport = json['isRadMedicalReport'];
+ vida3Id = json['vida3Id'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['SetupID'] = this.setupID;
+ data['ProjectID'] = this.projectID;
+ data['PatientID'] = this.patientID;
+ data['InvoiceLineItemNo'] = this.invoiceLineItemNo;
+ data['InvoiceNo'] = this.invoiceNo;
+ data['DoctorID'] = this.doctorID;
+ data['ClinicID'] = this.clinicID;
+ data['OrderDate'] = this.orderDate;
+ data['ReportData'] = this.reportData;
+ data['ImageURL'] = this.imageURL;
+ data['ProcedureID'] = this.procedureID;
+ data['AppointmentNo'] = this.appointmentNo;
+ data['DIAPacsURL'] = this.dIAPacsURL;
+ data['IsRead'] = this.isRead;
+ data['ReadOn'] = this.readOn;
+ data['AdmissionNo'] = this.admissionNo;
+ data['IsInOutPatient'] = this.isInOutPatient;
+ data['ActualDoctorRate'] = this.actualDoctorRate;
+ data['AdmissionDate'] = this.admissionDate;
+ data['AdmissionNumber'] = this.admissionNumber;
+ data['AppointmentDate'] = this.appointmentDate;
+ data['AppointmentNumber'] = this.appointmentNumber;
+ data['AppointmentTime'] = this.appointmentTime;
+ data['ClinicDescription'] = this.clinicDescription;
+ data['DIA_PACS_URL'] = this.dIAPACSURL;
+ data['DecimalDoctorRate'] = this.decimalDoctorRate;
+ data['Description'] = this.description;
+ data['DoctorImageURL'] = this.doctorImageURL;
+ data['DoctorName'] = this.doctorName;
+ data['DoctorRate'] = this.doctorRate;
+ data['DoctorStarsRate'] = this.doctorStarsRate;
+ data['DoctorTitle'] = this.doctorTitle;
+ data['Exam_id'] = this.examId;
+ data['Gender'] = this.gender;
+ data['GenderDescription'] = this.genderDescription;
+ data['InvoiceNo_VP'] = this.invoiceNoVP;
+ data['InvoiceType'] = this.invoiceType;
+ data['IsActiveDoctorProfile'] = this.isActiveDoctorProfile;
+ data['IsExecludeDoctor'] = this.isExecludeDoctor;
+ data['IsInOutPatientDescription'] = this.isInOutPatientDescription;
+ data['IsInOutPatientDescriptionN'] = this.isInOutPatientDescriptionN;
+ data['IsLiveCareAppointment'] = this.isLiveCareAppointment;
+ data['NationalityFlagURL'] = this.nationalityFlagURL;
+ data['NoOfPatientsRate'] = this.noOfPatientsRate;
+ data['OrderNo'] = this.orderNo;
+ data['ProcedureName'] = this.procedureName;
+ data['ProjectName'] = this.projectName;
+ data['QR'] = this.qR;
+ data['ReportDataHTML'] = this.reportDataHTML;
+ data['ReportDataTextString'] = this.reportDataTextString;
+ data['StrAppointmentDate'] = this.strAppointmentDate;
+ data['StrOrderDate'] = this.strOrderDate;
+ data['isCVI'] = this.isCVI;
+ data['isRadMedicalReport'] = this.isRadMedicalReport;
+ data['vida3Id'] = this.vida3Id;
+ return data;
+ }
+}
diff --git a/lib/features/radiology/radiology_repo.dart b/lib/features/radiology/radiology_repo.dart
new file mode 100644
index 0000000..d3e4f3d
--- /dev/null
+++ b/lib/features/radiology/radiology_repo.dart
@@ -0,0 +1,77 @@
+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/exceptions/api_failure.dart';
+import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
+import 'package:dartz/dartz.dart';
+import 'package:hmg_patient_app_new/features/radiology/models/resp_models/patient_radiology_response_model.dart';
+import 'package:hmg_patient_app_new/services/logger_service.dart';
+
+abstract class RadiologyRepo {
+ Future>>> getPatientRadiologyOrders({required String patientId});
+}
+
+class RadiologyRepoImp implements RadiologyRepo {
+ final ApiClient apiClient;
+ final LoggerService loggerService;
+
+ RadiologyRepoImp({required this.loggerService, required this.apiClient});
+
+ @override
+ Future>>> getPatientRadiologyOrders({required String patientId}) async {
+ final mapDevice = {
+ "isDentalAllowedBackend": false,
+ "VersionID": 50.0,
+ "Channel": 3,
+ "LanguageID": 2,
+ "IPAdress": "10.20.10.20",
+ "generalid": "Cs2020@2016\$2958",
+ "Latitude": 0.0,
+ "Longitude": 0.0,
+ "DeviceTypeID": 1,
+ "PatientType": 1,
+ "PatientTypeID": 1,
+ "TokenID": "@dm!n",
+ "PatientID": "1018977",
+ "PatientOutSA": "0",
+ "SessionID": "03478TYC02N80874CTYN04883475!?"
+ };
+
+ try {
+ GenericApiModel>? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ GET_PATIENT_ORDERS,
+ body: mapDevice,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus}) {
+ final radOrders;
+ try {
+ if (response['FinalRadiologyList'] != null && response['FinalRadiologyList'].length != 0) {
+ final list = response['FinalRadiologyList'];
+ radOrders = list.map((item) => PatientRadiologyResponseModel.fromJson(item as Map)).toList().cast();
+ } else {
+ final list = response['FinalRadiologyListAPI'];
+ radOrders = list.map((item) => PatientRadiologyResponseModel.fromJson(item as Map)).toList().cast();
+ }
+
+ apiResponse = GenericApiModel>(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: radOrders,
+ );
+ } 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()));
+ }
+ }
+}
diff --git a/lib/features/radiology/radiology_view_model.dart b/lib/features/radiology/radiology_view_model.dart
new file mode 100644
index 0000000..1bdba04
--- /dev/null
+++ b/lib/features/radiology/radiology_view_model.dart
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart';
+import 'package:hmg_patient_app_new/services/error_handler_service.dart';
+
+import 'models/resp_models/patient_radiology_response_model.dart';
+
+class RadiologyViewModel extends ChangeNotifier {
+ bool isRadiologyOrdersLoading = false;
+
+ RadiologyRepo radiologyRepo;
+ ErrorHandlerService errorHandlerService;
+
+ List patientRadiologyOrders = [];
+
+ RadiologyViewModel({required this.radiologyRepo, required this.errorHandlerService});
+
+ initRadiologyProvider() {
+ patientRadiologyOrders.clear();
+ isRadiologyOrdersLoading = true;
+ getPatientRadiologyOrders();
+ notifyListeners();
+ }
+
+ Future getPatientRadiologyOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async {
+ final result = await radiologyRepo.getPatientRadiologyOrders(patientId: "1231755");
+
+ 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) {
+ patientRadiologyOrders = apiResponse.data!;
+ isRadiologyOrdersLoading = false;
+ notifyListeners();
+ if (onSuccess != null) {
+ onSuccess(apiResponse);
+ }
+ }
+ },
+ );
+ }
+}
diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart
index c5f2592..0210e4c 100644
--- a/lib/generated/locale_keys.g.dart
+++ b/lib/generated/locale_keys.g.dart
@@ -774,8 +774,13 @@ abstract class LocaleKeys {
static const validPassportNumber = 'validPassportNumber';
static const continuePlan = 'continuePlan';
static const aboutApp = 'aboutApp';
- static const loginOrRegister = 'loginOrRegister';
static const dontHaveAccount = 'dontHaveAccount';
+ static const loginOrRegister = 'loginOrRegister';
+ static const myFiles = 'myFiles';
+ static const resultsPending = 'resultsPending';
+ static const resultsAvailable = 'resultsAvailable';
+ static const viewReport = 'viewReport';
+ static const prescriptionDeliveryError = 'prescriptionDeliveryError';
static const receiveOtpToast = 'receiveOtpToast';
static const enterPhoneNumber = 'enterPhoneNumber';
static const enterEmailDesc = 'enterEmailDesc';
@@ -789,5 +794,13 @@ abstract class LocaleKeys {
static const oR = 'oR';
static const sendOTPWHATSAPP = 'sendOTPWHATSAPP';
static const sendOTPSMS = 'sendOTPSMS';
+ static const fullName = 'fullName';
+ static const married = 'married';
+ static const uae = 'uae';
+ static const malE = 'malE';
+ static const loginBy = 'loginBy';
+ static const loginByOTP = 'loginByOTP';
+ static const guest = 'guest';
+ static const switchAccount = 'switchAccount';
}
diff --git a/lib/main.dart b/lib/main.dart
index f528886..e57d960 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -7,7 +7,9 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
-import 'package:hmg_patient_app_new/providers/bottom_navigation_provider.dart';
+import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
+import 'package:hmg_patient_app_new/features/radiology/radiology_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';
@@ -51,8 +53,23 @@ void main() async {
path: 'assets/langs',
fallbackLocale: Locale('en', 'US'),
child: MultiProvider(providers: [
- ChangeNotifierProvider(
- create: (_) => BottomNavigationProvider(),
+ ChangeNotifierProvider(
+ create: (_) => LabViewModel(
+ labRepo: getIt(),
+ errorHandlerService: getIt(),
+ ),
+ ),
+ ChangeNotifierProvider(
+ create: (_) => RadiologyViewModel(
+ radiologyRepo: getIt(),
+ errorHandlerService: getIt(),
+ ),
+ ),
+ ChangeNotifierProvider(
+ create: (_) => PrescriptionsViewModel(
+ prescriptionsRepo: getIt(),
+ errorHandlerService: getIt(),
+ ),
),
ChangeNotifierProvider(
create: (_) => AuthenticationViewModel(
diff --git a/lib/presentation/authentication/register_step2.dart b/lib/presentation/authentication/register_step2.dart
new file mode 100644
index 0000000..295dd8a
--- /dev/null
+++ b/lib/presentation/authentication/register_step2.dart
@@ -0,0 +1,313 @@
+import 'dart:convert';
+
+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/common_models/nationality_country_model.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/size_utils.dart';
+import 'package:hmg_patient_app_new/extensions/context_extensions.dart';
+import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
+import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
+import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
+import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
+import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dart';
+import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
+import 'package:hmg_patient_app_new/widgets/dropdown/dropdown_widget.dart';
+import 'package:hmg_patient_app_new/widgets/input_widget.dart';
+
+class RegisterNewStep2 extends StatefulWidget {
+ var nHICData;
+ var payload;
+
+ RegisterNewStep2(this.nHICData, this.payload, {Key? key}) : super(key: key);
+
+ @override
+ _RegisterNew createState() => _RegisterNew();
+}
+
+class _RegisterNew extends State {
+ bool isFromDubai = true;
+ List countriesList = [];
+ AppState? appState;
+ GenderTypeEnum? selectedGenderType;
+ MaritalStatusTypeEnum? selectedMaritalStatusType;
+ CountryEnum? selectedCountry;
+
+ @override
+ void initState() {
+ super.initState();
+ // isFromDubai = widget.payload.zipCode!.contains("971") || widget.payload.zipCode!.contains("+971");
+ loadCountriesList();
+ }
+
+ loadCountriesList() async {
+ appState = getIt.get();
+ final String response = await DefaultAssetBundle.of(context).loadString('assets/json/countriesList.json');
+ final List data = json.decode(response);
+ countriesList = data.map((e) => NationalityCountries.fromJson(e)).toList();
+ }
+
+ Widget build(BuildContext context) {
+ return Scaffold(
+
+ appBar: CustomAppBar(onBackPressed: () {}, onLanguageChanged: (lang) {}, hideLogoAndLang: true,),
+ body: SingleChildScrollView(
+ reverse: false,
+ padding: EdgeInsets.only(left: 24.h, right: 24.h, top: 24.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Directionality(
+ textDirection: Directionality.of(context),
+ child: Container(
+ decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)),
+ padding: EdgeInsets.only(left: 16.h, right: 16.h),
+ child: Column(
+ children: [
+ TextInputWidget(
+ labelText: isFromDubai ? LocaleKeys.fullName.tr() : LocaleKeys.name.tr(),
+ hintText: isFromDubai ? "name" ?? "" : (widget.nHICData!.firstNameEn!.toUpperCase() + " " + widget.nHICData!.lastNameEn!.toUpperCase()),
+ controller: null,
+ isEnable: true,
+ prefix: null,
+ isAllowRadius: false,
+ isBorderAllowed: false,
+ keyboardType: TextInputType.text,
+ isAllowLeadingIcon: true,
+ isReadOnly: isFromDubai ? false : true,
+ leadingIcon: AppAssets.user_circle).paddingSymmetrical(0.h,16.h),
+ Divider(height: 1, color: AppColors.greyColor,),
+ TextInputWidget(
+ labelText: LocaleKeys.nationalIdNumber.tr(),
+ hintText: isFromDubai ? "widget.payload.nationalID!" : (widget.nHICData!.idNumber ?? ""),
+ controller: null,
+ isEnable: true,
+ prefix: null,
+ isAllowRadius: false,
+ isBorderAllowed: false,
+ isAllowLeadingIcon: true,
+ isReadOnly: true,
+ leadingIcon: AppAssets.student_card).paddingSymmetrical(0.h,16.h),
+ Divider(height: 1, color: AppColors.greyColor,),
+ isFromDubai
+ ? DropdownWidget(
+ labelText: LocaleKeys.gender.tr(),
+ hintText: LocaleKeys.malE.tr(),
+ isEnable: true,
+ dropdownItems: GenderTypeEnum.values.map((e) => appState!.isArabic() ? e.typeAr : e.type).toList(),
+ selectedValue: appState!.isArabic() ? selectedGenderType!.typeAr : selectedGenderType?.type,
+ // selectionType: SelectionType.dropdown,
+ onChange: (val) {
+ if (val != null) {}
+ },
+ isBorderAllowed: false,
+ hasSelectionCustomIcon: true,
+ isAllowRadius: false,
+ padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0),
+ selectionCustomIcon: AppAssets.arrow_down,
+ leadingIcon: AppAssets.user_full,
+ ).withVerticalPadding(8)
+ : TextInputWidget(
+ labelText: LocaleKeys.gender.tr(),
+ hintText: (widget.nHICData!.gender ?? ""),
+ controller: null,
+ isEnable: true,
+ prefix: null,
+ isAllowRadius: false,
+ isBorderAllowed: false,
+ isAllowLeadingIcon: true,
+ isReadOnly: isFromDubai ? false : true,
+ leadingIcon: AppAssets.user_full,
+
+ onChange: (value) {}).paddingSymmetrical(0.h,16.h),
+ Divider(height: 1, color: AppColors.greyColor,),
+ isFromDubai
+ ? DropdownWidget(
+ labelText: LocaleKeys.maritalStatus.tr(),
+ hintText: LocaleKeys.married.tr(),
+ isEnable: true,
+ dropdownItems: MaritalStatusTypeEnum.values.map((e) => appState!.isArabic() ? e.typeAr : e.type).toList(),
+ selectedValue: appState!.isArabic() ? selectedMaritalStatusType!.typeAr : selectedMaritalStatusType?.type,
+ onChange: (val) {},
+ isBorderAllowed: false,
+ hasSelectionCustomIcon: true,
+ isAllowRadius: false,
+ padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0),
+ selectionCustomIcon: AppAssets.arrow_down,
+ leadingIcon: AppAssets.smart_phone,
+ ).withVerticalPadding(8)
+ : TextInputWidget(
+ labelText: LocaleKeys.maritalStatus.tr(),
+ hintText: appState!.isArabic()
+ ? (MaritalStatusTypeExtension.fromValue(widget.nHICData!.maritalStatusCode)!.typeAr)
+ : (MaritalStatusTypeExtension.fromValue(widget.nHICData!.maritalStatusCode)!.type),
+ isEnable: true,
+ prefix: null,
+ isAllowRadius: false,
+ isBorderAllowed: false,
+ isAllowLeadingIcon: true,
+ isReadOnly: true,
+ leadingIcon: AppAssets.smart_phone,
+ onChange: (value) {}).paddingSymmetrical(0.h,16.h),
+ Divider(height: 1, color: AppColors.greyColor,),
+ isFromDubai
+ ? DropdownWidget(
+ labelText: LocaleKeys.country.tr(),
+ hintText: LocaleKeys.uae.tr(),
+ isEnable: true,
+ dropdownItems: countriesList.map((e) => appState!.isArabic() ? e.nameN ?? "" : e.name ?? "").toList(),
+ selectedValue: appState!.isArabic() ? selectedCountry!.nameArabic ?? "" : selectedCountry?.name ?? "",
+ onChange: (val) {},
+ isBorderAllowed: false,
+ hasSelectionCustomIcon: true,
+ isAllowRadius: false,
+ padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0),
+ selectionCustomIcon: AppAssets.arrow_down,
+ leadingIcon: AppAssets.globe,
+ ).withVerticalPadding(8)
+ : TextInputWidget(
+ labelText: LocaleKeys.nationality.tr(),
+ hintText: appState!.isArabic()
+ ? (countriesList.firstWhere((e) => e.id == (widget.nHICData!.nationalityCode ?? ""), orElse: () => NationalityCountries()).nameN ?? "")
+ : (countriesList.firstWhere((e) => e.id == (widget.nHICData!.nationalityCode ?? ""), orElse: () => NationalityCountries()).name ?? ""),
+ isEnable: true,
+ prefix: null,
+ isAllowRadius: false,
+ isBorderAllowed: false,
+ isAllowLeadingIcon: true,
+ isReadOnly: true,
+ leadingIcon: AppAssets.globe,
+ onChange: (value) {}).paddingSymmetrical(0.h,16.h),
+ Divider(height: 1, color: AppColors.greyColor,),
+ TextInputWidget(
+ labelText: LocaleKeys.mobileNumber.tr(),
+ hintText: ("widget.payload.mobileNo" ?? ""),
+ controller: null,
+ isEnable: true,
+ prefix: null,
+ isAllowRadius: false,
+ isBorderAllowed: false,
+ isAllowLeadingIcon: true,
+ isReadOnly: true,
+ leadingIcon: AppAssets.call,
+ onChange: (value) {}).paddingSymmetrical(0.h,16.h),
+ Divider(height: 1, color: AppColors.greyColor,),
+ TextInputWidget(
+ labelText: LocaleKeys.dob.tr(),
+ hintText: isFromDubai ? "widget.payload.dob!" : (widget.nHICData!.dateOfBirth ?? ""),
+ controller: null,
+ isEnable: true,
+ prefix: null,
+ isBorderAllowed: false,
+ isAllowLeadingIcon: true,
+ isReadOnly: true,
+ // : SelectionType.calendar,
+ // selectedValue: widget.payload.dob != null ? Utils.formatDateToDisplay(widget.payload.dob.toString()) : null,
+ // selectionCustomIcon: AppAssets.calendar,
+ leadingIcon: AppAssets.birthday_cake,
+ onChange: (value) {}).paddingSymmetrical(0.h,16.h),
+ ],
+ ),
+ ),
+ ),
+ SizedBox(height: 50.h),
+ Row(
+ children: [
+ Expanded(
+ child: CustomButton(
+ text: LocaleKeys.cancel,
+ icon: AppAssets.cancel,
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ // fontFamily: context.fontFamily,
+ backgroundColor: AppColors.secondaryLightRedColor,
+ borderColor: AppColors.secondaryLightRedColor,
+ textColor: AppColors.primaryRedColor,
+ iconColor: AppColors.primaryRedColor,
+ ),
+ ),
+ SizedBox(
+ width: 16,
+ ),
+ Expanded(
+ child: CustomButton(
+ backgroundColor: AppColors.lightGreenColor,
+ borderColor: AppColors.lightGreenColor,
+ textColor: AppColors.textGreenColor,
+ text: LocaleKeys.confirm.tr(),
+ icon: AppAssets.confirm,
+ iconColor: AppColors.textGreenColor,
+ onPressed: () {
+ // if (isFromDubai) {
+ // if (name == null) {
+ // AppToast.showErrorToast(message: LocaleKeys.enterFullName);
+ // return;
+ // }
+ // if (!name!.contains(" ")) if (selectedGenderType == null) {
+ // AppToast.showErrorToast(message: TranslationBase.of(context).enterFullName);
+ // return;
+ // }
+ // if (selectedMaritalStatusType == null) {
+ // AppToast.showErrorToast(message: TranslationBase.of(context).chooseMaritalStatus);
+ // return;
+ // }
+ // if (selectedCountry == null) {
+ // AppToast.showErrorToast(message: TranslationBase.of(context).chooseCountry);
+ // return;
+ // }
+ // }
+
+ showModel(context: context);
+ },
+ ),
+ )
+ ],
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+ void showModel({required BuildContext context}) {
+ showModalBottomSheet(
+ context: context,
+ isScrollControlled: true,
+ isDismissible: false,
+ backgroundColor: Colors.transparent,
+ builder: (bottomSheetContext) => Padding(
+ padding: EdgeInsets.only(bottom: MediaQuery.of(bottomSheetContext).viewInsets.bottom),
+ child: SingleChildScrollView(
+ child: GenericBottomSheet(
+ textController: TextEditingController(),
+ isForEmail: true,
+ buttons: [
+ Padding(
+ padding: const EdgeInsets.only(bottom: 10),
+ child: CustomButton(
+ text: LocaleKeys.submit,
+ onPressed: () {
+ // if (emailAddress.text.isEmpty) {
+ // Utils.showErrorToast(TranslationBase.of(context).enterEmailAddress);
+ // return;
+ // } else {
+ // Navigator.of(context).pop();
+ // registerNow();
+ // }
+ },
+ backgroundColor: AppColors.bgGreenColor,
+ borderColor: AppColors.bgGreenColor,
+ textColor: AppColors.whiteColor),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/authentication/saved_login_screen.dart b/lib/presentation/authentication/saved_login_screen.dart
new file mode 100644
index 0000000..da04c40
--- /dev/null
+++ b/lib/presentation/authentication/saved_login_screen.dart
@@ -0,0 +1,289 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.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';
+import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/presentation/authentication/login.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
+import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
+import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dart';
+import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
+
+class SavedLogin extends StatefulWidget {
+ // final SelectDeviceIMEIRES savedLoginData;
+
+ // const SavedLogin(this.savedLoginData, {Key? key}) : super(key: key);
+ const SavedLogin();
+
+ @override
+ _SavedLogin createState() => _SavedLogin();
+}
+
+class _SavedLogin extends State {
+ LoginTypeEnum loginType = LoginTypeEnum.sms;
+
+ @override
+ void initState() {
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: CustomAppBar(
+ onBackPressed: () {},
+ onLanguageChanged: (lang) {},
+ ),
+ body: SafeArea(
+ child: Padding(
+ padding: EdgeInsets.symmetric(horizontal: 24.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ const Spacer(flex: 2),
+ // Welcome back text
+ LocaleKeys.welcomeBack.tr().toText16(color: AppColors.inputLabelTextColor),
+ SizedBox(height: 16.h),
+ ("widget.savedLoginData.name!.toLowerCase().capitalizeFirstofEach").toText26(isBold: true, height: 26 / 36, color: AppColors.textColor),
+ SizedBox(height: 24.h),
+ Container(
+ padding: EdgeInsets.all(16.h),
+ decoration: BoxDecoration(
+ color: AppColors.whiteColor,
+ border: Border.all(color: AppColors.whiteColor),
+ borderRadius: BorderRadius.circular(24.h),
+ boxShadow: [
+ BoxShadow(color: Color(0x0D000000), blurRadius: 16, offset: Offset(0, 0), spreadRadius: 5),
+ ],
+ ),
+ child: Column(
+ children: [
+ // Last login info
+ ('LocaleKeys.lastloginBy.tr()' + ' {getType(widget.savedLoginData.logInType!, context)}').toText14(isBold: true, color: AppColors.greyTextColor),
+ ('widget.savedLoginData.createdOn != null ? DateUtil.getFormattedDate(DateUtil.convertStringToDate(widget.savedLoginData.createdOn!), "d MMMM, y at HH:mm") : --')
+ .toText16(isBold: true, color: AppColors.textColor),
+
+ Container(margin: EdgeInsets.all(16.h), child: Utils.buildSvgWithAssets(icon: getTypeIcons(loginType.toInt), iconColor: loginType.toInt == 4 ? null : AppColors.primaryRedColor)),
+ // Face ID login button
+ Container(
+ height: 45,
+ child: CustomButton(
+ text: "${LocaleKeys.loginBy.tr()} ${loginType.displayName}",
+ onPressed: () {
+ if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
+ // loginWithFingerPrintFace(loginType.toInt, widget.savedLoginData.iMEI!);
+ } else {
+ int? val = loginType.toInt;
+ //checkUserAuthentication(val);
+ }
+ },
+ backgroundColor: Color(0xffED1C2B),
+ borderColor: Color(0xffFEE9EA),
+ textColor: Colors.white,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
+ icon: AppAssets.apple_finder,
+ ),
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(height: 24),
+ Padding(
+ padding: EdgeInsets.symmetric(horizontal: 16.0),
+ child: Text(
+ LocaleKeys.oR.tr(),
+ style: context.dynamicTextStyle(fontSize: 16, fontWeight: FontWeight.w500),
+ ),
+ ),
+ const SizedBox(height: 24),
+ // OTP login button
+ loginType != null && loginType.toInt != 1
+ ? Column(
+ children: [
+ loginType.toInt != 1
+ ? CustomButton(
+ text: LocaleKeys.loginByOTP.tr(),
+ onPressed: () {
+ showModalBottomSheet(
+ context: context,
+ isScrollControlled: true,
+ isDismissible: false,
+ useSafeArea: true,
+ backgroundColor: Colors.transparent,
+ enableDrag: false,
+ // Prevent dragging to avoid focus conflicts
+ builder: (bottomSheetContext) => StatefulBuilder(builder: (BuildContext context, StateSetter setModalState) {
+ return Padding(
+ padding: EdgeInsets.only(bottom: MediaQuery.of(bottomSheetContext).viewInsets.bottom),
+ child: SingleChildScrollView(
+ child: GenericBottomSheet(
+ countryCode: "966",
+ initialPhoneNumber: "",
+ textController: TextEditingController(),
+ isFromSavedLogin: true,
+ isEnableCountryDropdown: true,
+ onCountryChange: (value) {},
+ onChange: (String? value) {},
+ buttons: [
+ Padding(
+ padding: EdgeInsets.only(bottom: 10.h),
+ child: CustomButton(
+ text: LocaleKeys.sendOTPSMS.tr(),
+ onPressed: () {
+ Navigator.of(context).pop();
+ loginType = LoginTypeEnum.sms;
+ int? val = loginType.toInt;
+ // checkUserAuthentication(val);
+ },
+ backgroundColor: AppColors.primaryRedColor,
+ borderColor: AppColors.primaryRedBorderColor,
+ textColor: AppColors.whiteColor,
+ icon: AppAssets.message,
+ ),
+ ),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Padding(padding: EdgeInsets.symmetric(horizontal: 8.h), child: (LocaleKeys.oR.tr()).toText16(color: AppColors.textColor)),
+ ],
+ ),
+ Padding(
+ padding: const EdgeInsets.only(bottom: 10, top: 10),
+ child: CustomButton(
+ text: LocaleKeys.sendOTPWHATSAPP.tr(),
+ onPressed: () {
+ Navigator.of(context).pop();
+ loginType = LoginTypeEnum.whatsapp;
+ int? val = loginType.toInt;
+ // checkUserAuthentication(val);
+ },
+ backgroundColor: AppColors.transparent,
+ borderColor: AppColors.textColor,
+ textColor: AppColors.textColor,
+ icon: AppAssets.whatsapp,
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }),
+ );
+ },
+ backgroundColor: AppColors.whiteColor,
+ borderColor: AppColors.borderOnlyColor,
+ textColor: AppColors.textColor,
+ borderWidth: 2,
+ padding: EdgeInsets.fromLTRB(0, 14, 0, 14),
+ icon: AppAssets.password_validation,
+ )
+ : Container(),
+ SizedBox(
+ height: 20,
+ ),
+ ],
+ )
+ : CustomButton(
+ text: "${LocaleKeys.loginBy.tr()} ${LoginTypeEnum.whatsapp.displayName}",
+ onPressed: () {
+ if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
+ // loginWithFingerPrintFace(loginType.toInt, "iMEI");
+ } else {
+ loginType = LoginTypeEnum.whatsapp;
+ int? val = loginType.toInt;
+ // checkUserAuthentication(val);
+ }
+ },
+ backgroundColor: AppColors.whiteColor,
+ borderColor: Color(0xFF2E3039),
+ textColor: Color(0xFF2E3039),
+ borderWidth: 2,
+ padding: EdgeInsets.fromLTRB(0, 14, 0, 14),
+ icon: AppAssets.whatsapp,
+ ),
+ const Spacer(flex: 2),
+ // OR divider
+
+ const SizedBox(height: 24),
+ // Guest and Switch account
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Expanded(
+ child: Container(
+ height: 56,
+ child: CustomButton(
+ text: LocaleKeys.guest.tr(),
+ onPressed: () {
+ Navigator.of(context).pushReplacement(
+ MaterialPageRoute(builder: (BuildContext context) => LoginScreen()),
+ );
+ },
+ backgroundColor: Color(0xffFEE9EA),
+ borderColor: Color(0xffFEE9EA),
+ textColor: Color(0xffED1C2B),
+ fontSize: 16,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
+ // icon: "assets/images/svg/apple-finder.svg",
+ ),
+ ),
+ ),
+ SizedBox(
+ width: MediaQuery.of(context).size.width * 0.05,
+ ),
+ Expanded(
+ child: Container(
+ height: 56,
+ child: CustomButton(
+ text: LocaleKeys.switchAccount.tr(),
+ onPressed: () {
+ Navigator.of(context).pushReplacement(
+ MaterialPageRoute(builder: (BuildContext context) => LoginScreen()),
+ );
+ },
+ backgroundColor: Color(0xffFEE9EA),
+ borderColor: Color(0xffFEE9EA),
+ textColor: Color(0xffED1C2B),
+ fontSize: 15,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
+ // icon: "assets/images/svg/apple-finder.svg",
+ ),
+ ),
+ ),
+ ],
+ ),
+ const SizedBox(height: 20),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+
+ String getTypeIcons(int type) {
+ final types = {
+ 1: AppAssets.sms,
+ 2: AppAssets.fingerprint,
+ 3: AppAssets.fingerprint,
+ 4: AppAssets.whatsapp,
+ };
+
+ if (types.containsKey(type)) {
+ return types[type]!;
+ } else {
+ throw Exception('Invalid login type: $type');
+ }
+ }
+}
diff --git a/lib/presentation/home/data/landing_page_data.dart b/lib/presentation/home/data/landing_page_data.dart
index b34d9bc..ad524e3 100644
--- a/lib/presentation/home/data/landing_page_data.dart
+++ b/lib/presentation/home/data/landing_page_data.dart
@@ -6,6 +6,7 @@ import 'package:hmg_patient_app_new/theme/colors.dart';
class LandingPageData {
static List getNotLoggedInServiceCardsList = [
ServiceCardData(
+ serviceName: "emergency",
icon: AppAssets.emergency_services_icon,
title: "Emergency",
subtitle: "Services",
@@ -15,6 +16,7 @@ class LandingPageData {
isBold: true,
),
ServiceCardData(
+ serviceName: "indoor_navigation",
icon: AppAssets.indoor_nav_icon,
title: "Indoor",
subtitle: "Navigation",
@@ -24,6 +26,7 @@ class LandingPageData {
isBold: false,
),
ServiceCardData(
+ serviceName: "search_doctor",
icon: AppAssets.search_doctor_icon,
title: "Search",
subtitle: "Doctor",
@@ -33,6 +36,7 @@ class LandingPageData {
isBold: false,
),
ServiceCardData(
+ serviceName: "health_calculators",
icon: AppAssets.health_calculators_icon,
title: "Health",
subtitle: "Calculators",
@@ -42,6 +46,7 @@ class LandingPageData {
isBold: false,
),
ServiceCardData(
+ serviceName: "health_converters",
icon: AppAssets.health_calculators_icon,
title: "Health",
subtitle: "Converters",
@@ -51,6 +56,7 @@ class LandingPageData {
isBold: false,
),
ServiceCardData(
+ serviceName: "parking_guide",
icon: AppAssets.health_calculators_icon,
title: "Parking",
subtitle: "Guide",
@@ -63,6 +69,7 @@ class LandingPageData {
static List getLoggedInServiceCardsList = [
ServiceCardData(
+ serviceName: "emergency",
icon: AppAssets.emergency_services_icon,
title: "Emergency",
subtitle: "Services",
@@ -72,6 +79,7 @@ class LandingPageData {
isBold: true,
),
ServiceCardData(
+ serviceName: "lab_results",
icon: AppAssets.lab_result_icon,
title: "My Lab",
subtitle: "Results",
@@ -81,6 +89,17 @@ class LandingPageData {
isBold: false,
),
ServiceCardData(
+ serviceName: "radiology_results",
+ icon: AppAssets.lab_result_icon,
+ title: "My Radiology",
+ subtitle: "Results",
+ backgroundColor: AppColors.whiteColor,
+ iconColor: AppColors.blackColor,
+ textColor: AppColors.blackColor,
+ isBold: false,
+ ),
+ ServiceCardData(
+ serviceName: "prescriptions",
icon: AppAssets.my_prescription_icon,
title: "My",
subtitle: "Prescriptions",
@@ -90,6 +109,7 @@ class LandingPageData {
isBold: false,
),
ServiceCardData(
+ serviceName: "insurance_update",
icon: AppAssets.insurance_update_icon,
title: "Insurance",
subtitle: "Update",
@@ -99,6 +119,7 @@ class LandingPageData {
isBold: false,
),
ServiceCardData(
+ serviceName: "my_doctors",
icon: AppAssets.insurance_update_icon,
title: "My",
subtitle: "Doctors",
@@ -108,6 +129,7 @@ class LandingPageData {
isBold: false,
),
ServiceCardData(
+ serviceName: "sick_leaves",
icon: AppAssets.insurance_update_icon,
title: "My Sick",
subtitle: "Leaves",
diff --git a/lib/presentation/home/data/service_card_data.dart b/lib/presentation/home/data/service_card_data.dart
index 856a15e..49e7e3d 100644
--- a/lib/presentation/home/data/service_card_data.dart
+++ b/lib/presentation/home/data/service_card_data.dart
@@ -3,6 +3,7 @@ import 'dart:ui';
import 'package:hmg_patient_app_new/theme/colors.dart';
class ServiceCardData {
+ final String serviceName;
final String icon;
final String title;
final String subtitle;
@@ -13,6 +14,7 @@ class ServiceCardData {
final String largeCardIcon;
ServiceCardData({
+ this.serviceName = "",
this.icon = "",
this.title = "",
this.subtitle = "",
diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart
index 0710d7c..3592acd 100644
--- a/lib/presentation/home/landing_page.dart
+++ b/lib/presentation/home/landing_page.dart
@@ -19,6 +19,7 @@ import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.
import 'package:hmg_patient_app_new/providers/bottom_navigation_provider.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
+import 'package:hmg_patient_app_new/widgets/bottom_navigation/bottom_navigation.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
diff --git a/lib/presentation/home/widgets/small_service_card.dart b/lib/presentation/home/widgets/small_service_card.dart
index a138db6..297ed2b 100644
--- a/lib/presentation/home/widgets/small_service_card.dart
+++ b/lib/presentation/home/widgets/small_service_card.dart
@@ -2,11 +2,16 @@ import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
+import 'package:hmg_patient_app_new/presentation/lab/lab_orders_page.dart';
+import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
+import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import '../../../core/utils/utils.dart';
import '../../../theme/colors.dart';
+import '../../radiology/radiology_orders_page.dart' show RadiologyOrdersPage;
class SmallServiceCard extends StatelessWidget {
+ final String serviceName;
final String icon;
final String title;
final String subtitle;
@@ -18,6 +23,7 @@ class SmallServiceCard extends StatelessWidget {
SmallServiceCard({
super.key,
this.icon = "",
+ this.serviceName = "",
this.title = "",
this.subtitle = "",
this.backgroundColor = AppColors.whiteColor,
@@ -48,6 +54,35 @@ class SmallServiceCard extends StatelessWidget {
),
),
),
- );
+ ).onPress(() {
+ switch (serviceName) {
+ case "lab_results":
+ Navigator.of(context).push(
+ FadePage(
+ page: LabOrdersPage(),
+ ),
+ );
+ break;
+ case "radiology_results":
+ Navigator.of(context).push(
+ FadePage(
+ page: RadiologyOrdersPage(),
+ ),
+ );
+ break;
+ case "prescriptions":
+ Navigator.of(context).push(
+ FadePage(
+ page: PrescriptionsListPage(),
+ ),
+ );
+ break;
+ case "insurance_update":
+ break;
+ default:
+ // Handle unknown service
+ break;
+ }
+ });
}
}
diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart
new file mode 100644
index 0000000..8a0ce26
--- /dev/null
+++ b/lib/presentation/lab/lab_orders_page.dart
@@ -0,0 +1,265 @@
+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/app_assets.dart';
+import 'package:hmg_patient_app_new/core/utils/date_util.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/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/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/features/lab/lab_view_model.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/shimmer/movies_shimmer_widget.dart';
+import 'package:provider/provider.dart';
+
+class LabOrdersPage extends StatefulWidget {
+ const LabOrdersPage({super.key});
+
+ @override
+ State createState() => _LabOrdersPageState();
+}
+
+class _LabOrdersPageState extends State {
+ late LabViewModel labProvider;
+
+ int? expandedIndex;
+
+ @override
+ void initState() {
+ scheduleMicrotask(() {
+ labProvider.initLabProvider();
+ });
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ labProvider = Provider.of(context);
+ return Scaffold(
+ backgroundColor: AppColors.bgScaffoldColor,
+ appBar: AppBar(
+ title: LocaleKeys.labResults.tr(context: context).toText18(),
+ backgroundColor: AppColors.bgScaffoldColor,
+ ),
+ body: Padding(
+ padding: EdgeInsets.all(24.h),
+ child: SingleChildScrollView(
+ child: Consumer(
+ builder: (context, model, child) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ LocaleKeys.labResults.tr(context: context).toText24(isBold: true),
+ Utils.buildSvgWithAssets(icon: AppAssets.search_icon),
+ ],
+ ),
+ SizedBox(height: 16.h),
+ // Build Tab Bar
+ SizedBox(height: 16.h),
+ // Expandable list
+ ListView.builder(
+ shrinkWrap: true,
+ physics: NeverScrollableScrollPhysics(),
+ itemCount: model.isLabOrdersLoading ? 5 : model.patientLabOrders.length,
+ itemBuilder: (context, index) {
+ final isExpanded = expandedIndex == index;
+ return model.isLabOrdersLoading
+ ? const MoviesShimmerWidget()
+ : 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,
+ margin: EdgeInsets.symmetric(vertical: 8.h),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
+ child: InkWell(
+ onTap: () {
+ setState(() {
+ expandedIndex = isExpanded ? null : index;
+ });
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomButton(
+ text: getLabOrderStatusText(model.patientLabOrders[index].status!),
+ onPressed: () {},
+ backgroundColor: getLabOrderStatusColor(model.patientLabOrders[index].status!).withOpacity(0.15),
+ borderColor: getLabOrderStatusColor(model.patientLabOrders[index].status!).withOpacity(0.01),
+ textColor: getLabOrderStatusColor(model.patientLabOrders[index].status!),
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ Image.network(
+ model.patientLabOrders[index].doctorImageURL!,
+ width: 24.h,
+ height: 24.h,
+ fit: BoxFit.fill,
+ ).circle(100),
+ SizedBox(width: 4.h),
+ model.patientLabOrders[index].doctorName!.toText16(isBold: true)
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ CustomButton(
+ text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(model.patientLabOrders[index].createdOn), false),
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 24.h,
+ ),
+ SizedBox(width: 8.h),
+ CustomButton(
+ text: model.patientLabOrders[index].clinicDescription!,
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 24.h,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ AnimatedSwitcher(
+ duration: Duration(milliseconds: 300),
+ switchInCurve: Curves.easeIn,
+ switchOutCurve: Curves.easeOut,
+ transitionBuilder: (Widget child, Animation animation) {
+ return FadeTransition(
+ opacity: animation,
+ child: SizeTransition(
+ sizeFactor: animation,
+ axisAlignment: 0.0,
+ child: child,
+ ),
+ );
+ },
+ child: isExpanded
+ ? Container(
+ key: ValueKey(index),
+ padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ ...model.patientLabOrders[index].testDetails!.map((detail) {
+ return Padding(
+ padding: EdgeInsets.only(bottom: 8.h),
+ child: '● ${detail.description}'.toText14(weight: FontWeight.w500),
+ );
+ }).toList(),
+ SizedBox(height: 16.h),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ SizedBox(),
+ CustomButton(
+ icon: AppAssets.view_report_icon,
+ iconColor: AppColors.primaryRedColor,
+ iconSize: 16.h,
+ text: LocaleKeys.viewReport.tr(context: context),
+ onPressed: () {},
+ backgroundColor: AppColors.secondaryLightRedColor,
+ borderColor: AppColors.secondaryLightRedColor,
+ textColor: AppColors.primaryRedColor,
+ fontSize: 14,
+ fontWeight: FontWeight.bold,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ ],
+ ),
+ ],
+ ),
+ )
+ : SizedBox.shrink(key: ValueKey(-index)),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ },
+ ),
+ ],
+ );
+ },
+ ),
+ ),
+ ),
+ );
+ }
+
+ Color getLabOrderStatusColor(num status) {
+ switch (status) {
+ case 44:
+ return AppColors.warningColorYellow;
+ case 45:
+ return AppColors.warningColorYellow;
+ case 16:
+ return AppColors.successColor;
+ case 17:
+ return AppColors.successColor;
+ default:
+ return AppColors.greyColor;
+ }
+ }
+
+ String getLabOrderStatusText(num status) {
+ switch (status) {
+ case 44:
+ return LocaleKeys.resultsPending.tr(context: context);
+ case 45:
+ return LocaleKeys.resultsPending.tr(context: context);
+ case 16:
+ return LocaleKeys.resultsAvailable.tr(context: context);
+ case 17:
+ return LocaleKeys.resultsAvailable.tr(context: context);
+ default:
+ return "";
+ }
+ }
+}
diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart
index 1e5143d..9b2265c 100644
--- a/lib/presentation/medical_file/medical_file_page.dart
+++ b/lib/presentation/medical_file/medical_file_page.dart
@@ -5,6 +5,7 @@ import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/presentation/medical_file/widgets/medical_file_card.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/input_widget.dart';
@@ -85,9 +86,6 @@ class MedicalFilePage extends StatelessWidget {
),
SizedBox(width: 4.h),
CustomButton(
- icon: AppAssets.checkmark_icon,
- iconColor: AppColors.successColor,
- iconSize: 13.h,
text: LocaleKeys.verified.tr(context: context),
onPressed: () {},
backgroundColor: AppColors.greyColor,
@@ -164,7 +162,7 @@ class MedicalFilePage extends StatelessWidget {
SizedBox(height: 16.h),
//Insurance Tab Data
Container(
- height: 150.h,
+ // height: 150.h,
width: double.infinity,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
@@ -173,6 +171,7 @@ class MedicalFilePage extends StatelessWidget {
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -201,10 +200,75 @@ class MedicalFilePage extends StatelessWidget {
),
],
),
+ SizedBox(height: 12.h),
+ "NCCI".toText12(isBold: true),
+ "NC_Dr Sulaiman Al Habib Medical Group".toText12(isBold: true),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ CustomButton(
+ icon: AppAssets.cross_circle,
+ iconColor: AppColors.primaryRedColor,
+ iconSize: 13.h,
+ text: "Expiry: 18 Mar, 2025",
+ onPressed: () {},
+ backgroundColor: AppColors.primaryRedColor.withOpacity(0.1),
+ borderColor: AppColors.primaryRedColor.withOpacity(0.0),
+ textColor: AppColors.primaryRedColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ SizedBox(width: 5.h),
+ CustomButton(
+ text: "Patient Card ID: 3628599",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.normal,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ SizedBox(height: 10.h),
+ CustomButton(
+ icon: AppAssets.cross_circle,
+ iconColor: AppColors.primaryRedColor,
+ iconSize: 13.h,
+ text: "${LocaleKeys.updateInsurance.tr(context: context)} ${LocaleKeys.updateInsuranceSubtitle.tr(context: context)}",
+ onPressed: () {},
+ backgroundColor: AppColors.bgGreenColor.withOpacity(0.20),
+ borderColor: AppColors.bgGreenColor.withOpacity(0.0),
+ textColor: AppColors.bgGreenColor,
+ fontSize: 14,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
],
),
),
),
+ SizedBox(height: 10.h),
+ GridView(
+ gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, crossAxisSpacing: 13, mainAxisSpacing: 13),
+ physics: NeverScrollableScrollPhysics(),
+ padding: EdgeInsets.only(top: 12),
+ shrinkWrap: true,
+ children: [
+ MedicalFileCard(label: "Update Insurance", textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon),
+ MedicalFileCard(label: "Insurance Approvals", textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon),
+ MedicalFileCard(label: "My Invoices List", textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon),
+ MedicalFileCard(label: "Ancillary Orders List", textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon),
+ ],
+ ),
],
),
),
diff --git a/lib/presentation/medical_file/widgets/medical_file_card.dart b/lib/presentation/medical_file/widgets/medical_file_card.dart
new file mode 100644
index 0000000..92bb4ee
--- /dev/null
+++ b/lib/presentation/medical_file/widgets/medical_file_card.dart
@@ -0,0 +1,44 @@
+import 'package:flutter/material.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';
+
+class MedicalFileCard extends StatelessWidget {
+ final String label;
+
+ // final Color svgColor;
+ final Color textColor;
+ final Color backgroundColor;
+ final String svgIcon;
+
+ MedicalFileCard({
+ required this.label,
+ // required this.svgColor,
+ required this.textColor,
+ required this.backgroundColor,
+ this.svgIcon = "",
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: backgroundColor,
+ borderRadius: 20,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(8.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Utils.buildSvgWithAssets(icon: svgIcon, width: 30.h, height: 30.h, fit: BoxFit.contain),
+ SizedBox(height: 12.h),
+ label.toText11(color: textColor, isBold: true),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/prescriptions/prescription_detail_page.dart b/lib/presentation/prescriptions/prescription_detail_page.dart
new file mode 100644
index 0000000..0231c67
--- /dev/null
+++ b/lib/presentation/prescriptions/prescription_detail_page.dart
@@ -0,0 +1,313 @@
+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/app_assets.dart';
+import 'package:hmg_patient_app_new/core/utils/date_util.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/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/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_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/buttons/custom_button.dart';
+import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
+import 'package:provider/provider.dart';
+
+class PrescriptionDetailPage extends StatefulWidget {
+ PrescriptionDetailPage({super.key, required this.prescriptionsResponseModel});
+
+ PatientPrescriptionsResponseModel prescriptionsResponseModel;
+
+ @override
+ State createState() => _PrescriptionDetailPageState();
+}
+
+class _PrescriptionDetailPageState extends State {
+ late PrescriptionsViewModel prescriptionsViewModel;
+
+ @override
+ void initState() {
+ scheduleMicrotask(() {
+ prescriptionsViewModel.getPrescriptionDetails(widget.prescriptionsResponseModel);
+ });
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ prescriptionsViewModel = Provider.of(context, listen: false);
+ return Scaffold(
+ backgroundColor: AppColors.bgScaffoldColor,
+ appBar: AppBar(
+ title: LocaleKeys.prescriptions.tr(context: context).toText18(),
+ backgroundColor: AppColors.bgScaffoldColor,
+ ),
+ body: SingleChildScrollView(
+ child: Consumer(builder: (context, prescriptionVM, child) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.prescriptions.tr(context: context).toText24(isBold: true).paddingSymmetrical(24.h, 0.h),
+ SizedBox(height: 24.h),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 20.h,
+ hasShadow: true,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Image.network(
+ widget.prescriptionsResponseModel.doctorImageURL!,
+ width: 24.h,
+ height: 24.h,
+ fit: BoxFit.fill,
+ ).circle(100),
+ SizedBox(width: 8.h),
+ Expanded(child: widget.prescriptionsResponseModel.doctorName!.toText16(isBold: true)),
+ ],
+ ),
+ SizedBox(height: 16.h),
+ Wrap(
+ direction: Axis.horizontal,
+ spacing: 6.h,
+ runSpacing: 6.h,
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ icon: AppAssets.doctor_calendar_icon,
+ iconColor: AppColors.textColor,
+ iconSize: 13.h,
+ text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.prescriptionsResponseModel.appointmentDate), false),
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ text: widget.prescriptionsResponseModel.clinicDescription!,
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ icon: AppAssets.rating_icon,
+ iconColor: AppColors.ratingColorYellow,
+ iconSize: 13.h,
+ text: "Rating: ${widget.prescriptionsResponseModel.decimalDoctorRate}",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ text: widget.prescriptionsResponseModel.name!,
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ).paddingSymmetrical(24.h, 0.h),
+ SizedBox(height: 16.h),
+ ListView.builder(
+ shrinkWrap: true,
+ physics: NeverScrollableScrollPhysics(),
+ itemCount: prescriptionVM.isPrescriptionsDetailsLoading ? 5 : prescriptionVM.prescriptionDetailsList.length,
+ itemBuilder: (context, index) {
+ return prescriptionVM.isPrescriptionsDetailsLoading
+ ? const MoviesShimmerWidget()
+ : 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,
+ margin: EdgeInsets.symmetric(vertical: 8.h),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Container(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Image.network(
+ prescriptionVM.prescriptionDetailsList[index].imageSRCUrl!,
+ width: 60.h,
+ height: 60.h,
+ fit: BoxFit.fill,
+ ).circle(100),
+ SizedBox(width: 8.h),
+ Expanded(
+ child: prescriptionVM.prescriptionDetailsList[index].itemDescription!.toText16(isBold: true, maxlines: 2),
+ ),
+ ],
+ ),
+ SizedBox(height: 16.h),
+ Wrap(
+ direction: Axis.horizontal,
+ spacing: 6.h,
+ runSpacing: 6.h,
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ text: "${LocaleKeys.route.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].route}",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ text: "${LocaleKeys.frequency.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].frequency}",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ text: "${LocaleKeys.dailyDoses.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].doseDailyQuantity}",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CustomButton(
+ text: "${LocaleKeys.days.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].days}",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Utils.buildSvgWithAssets(icon: AppAssets.prescription_remarks_icon, width: 18.h, height: 18.h),
+ SizedBox(width: 9.h),
+ Expanded(child: "${LocaleKeys.remarks.tr(context: context)}: ${prescriptionVM.prescriptionDetailsList[index].remarks!}".toText10(isBold: true)),
+ ],
+ )
+ ],
+ ),
+ ),
+ )
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+ },
+ ).paddingSymmetrical(24.h, 0.h),
+ ],
+ );
+ }),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/prescriptions/prescriptions_list_page.dart b/lib/presentation/prescriptions/prescriptions_list_page.dart
new file mode 100644
index 0000000..4aa1a1b
--- /dev/null
+++ b/lib/presentation/prescriptions/prescriptions_list_page.dart
@@ -0,0 +1,299 @@
+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/app_assets.dart';
+import 'package:hmg_patient_app_new/core/utils/date_util.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/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/prescriptions/prescriptions_view_model.dart';
+import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
+import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
+import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
+import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
+import 'package:provider/provider.dart';
+
+class PrescriptionsListPage extends StatefulWidget {
+ const PrescriptionsListPage({super.key});
+
+ @override
+ State createState() => _PrescriptionsListPageState();
+}
+
+class _PrescriptionsListPageState extends State {
+ int? expandedIndex;
+
+ late PrescriptionsViewModel prescriptionsViewModel;
+
+ @override
+ void initState() {
+ scheduleMicrotask(() {
+ prescriptionsViewModel.initPrescriptionsViewModel();
+ });
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ prescriptionsViewModel = Provider.of(context, listen: false);
+ return Scaffold(
+ backgroundColor: AppColors.bgScaffoldColor,
+ appBar: AppBar(
+ title: LocaleKeys.prescriptions.tr(context: context).toText18(),
+ backgroundColor: AppColors.bgScaffoldColor,
+ ),
+ body: SingleChildScrollView(
+ child: Consumer(builder: (context, model, child) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.prescriptions.tr(context: context).toText24(isBold: true).paddingSymmetrical(24.h, 0.h),
+ SizedBox(height: 16.h),
+ // Build Tab Bar
+ SizedBox(height: 16.h),
+ // Clinic & Hospital Sort
+ Row(
+ children: [
+ CustomButton(
+ text: LocaleKeys.byClinic.tr(context: context),
+ onPressed: () {
+ model.setIsSortByClinic(true);
+ },
+ backgroundColor: model.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
+ borderColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
+ textColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 10,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ SizedBox(width: 8.h),
+ CustomButton(
+ text: LocaleKeys.byHospital.tr(context: context),
+ onPressed: () {
+ model.setIsSortByClinic(false);
+ },
+ backgroundColor: model.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor,
+ borderColor: model.isSortByClinic ? AppColors.textColor.withOpacity(0.2) : AppColors.primaryRedColor,
+ textColor: model.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 10,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ ],
+ ).paddingSymmetrical(24.h, 0.h),
+ SizedBox(height: 20.h),
+ // Expandable list
+ ListView.builder(
+ itemCount: model.isPrescriptionsOrdersLoading ? 4 : model.patientPrescriptionOrdersViewList.length,
+ physics: NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
+ padding: const EdgeInsets.only(left: 0, right: 8),
+ itemBuilder: (context, index) {
+ final isExpanded = expandedIndex == index;
+ return model.isPrescriptionsOrdersLoading
+ ? const MoviesShimmerWidget()
+ : 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,
+ margin: EdgeInsets.symmetric(vertical: 8.h),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
+ child: InkWell(
+ onTap: () {
+ setState(() {
+ expandedIndex = isExpanded ? null : index;
+ });
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomButton(
+ text: "${model.patientPrescriptionOrdersViewList[index].prescriptionsList!.length} Prescriptions Available",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ model.patientPrescriptionOrdersViewList[index].filterName!.toText16(isBold: true)
+ ],
+ ),
+ ),
+ AnimatedSwitcher(
+ duration: Duration(milliseconds: 500),
+ switchInCurve: Curves.easeIn,
+ switchOutCurve: Curves.easeOut,
+ transitionBuilder: (Widget child, Animation animation) {
+ return FadeTransition(
+ opacity: animation,
+ child: SizeTransition(
+ sizeFactor: animation,
+ axisAlignment: 0.0,
+ child: child,
+ ),
+ );
+ },
+ child: isExpanded
+ ? Container(
+ key: ValueKey(index),
+ padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ ...model.patientPrescriptionOrdersViewList[index].prescriptionsList!.map((prescription) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Image.network(
+ prescription.doctorImageURL!,
+ width: 24.h,
+ height: 24.h,
+ fit: BoxFit.fill,
+ ).circle(100),
+ SizedBox(width: 8.h),
+ Expanded(child: prescription.doctorName!.toText14(weight: FontWeight.w500)),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ CustomButton(
+ text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescription.appointmentDate), false),
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 24.h,
+ ),
+ SizedBox(width: 8.h),
+ CustomButton(
+ text: model.isSortByClinic ? prescription.name! : prescription.clinicDescription!,
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 24.h,
+ ),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ Expanded(
+ flex: 6,
+ child: CustomButton(
+ text: prescription.isHomeMedicineDeliverySupported!
+ ? LocaleKeys.resendOrder.tr(context: context)
+ : LocaleKeys.prescriptionDeliveryError.tr(context: context),
+ onPressed: () {},
+ backgroundColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor.withOpacity(0.15) : AppColors.greyF7Color,
+ borderColor: AppColors.successColor.withOpacity(0.01),
+ textColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35),
+ fontSize: prescription.isHomeMedicineDeliverySupported! ? 14 : 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ icon: AppAssets.prescription_refill_icon,
+ iconColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35),
+ iconSize: 14.h,
+ ),
+ ),
+ SizedBox(width: 8.h),
+ Expanded(
+ flex: 1,
+ child: Container(
+ height: 40.h,
+ width: 40.h,
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.textColor,
+ borderRadius: 10.h,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(8.h),
+ child: Utils.buildSvgWithAssets(
+ icon: AppAssets.forward_arrow_icon,
+ width: 10.h,
+ height: 10.h,
+ fit: BoxFit.contain,
+ ),
+ ),
+ ).onPress(() {
+ model.setPrescriptionsDetailsLoading();
+ Navigator.of(context).push(
+ FadePage(
+ page: PrescriptionDetailPage(prescriptionsResponseModel: prescription),
+ ),
+ );
+ }),
+ ),
+ ],
+ ),
+ SizedBox(height: 12.h),
+ Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
+ SizedBox(height: 12.h),
+ ],
+ );
+ }).toList(),
+ ],
+ ),
+ )
+ : SizedBox.shrink(),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ },
+ ).paddingSymmetrical(24.h, 0.h),
+ ],
+ );
+ }),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/radiology/radiology_orders_page.dart b/lib/presentation/radiology/radiology_orders_page.dart
new file mode 100644
index 0000000..d1b3830
--- /dev/null
+++ b/lib/presentation/radiology/radiology_orders_page.dart
@@ -0,0 +1,251 @@
+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/app_assets.dart';
+import 'package:hmg_patient_app_new/core/utils/date_util.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/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/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/features/lab/lab_view_model.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/shimmer/movies_shimmer_widget.dart';
+import 'package:provider/provider.dart';
+
+import '../../features/radiology/radiology_view_model.dart';
+
+class RadiologyOrdersPage extends StatefulWidget {
+ const RadiologyOrdersPage({super.key});
+
+ @override
+ State createState() => _RadiologyOrdersPageState();
+}
+
+class _RadiologyOrdersPageState extends State {
+ late RadiologyViewModel radiologyViewModel;
+
+ int? expandedIndex;
+
+ @override
+ void initState() {
+ scheduleMicrotask(() {
+ radiologyViewModel.initRadiologyProvider();
+ });
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ radiologyViewModel = Provider.of(context);
+ return Scaffold(
+ backgroundColor: AppColors.bgScaffoldColor,
+ appBar: AppBar(
+ title: LocaleKeys.radiology.tr(context: context).toText18(),
+ backgroundColor: AppColors.bgScaffoldColor,
+ ),
+ body: Padding(
+ padding: EdgeInsets.all(24.h),
+ child: SingleChildScrollView(
+ child: Consumer(
+ builder: (context, model, child) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ LocaleKeys.radiology.tr(context: context).toText24(isBold: true),
+ Utils.buildSvgWithAssets(icon: AppAssets.search_icon),
+ ],
+ ),
+ SizedBox(height: 16.h),
+ // Build Tab Bar
+ SizedBox(height: 16.h),
+ // Expandable list
+ ListView.builder(
+ shrinkWrap: true,
+ physics: NeverScrollableScrollPhysics(),
+ itemCount: model.isRadiologyOrdersLoading ? 5 : model.patientRadiologyOrders.length,
+ itemBuilder: (context, index) {
+ final isExpanded = expandedIndex == index;
+ return model.isRadiologyOrdersLoading
+ ? const MoviesShimmerWidget()
+ : 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,
+ margin: EdgeInsets.symmetric(vertical: 8.h),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
+ child: InkWell(
+ onTap: () {
+ setState(() {
+ expandedIndex = isExpanded ? null : index;
+ });
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomButton(
+ text: LocaleKeys.resultsAvailable.tr(context: context),
+ onPressed: () {},
+ backgroundColor: AppColors.successColor.withOpacity(0.15),
+ borderColor: AppColors.successColor.withOpacity(0.01),
+ textColor: AppColors.successColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ Image.network(
+ model.patientRadiologyOrders[index].doctorImageURL!,
+ width: 24.h,
+ height: 24.h,
+ fit: BoxFit.fill,
+ ).circle(100),
+ SizedBox(width: 4.h),
+ model.patientRadiologyOrders[index].doctorName!.toText16(isBold: true)
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ CustomButton(
+ text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(model.patientRadiologyOrders[index].orderDate), false),
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 24.h,
+ ),
+ SizedBox(width: 8.h),
+ CustomButton(
+ text: model.patientRadiologyOrders[index].clinicDescription!,
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 24.h,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ AnimatedCrossFade(
+ firstChild: SizedBox.shrink(),
+ secondChild: Padding(
+ padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: EdgeInsets.only(bottom: 8.h),
+ child: '● ${model.patientRadiologyOrders[index].description}'.toText14(weight: FontWeight.w500),
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ SizedBox(),
+ CustomButton(
+ icon: AppAssets.view_report_icon,
+ iconColor: AppColors.primaryRedColor,
+ iconSize: 16.h,
+ text: LocaleKeys.viewReport.tr(context: context),
+ onPressed: () {},
+ backgroundColor: AppColors.secondaryLightRedColor,
+ borderColor: AppColors.secondaryLightRedColor,
+ textColor: AppColors.primaryRedColor,
+ fontSize: 14,
+ fontWeight: FontWeight.bold,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst,
+ duration: Duration(milliseconds: 300),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ },
+ ),
+ ],
+ );
+ },
+ ),
+ ),
+ ),
+ );
+ }
+
+ Color getLabOrderStatusColor(num status) {
+ switch (status) {
+ case 44:
+ return AppColors.warningColorYellow;
+ case 45:
+ return AppColors.warningColorYellow;
+ case 16:
+ return AppColors.successColor;
+ case 17:
+ return AppColors.successColor;
+ default:
+ return AppColors.greyColor;
+ }
+ }
+
+ String getLabOrderStatusText(num status) {
+ switch (status) {
+ case 44:
+ return LocaleKeys.resultsPending.tr(context: context);
+ case 45:
+ return LocaleKeys.resultsPending.tr(context: context);
+ case 16:
+ return LocaleKeys.resultsAvailable.tr(context: context);
+ case 17:
+ return LocaleKeys.resultsAvailable.tr(context: context);
+ default:
+ return "";
+ }
+ }
+}
diff --git a/lib/providers/bottom_navigation_provider.dart b/lib/providers/bottom_navigation_provider.dart
deleted file mode 100644
index 58a0d4e..0000000
--- a/lib/providers/bottom_navigation_provider.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-import 'package:flutter/material.dart';
-
-class BottomNavigationProvider extends ChangeNotifier {
- int _currentIndex = 0;
-
- int get currentIndex => _currentIndex;
-
- void setIndex(int index) {
- _currentIndex = index;
- notifyListeners();
- }
-}
\ No newline at end of file
diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart
index 3aefebf..166783d 100644
--- a/lib/theme/colors.dart
+++ b/lib/theme/colors.dart
@@ -30,9 +30,16 @@ class AppColors {
static const Color textColor = Color(0xFF2E3039);
static const Color borderOnlyColor = Color(0xFF2E3039);
static const Color dividerColor = Color(0xFFD2D2D2);
+ static const Color warningColorYellow = Color(0xFFF4A308);
static const Color blackBgColor = Color(0xFF2E3039);
static const blackColor = textColor;
static const inputLabelTextColor = Color(0xff898A8D);
+ static const greyTextColor = Color(0xFF8F9AA3);
+
+
+ static const lightGreenColor = Color(0xFF0ccedde);
+ static const textGreenColor = Color(0xFF18C273);
+ static const Color ratingColorYellow = Color(0xFFFFAF15);
//Chips
static const Color successColor = Color(0xff18C273);
@@ -42,10 +49,12 @@ class AppColors {
static const Color warningColor = Color(0xFFFFCC00);
static const Color greyColor = Color(0xFFEFEFF0);
- static const Color successLightColor = Color(0xFF18C27326);
- static const Color errorLightColor = Color(0xFFED1C2B1A);
- static const Color alertLightColor = Color(0xFFD48D0526);
- static const Color infoLightColor = Color(0xFF0B85F726);
- static const Color warningLightColor = Color(0xFFFFCC0026);
- static const Color greyLightColor = Color(0xFFEFEFF026);
+static const Color successLightColor = Color(0xFF18C273);
+static const Color errorLightColor = Color(0xFFED1C2B);
+static const Color alertLightColor = Color(0xFFD48D05);
+static const Color infoLightColor = Color(0xFF0B85F7);
+static const Color warningLightColor = Color(0xFFFFCC00);
+static const Color greyLightColor = Color(0xFFEFEFF0);
+
+static const Color bottomNAVBorder = Color(0xFFEEEEEE);
}
diff --git a/lib/widgets/bottom_navigation/bottom_navigation.dart b/lib/widgets/bottom_navigation/bottom_navigation.dart
new file mode 100644
index 0000000..a052bc6
--- /dev/null
+++ b/lib/widgets/bottom_navigation/bottom_navigation.dart
@@ -0,0 +1,59 @@
+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/utils/utils.dart';
+import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
+
+class BottomNavigation extends StatelessWidget {
+ const BottomNavigation({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ padding: const EdgeInsets.symmetric(vertical: 12),
+ decoration: const BoxDecoration(
+ color: Colors.white,
+ border: Border(
+ top: BorderSide(color: AppColors.bottomNAVBorder, width: 0.5),
+ ),
+
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ _buildNavItem(AppAssets.homeBottom, LocaleKeys.home.tr()),
+ _buildNavItem(AppAssets.myFilesBottom, LocaleKeys.myFiles.tr()),
+ _buildNavItem(AppAssets.bookAppoBottom, LocaleKeys.appointment.tr(), iconSize: 32),
+ _buildNavItem(AppAssets.toDoBottom, LocaleKeys.todoList.tr()),
+ _buildNavItem(AppAssets.servicesBottom, LocaleKeys.services2.tr()),
+ ],
+ ),
+ );
+ }
+
+ Widget _buildNavItem(String iconName, String label,{ double iconSize = 24}) {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ padding: const EdgeInsets.all(10),
+ child: Utils.buildSvgWithAssets(
+ icon: iconName,
+ height: iconSize,
+ width: iconSize
+ ),
+ ),
+ // const SizedBox(height: 4),
+ Text(
+ label,
+ style: TextStyle(
+ fontSize: 13,
+ fontWeight: FontWeight.w500,
+ color: Colors.black87,
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/dropdown/country_dropdown_widget.dart b/lib/widgets/dropdown/country_dropdown_widget.dart
index 5e4bddf..3d28e23 100644
--- a/lib/widgets/dropdown/country_dropdown_widget.dart
+++ b/lib/widgets/dropdown/country_dropdown_widget.dart
@@ -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/enums.dart';
@@ -5,17 +6,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/generated/locale_keys.g.dart';
class CustomCountryDropdown extends StatefulWidget {
final List countryList;
final Function(CountryEnum)? onCountryChange;
+ final Function(String)? onPhoneNumberChanged;
final bool isRtl;
+ final bool isFromBottomSheet;
+ final bool isEnableTextField;
+ Widget? textField;
- const CustomCountryDropdown({
+ CustomCountryDropdown({
Key? key,
required this.countryList,
this.onCountryChange,
+ this.onPhoneNumberChanged,
required this.isRtl,
+ this.isFromBottomSheet = false,
+ this.isEnableTextField = false,
+ this.textField,
}) : super(key: key);
@override
@@ -26,48 +36,103 @@ class _CustomCountryDropdownState extends State {
CountryEnum? selectedCountry;
late OverlayEntry _overlayEntry;
bool _isDropdownOpen = false;
+ FocusNode textFocusNode = new FocusNode();
@override
void initState() {
super.initState();
selectedCountry = CountryEnum.saudiArabia;
+
+ if (widget.isEnableTextField && widget.isFromBottomSheet) {
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ if (mounted && textFocusNode.canRequestFocus) {
+ FocusScope.of(context).requestFocus(textFocusNode);
+ }
+ });
+ }
+ }
+
+ @override
+ void dispose() {
+ textFocusNode.dispose();
+ super.dispose();
}
@override
Widget build(BuildContext context) {
- return GestureDetector(
- onTap: () {
- if (_isDropdownOpen) {
- _closeDropdown();
- } else {
- _openDropdown();
- }
- },
- child: Container(
- height: 40.h,
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 10.h),
- child: Row(
- children: [
- Utils.buildSvgWithAssets(icon: selectedCountry != null ? selectedCountry!.iconPath : AppAssets.ksa, width: 40.h, height: 40.h),
- SizedBox(width: 8.h),
- Utils.buildSvgWithAssets(icon: _isDropdownOpen ? AppAssets.dropdow_icon : AppAssets.dropdow_icon),
- SizedBox(width: 4.h),
+ return Container(
+ height: 40.h,
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 10.h),
+ child: Row(
+ children: [
+ GestureDetector(
+ onTap: () {
+ if (_isDropdownOpen) {
+ _closeDropdown();
+ } else {
+ _openDropdown();
+ }
+ },
+ child: Utils.buildSvgWithAssets(icon: selectedCountry != null ? selectedCountry!.iconPath : AppAssets.ksa, width: 40.h, height: 40.h)),
+ SizedBox(width: 8.h),
+ Utils.buildSvgWithAssets(icon: _isDropdownOpen ? AppAssets.dropdow_icon : AppAssets.dropdow_icon),
+ SizedBox(width: 4.h),
+ if (widget.isFromBottomSheet)
+ GestureDetector(
+ onTap: () {
+ if (widget.isEnableTextField && textFocusNode.canRequestFocus) {
+ FocusScope.of(context).requestFocus(textFocusNode);
+ }
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Row(
+ children: [
+ Text(
+ LocaleKeys.phoneNumber.tr(),
+ style: TextStyle(fontSize: 12.fSize, height: 21 / 12, fontWeight: FontWeight.w500, letterSpacing: -1),
+ ),
+ ],
+ ),
+ Row(
+ children: [
+ Text(
+ selectedCountry!.countryCode,
+ style: TextStyle(fontSize: 12.fSize, height: 21 / 18, fontWeight: FontWeight.w600, letterSpacing: -0.2),
+ ),
+ SizedBox(width: 4.h),
+ if (widget.isEnableTextField)
+ SizedBox(
+ height: 20,
+ width: 200,
+ child: TextField(
+ focusNode: textFocusNode,
+ decoration: InputDecoration(hintText: "", isDense: true, border: InputBorder.none),
+ keyboardType: TextInputType.phone,
+ onChanged: widget.onPhoneNumberChanged),
+ ),
+ ],
+ )
+ ],
+ ),
+ ),
+ if (!widget.isFromBottomSheet)
Text(
selectedCountry != null ? selectedCountry!.displayName : "Select Country",
- style: TextStyle(
- fontSize: 14.fSize,
- height: 21 / 14,
- fontWeight: FontWeight.w500,
- letterSpacing: -0.2,
- ),
+ style: TextStyle(fontSize: 14.fSize, height: 21 / 14, fontWeight: FontWeight.w500, letterSpacing: -0.2),
),
- ],
- ),
+ ],
),
);
}
void _openDropdown() {
+ if (textFocusNode.hasFocus) {
+ textFocusNode.unfocus();
+ }
+
RenderBox renderBox = context.findRenderObject() as RenderBox;
Offset offset = renderBox.localToGlobal(Offset.zero);
@@ -84,27 +149,11 @@ class _CustomCountryDropdownState extends State {
),
Positioned(
top: offset.dy + renderBox.size.height,
- left: widget.isRtl ? offset.dx + 15.h : offset.dx - 15.h,
+ left: widget.isRtl ? offset.dx + 6.h : offset.dx - 6.h,
width: renderBox.size.width,
child: Material(
child: Container(
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- color: Colors.white,
- borderRadius: 12,
- ),
- // decoration: BoxDecoration(
- // borderRadius: BorderRadius.circular(12),
- // boxShadow: [
- // BoxShadow(
- // color: Color(0xFFF8F8FA),
- // blurRadius: 8.h,
- // offset: Offset(
- // 0,
- // 2,
- // ),
- // ),
- // ],
- // ),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: Colors.white, borderRadius: 12),
child: Column(
children: widget.countryList
.map(
@@ -117,25 +166,13 @@ class _CustomCountryDropdownState extends State {
_closeDropdown();
},
child: Container(
- padding: EdgeInsets.symmetric(vertical: 12.h, horizontal: 16.h),
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- borderRadius: 16.h,
- ),
+ padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 16.h),
child: Row(
children: [
- Utils.buildSvgWithAssets(
- icon: country.iconPath,
- width: 38.h,
- height: 38.h,
- ),
- SizedBox(width: 12.h),
- Text(country.displayName,
- style: TextStyle(
- fontSize: 14.fSize,
- height: 21 / 14,
- fontWeight: FontWeight.w500,
- letterSpacing: -0.2,
- )),
+ Utils.buildSvgWithAssets(icon: country.iconPath, width: 38.h, height: 38.h),
+ if (!widget.isFromBottomSheet) SizedBox(width: 12.h),
+ if (!widget.isFromBottomSheet) Text(country.displayName, style: TextStyle(fontSize: 14.fSize, height: 21 / 14, fontWeight: FontWeight.w500, letterSpacing: -0.2)),
],
),
),
@@ -161,5 +198,13 @@ class _CustomCountryDropdownState extends State {
setState(() {
_isDropdownOpen = false;
});
+
+ if (widget.isEnableTextField && widget.isFromBottomSheet) {
+ Future.delayed(Duration(milliseconds: 100), () {
+ if (mounted && textFocusNode.canRequestFocus) {
+ FocusScope.of(context).requestFocus(textFocusNode);
+ }
+ });
+ }
}
}
diff --git a/lib/widgets/dropdown/dropdown_widget.dart b/lib/widgets/dropdown/dropdown_widget.dart
index 268e44a..2a0cad3 100644
--- a/lib/widgets/dropdown/dropdown_widget.dart
+++ b/lib/widgets/dropdown/dropdown_widget.dart
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart' show Icons, PopupMenuItem, showMenu, Colo
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/widget_extensions.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
class DropdownWidget extends StatelessWidget {
final String labelText;
@@ -16,6 +17,7 @@ class DropdownWidget extends StatelessWidget {
final EdgeInsetsGeometry? padding;
final bool hasSelectionCustomIcon;
final String? selectionCustomIcon;
+ final String? leadingIcon;
const DropdownWidget({
Key? key,
@@ -30,29 +32,49 @@ class DropdownWidget extends StatelessWidget {
this.padding,
this.hasSelectionCustomIcon = false,
this.selectionCustomIcon,
+ this.leadingIcon,
}) : super(key: key);
@override
Widget build(BuildContext context) {
+ Widget content = Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [_buildLabelText(), _buildDropdown(context)],
+ );
+
return Container(
padding: padding,
- alignment: Alignment.center,
+ alignment: Alignment.center, // This might need adjustment based on layout
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: Colors.white,
borderRadius: isAllowRadius ? 15.h : null,
side: isBorderAllowed ? BorderSide(color: const Color(0xffefefef), width: 1) : null,
),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.start,
+ child: Row(
+ // Wrap with a Row
+ crossAxisAlignment: CrossAxisAlignment.center, // Align items vertically in the center
children: [
- _buildLabelText(),
- _buildDropdown(context),
+ if (leadingIcon != null) ...[
+ _buildLeadingIcon(),
+ SizedBox(width: 3.h),
+ ],
+ Expanded(child: content),
],
),
);
}
+ Widget _buildLeadingIcon() {
+ return Container(
+ height: 40.h,
+ width: 40.h,
+ margin: EdgeInsets.only(right: 10.h),
+ padding: EdgeInsets.all(8.h),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 10.h, color: AppColors.greyColor),
+ child: Utils.buildSvgWithAssets(icon: leadingIcon!));
+ }
+
Widget _buildLabelText() {
return Text(
labelText,
diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart
index ca72fe8..b8d36e7 100644
--- a/lib/widgets/input_widget.dart
+++ b/lib/widgets/input_widget.dart
@@ -1,8 +1,10 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
+import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
+import 'package:hmg_patient_app_new/widgets/dropdown/country_dropdown_widget.dart';
// TODO: Import AppColors if bgRedColor is defined there
// import 'package:hmg_patient_app_new/core/ui_utils/app_colors.dart';
@@ -72,17 +74,32 @@ class TextInputWidget extends StatelessWidget {
child: Row(
textDirection: Directionality.of(context),
children: [
- if (isAllowLeadingIcon && leadingIcon != null) _buildLeadingIcon(context),
- Expanded(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- _buildLabelText(),
- _buildTextField(context),
- ],
- ),
- ),
+ if (isAllowLeadingIcon && leadingIcon != null && !isCountryDropDown)
+ _buildLeadingIcon(context),
+ isCountryDropDown
+ ? CustomCountryDropdown(
+ countryList: CountryEnum.values,
+ onCountryChange: (CountryEnum? value) {
+ print(value);
+ },
+ isRtl: Directionality.of(context) == TextDirection.rtl,
+ isFromBottomSheet: isCountryDropDown,
+ isEnableTextField: true,
+ onPhoneNumberChanged: (value) {
+ print(value);
+ },
+ textField: _buildTextField(context),
+ )
+ : Expanded(
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ _buildLabelText(),
+ _buildTextField(context),
+ ],
+ ),
+ ),
],
),
),
diff --git a/pubspec.yaml b/pubspec.yaml
index 9c78b48..a2637f5 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -82,6 +82,7 @@ flutter:
- assets/
- assets/fonts/
- assets/langs/
+ - assets/json/
- assets/images/
- assets/images/svg/
- assets/images/png/
@@ -99,8 +100,8 @@ flutter:
# weight: 700
- asset: assets/fonts/poppins/Poppins-SemiBold.ttf
weight: 600
-# - asset: assets/fonts/poppins/Poppins-Medium.ttf
-# weight: 500
+ - asset: assets/fonts/poppins/Poppins-Medium.ttf
+ weight: 500
- asset: assets/fonts/poppins/Poppins-Regular.ttf
weight: 400
# - asset: assets/fonts/poppins/Poppins-Light.ttf
@@ -115,8 +116,8 @@ flutter:
fonts:
- asset: assets/fonts/gess_two/GE_SS_Two_Bold.otf
weight: 600
-# - asset: assets/fonts/gess_two/GE_SS_Two_Medium.otf
-# weight: 500
+ - asset: assets/fonts/gess_two/GE_SS_Two_Medium.otf
+ weight: 500
- asset: assets/fonts/gess_two/GE_SS_Two_Light.otf
weight: 400