From 04c92804b85d7d35d5d22d0b5e1ac5b3909d50d0 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 7 Oct 2025 09:49:18 +0200 Subject: [PATCH 01/45] BUG: Fix blank screen on load --- Frontend/lib/main.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Frontend/lib/main.dart b/Frontend/lib/main.dart index 4bdbd191..c519fbb4 100644 --- a/Frontend/lib/main.dart +++ b/Frontend/lib/main.dart @@ -74,9 +74,16 @@ class _MzansiInnovationHubState extends State { debugShowCheckedModeBanner: false, routerConfig: widget.router, builder: (context, child) { + if (child == null) { + return const Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } return UpgradeAlert( navigatorKey: widget.router.routerDelegate.navigatorKey, - child: child ?? const Text('Upgrade Alert'), + child: child, ); }, ); From ba394e7feaa21d58efba369a1325332068d0c58b Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 7 Oct 2025 10:38:04 +0200 Subject: [PATCH 02/45] BUG: Business QR Code Picture Display --- .../package_tools/mih_business_qr_code.dart | 48 ++----------------- 1 file changed, 4 insertions(+), 44 deletions(-) diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart index 4f1b34d9..96592644 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart @@ -89,43 +89,6 @@ class _MihBusinessQrCodeState extends State { mimeType: MimeType.png, ); } - // if (kIsWeb) { - // final blob = html.Blob([imageBytes]); - // final url = html.Url.createObjectUrlFromBlob(blob); - // final anchor = html.document.createElement('a') as html.AnchorElement - // ..href = url - // ..style.display = 'none' - // ..download = filename; // Suggested filename for the download - - // html.document.body!.children.add(anchor); - // anchor.click(); // Programmatically click the link to trigger download - - // html.document.body!.children.remove(anchor); - // html.Url.revokeObjectUrl(url); - // } else { - // var permission = await FlDownloader.requestPermission(); - // if (permission == StoragePermissionStatus.granted) { - // try { - // mihLoadingPopUp(); - // KenLogger.success("Downloading from URL: $url"); - // await FlDownloader.download(url); - // Navigator.of(context).pop(); - // } on Exception catch (error) { - // Navigator.of(context).pop(); - // print(error); - // } - // } else { - // print("denied"); - // } - // try { - // final directory = await getDownloadsDirectory(); - // final file = File('${directory?.path}/$filename'); - // await file.writeAsBytes(imageBytes); - // KenLogger.success("File saved at: ${file.path}"); - // } catch (e) { - // KenLogger.error("Error saving file: $e"); - // } - // } } void mihLoadingPopUp() { @@ -139,10 +102,6 @@ class _MihBusinessQrCodeState extends State { Future downloadQrCode() async { if (_isUserSignedIn) { - // final Uri uri = Uri.parse(getQrCodeData(1024)); - // if (!await launchUrl(uri)) { - // throw 'Could not launch $uri'; - // } await screenshotController.capture().then((image) { KenLogger.success("Image Captured: $image"); setState(() { @@ -244,7 +203,8 @@ class _MihBusinessQrCodeState extends State { if (asyncSnapshot.connectionState == ConnectionState.done && asyncSnapshot.hasData) { - if (asyncSnapshot.requireData != "") { + if (asyncSnapshot.requireData != "" || + asyncSnapshot.requireData.isNotEmpty) { return MihCircleAvatar( imageFile: NetworkImage(asyncSnapshot.requireData), width: profilePictureWidth, @@ -263,7 +223,7 @@ class _MihBusinessQrCodeState extends State { return Icon( MihIcons.iDontKnow, size: profilePictureWidth, - color: MihColors.getSecondaryColor( + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ); @@ -272,7 +232,7 @@ class _MihBusinessQrCodeState extends State { return Icon( MihIcons.mihRing, size: profilePictureWidth, - color: MihColors.getSecondaryColor( + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ); From cadd51535eb458ae969c4edfd5fbf568b633b278 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 7 Oct 2025 10:38:26 +0200 Subject: [PATCH 03/45] Add Meta Ads SDK --- Frontend/ios/Podfile.lock | 15 +++++++++++++++ Frontend/ios/Runner/Info.plist | 11 +++++++++++ Frontend/pubspec.lock | 8 ++++++++ Frontend/pubspec.yaml | 1 + 4 files changed, 35 insertions(+) diff --git a/Frontend/ios/Podfile.lock b/Frontend/ios/Podfile.lock index 0e15c6d8..3a6b5ba9 100644 --- a/Frontend/ios/Podfile.lock +++ b/Frontend/ios/Podfile.lock @@ -34,6 +34,7 @@ PODS: - DKPhotoGallery/Resource (0.0.19): - SDWebImage - SwiftyGif + - FBAudienceNetwork (6.20.1) - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter @@ -49,12 +50,18 @@ PODS: - geolocator_apple (1.2.0): - Flutter - FlutterMacOS + - gma_mediation_meta (1.4.1): + - Flutter + - GoogleMobileAdsMediationFacebook (~> 6.20.1.0) - Google-Mobile-Ads-SDK (12.2.0): - GoogleUserMessagingPlatform (>= 1.1) - google_mobile_ads (6.0.0): - Flutter - Google-Mobile-Ads-SDK (~> 12.2.0) - webview_flutter_wkwebview + - GoogleMobileAdsMediationFacebook (6.20.1.0): + - FBAudienceNetwork (= 6.20.1) + - Google-Mobile-Ads-SDK (~> 12.0) - GoogleUserMessagingPlatform (3.0.0) - local_auth_darwin (0.0.1): - Flutter @@ -101,6 +108,7 @@ DEPENDENCIES: - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - flutter_tts (from `.symlinks/plugins/flutter_tts/ios`) - geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`) + - gma_mediation_meta (from `.symlinks/plugins/gma_mediation_meta/ios`) - google_mobile_ads (from `.symlinks/plugins/google_mobile_ads/ios`) - local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`) - mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`) @@ -119,7 +127,9 @@ SPEC REPOS: trunk: - DKImagePickerController - DKPhotoGallery + - FBAudienceNetwork - Google-Mobile-Ads-SDK + - GoogleMobileAdsMediationFacebook - GoogleUserMessagingPlatform - SDWebImage - SwiftyGif @@ -143,6 +153,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_tts/ios" geolocator_apple: :path: ".symlinks/plugins/geolocator_apple/darwin" + gma_mediation_meta: + :path: ".symlinks/plugins/gma_mediation_meta/ios" google_mobile_ads: :path: ".symlinks/plugins/google_mobile_ads/ios" local_auth_darwin: @@ -175,6 +187,7 @@ SPEC CHECKSUMS: device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 + FBAudienceNetwork: 08e86d63a05b3a5a59414af12e4af8d756943c80 file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6 fl_downloader: dc99aa8dd303f862cccb830087f37acc9b0156ee @@ -182,8 +195,10 @@ SPEC CHECKSUMS: flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf flutter_tts: b88dbc8655d3dc961bc4a796e4e16a4cc1795833 geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e + gma_mediation_meta: 44defcf3b61414cdca65c0f897360e31b9332a09 Google-Mobile-Ads-SDK: 1dfb0c3cb46c7e2b00b0f4de74a1e06d9ea25d67 google_mobile_ads: 535223588a6791b7a3cc3513a1bc7b89d12f3e62 + GoogleMobileAdsMediationFacebook: b11a92ae3bfdae19853b882252b7e62791c18162 GoogleUserMessagingPlatform: f8d0cdad3ca835406755d0a69aa634f00e76d576 local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391 mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93 diff --git a/Frontend/ios/Runner/Info.plist b/Frontend/ios/Runner/Info.plist index 66f13c22..410a60ed 100644 --- a/Frontend/ios/Runner/Info.plist +++ b/Frontend/ios/Runner/Info.plist @@ -2,6 +2,17 @@ + SKAdNetworkItems + + + SKAdNetworkIdentifier + v9wttpbfk9.skadnetwork + + + SKAdNetworkIdentifier + n38lu8286q.skadnetwork + + GADApplicationIdentifier ca-app-pub-4781880856775334~6935644635 CADisableMinimumFrameDurationOnPhone diff --git a/Frontend/pubspec.lock b/Frontend/pubspec.lock index 006b5171..59bae95d 100644 --- a/Frontend/pubspec.lock +++ b/Frontend/pubspec.lock @@ -656,6 +656,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + gma_mediation_meta: + dependency: "direct main" + description: + name: gma_mediation_meta + sha256: "8c9448d194faf85dbd7e09e4cd602192018915b2803b1605af01549fb72088b3" + url: "https://pub.dev" + source: hosted + version: "1.4.1" go_router: dependency: "direct main" description: diff --git a/Frontend/pubspec.yaml b/Frontend/pubspec.yaml index 43d2c8fa..75f5cd3b 100644 --- a/Frontend/pubspec.yaml +++ b/Frontend/pubspec.yaml @@ -45,6 +45,7 @@ dependencies: app_settings: ^6.1.1 pwa_install: ^0.0.6 google_mobile_ads: ^6.0.0 + gma_mediation_meta: ^1.4.1 redacted: ^1.0.13 custom_rating_bar: ^3.0.0 country_code_picker: ^3.3.0 From 18e8217ce18cf39c4885021b84944d51a1877072 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 7 Oct 2025 11:45:37 +0200 Subject: [PATCH 04/45] NEW: Engen Card Added to Mzansi Wallet --- .../images/loyalty_cards/mini/engen-min.png | Bin 0 -> 23948 bytes .../components/mih_add_card_window.dart | 1 + .../components/mih_card_display.dart | 3 +++ 3 files changed, 4 insertions(+) create mode 100644 Frontend/lib/mih_components/mih_package_components/assets/images/loyalty_cards/mini/engen-min.png diff --git a/Frontend/lib/mih_components/mih_package_components/assets/images/loyalty_cards/mini/engen-min.png b/Frontend/lib/mih_components/mih_package_components/assets/images/loyalty_cards/mini/engen-min.png new file mode 100644 index 0000000000000000000000000000000000000000..fb37347c77d7e035ea596e473fec06e234cabf00 GIT binary patch literal 23948 zcmd?Q1zTG|*EWh%T#6JgR*Jhj6nA%M@#2u+R@{oayK8Z$xCeLF;O=_T=Q-bd{1=>D zNp>c4uY1{Q#Poes=u{wEQe3qoAzi zhmH>cAvs9v0HC0lDF3~n-3oG|~h z_U``q{NnBeTN#Qf>hkIyjxpx&GjRS*wpUM-Z=(q?B?#- z)%C*(q1q{l`tthm-Q6Q0SKJAv^4jLf9{A$;^rp3Y`4z(Y@bWafa&UA-C6Wxs6w^Jh zOe>mH)j0h)v2glX<6P0#gJi0*S;^bOV@}!Vef!`;_b7=#(nJ5m!^1Pw=SaC9MXb_k(~ID_<->-K#klMiDXCbKhGO`7pA@wbNj;D`L!*x_jP~I z)d07J^+RLp{&9cxtV^Iw4#wSiJv%J z2`8vZ7e-#^GPXBqc* zB}OE4Tv!KOI!9fHXJ5zULlH%CtLE7IHC?&Ic=%OEXY^l3W#<+5f00c0`rRI#(shEU z6cAn?72l$$pMB{NaTT1FmERMd(wCUlVPRiHBARyT73&>bpPoN(0;hOs6%v=$_4f82 zm(qR$r4WoVf^>_|F?H29uev%C@Ae+nQx-%Zp$aD zo;GuH(0?6Q#0=Vm3K+F>L>TK6rQC7kdgZ>dp!AC}(!tZBPsv6g&jQuUGhx4FR!bC2 zAxYzz2|1uo@{DhPi6CIII{?ak4-cD3wPhMlDw&}k4fkvrn}*46xpx)Xc=JeK-F*Wn z2@8T(H_jJk6yvF6;{NBU*qV^PLHqtdOB*-xPP17UO8H*lDl;W%XPzu3@;0G(ZzzMM zWrxHZox?3Pe{u$8#S(Nuk^}~=#vcCv= zD~`X@Y$0Y$JX6rG|48P@k$2R2Cy;>J0Qu}s3`BC8 zq#lt;{$Gu0>Jd?V2ogf9qSy+@dw~5vjnDW8|8IC%2p+~D1_k*4hS$$Qaq?sOAO0|> zY4{eA|Al9ohX23w|L=H-*8dLn|G@w6!v9h3ALJiCmT3h3KY0C|2&Y)|{|o>BG#(r9 z4k0>Wk?_mFn|G)U;{~1gI!haA`j(GdXaSnSBBemj2HY-{z0Jq~E zN<(tx5ITd-x7+^x15;m32DBTo9;aalA(0B5HnK+*l{h~Gbf zm|lngG*rkx0rDt;!-NnjV%JIX=z6P72=x12Ga|;?Btii3y>cPZ+{N!+(oaB2LKdg> z-d}bc1QvovlW5eNf2H(WRla51hKh6hC+v_q9^9}+dCuluqwt<%C4-oEYNUwy{>Idi zIv>D^qkHxhew61u#R@@Z*=vS$bS3mcI$n(bbX8e=bGzNL}6`IKL zo?wM2GVawwI_eW39fy;uQ67D{>=FMY6dAxJQY3uUDfy(1hxPyI=q3DcouGs<4;!Rt z4VOvdk`x=8%>(Sq_4$}Y-1?f-$bXcr*I?gWCd_16?)&qIQ4Qs+nZ;MEOX!siduHb2 zN1bRspeAL1d%TT@6r9 zyiVJXYFFWdI8FPgAQ{lGBIxBtTJR|)Ek1sEd6~~#-cV<5=sI~}weEEocH*p3xaqsP zCJ^sF2SCaR&fnLc(|qrt57~G;I=U|ZqBuMZ0*%QlC@LtN$&{v+rt%V39IFIa1x=REXNpyQ0 zOglzefFD2ZpFCe!R4cZY+PJwWB_9l`S?zDOPsuF^@Y~CDrXuHRi*rK5^X_)aRh@-`%vbHWC$JOT zl=Z$+lvZ{^nknQdNXtu0+tl9P@>Df2FuYK0@9uD%A5D64;C3It?b7*riP-hxwuWdA zJb78~4$$M)ukm>uON~S+9~}h%;^RFUjhM?HEwB48y?%H}Py0oZfoUHfl~(6{Kq)7r zb|Z**j1{&vOEu2EgDak$b$9E*A%t}1!ZDhkCYWPQt@SA`|P( zE7$7mz;9^B7V8aej&@4>_p{sO3l$k@#;Vco2kirB*FTMfT-Vv-2ln=EpxgjIR1DU} z(Cl5>1U3b^+ zE-Gi@?C$ET=_FaD<4$tOibk^J=8%JiJvvMcZJ(IP zjE>t@={1`94zAS^(oLsfD@Hx|DxE425uFLun*9K9qdbH$FW?u%kfu+@M!JK;UW@GB zW(vZ3qn#VQzW+GgMVS|T1Df?O76q!Q%q%`WqqOP$#nAH@Z_xQSYb1sxwJcxXnaY6H z&MQXRpLT1zj8a)u`mA@~nsx+J=ZVngo!<$(%$M$-LGs@O?{dV6RzMRrD|e;}h6}C< zU0LmJS4kiecU>8^Wm<8c*~b_B2oIofN5lRFNx@(S(9$H;eLir|uum}F6Z z;p%Kzhe$3BG8J2eYqH9-El$9ant3~BHNW%Z+%u?Hq2n<=ZOg!&P}$IXJ;@o3UKZOU zx5%?8;r^v(alX)X-A*x@_F!>nR|P;i}qG-2!MtZ$9~eAObsNPK!)0g2G;p`@rdU(E8e7k+T6b6h4`#>Ia*9~523VG>wJ(cS`B%M8a3@uWqqY2;bg-PB&s~F zF}S+UoP$6}Eu z)fjY_nlPlQhcoT`U9fuc3R!TXEwvfXGYcF4+|5g+m-G#}4Io37E@?!^u@ z-Kl`=DVfG{LEkn%7*5rg9NA+cWm|OE?yn^i*33qyI^wi71IY^$37CGR^J!qOl3Lb* z)SE$wxCH*Hh5iReepHUy9|zC%FB#_TeQH}bf5a<4cN9%_pHCx!oqatV@1L;ct`+~- zOD`D`?Gg8!apz?6qiB8%WMrZjs#$m3!ep2s&kMMoXf?Pu;JxkN{xePyAV74|wV;|f zj72QAJUzX^oSBhuH}M*ejgn*}F0IN@HToRV|i4BqW$eH}d~1;YSC4=_P`=RWO) z`OOI6*fnJrjr_6o6T8Nr>U77)vnMTIXO4U;XoU(@$hqQ-w&F4vxUgm6v`Wy zso7xP>+E$p;#xg>Erz5KNu<3Ft74GL)D$0>-0Hn`AmqT_n2onPP9%;ZMsR@|G^^=# z-lj7Sx}*-`wt!w#yLCeqVk$K5u)EjTxv7-io?Xd3^%jmq~eVX;B>;{xRs2 z$$tQ6!RKBN<4?E}Q>!T`2`wBnx;&?W#x@j0N3n+r1(V`evQa@TbBAbjn1kBpW<$I& z^YY)3G4DqJTTr>q-dyAp{V>W5&Qi4HWZyQ3y zarm;7ws4TwC~qn@yQHcr;SQm^bqY^6+I;dZ*7gOaV{4VzR+K51oncc+S%*#b^*;lg z$=U49P!HSdqU7U*dsNSg@x%;HnA)h?*@0rxvXfc<9NKBRd9g`H3xJyl3nz zQg82Lp5J{+15Gh`J2IsR5+7zPsAYLiuhW@rpbjF?N#qy$+>ezMPxV!_VYs7~KJnPM zSP!xTFdsGhO8jq#_X?`*-BHiExq)L0-jdF z)QCRs?nmp<@O>EQpoB7qQk7E&wBU-UsVA|cn<*dglU8&9WI<4;@6L?`QzqKG^T|}` zK4s8j1R5B26btMDE(Ib=;F@6_O;^f)aTLJ(&iUBLb6PCqaw#YzZDe||=`mIAP=4O| zZ0h}kQol7*be_~Xszgvgv?W<6C`CZ(fNdWB*<4LV(!et?)1}#L?#+lBVgZm7*!G-w zNxQi?37NiTuf90|D^*6D3!wTQi@udH6pG*3)NN@|KUaM*Ba4LSJB2__Qc#!nm~p+9 zj-ofFZ}8B~%0h(gIaHg9^6hAatIx%t$I?ps;S1XShkR~+F2tYgTikDVv=HA~8iOQ< zTfpNeAePgAtU7&;#_s9@kcOHR{A@#??f&&b|I9*F6 zGn%{nnuRMy=s=!6;aJsj1Fd2QUMx!ShNZQbM3AHMs!uoK89_XR%8VR)w9b0;km|h7 z5`|&^f*{%9VH*U3SGWB1r=ruy*z{P8d@VS;P0qMpqkD@JiX^9Qn)g0gDr-ns(->%c z*CWI6kxi*^j0lysjfnGfuA9RIb0qU&@?6T&x4VT50L>?Dk$c^^ZV$mSjI9VSuEqLZ2`of4d6GKll!Qa99`&;i zNxO#>Yl9BlSj)n7vuYZSJFI)KVF11;PN`SP9bp$gH=6Mqp)Y*f!`@ST?z4t)@k zVYB{vJV( zz}Qrt1dhbsD>_s18bgGPpaFU$YtPcMzwgV?4$-Fik)Ki_DR538(!cg?O#Q9ncJZ}s znx}Gh@`e__AOOh43hs2W@;3BL6ZUJU(FhdhL6pQ_heaVTmW=V9S@Oy4OG=QtpF zcSFm81#`TVDm8+3(@8Ff!lu1~hWo~ES0yHFENx|uF zbsa*?onIWvwCogQ^%LFfAU_6HZVhGpglwXJ}qA=+jHv?N#@uPcN;X zK%ImtcLQ9NB#K_*0iPabIn^BJH)Ym(R}IvrwJ6f<=l_x8fmgFnb<>+BIDaKJ9ZQz& zwA+8U75m^RIab~b6VnpCbR;B6L`bvv$p0^(x7#n5gF=W7D3(4e9*$I^rn=1ytyGE= zsyCbmH(V8m4F>Td$YB>xlq|15OXKfYF_Yvl6YP7v0epon9579@QI204nT)Ft0I|fk z{xnTY)+J)|A`0J&&J1)soZmOOo1q}NruQ+88?<+u9=%d?b(hdWXUle#0n=d0rK&-D zx5rX`hD6rU{P0BZPoJ#}Pw-<13b6MBs7*VxMOrVi-N0IgGDGeoc|Z=`WC*L;eNDif zR^@BAqtL&l=i=D_IIi@{^Ck4L=6znu z?MV_wi#{tUfc*hZi9D8FByuhh-B^o?76%z!BQV}vPh2ZMQ3h4#^N1#)Ek#lSccu~Uu#PIz9hux)9aw8(#rc~sR>&)%V!s{Or;}FvjIx{xtNf8xv3m772?lIx< zF+Kwmm=M4#jkQ>=x*z@B9M*QpaSRWLt_S9eFVMAS*w#rExNStqeuoR-tQq=4wE2)z z?Q3s!r^;G#6F@La)m2>NZE`uirBB%@_Lf2KXYf7MVHVVJ#z+2@Bo}4&& z2^%iI5_e8CmqTK_4Rme{eAJ&XoBwbSdWQb9*w?DNoS70B$m9jy-HWh^;Tyr(_GDU_5Lo#LXsxn@d^}0YD7&RSq?zPpTv{=shtT1H2jyro5 zgT6py5$3#bajZW-X%2I`+E$#LH(F~bkRAZheKS)|snVp4pI#78`l$R`b9&fnPvO?F zY$xTZ(aA7#G#n!!ZKISz~3Ax3Ql)V^YRig7png3+u>q9VcDC<`-?l2pMUHqXi&J@L-@qq^>J;}trdeDx15 zaMKQ8HvjWTuO(uzdK@V;Zk0ptv7H#p%WsYH=%VN;qSJBq9e9%acth(ysnWWMe-m%i z!J-j_o~H9HQk}XXf{B#1-#xpTkJIaX#jIs6gnXDSVHodqDjmJ*-$XA!!$~A+{6~(H z{%1E-xOUZwu_?ZW2iADw<$eu^S(&+58UBo&i7@ORB}t@&**nJz+pKMFfc z)ju^5#$&W z$=}BC)866N(20KA)kqjs?p0SLP(a+*?O=)jc#*6jp9pR(FSA7g5O0KAE!D0tE)3A& zWq6$99Jq{gfBVk$AFWY5K(;P;9*>O5Ulmz-t|cA!BHwsaevRU#b0+(OWu^Fc;WgPl zc?U72`+8)D;sICNCUg&`=ZaAlPqZf2()w5gc8ueLe+elPMQs%>UeK`G?rSiukv zyQRC1Q-6Rsy^m;eXN%1hw&21PJpIl|ila-}wA*pbdg;zv3bt=NFZ{DhY6oJy3adlG z$WSL>mr4}k2@jLQ7B*uBBnW;n+JqKaATfMh&PM4;)10E}6P$Poum+d%XAtjzV`5B~ zNj^?4B@l~8*ujz4GfW67%`V4sfhxI8Y$Y;M5cZ3~;m$lQ_$x+cDNn@iO^$97y<}9h zQG+Yezxl&WZs?{@C~`w-cuV8Fg_|ohX+ygivq5MBj}0gsn;fDd9)hsF+yjkbw( z@GCXYfpKwJ>ZYYdo3yj&q8Vz6Ab|M%K63#aWL;HwXt-VEU4jaFQBnEWB~f}>ma*V& zE13kxmiCRiwT_V>-b~@w34ZjnVL(UjsME&;5gm&nb%2CGW3Ml-o}K^6z#)LcC53qU zR%dDGK+-MxqpY5g#+6o4Fu;IDEAMy3_uhdPxZHeTtjNTh6jnMGX&`TMbG#M*Wnjj$ zq{t}mUfSk~60^~Kn!>+O4g*lwX4>$@svIL$9mIK9xANOh-gFl+rv}qEzj>Q48PP+` zlpE2{JN$;i&#<(B4y>9aVxLZPuM)&$fTn(Ip;%Q*#cywl#0-p@?1z25?vEF?%P0L{ zu#Hy0c_UV?fU(@v#>l#?Dd=fwL@Ijt)qn$%mpbAX4hVD)!kJ=MIg0-P>Rd9Q8Nr1~ zdaD*OFNq7_e_Rr9f?zo=*hakeJT)!4>H9BhRzyI*3^fBTdT{pC%d!gXKZ|~Y>?N#> ze%xrKm-h?iFf*)*O!aO=4SMj*^=ESaeH zk@`P_>VstNjwRw#9rs09fHGmiuT|6I0}hi&UMejf#tHp+CwTUGsAAdulZC=20ggwk z@cOMYN#?jVK^j>qp8;XHO{E#0QWWpIo5=sN<6_3gT8px7`4A%X%uDNOtLwMW7W{{- zJk*cNpB4hf&olJI{~3z>hEa~D>1?F&8b`mCTs4Dh`ez%Lel@I*d(&GIvm|$V#d(+z zddQ?jDZuF@Qs&@ZAXk+KIAUEcix0*nIi;pMz{hCNF_~S*wP~*R{|u>!vIob)-)X8J z2bkrsV@Q#4ieRsu6qF7GYT^vH8*d1Rj8VOH+wYzz{weu2Gkzp`|BtC85J|+h9#K(& z@~%(Jq4V!Ae2?v%GuI~dK@WaLBTu^|9;t&mtf#zybZyQ^4-JZG=X@m{4}{a>4{u<$ z*_NJZaHz9Zj7H;GaKb+oG!J%*oo!r)mUE}S<;Z2gb{2n%$uFs442AB8et9lYPq8Bq6fBMGeWgNcRmYRLlR(8OQtHB3y~5 zYf#2v-+x5r^)eqPkPtN~I@OFaZqtjP(814oIQDDjr}Tt|mfMp!>Pt?pu^1yRD~jXp zpl~{U$*q2xIQlBD$Meugq4m9CJOvPl?$-I*R9jjf-x=4JBL}>Nc0T)fey+R1w)F{vftF7HjO`X6YS&o{V;@up6oO9%TPPd;`Ly~n} z=tDOxHXW@}x9%aYX7U3X46Lk}N4}DP4IbJYdQJh!>ONk#V~FPooTFssKCc1{PaWzx zlNOOT96FyBvzSs|#y9BCVyRv-qAiKCQm*I}0{#J+L0)KgEoca<35~8*fnQMk^Y$zdY@0PY>ppH%ii*UQ)+Oz*}L$U~*s} zx;Eqd#<+*gMK@eL4=^m(Q`}$>jr*EhUT%pA3 zsVTm7ie|kXX<{dIdG38U;WafN?#ygD;Ew0}<_*a*$S0u=`;K{+O#7{c5F5TI+wz ze)W~lzb)rh#Q>pPTdRzIr7UP^*|F>_w2r+&x0F3{`V{-`YWjt=*o5nuFiW6kJa2Z! z#`%k(rn;j_SE!xfv5&jHytfu3m~-ZDNS@H>p#|@;JF)+B>%;9nnV>5_kz(L2vKBsq z2x5-OGRNBqpC8mu{FxCRiH6amLXInjv=jfKf!ttiy1B{fEb6OZYt=L%SlH|fx>0P< zvNxOfcO2WdG06TV&tP8l48Bsyhj={J-&AYid48m|Q{!Ty@4lbcDm2xWZ^QIj^TsCS7sI}=i@!J& z2n1KLe2Li4Y7ksXquQ+fjfELHF)2e%3F4K>omkptpbz;}!?dWiDB+ zrCu36>|5iYLZs7AU-2*TGN5oCi?lRcN>!4?NG?m`{7%VSt4I^ro_bI zm*qZVP9F*|Mc}FpXqA#K%s2M4E&4cB@^|*Rsr5vwtuSxrW?(d*l(^`d@@A~qcx(6} z@Lgg$OhX?m?rLXBPZDToXR`yQ8&1e8#}-0U2-YwKIp{oJ@_cK$s!a;=O&%_XMpblN zJykIDh>!0ZaeuJI5^R)})v1JUGb~mw-dP2hIsbOz`zGo|Ez+L+T`-^yNtB*s)8Qmz-DmT@@hvo)OkiNVp4I%CI(x z=y=FaVl->0_z4E~n4+#pI;KrL{dhf{@XWqq z-(c6SyJ`Q8ldpJ+9PI2#JNVl&#T=ux863pcyF|zs6N2%UXWCIopq#~_?0z^u^B^!b z0b`&jA{bc?n*%$^%3N}yx?NCp2=u9US39GLB4x_YUzo-eb2%AzVY~G!PM7*-cK%56 zh@-Ud!fvs~QU!Bhg=R(N4X7o8BKZ~NOfIBkz=wnhzOsvI@i_XBU-nwa77&SY(mVh*9<#xYH z%Iu8k%--R2{c!8)u(?!UZt@RaG|!Jei?<@kP`daNhOy^9lv;^KgK?R= z%`vLubN+xdUr}eBgT!0vNPJP5r1J<7&n&QbK+7JXe4$g%XgTNfNKZ~hPJ=dtm=Wg& zUamD2Y*CPLO|4jo5gl(>p7{BTRL8B(=s|;1!>`|kUXFVF3^-a zzgvnnh9p^elZ>Qng`l(fksv9LXj`qwW+^PY2=`lw`Ym%ik&m4DwgMlrV)Syla4UOtZdB(kj6XmYg!^0hz1^VF!mUKE&~#F7Qu+{c z^>q8L+)vOay#>tnMiQ^il>~PO*hjZd`2(TrLBr*@Cr6mUs&kwFq92BO4W_o-8+jf< zJ|fz`nD}Re#Qs8{REauQv1n2F*oXebdW3<>MfYu|EE#@@rPmn}E)lt=^YDfEDxdfC z{t}mNqXk%qU4w^n-4WrllE~wfJ-%u7n}hI=#w_g1^E^#ohENHSju}#*HfHs-;!fmO zHs^Bx_G3=|Xg_Ao_TizQKh>L+=F7eK0`XP5908_;)=gpMsmh$e5>sB|t`@HOy{oTb z1(oH|MohQ^KkP+9jAGN>e;BUt@VB}b1TkjYxEtLBp?&njHpIMyeqM8V=bBZW8%Ibi zgPDW|pX1y2xxV3&olVJFl(u^CY`0u4B!5L>2X~7(s5R+y28*bH-}kz+Ll3rhTCVi z41+F9ed)ediqbxlk=^k4NiDl0vaDHc5;KwoY`AVzzf#MnkA#&?o7ZvG?$J~uhO^IUb!i*Xe5UO>{Gg0BH`zOWGM{XBF z1KpxHXHC}E6n4Js8Hy+ty`?{lY01&gM5D%Rmbtmeu(X5SS&!Lo7j1Lbdud%0HXS!i zbq(9aOw1F`?|FSFTw+<)8>R{XIz;b?BP2}Jv@&Ff`@K(iZFuvqp+vJ;ii+;kCM*O; z)Cady$ue<|p)_5YJV=D;@l2iC_6CsLGLT2(m$6v+=mp(NfrXi~Xofb-8a3~@UVYk* z`^GeryABtzC$n7$Vfo}8UT;s^OA9TvW>kz??kXt%nfAA)fm^(`-yn;Y#9x!Jhsa*> zOo`Jp;;_JR)6ep}@!`s`NceN%vWaSXubZ04LCSg!PD9pn)!h%?ZneJt+?CtS8(@d!4J zHbg~t;UJ}D{@8Eo&;mm&<5$P!!$JAG_yK&zXIp1OdNlKyzpVy^TB%;KWt3xftH=59 zrdfd_4)}mC8gv=oy7ge17knHF_WJiTz+|U;smWFOLyAS^;z~R&$dQ9EIytsGvD12m zDV(@#mX)E3FIcX4CMcIfmpE$IODW=BaP{{$ZLEYRh3ompu%Z?NhC{*lw1e6k*wo4} zqoX(P_NG5My(V%WC#a7X&lTs4a+Aw^VE*Nk)0iim4IUA4LLnL~sV`k*eODXSFH*!H zQf|GTk6OFClHPAZl0p#R+>1@zOFdIU)+YcXzCvNvgjn~G?}`tLiq zHMxelMq`H+I^#+?!Ig5ffyT`<2?2~YhoDh4qGKJG6L7W(WH}?g#gb0^5duHIKa*(g z)%pnSF$i?+H0`9$@tXMOpAgF=HJKfDC^BMi$2!tBW$cXc6oq{Rs+YV0E}!$7$rUhf zZepV`fge2Dedv6@+vLjky{1;|2$VKj+5_{1(zCTkx-=W-E1GdqH_RI)zpM(^0Hl@( ze+Sy;RTnZEhcprQ~GT+A}+E`ssI2se&;%j@y6eMeET*G z<(vH}D|6MuVR5qSzt99&L%+>rRCy>@Pz9j^U+Oj)%ub@{8tT8I ziX7wy#@S4zu|&)1;7I%xNwC-g9u3f|xy+w8tLMyj7!lS{Ez(M1DjNC~nwwQi zM}0 zW5PF0O3-;_4Wxinw03`X((ssuhL;x*V}wxg{#??RspBg)Ih-W>oE1iC&NM2fd!(srhnV zM`Ef5?9$5v9+qtCX1~?=_Qj`5)=D!ATwmKDJ{CFtU1?{Z13j9l!CkgaS`cMdg1|W^UsMyhSz~TEmj;Xp zxZ&K6OtR7Sj=99`dW6@u9L=*z8F3e}kpa6qx(4j;O&8>QO}{ z?)7GKf4g3Qk8OQ({vci2pd4|~$8q$Y&0?)Igrf|MF9_*LuPCl*zI9q~BjJS4F#VC4 zPXoUiRdUbD52|a|iF_Ko9B#~tiaql|#|@5{ls%oxk7J8fY+NG&Zbdx}wWh3NGQTXw z4ryDA6YXrJJ|AG-lsl~vV0V7g)U{$uwYhD4x`mFY^O;(0TYt4#TUvP=(%h`9s2EEc zrotXpTB)ru#DN9>{1zqYDzLO4$+9-+ZrWu$$tjKr9C}nzxh{_WXb@ea)JZY4Kvvz` zaqx52guEGMF7$kD+sY7UU7`iUi@#e3$6rxi))LucItKL1DU!;$gt82nraX79OQ6ST zYNFEe$?F2{YkdhNw{&K_5UI?6+}lU3Zv}Ttx(Nr533-*sK=&p=va4QY8qH<8&D@Ld z2eL#Cd-)p*#P7s;;}-^F;res}wKXn%x+*itOgMg6!&#=hFB=~bFb&XB2>OPKLu?lW z9Gbt48+`n3#-!EUxS|QE_ZD#bgMRdy1=f-_XAy$>LWb?jQKzNJez_$yQN=v3nK8 ze|m8?AI7VGX8~D=e0pi+rgWkc0ZZ1@P~$>kxQjK%^Zpk(i=(qkyL|vL3|NLWLQ~0} z+TGcwA;#aXX&ImRzjXemBsByK3+JIkH=6XA1V2s`KEm;uibWSHgzk#lM>O-$N2J#|haYhU%z zJ{2~6b2z!P_gOk+T|iSG>6tccg&Hfc;F4hZ1HYAWwy>~)c5f|*i>VN__fA9m?1d9E z050HHBZoMUDO=~#$;}PwN_<$_R1p6ig+#uHGJ{gQoC*cE1RePBdQQVY$ThMs(Mv?( z&gBcs=T1u4z#Fz2kLyh_t^UeOzTYpjq-1U?y~`M)!hsv7YS@mSF8pO$t!{QdllaRp z?r8@PvemyQH&kd=;$m9r64I6m#Hz9i9!S&3#1f2W{{7|FYvzfv^a-3?6!1ghPs)d) z&`P{3I=~L#`?9=`Lsbh7eG095zg-t%GWegz7hw8imD)J~HSf#6;$zfm|LSH4blGj$ zGk&xx(?YCJnd0efMR9K|wm-YI?%TL$I^rH~=qf;LuPJ2N^@(%tDwQJylvQ>|OvVE~ z@FkFOv{bn6>@_pxU~OXM|HWA&9BaGS*l2|U1|!9F1brZ4zx7$a)c_v(*4MZTUAfz4 zXgHKxfW-QS zN;@Xt0>pQf=W7#Np{rMf$kZsn#_v4J;ZF)U&f)VJrz`au09LjY(4Kds4#TcGap~uP zN3>thqXlE$5HZKuL_fyM<tnO z;sIg04FsJr>X`pBA(}Ol^wly+GMFzzhWMwE)(?}YvvI*7q0Tp^A}7kett=w=CFVs{K9KTDwDv}9JsDBWUZxDZ`2H__p+JLINN_sBU`rL~8Z zjW?$YRrt8+h?b0gnlI`$2+m%SEBH=gnOWvx^VjuD@!`O-v8q5)R3_bqyMMJnV`oT zDueghO$N9yk?Ay<0Qm5PHn(5YN~l$wQKk{J9Rgla#Ok$ybNPj1A)#43AZSP372YfP zokQ`D$8ZN|)_5E&>6rPg4(VS}kNku(_QpmloB6>z_myLvf&NEG3;4^o1 z&epTeYb5VU?&o}%L%hd=WRy(29@ps3kPwE6!iR z5@Mx^1g`d%y;(IiGB#;svvDoHf(bbvSPaVef2zS4lX^i1Wemhz+xKsg9;1ZR)q|AW=^( z&dWryFAX)-jbyX_&P(@!i*Y$w*8K?u>N@8l|@dlSjemhDTtHRk){|7 z8ljXVZ834d*B`R9X|WH(&QJ3SkfY@+E7I3onRN%T>dRn=uOW9^n3LO{SVJY3jwtlV zvmkwtk>)_M#Lh*CSLHa05cgwc{v-ZaX~p1Pafw`ckKZj|ZR`0}>#=Izx+-uBgmSLVF< zI3Y`>^oTgVak{;N$R6#EY$Ydz5}Q6=n5of~AW1b3Mhe=rX}+yH8AW(rw<_wn+#a(L!9k1l>K9Ypf~OO5sIF(2l9 z_SUT-zqMj(sdatuQ}7V9K~2I+;{H)>`f(5z>KB3EyxkQZhxYP_5}S{%t#eZ$D+`<5 z#qIcU*}nmBPt-Lae8hZ$?`K;yrswkVKap<>Xz5aVoT9xN7u8icO!X(iuEt?VH`V9P zn=sXMJLc_)=}i}@8y)b*#(uo33?={>*t&cxk7g45|E6~7!|}nqW(0y}g6$$8`^PRn zOWAjPLVh!S!kv0Du&af?lsz63(+ZbA7q$voQiUDM#{dsn#}`}wmU)8OXELttR@G4I zwu4%{Qjdl1H2g>Al>&a8=*H^JYHp*3U7_sk`+CW9H`FkIS3VBnZ}W``WW$UtwEEohYrIx2#vhRz@@VA7TL*CFt%)9e45=Y*T~Cn zE{z*kZfYLck>#vP{Aq0vaDd}aj_Jwwg|tkwjtTU++rMGNo+xzaSKO4LkhOx>8l}{T zB!KM~e-z3W*;CB*ZOE+DTT35-#hh_f6l96ooxC;JJTz-;c|k54h+qV>#qORwjLbGP z?qPYW$Jpl}a7@EjQT>}1OoWq;VYu0Oz_DGu$l7T>H|+f7()%Q9bjQ^znt9Ar$Kg;c zvYexm)lV}kN8~*v+}@gZrSGi`EXfJIJMgdA7i+2x>|twW^1zQ&}zF zad2EQoh2``*Rih^GXI}edKe6=^zMs{*3;sdQu95PluYjlg;K;hVI2P)?%OB{;+bEH zbbjS>A?l&mIieV%Iq!faX5^io^>|?61G8_kQy55bp@R1Hxr~i_*}Z$Mr|z_B=}7xD zdVg$Hf21a`go_7d{`@aqaBgpi1C_U20FP9T5lg;)Vq*56``kUN_Fuck@jeNY#2G*C zHbf-2v+;Pq0;wbOEH!2t1K00oAKLi7;T={;BB*KDBRo91A(y3gTdM_tgtXvcNc?>K zR*!St8}}Z)wQP!9Nn1XrgLKwuFd8}Im_tP`3~}Mu~K>&=-~$jV0RU*rV^TD!5BEFaLt_FxD^?A&Trg za~{8*)h^8F#Ah(;`D2X7q_Ot>(<8-ESbwHM2)Uxgr?Jm^x0H${UXtpW(L5NWH<)lw zI!qG1rhckNb-3YD&x`#2hA14W^Gxs;<)E}@=g#?x#3v2}JG~(|NoURgpL_oWR4+#X zo%ufc5K#+Zt1s@<1F|lpl46BrtNYv1eY`NQ#ucCmzN(E`%x6C>s%OcMP`dksl&&}A zmNIBv)te~UMt6C{*|j&&NUZf zMzd}PQ~r}~;U`bR&*^~;{#ib(*T4|Z)7`NQV_saR*c+=m(1R?Y58oaG!@mFnCKaK| zvwv(a4(y{g`!3#a@RQ7nG07zL{IDva4wjYv5JhTvy!?Ptd6VE;-BU%?mT^p7SEsAmFhDoPpa z#orD1KodxZ$&@++aVVZOE41tigIh(Yhv$~ykghs}nWW5gYpMxG7`i}gca5H*l|%J!gX`d{e8VX+b&;qY66im zhT@bZ;(3YEny_XM>gkay>o+ZCZUz$k=oGsm742kOz%%bj(rl2eE7 zFP!s;j!!Nml;^owTo7m{$3aZH#F+QaR05yuq71wr{H`rOxuyvCGiCjfBZ8l({2Ped zF6hV>KaPM!Q-c6_zjb2#ZgGXH{hxddjJ%n`QwGc{DtjqsDkmv?;^qoKh<%Cs{J)j) z)nRRP-?~Lw+}*8s@gl)P(BiHED!6-FpcF5q#a)6!8wiwAEI2Ke0!^VnaSagMU2gc! z@1FbJbLOvE@2vH%_gOQupLzD|z1HexrBZsJ?R3JX$1kg2Vz=rH3iT-MlUQVC_~E|Z z`|JsAO}i|C-upA8Wgs7%4t1?cTHP9G1^E%ZFJ{mEYFFl%K3!e=T`%MnG05<4P;aIi zmMN+gqT6lpg*o_rV5+iD?1a1N36>d{oZLTJ&{7IQ+EjLk%P96pq)ABxeCJhc8ROF2 z+I+!*pjcnaKPW}zu$os{4U#OsCxWKXCkWuzmqy~JwU=DUX8I?Yg+tZNUFbd`Z>cK)>%59n&;C@MOTBjzN($mbhK+< zWf|#5VuHi4w|=;?pa9GyJL6xgkEWxN=3o2ttWCZorI3WXI5G?NEbx#jliBJJkjVZR z0gL1-+443-?)Y@!y;rgs{jMauVkcoO9aOF-x38pqmo>wz&t-TX z&!VO!itZ?nR6L3@MAY;CA$K6D?2hE)|wSzR(Cu<;%lHabPSYSn9cmuQ4h+w>n zfbzr3`RyogVY}R$7v+CnevmloS zX1T1fEuMHJsW&S-i^{PDsUDD{*53M2+aK06NSBMBs0|463S}uBr_sOFHr1te=EmDw zT_|R1E#KId;>-2BbadNs!(W=lqPQ;X5@IaxZD;Mp)dA#knX@sXmX9keJzr;wI$aAs z#Em;Lwoy%&dV4fXuQ3^_r039`LbUN9F72yv$P=OsN_4#cw04?@3*Yi7_5IIU+FTZA zh#}jGtCEUzEOmrh_XzNGgiw6}|Gi;gIGaX#P@aYPS># z3>9TWs!+G8d{pF%C_TpRZLvSFR~R7_2u(IE(s1|KB?13w*zIaDYwWz+3fX@n~v$z(@T`GXLJks3kF>HhsOBpz;lM{uB?IAK;&{3 zSc9BX>I?G( z#hVM-cd4HDXJ3-d4{6^)SJFgQ^={u`U>0tL8ZoXf8N%WS7Ow-B;v*a~{ z$qiYMF)1LnFtXLsJaX4yQUEaXtUGCz0Cv7Q`%#6ym)xN$DA{xjCDF+YUlIz>P~;We z-ThR;OljvI(JQ^itX-6knV{;Yw8AtJDj!y!%#qFFC0ln=y>N2aJouRD<~n3ZjR=U9 zN_y(&_?nuoZ;RQRMPF8X(>MG^84n094kdx`9@ph>1VM1!Ef36?>2MzZqVL8Ppv0)U&kIT#Sr`AvpB`rZhriVwlY@=K>sDOOecAd8?-D6)vU?t8~CXwr4fYhfdUP%ul`jkkx0XP%`_NV zp=fi^wXtL@OaLBy5{KTqc~nSfwwJKCSvUgC0quML41&lHsCdV|$Y$E`av)EK@vM0X zf&-%hPv};dBlIq+xr~CpZ=b{JfkgaD@+vsl%vIJTo6(gso2f;grg!iC447$*8todx z(xH-p@^e(o;ti%q;KDU;Xf;8!n=OIH+B?V{{{rTU-|Va8M~4Km?+2K!35d&8UTT=?_Kep=rycWbv+%)n}Xp% zMG$7+pSGZj&pxEV_~Tw($tdBK7K{Wx9kly96PU}*+rIPll*3Ex(AJQc%Pc~^Zq)p2 zcKb^;~v zEg+=kosY3LV6Fa5TM**gh(3PS0e&KBn)CZ5*z3wldW>8jvOvq^`?M!u~wJ+|)j1vm-Hv3wDXo3_df>ehbgDTAcmKVwVm_r+Cr zCA$v#h9C@~?W67r5_xda{bj5)YsnXNbJ3)M4aqCQKPyc-c(EqW0GybTU|O?lX#8xE zygKqQH;O&9mq}v%h)7;Hb=SLw=)unY)DX@r|5n_ru2cnc%AfBLOF4^Qx83uxuZR|2 zA;inb4@=kNn?r(ddk(Cw{P2Ly00ET%t|D7eMc(4RX;md)qzHMjfW`={{s^fW@CJID%~P10s4-6^qVEbYcEV5@gV!wDEvt)>QJ>qDMA z1(1a2@hYuqEw^abBXSn$B-CVaM4)5OiAg8SjK=llWp@%sm;HTI$D?y3$-{t$RNY)v zfpvWHtrNu(l};W!y70{Jg^aadh}BS`Nxt~6Bi<&khXjMrSL0Td?1gSkcKIGcwZyzm&0 z!@CKa;jE-B@q^10b5mnUmwuJSpLIT%=w<@~tPPrT{fN}p_#@8&>EQqugh{@zCGu6Rf`3drFUa^&$AB+PeyWzvgrz z%nr=+muWsVN(UW)t!@bP7p7M8gxAr=QM`pnD5HP~@3QJ!lyvPV`3=DZwx)nOTD z96XWD)V4LsJv*-d2_@np{Da6Z0U$c>%RoD9OnDe3iIz*~xAjXfcr4T2T(^~?&2{!; zkjJ|c8qxQTZ5^r*L3pxZU=tFQU~bUd;+(d8cau276G$7?lgcQk~7so=n`Z-Gp{3WWN{kwzR0xseQIBKz(9 zODUT0(s$Z#o4}Mcob)9rqAw|gJQ6M43YaWTCHpBfUlBfsH1UMScVE#x==&{KJK4Nw zq&`_3?QRji7PsCpHE@otmWQxkbx{eo#%$Q_BhU2nVCdM^Uj_a!W;s;750)o0gZWJD z2%ou?y(EU_O=WhHPqxG&&&t^3W18MVZZgPAM=u~Q#d4|^58~GxXM5!Nzpe0-y~4Kk zx0AB?buC5(dVXk83$W+T9}Q>Cy0LD5O~Ok`;H!t{(U+%6Sa0<-*>~O4o?!|7B3JWw+O0bL z-CEPUM=3<|jFdy)JvBiIXUb|ZHw&m?CD2*FEAl<1{(2K67P~>`KKigbANrL8FB8bY zNoVDrPy|_=7J3!JPj#_Le((b?-;&e>R$HypdnLRyVcMy3G0oNT>K2qM(2Fa7Dv1`3 zUWF4Tf@t(6!@~QPq3#zc``K%wPmX4CeVhl3sgBk)J0^%`0E*fkVKNaM772DS`4vy#pONa%j2l6lF@B6Y1CxqR;wr6cD!3(>Bo5boQMu(o_Tk2I=a*Nq zZ4Wyt>7Y~`olVop<3INJY`n>)+3JR!S1HfYonZ!Q)qFckMn~oZct(N5)m@w+S9RUG z>}fnYdmdnX-5??Axt;Zi9`>gG=EXozM|nYF>2Gpe6-;fUkRKhy?KfVXu3(E73+?2< zQ_IGG5|2|n&%&OT`V!nLesay<Lg5j$8{d`5W1XrhD=W5b$pJ+&pT#D+0Ut42Jf3U%U!c>%a#Pb5Q^UyN zY2B=B@}vXYVtJp)BPgeR_|OPVg75O5i>P|tav6B^l34SXsE&KYBj{nBXUc5{b$#Rx zW(i>Sm^4s-(e90qX2HGpzoUZtU|iMTPRRzpk>!xgB)QKy3!V45-)rPU1~B!pd49H~ zE4%f)ydQlRq@^VO^RSaWf320#)n$JPy123Lp1RQVeyELNRo(@g)Op39wZ?hz1gnxA zN;`Tq@vL7aiaFv9?&~#nQO$w?j`^7YpNan0#&Ndl?UkC|xmVA>iM$2b(wAfon7}2+ zKoNWy9bIEZe_B;%fUNOQwv8-cWCu5uB-%arwcrUB@qru#?r+wv$L_DhXo6f#1I4*@1O&{*rmT>j7_}0FE7vqzJ6Y7v6+{)pp_*mlbJb8Kd z&&!_8F~%^R5YFQ(YnidR<}a&&rt0fRF#lZo^u7%apdS_0&WfG_?L+JHD}GkC!8u$m zG~(#utd%I*hX%&K^62(}rNavO%G!i44ETEuNslsFS_L3jeZ*l)UA2EQ&Q1p|mted3 zeJL~AeAyO!`VLqhPtCadfy4Ee2$KB{+BHwx)$t$5ba-&L(lip{{?o#CVeeR=r7N>1 zC+~(QDKgLaLhuwWb&Nx_3UYJjT=Al<8`=tUS!MO_vQ#F-5(ctu@tsU^-a@X+^@_rn%tV^-q5F?=Sz8pd-{*}(W zLSrw?F96YLHb$_oy8Kt^=W+d~zOC1b3#j$Mw;Dh|KcK9SuBjf7>YrNoMa-sSHF0v9 z!{)yAA20hF=eePxo%|XlgtTQ|kK|2}m_E0N`+WeC3QTS%-?o4HIhT;1y!`wo`(hE4gG7swuRbnjio2^N$4_)pL4a14_a{I_?C9Cpf77qtEQWVYM<|& zeLP*mt}mu57x2T2lD-bi7nNxiKK~w4=_#J;@w)59S=Wzs;2ar_FQ)t4tmT?CelVfy zmHw}*GY?o1Tit2S-f7%*-hO5c#6reoZU!!ITl`{hhb9T<+C!z$_K{ueLGb{x?EG`$ z^uY%ezj<;+twyjEDR}bDhWErXk;I>dkbIV+k`#Q-1=dp|ac5O>Dm6xbKOZ^pXL<-JZtXoOKXLdUT{o_UN5?R|BrJj`yv? zVr)Fq)GQz7IU2=L=&+N~nh$*X;`{BnwvrI}+BEO$ckAI%6k z+kL1cC|JF!dL(xFmo-n2jJufAq4_@1#KsP0Zy)OVE9DA1-s_w~>q~tirN82QSN+LL z8)Lm}(YZ_~7B`oTlNS*_nOG3(0bX=MOu}dRtPi1jVKq zOT!lu9X19`m8^-k5?T$=9G2mw@e*E{{77arI@Q+Kys2J?Z3BF0vO_wo$m%*cTH46);)%f#=)Ef%FlhEOx#IbO2oEGpBv1_!i$`RqgP@wR zjt?_mX$jgUn48?#J`quq7p{!(O~O%tjlhn($sYaSaY~;^Z|Q|Z=L+U!{K#Bs07+Du zb@l3x2nDwN?zkHLHXiSrhI37lH=`R%dErp5Y z*-T!v4;2N=?P@qZcp@3?0_ab^Q7^5WCoqQrGV9aFL<7j!ln71JkMU{iGeX(k<(3vS zogD6_dho>WR1zq>Ugr;3E5tlIVSW|<`*^fEMRsOguGKx^{dL|>;omuLlt&;LXX$lM zQs>PrP7X`uWk)sc{`d-nH9;rZcPBMzrAwQy{qtQn4mQ< z0prMzMwk@5qDsnThBux+d9iBornlN1WuhluFai!b{-}o-f_sS{U1g@jY`)xa7{QP0 zpd`A8?K$AB(c`9dBjvkvmg`f4a+{`}f$KCksP(^ZGEEn4?$}+>cr~&{((OWy6K#>1 zC3PjNtfk@1Xa@GS12-?k#HL*6Y*CSmkbblb=4E0SnPoGrkm48FAQjSZ3YNI$V07|L zxd-<_yN+7s?#DW}6a7p^Q@E+?BP=JMO!6uGeY${U{m4;7aEDZh9{;t;2aLdM-dVpN zf~~f@`y??LeK-tPf%H76G!!!Z#?$y99hNG>gOUJbEAeMC%3gh?fg7TqOn3&Tq{Ct} zdY#l~b5giK>=j$-iXlVU-YqWKH7%&vxX7}RR-p$g54rs#F*OOPQBoCrBgUVo`Q>Z6 z1Ym${Hp}1b_Pj}}`TOKL+k3s>*D%6fLp_Fjvq}CAD^N5FF)r@4cC9(#d~cDRcc9cw zTEM+otj^MFom3%b*ryUR!Z^_SgPiBV&&7+%sxC$4uOt3PNQ2TZ3_Kx*ZXl~$66 zQJY)`m(z$**0U4>XYBHO^Y9ir!TfhxDUjTa!=T41@RdJ6J>|?vxIhpew(Phe=A5Yo z8j+VIToWKkq(X|Uvy$s4SpVv$0l)&AZMdG`(v>=Ky)?a#F$K0n~5%6iJYNmNJzRMdZ)X*d{E^B;5t*I(ryr~fw7s744d=v}D6KcW9N@cj+u?$+oI z=D@^aU<%}aB|!d18w={+jQ>h-$B4=EA2F)`e}ex(_%GA2LB+{A?qTfk7fLPRdNCqJ1WRXOOY6{3{{oTWg;X(>6(tIqg6c*VMwTA$I_4gP@ zV#?%|5eBw9M;X-=V<(Gu7{(-WjN>AE3Ro5deAw)-983-H~@-CyY}u*TBO#)=70pwyYL9r6z#PI3N6q4 z67@8nk+5iA&fyJqUIgnFGbiVO$Ra>i_3P8yW5T`p!aU8uBh`N$w=QI)xR@^J_i)dx eYebdrTBz$w*IqLx{FR!&gSFK3RI63&BmNIACEu$6 literal 0 HcmV?d00001 diff --git a/Frontend/lib/mih_packages/mzansi_wallet/components/mih_add_card_window.dart b/Frontend/lib/mih_packages/mzansi_wallet/components/mih_add_card_window.dart index b194d0ce..b3a845f7 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/components/mih_add_card_window.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/components/mih_add_card_window.dart @@ -185,6 +185,7 @@ class _MihAddCardWindowState extends State { "Carrefour", "Dis-Chem", "Edgars", + "Engen", "Eskom", "Exclusive Books", "Fresh Stop", diff --git a/Frontend/lib/mih_packages/mzansi_wallet/components/mih_card_display.dart b/Frontend/lib/mih_packages/mzansi_wallet/components/mih_card_display.dart index 5f590c57..4829c409 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/components/mih_card_display.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/components/mih_card_display.dart @@ -153,6 +153,9 @@ class _MihCardDisplayState extends State { case "total energies": return Image.asset( 'lib/mih_components/mih_package_components/assets/images/loyalty_cards/mini/total_energies-min.png'); + case "engen": + return Image.asset( + 'lib/mih_components/mih_package_components/assets/images/loyalty_cards/mini/engen-min.png'); default: return null; } From 081e7d5533d01c613550aded59a2108b9e17dfe6 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 8 Oct 2025 09:40:34 +0200 Subject: [PATCH 05/45] BUG: Special Chars in Business Type --- .../package_tools/mih_business_details.dart | 3 ++- .../business_profile/profile_business_add.dart | 3 ++- .../lib/mih_services/mih_validation_services.dart | 11 +++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart index 00c22f00..4399f5ea 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart @@ -359,7 +359,8 @@ class _MihBusinessDetailsState extends State { requiredText: true, hintText: "Business Type", validator: (value) { - return MihValidationServices().isEmpty(value); + return MihValidationServices() + .validateNoSpecialChars(value); }, ), const SizedBox(height: 10), diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/profile_business_add.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/profile_business_add.dart index 5362dde8..550d5fd0 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/profile_business_add.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/profile_business_add.dart @@ -387,7 +387,8 @@ class _ProfileBusinessAddState extends State { requiredText: true, hintText: "Business Type", validator: (value) { - return MihValidationServices().isEmpty(value); + return MihValidationServices() + .validateNoSpecialChars(value); }, ), const SizedBox(height: 10.0), diff --git a/Frontend/lib/mih_services/mih_validation_services.dart b/Frontend/lib/mih_services/mih_validation_services.dart index d7085268..8d750099 100644 --- a/Frontend/lib/mih_services/mih_validation_services.dart +++ b/Frontend/lib/mih_services/mih_validation_services.dart @@ -6,6 +6,17 @@ class MihValidationServices { return null; } + String? validateNoSpecialChars(String? value) { + if (value == null || value.isEmpty) { + return "This field is required"; + } + final specialCharRegex = RegExp(r"^[\w,'& ]+$"); + if (!specialCharRegex.hasMatch(value)) { + return "Only , ' & _ Special characters are allowed"; + } + return null; + } + String? validateLength(String? value, int maxLength) { if (value == null || value.isEmpty) { return "This field is required"; From ef479b633d85ed09b960e525b55e88843ac5a925 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 8 Oct 2025 12:51:52 +0200 Subject: [PATCH 06/45] NEW: Add Test Device to main dev --- Frontend/lib/main_dev.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Frontend/lib/main_dev.dart b/Frontend/lib/main_dev.dart index 81ca7e45..c0bd70f0 100644 --- a/Frontend/lib/main_dev.dart +++ b/Frontend/lib/main_dev.dart @@ -20,6 +20,12 @@ void main() async { apiBasePath: "/auth", ); if (!kIsWeb) { + const List testDeviceIds = ['733d4c68-9b54-453a-9622-2df407310f40']; + MobileAds.instance.updateRequestConfiguration( + RequestConfiguration( + testDeviceIds: testDeviceIds, + ), + ); MobileAds.instance.initialize(); } else { usePathUrlStrategy(); @@ -29,5 +35,7 @@ void main() async { }); final GoRouter appRouter = MihGoRouter().mihRouter; FlutterNativeSplash.remove(); - runApp(MzansiInnovationHub(router: appRouter,)); + runApp(MzansiInnovationHub( + router: appRouter, + )); } From 0edbfadc9015193b57ebb1d1b7173f1152b9ddd1 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 8 Oct 2025 12:53:09 +0200 Subject: [PATCH 07/45] NEW: Import & Set Up Provider --- .../android/app/src/main/AndroidManifest.xml | 3 +- Frontend/lib/main.dart | 47 +++++++++++-------- Frontend/pubspec.lock | 2 +- Frontend/pubspec.yaml | 1 + 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/Frontend/android/app/src/main/AndroidManifest.xml b/Frontend/android/app/src/main/AndroidManifest.xml index 41e80cd2..6683a646 100644 --- a/Frontend/android/app/src/main/AndroidManifest.xml +++ b/Frontend/android/app/src/main/AndroidManifest.xml @@ -19,7 +19,8 @@ + android:icon="@mipmap/launcher_icon" + android:enableOnBackInvokedCallback="true"> { double width = MediaQuery.sizeOf(context).width; theme.setScreenType(width); precacheImage(theme.loadingImage(), context); - return MaterialApp.router( - title: getTitle(), - themeMode: ThemeMode.dark, - theme: theme.getThemeData(), - darkTheme: theme.getThemeData(), - debugShowCheckedModeBanner: false, - routerConfig: widget.router, - builder: (context, child) { - if (child == null) { - return const Scaffold( - body: Center( - child: CircularProgressIndicator(), - ), + return MultiProvider( + providers: [ + ChangeNotifierProvider( + create: (context) => MzansiWalletProvider(), + ), + ], + child: MaterialApp.router( + title: getTitle(), + themeMode: ThemeMode.dark, + theme: theme.getThemeData(), + darkTheme: theme.getThemeData(), + debugShowCheckedModeBanner: false, + routerConfig: widget.router, + builder: (context, child) { + if (child == null) { + return const Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } + return UpgradeAlert( + navigatorKey: widget.router.routerDelegate.navigatorKey, + child: child, ); - } - return UpgradeAlert( - navigatorKey: widget.router.routerDelegate.navigatorKey, - child: child, - ); - }, + }, + ), ); } } diff --git a/Frontend/pubspec.lock b/Frontend/pubspec.lock index 59bae95d..83c03080 100644 --- a/Frontend/pubspec.lock +++ b/Frontend/pubspec.lock @@ -1129,7 +1129,7 @@ packages: source: hosted version: "4.1.0" provider: - dependency: transitive + dependency: "direct main" description: name: provider sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" diff --git a/Frontend/pubspec.yaml b/Frontend/pubspec.yaml index 75f5cd3b..0c1b30b9 100644 --- a/Frontend/pubspec.yaml +++ b/Frontend/pubspec.yaml @@ -57,6 +57,7 @@ dependencies: upgrader: ^12.0.0 screenshot: ^3.0.0 file_saver: ^0.3.1 + provider: ^6.1.5+1 dev_dependencies: flutter_test: From 7373a1b8cb9b27d60d25bccf0f6efbd513ac7288 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 8 Oct 2025 13:35:47 +0200 Subject: [PATCH 08/45] NEW: Mzansi Wallet Provider Setup --- .../mih_providers/mzansi_wallet_provider.dart | 48 +++++++++++ .../mine_sweeper/mih_mine_sweeper.dart | 15 ++++ .../builder/build_loyalty_card_list.dart | 58 +++++++------ .../components/mih_add_card_window.dart | 14 +-- .../mzansi_wallet/mih_wallet.dart | 65 ++++++++++---- .../package_tools/mih_card_favourites.dart | 86 +++++-------------- .../package_tools/mih_cards.dart | 44 ++++------ .../mih_mzansi_wallet_services.dart | 51 +++++++---- 8 files changed, 215 insertions(+), 166 deletions(-) create mode 100644 Frontend/lib/mih_components/mih_providers/mzansi_wallet_provider.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart diff --git a/Frontend/lib/mih_components/mih_providers/mzansi_wallet_provider.dart b/Frontend/lib/mih_components/mih_providers/mzansi_wallet_provider.dart new file mode 100644 index 00000000..9358eaa1 --- /dev/null +++ b/Frontend/lib/mih_components/mih_providers/mzansi_wallet_provider.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/loyalty_card.dart'; + +class MzansiWalletProvider extends ChangeNotifier { + List loyaltyCards; + List favouriteCards; + int toolIndex; + + MzansiWalletProvider({ + this.loyaltyCards = const [], + this.favouriteCards = const [], + this.toolIndex = 0, + }); + + void setToolIndex(int index) { + toolIndex = index; + notifyListeners(); + } + + void setLoyaltyCards({required List cards}) async { + loyaltyCards = cards; + notifyListeners(); + } + + void setFavouriteCards({required List cards}) async { + favouriteCards = cards; + notifyListeners(); + } + + void addLoyaltyCard({required MIHLoyaltyCard newCard}) { + loyaltyCards.add(newCard); + notifyListeners(); + } + + void deleteLoyaltyCard({required int cardId}) { + loyaltyCards.removeWhere((card) => card.idloyalty_cards == cardId); + notifyListeners(); + } + + void editLoyaltyCard({required MIHLoyaltyCard updatedCard}) { + int index = loyaltyCards.indexWhere( + (card) => card.idloyalty_cards == updatedCard.idloyalty_cards); + if (index != -1) { + loyaltyCards[index] = updatedCard; + notifyListeners(); + } + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart b/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart new file mode 100644 index 00000000..98fd163f --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class MihMineSweeper extends StatefulWidget { + const MihMineSweeper({super.key}); + + @override + State createState() => _MihMineSweeperState(); +} + +class _MihMineSweeperState extends State { + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} diff --git a/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart b/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart index b791c364..9e70cd87 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart @@ -3,10 +3,10 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:go_router/go_router.dart'; import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_banner_ad.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_wallet_services.dart'; @@ -22,6 +22,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/loyalty_card.da import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_card_display.dart'; import 'package:flutter/material.dart'; import 'package:barcode_widget/barcode_widget.dart'; +import 'package:provider/provider.dart'; import 'package:screen_brightness/screen_brightness.dart'; class BuildLoyaltyCardList extends StatefulWidget { @@ -149,6 +150,7 @@ class _BuildLoyaltyCardListState extends State { .updateLoyaltyCardAPICall( widget.signedInUser, widget.cardList[index].idloyalty_cards, + widget.cardList[index].shop_name, widget.cardList[index].favourite, widget.cardList[index].priority_index, _nicknameController.text, @@ -158,13 +160,28 @@ class _BuildLoyaltyCardListState extends State { if (statusCode == 200) { context.pop(); context.pop(); - context.goNamed( - "mzansiWallet", - extra: WalletArguments( - widget.signedInUser, - 0, - ), - ); + // context + // .read() + // .editLoyaltyCard( + // updatedCard: MIHLoyaltyCard( + // idloyalty_cards: + // widget.cardList[index].idloyalty_cards, + // app_id: widget.signedInUser.app_id, + // shop_name: widget.cardList[index].shop_name, + // card_number: _cardNumberController.text, + // favourite: widget.cardList[index].favourite, + // priority_index: + // widget.cardList[index].priority_index, + // nickname: _nicknameController.text, + // ), + // ); + // context.goNamed( + // "mzansiWallet", + // extra: WalletArguments( + // widget.signedInUser, + // 0, + // ), + // ); } else { internetConnectionPopUp(); } @@ -212,9 +229,6 @@ class _BuildLoyaltyCardListState extends State { context, ); if (statusCode == 200) { - setState(() { - widget.cardList.removeAt(index); - }); context.pop(); context.pop(); } else { @@ -260,6 +274,7 @@ class _BuildLoyaltyCardListState extends State { await MIHMzansiWalletApis.updateLoyaltyCardAPICall( widget.signedInUser, widget.cardList[index].idloyalty_cards, + widget.cardList[index].shop_name, "Yes", _noFavourites, widget.cardList[index].nickname, @@ -269,13 +284,9 @@ class _BuildLoyaltyCardListState extends State { if (statusCode == 200) { context.pop(); context.pop(); - context.goNamed( - "mzansiWallet", - extra: WalletArguments( - widget.signedInUser, - 1, - ), - ); + await MIHMzansiWalletApis.getFavouriteLoyaltyCards( + widget.signedInUser.app_id, context); + context.read().setToolIndex(1); } else { internetConnectionPopUp(); } @@ -345,6 +356,7 @@ class _BuildLoyaltyCardListState extends State { await MIHMzansiWalletApis.updateLoyaltyCardAPICall( widget.signedInUser, widget.cardList[index].idloyalty_cards, + widget.cardList[index].shop_name, "", 0, widget.cardList[index].nickname, @@ -354,13 +366,9 @@ class _BuildLoyaltyCardListState extends State { if (statusCode == 200) { context.pop(); context.pop(); - context.goNamed( - "mzansiWallet", - extra: WalletArguments( - widget.signedInUser, - 0, - ), - ); + await MIHMzansiWalletApis.getFavouriteLoyaltyCards( + widget.signedInUser.app_id, context); + context.read().setToolIndex(0); } else { internetConnectionPopUp(); } diff --git a/Frontend/lib/mih_packages/mzansi_wallet/components/mih_add_card_window.dart b/Frontend/lib/mih_packages/mzansi_wallet/components/mih_add_card_window.dart index b3a845f7..9d990cf2 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/components/mih_add_card_window.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/components/mih_add_card_window.dart @@ -1,12 +1,9 @@ -// ignore_for_file: must_be_immutable - import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/loyalty_card.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; @@ -22,12 +19,10 @@ import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart' class MihAddCardWindow extends StatefulWidget { final AppUser signedInUser; - Future> cardList; - MihAddCardWindow({ + const MihAddCardWindow({ super.key, required this.signedInUser, - required this.cardList, }); @override @@ -133,8 +128,6 @@ class _MihAddCardWindowState extends State { } } - // ... rest of your existing methods - @override Widget build(BuildContext context) { final double width = MediaQuery.sizeOf(context).width; @@ -320,11 +313,6 @@ class _MihAddCardWindowState extends State { context, ); if (statusCode == 201) { - setState(() { - widget.cardList = - MIHMzansiWalletApis.getLoyaltyCards( - widget.signedInUser.app_id); - }); context.pop(); KenLogger.error("Card Added Successfully"); successPopUp( diff --git a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart index bff4aa00..7392b322 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart @@ -3,17 +3,19 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; +import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/package_tools/mih_cards.dart'; -import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_wallet_services.dart'; +import 'package:provider/provider.dart'; class MihWallet extends StatefulWidget { final WalletArguments arguments; - // final AppUser signedInUser; const MihWallet({ super.key, required this.arguments, - // required this.signedInUser, }); @override @@ -21,13 +23,34 @@ class MihWallet extends StatefulWidget { } class _MihWalletState extends State { - late int _selcetedIndex; + bool isLoading = true; + + void setPackageIndex() { + if (widget.arguments.index >= 0 && widget.arguments.index <= 3) { + context.read().setToolIndex(widget.arguments.index); + } + } + + Future setLoyaltyCards() async { + await MIHMzansiWalletApis.getLoyaltyCards( + widget.arguments.signedInUser.app_id, context); + } + + Future setFavouritesCards() async { + await MIHMzansiWalletApis.getFavouriteLoyaltyCards( + widget.arguments.signedInUser.app_id, context); + } @override void initState() { super.initState(); - setState(() { - _selcetedIndex = widget.arguments.index; + WidgetsBinding.instance.addPostFrameCallback((_) async { + setPackageIndex(); + await setLoyaltyCards(); + await setFavouritesCards(); + setState(() { + isLoading = false; + }); }); } @@ -38,12 +61,13 @@ class _MihWalletState extends State { appTools: getTools(), appBody: getToolBody(), appToolTitles: getToolTitle(), - selectedbodyIndex: _selcetedIndex, - onIndexChange: (newValue) { - setState(() { - _selcetedIndex = newValue; - }); - print("Index: $_selcetedIndex"); + selectedbodyIndex: context.watch().toolIndex, + onIndexChange: (newIndex) { + context.read().setToolIndex(newIndex); + // setState(() { + // _selcetedIndex = newValue; + // }); + // print("Index: $_selcetedIndex"); }, ); } @@ -65,19 +89,15 @@ class _MihWalletState extends State { MihPackageTools getTools() { Map temp = {}; temp[const Icon(Icons.card_membership)] = () { - setState(() { - _selcetedIndex = 0; - }); + context.read().setToolIndex(0); }; temp[const Icon(Icons.favorite)] = () { - setState(() { - _selcetedIndex = 1; - }); + context.read().setToolIndex(1); }; return MihPackageTools( tools: temp, - selcetedIndex: _selcetedIndex, + selcetedIndex: context.watch().toolIndex, ); } @@ -90,6 +110,13 @@ class _MihWalletState extends State { signedInUser: widget.arguments.signedInUser, ), ]; + if (isLoading) { + return [ + const Center( + child: Mihloadingcircle(), + ) + ]; + } return toolBodies; } diff --git a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart index 2cd705e2..af483d2d 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_banner_ad.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_wallet_services.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/loyalty_card.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart'; +import 'package:provider/provider.dart'; class MihCardFavourites extends StatefulWidget { final AppUser signedInUser; @@ -24,13 +24,17 @@ class _MihCardFavouritesState extends State { late MihBannerAd _bannerAd; List listOfCards = []; + void getFavouriteLoyaltyCards(BuildContext context) async { + setState(() { + listOfCards = context.read().favouriteCards; + }); + } + @override void initState() { - super.initState(); _bannerAd = MihBannerAd(); - cardList = MIHMzansiWalletApis.getFavouriteLoyaltyCards( - widget.signedInUser.app_id, - ); + getFavouriteLoyaltyCards(context); + super.initState(); } @override @@ -47,69 +51,23 @@ class _MihCardFavouritesState extends State { MihSingleChildScroll( child: Column( children: [ - FutureBuilder( - future: cardList, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center( - child: Mihloadingcircle(), - ); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - listOfCards = snapshot.data!; - // searchShop(); - return BuildLoyaltyCardList( - cardList: listOfCards, - signedInUser: widget.signedInUser, - navIndex: 0, - bannerAd: _bannerAd, - favouritesMode: true, - searchText: TextEditingController(), - onCardViewClose: () { - setState(() { - _bannerAd = MihBannerAd(); - }); - Navigator.pop(context); - }, - ); - } else { - return const Center( - child: Text("Error Loading Loyalty Cards"), - ); - } + BuildLoyaltyCardList( + cardList: listOfCards, + signedInUser: widget.signedInUser, + navIndex: 0, + bannerAd: _bannerAd, + favouritesMode: true, + searchText: TextEditingController(), + onCardViewClose: () { + setState(() { + _bannerAd = MihBannerAd(); + }); + Navigator.pop(context); }, ), ], ), ), - // Positioned( - // right: 0, - // bottom: 0, - // child: MihFloatingMenu( - // animatedIcon: AnimatedIcons.menu_close, - // children: [ - // SpeedDialChild( - // child: Icon( - // Icons.add, - // color: - // MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // label: "Add Loyalty Card", - // labelBackgroundColor: - // MihColors.getGreenColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // labelStyle: TextStyle( - // color: - // MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // fontWeight: FontWeight.bold, - // ), - // backgroundColor: - // MihColors.getGreenColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // onTap: () { - // // addCardWindow(context); - // }, - // ) - // ]), - // ) ], ); } diff --git a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart index e806717c..26bf46a7 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart @@ -3,21 +3,21 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_banner_ad.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_add_card_window.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_wallet_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/loyalty_card.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart'; import 'package:flutter/material.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; +import 'package:provider/provider.dart'; class MihCards extends StatefulWidget { final AppUser signedInUser; @@ -33,7 +33,6 @@ class MihCards extends StatefulWidget { class _MihCardsState extends State { final TextEditingController cardSearchController = TextEditingController(); final FocusNode searchFocusNode = FocusNode(); - late Future> cardList; MihBannerAd _bannerAd = MihBannerAd(); List listOfCards = []; final ValueNotifier> searchShopName = ValueNotifier([]); @@ -132,7 +131,6 @@ class _MihCardsState extends State { barrierDismissible: false, builder: (context) => MihAddCardWindow( signedInUser: widget.signedInUser, - cardList: cardList, ), ); } @@ -146,9 +144,16 @@ class _MihCardsState extends State { super.dispose(); } + void getLoyaltyCards(BuildContext context) async { + setState(() { + listOfCards = context.read().loyaltyCards; + }); + searchShop(); + } + @override void initState() { - cardList = MIHMzansiWalletApis.getLoyaltyCards(widget.signedInUser.app_id); + getLoyaltyCards(context); cardSearchController.addListener(searchShop); super.initState(); } @@ -187,23 +192,14 @@ class _MihCardsState extends State { ), ), const SizedBox(height: 10), - FutureBuilder( - future: cardList, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center( - child: Mihloadingcircle(), - ); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - listOfCards = snapshot.data!; - searchShop(); - return ValueListenableBuilder( + Consumer( + builder: (context, mzansiWalletProvider, child) { + listOfCards = mzansiWalletProvider.loyaltyCards; + return ValueListenableBuilder>( valueListenable: searchShopName, - builder: (BuildContext context, - List value, Widget? child) { + builder: (context, filteredCards, child) { return BuildLoyaltyCardList( - cardList: value, + cardList: filteredCards, //listOfCards, signedInUser: widget.signedInUser, navIndex: 0, bannerAd: _bannerAd, @@ -216,13 +212,7 @@ class _MihCardsState extends State { // Navigator.pop(context); }, ); - }, - ); - } else { - return const Center( - child: Text("Error Loading Loyalty Cards"), - ); - } + }); }, ), ], diff --git a/Frontend/lib/mih_services/mih_mzansi_wallet_services.dart b/Frontend/lib/mih_services/mih_mzansi_wallet_services.dart index 01254196..7dcdd4e1 100644 --- a/Frontend/lib/mih_services/mih_mzansi_wallet_services.dart +++ b/Frontend/lib/mih_services/mih_mzansi_wallet_services.dart @@ -5,6 +5,8 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/loyalty_card.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; +import 'package:provider/provider.dart'; import 'package:supertokens_flutter/http.dart' as http; import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; @@ -14,45 +16,39 @@ import '../mih_config/mih_env.dart'; class MIHMzansiWalletApis { final baseAPI = AppEnviroment.baseApiUrl; - /// This function is used to fetch a list of loyalty cards for a user. - /// - /// Patameters: app_id . - /// - /// Returns List. - static Future> getLoyaltyCards( + static Future getLoyaltyCards( String app_id, + BuildContext context, ) async { final response = await http.get(Uri.parse( "${AppEnviroment.baseApiUrl}/mzasni-wallet/loyalty-cards/$app_id")); if (response.statusCode == 200) { Iterable l = jsonDecode(response.body); - List patientQueue = List.from( + List myCards = List.from( l.map((model) => MIHLoyaltyCard.fromJson(model))); - return patientQueue; + context.read().setLoyaltyCards(cards: myCards); + // return myCards; } else { throw Exception('failed to fatch loyalty cards'); } } - /// This function is used to fetch a list of loyalty cards for a user. - /// - /// Patameters: app_id . - /// - /// Returns List. - static Future> getFavouriteLoyaltyCards( + static Future getFavouriteLoyaltyCards( String app_id, + BuildContext context, ) async { //print("Patien manager page: $endpoint"); final response = await http.get(Uri.parse( "${AppEnviroment.baseApiUrl}/mzasni-wallet/loyalty-cards/favourites/$app_id")); if (response.statusCode == 200) { Iterable l = jsonDecode(response.body); - List patientQueue = List.from( + List myCards = List.from( l.map((model) => MIHLoyaltyCard.fromJson(model))); - return patientQueue; - } else { - throw Exception('failed to fatch loyalty cards'); + context.read().setFavouriteCards(cards: myCards); } + // else { + // throw Exception('failed to fatch loyalty cards'); + // } } /// This function is used to Delete loyalty card from users mzansi wallet. @@ -80,6 +76,11 @@ class MIHMzansiWalletApis { //print("Here4"); //print(response.statusCode); context.pop(); + if (response.statusCode == 200) { + context + .read() + .deleteLoyaltyCard(cardId: idloyalty_cards); + } return response.statusCode; // if (response.statusCode == 200) { // Navigator.of(context).pop(); @@ -165,6 +166,7 @@ class MIHMzansiWalletApis { static Future updateLoyaltyCardAPICall( AppUser signedInUser, int idloyalty_cards, + String shopName, String favourite, int priority_index, String nickname, @@ -187,6 +189,19 @@ class MIHMzansiWalletApis { }), ); context.pop(); + if (response.statusCode == 200) { + context.read().editLoyaltyCard( + updatedCard: MIHLoyaltyCard( + idloyalty_cards: idloyalty_cards, + app_id: signedInUser.app_id, + shop_name: shopName, + card_number: card_number, + favourite: favourite, + priority_index: priority_index, + nickname: nickname, + ), + ); + } return response.statusCode; } From a1b7a3ef285185c1694a8aad545b49901ce34adf Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 8 Oct 2025 14:43:03 +0200 Subject: [PATCH 09/45] NEW: MIH Banner Ads Provider Set Up --- Frontend/lib/main.dart | 4 + .../mih_package_components/mih_banner_ad.dart | 78 +++++-------------- .../mih_providers/mih_banner_ad_provider.dart | 50 ++++++++++++ .../calculator/mih_calculator.dart | 10 +++ .../package_tools/currency_exchange_rate.dart | 11 +-- .../calculator/package_tools/tip_calc.dart | 11 +-- .../builder/build_loyalty_card_list.dart | 11 ++- .../mzansi_wallet/mih_wallet.dart | 2 + .../package_tools/mih_card_favourites.dart | 10 --- .../package_tools/mih_cards.dart | 9 --- 10 files changed, 103 insertions(+), 93 deletions(-) create mode 100644 Frontend/lib/mih_components/mih_providers/mih_banner_ad_provider.dart diff --git a/Frontend/lib/main.dart b/Frontend/lib/main.dart index d8c06955..4cf0b810 100644 --- a/Frontend/lib/main.dart +++ b/Frontend/lib/main.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:provider/provider.dart'; @@ -73,6 +74,9 @@ class _MzansiInnovationHubState extends State { ChangeNotifierProvider( create: (context) => MzansiWalletProvider(), ), + ChangeNotifierProvider( + create: (context) => MihBannerAdProvider(), + ), ], child: MaterialApp.router( title: getTitle(), diff --git a/Frontend/lib/mih_components/mih_package_components/mih_banner_ad.dart b/Frontend/lib/mih_components/mih_package_components/mih_banner_ad.dart index 521b3f88..8c52c32c 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_banner_ad.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_banner_ad.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:provider/provider.dart'; class MihBannerAd extends StatefulWidget { const MihBannerAd({super.key}); @@ -10,66 +12,26 @@ class MihBannerAd extends StatefulWidget { } class _MihBannerAdState extends State { - BannerAd? _bannerAd; - bool _isBannerAdLoaded = false; - final adUnitId = AppEnviroment.bannerAdUnitId; - String errorMessage = ''; - - void _loadBannerAd() { - _bannerAd = BannerAd( - adUnitId: adUnitId, - request: const AdRequest(), - size: AdSize.banner, - listener: BannerAdListener( - onAdLoaded: (ad) { - debugPrint('$ad loaded.'); - setState(() { - _isBannerAdLoaded = true; - }); - }, - onAdFailedToLoad: (ad, err) { - debugPrint('BannerAd failed to load: $err'); - setState(() { - errorMessage = - 'Failed to load ad- Message: ${err.message} Code :${err.code}'; - }); - ad.dispose(); // Dispose the ad to free resources - }, - onAdOpened: (Ad ad) => debugPrint('$ad opened.'), - onAdClosed: (Ad ad) => debugPrint('$ad closed.'), - onAdImpression: (Ad ad) => debugPrint('$ad impression.'), - ), - ); - - _bannerAd!.load(); - } - - @override - void dispose() { - _bannerAd?.dispose(); // Dispose the ad when the widget is removed - super.dispose(); - } - - @override - void initState() { - super.initState(); - _loadBannerAd(); - } - @override Widget build(BuildContext context) { - return Column( - children: [ - _bannerAd != null && _isBannerAdLoaded - ? SizedBox( - width: _bannerAd!.size.width.toDouble(), - height: _bannerAd!.size.height.toDouble(), - child: AdWidget(ad: _bannerAd!)) - : SizedBox( - child: - Text(AppEnviroment.getEnv() == "Dev" ? errorMessage : ""), - ), - ], + return Consumer( + builder: (context, bannerAdProvider, child) { + return Column( + children: [ + bannerAdProvider.bannerAd != null && + bannerAdProvider.isBannerAdLoaded + ? SizedBox( + width: bannerAdProvider.bannerAd!.size.width.toDouble(), + height: bannerAdProvider.bannerAd!.size.height.toDouble(), + child: AdWidget(ad: bannerAdProvider.bannerAd!)) + : SizedBox( + child: Text(AppEnviroment.getEnv() == "Dev" + ? bannerAdProvider.errorMessage + : ""), + ), + ], + ); + }, ); } } diff --git a/Frontend/lib/mih_components/mih_providers/mih_banner_ad_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_banner_ad_provider.dart new file mode 100644 index 00000000..610c5697 --- /dev/null +++ b/Frontend/lib/mih_components/mih_providers/mih_banner_ad_provider.dart @@ -0,0 +1,50 @@ +import 'package:flutter/foundation.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; + +class MihBannerAdProvider extends ChangeNotifier { + BannerAd? bannerAd; + final adUnitId = AppEnviroment.bannerAdUnitId; + bool isBannerAdLoaded = false; + String errorMessage = ''; + + MihBannerAdProvider({ + this.bannerAd, + this.isBannerAdLoaded = false, + this.errorMessage = '', + }); + + @override + void dispose() { + bannerAd?.dispose(); + super.dispose(); + } + + void loadBannerAd() { + bannerAd = BannerAd( + adUnitId: adUnitId, + request: const AdRequest(), + size: AdSize.banner, + listener: BannerAdListener( + onAdLoaded: (ad) { + debugPrint('$ad loaded.'); + isBannerAdLoaded = true; + notifyListeners(); + }, + onAdFailedToLoad: (ad, err) { + debugPrint('BannerAd failed to load: $err'); + errorMessage = + 'Failed to load ad- Message: ${err.message} Code :${err.code}'; + ad.dispose(); // Dispose the ad to free resources + isBannerAdLoaded = false; // ⬅️ Explicitly set to false + bannerAd = null; // ⬅️ Explicitly set to null + notifyListeners(); + }, + onAdOpened: (Ad ad) => debugPrint('$ad opened.'), + onAdClosed: (Ad ad) => debugPrint('$ad closed.'), + onAdImpression: (Ad ad) => debugPrint('$ad impression.'), + ), + ); + bannerAd!.load(); + } +} diff --git a/Frontend/lib/mih_packages/calculator/mih_calculator.dart b/Frontend/lib/mih_packages/calculator/mih_calculator.dart index cf52264f..01a9f860 100644 --- a/Frontend/lib/mih_packages/calculator/mih_calculator.dart +++ b/Frontend/lib/mih_packages/calculator/mih_calculator.dart @@ -2,10 +2,12 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/calculator/package_tools/currency_exchange_rate.dart'; import 'package:mzansi_innovation_hub/mih_packages/calculator/package_tools/simple_calc.dart'; import 'package:mzansi_innovation_hub/mih_packages/calculator/package_tools/tip_calc.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class MIHCalculator extends StatefulWidget { final bool personalSelected; @@ -21,6 +23,14 @@ class MIHCalculator extends StatefulWidget { class _MIHCalculatorState extends State { int _selectedIndex = 0; + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + context.read().loadBannerAd(); + }); + } + @override Widget build(BuildContext context) { return MihPackage( diff --git a/Frontend/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart b/Frontend/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart index a91104ec..2cd27f3f 100644 --- a/Frontend/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart +++ b/Frontend/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart @@ -10,10 +10,12 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_currency_exchange_rate_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; class CurrencyExchangeRate extends StatefulWidget { const CurrencyExchangeRate({super.key}); @@ -29,7 +31,6 @@ class _CurrencyExchangeRateState extends State { final TextEditingController _fromAmountController = TextEditingController(); final TextEditingController _toAmountController = TextEditingController(); late Future> availableCurrencies; - MihBannerAd _bannerAd = MihBannerAd(); Future submitForm() async { String fromCurrencyCode = _fromCurrencyController.text.split(" - ")[0]; @@ -67,9 +68,7 @@ class _CurrencyExchangeRateState extends State { fullscreen: false, windowTitle: "Calculation Results", onWindowTapClose: () { - setState(() { - _bannerAd = MihBannerAd(); - }); + context.read().loadBannerAd(); Navigator.pop(context); }, windowBody: Column( @@ -160,7 +159,9 @@ class _CurrencyExchangeRateState extends State { ], ), SizedBox(height: 10), - SizedBox(child: _bannerAd), + Consumer(builder: (context, bannerAdDisplay, child) { + return MihBannerAd(); + }), ], ), ), diff --git a/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart b/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart index f9269868..229dbd1e 100644 --- a/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart +++ b/Frontend/lib/mih_packages/calculator/package_tools/tip_calc.dart @@ -1,5 +1,6 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_banner_ad.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; @@ -14,6 +15,7 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:math_expressions/math_expressions.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; +import 'package:provider/provider.dart'; class TipCalc extends StatefulWidget { const TipCalc({super.key}); @@ -30,7 +32,6 @@ class _TipCalcState extends State { final ValueNotifier splitValue = ValueNotifier(""); late bool splitPosition; final _formKey = GlobalKey(); - MihBannerAd _bannerAd = MihBannerAd(); String tip = ""; String total = ""; String amountPerPerson = ""; @@ -98,9 +99,7 @@ class _TipCalcState extends State { fullscreen: false, windowTitle: "Calculation Results", onWindowTapClose: () { - setState(() { - _bannerAd = MihBannerAd(); - }); + context.read().loadBannerAd(); Navigator.pop(context); }, windowBody: Column( @@ -231,7 +230,9 @@ class _TipCalcState extends State { ), ), SizedBox(height: 10), - SizedBox(child: _bannerAd), + Consumer(builder: (context, bannerAdDisplay, child) { + return MihBannerAd(); + }), // if (splitBillController.text == "Yes") const Divider(), ], ), diff --git a/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart b/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart index 9e70cd87..90ea7719 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart @@ -6,6 +6,7 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_banner_ad.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; @@ -29,10 +30,8 @@ class BuildLoyaltyCardList extends StatefulWidget { final AppUser signedInUser; final List cardList; final int navIndex; - final MihBannerAd? bannerAd; final bool favouritesMode; final TextEditingController searchText; - final void Function()? onCardViewClose; const BuildLoyaltyCardList({ super.key, @@ -41,8 +40,6 @@ class BuildLoyaltyCardList extends StatefulWidget { required this.navIndex, required this.favouritesMode, required this.searchText, - this.bannerAd, - this.onCardViewClose, }); @override @@ -487,7 +484,7 @@ class _BuildLoyaltyCardListState extends State { ), ], onWindowTapClose: () { - widget.onCardViewClose; + context.read().loadBannerAd(); resetScreenBrightness(); context.pop(); }, @@ -549,7 +546,9 @@ class _BuildLoyaltyCardListState extends State { ), ), SizedBox(height: 10), - widget.bannerAd ?? SizedBox(), + Consumer(builder: (context, bannerAdDisplay, child) { + return MihBannerAd(); + }), // MihBannerAd(), ], ), diff --git a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart index 7392b322..60d3c0e2 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart @@ -4,6 +4,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart'; @@ -48,6 +49,7 @@ class _MihWalletState extends State { setPackageIndex(); await setLoyaltyCards(); await setFavouritesCards(); + context.read().loadBannerAd(); setState(() { isLoading = false; }); diff --git a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart index af483d2d..1d1a19c2 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_banner_ad.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; @@ -21,7 +20,6 @@ class MihCardFavourites extends StatefulWidget { class _MihCardFavouritesState extends State { late Future> cardList; - late MihBannerAd _bannerAd; List listOfCards = []; void getFavouriteLoyaltyCards(BuildContext context) async { @@ -32,7 +30,6 @@ class _MihCardFavouritesState extends State { @override void initState() { - _bannerAd = MihBannerAd(); getFavouriteLoyaltyCards(context); super.initState(); } @@ -55,15 +52,8 @@ class _MihCardFavouritesState extends State { cardList: listOfCards, signedInUser: widget.signedInUser, navIndex: 0, - bannerAd: _bannerAd, favouritesMode: true, searchText: TextEditingController(), - onCardViewClose: () { - setState(() { - _bannerAd = MihBannerAd(); - }); - Navigator.pop(context); - }, ), ], ), diff --git a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart index 26bf46a7..32658638 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart @@ -1,7 +1,6 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_banner_ad.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; @@ -33,7 +32,6 @@ class MihCards extends StatefulWidget { class _MihCardsState extends State { final TextEditingController cardSearchController = TextEditingController(); final FocusNode searchFocusNode = FocusNode(); - MihBannerAd _bannerAd = MihBannerAd(); List listOfCards = []; final ValueNotifier> searchShopName = ValueNotifier([]); final MobileScannerController scannerController = MobileScannerController( @@ -202,15 +200,8 @@ class _MihCardsState extends State { cardList: filteredCards, //listOfCards, signedInUser: widget.signedInUser, navIndex: 0, - bannerAd: _bannerAd, favouritesMode: false, searchText: cardSearchController, - onCardViewClose: () { - setState(() { - _bannerAd = MihBannerAd(); - }); - // Navigator.pop(context); - }, ); }); }, From bbadc58ab82b476bac1ff9ccbc5fde054a49212e Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 8 Oct 2025 15:06:04 +0200 Subject: [PATCH 10/45] NEW: MIH Calculator Provider Setup --- Frontend/lib/main.dart | 4 + .../mih_calculator_provider.dart | 21 ++ .../calculator/mih_calculator.dart | 30 +- .../package_tools/currency_exchange_rate.dart | 278 ++++++++---------- .../mih_currency_exchange_rate_services.dart | 11 +- 5 files changed, 174 insertions(+), 170 deletions(-) create mode 100644 Frontend/lib/mih_components/mih_providers/mih_calculator_provider.dart diff --git a/Frontend/lib/main.dart b/Frontend/lib/main.dart index 4cf0b810..c3c12b52 100644 --- a/Frontend/lib/main.dart +++ b/Frontend/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calculator_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:provider/provider.dart'; @@ -77,6 +78,9 @@ class _MzansiInnovationHubState extends State { ChangeNotifierProvider( create: (context) => MihBannerAdProvider(), ), + ChangeNotifierProvider( + create: (context) => MihCalculatorProvider(), + ), ], child: MaterialApp.router( title: getTitle(), diff --git a/Frontend/lib/mih_components/mih_providers/mih_calculator_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_calculator_provider.dart new file mode 100644 index 00000000..e2c66757 --- /dev/null +++ b/Frontend/lib/mih_components/mih_providers/mih_calculator_provider.dart @@ -0,0 +1,21 @@ +import 'package:flutter/foundation.dart'; + +class MihCalculatorProvider extends ChangeNotifier { + List availableCurrencies; + int toolIndex; + + MihCalculatorProvider({ + this.availableCurrencies = const [], + this.toolIndex = 0, + }); + + void setToolIndex(int index) { + toolIndex = index; + notifyListeners(); + } + + void setAvailableCurrencies({required List currencies}) async { + availableCurrencies = currencies; + notifyListeners(); + } +} diff --git a/Frontend/lib/mih_packages/calculator/mih_calculator.dart b/Frontend/lib/mih_packages/calculator/mih_calculator.dart index 01a9f860..96fcbcee 100644 --- a/Frontend/lib/mih_packages/calculator/mih_calculator.dart +++ b/Frontend/lib/mih_packages/calculator/mih_calculator.dart @@ -3,10 +3,12 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calculator_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/calculator/package_tools/currency_exchange_rate.dart'; import 'package:mzansi_innovation_hub/mih_packages/calculator/package_tools/simple_calc.dart'; import 'package:mzansi_innovation_hub/mih_packages/calculator/package_tools/tip_calc.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_currency_exchange_rate_services.dart'; import 'package:provider/provider.dart'; class MIHCalculator extends StatefulWidget { @@ -21,13 +23,16 @@ class MIHCalculator extends StatefulWidget { } class _MIHCalculatorState extends State { - int _selectedIndex = 0; + Future getCurrencyCodeList() async { + await MihCurrencyExchangeRateServices.getCurrencyCodeList(context); + } @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { context.read().loadBannerAd(); + await getCurrencyCodeList(); }); } @@ -38,12 +43,9 @@ class _MIHCalculatorState extends State { appTools: getTools(), appBody: getToolBody(), appToolTitles: getToolTitle(), - selectedbodyIndex: _selectedIndex, - onIndexChange: (newValue) { - setState(() { - _selectedIndex = newValue; - }); - print("Index: $_selectedIndex"); + selectedbodyIndex: context.watch().toolIndex, + onIndexChange: (newIndex) { + context.read().setToolIndex(newIndex); }, ); } @@ -65,23 +67,17 @@ class _MIHCalculatorState extends State { MihPackageTools getTools() { Map temp = {}; temp[const Icon(Icons.calculate)] = () { - setState(() { - _selectedIndex = 0; - }); + context.read().setToolIndex(0); }; temp[const Icon(Icons.money)] = () { - setState(() { - _selectedIndex = 1; - }); + context.read().setToolIndex(1); }; temp[const Icon(Icons.currency_exchange)] = () { - setState(() { - _selectedIndex = 2; - }); + context.read().setToolIndex(2); }; return MihPackageTools( tools: temp, - selcetedIndex: _selectedIndex, + selcetedIndex: context.watch().toolIndex, ); } diff --git a/Frontend/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart b/Frontend/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart index 2cd27f3f..b0680632 100644 --- a/Frontend/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart +++ b/Frontend/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart @@ -9,8 +9,8 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calculator_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_currency_exchange_rate_services.dart'; @@ -30,7 +30,6 @@ class _CurrencyExchangeRateState extends State { final TextEditingController _toCurrencyController = TextEditingController(); final TextEditingController _fromAmountController = TextEditingController(); final TextEditingController _toAmountController = TextEditingController(); - late Future> availableCurrencies; Future submitForm() async { String fromCurrencyCode = _fromCurrencyController.text.split(" - ")[0]; @@ -276,7 +275,6 @@ class _CurrencyExchangeRateState extends State { @override void initState() { super.initState(); - availableCurrencies = MihCurrencyExchangeRateServices.getCurrencyCodeList(); } @override @@ -290,177 +288,155 @@ class _CurrencyExchangeRateState extends State { } Widget getBody(double width) { - return FutureBuilder( - future: availableCurrencies, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Mihloadingcircle(); - } else if (snapshot.connectionState == ConnectionState.done) { - return MihSingleChildScroll( - child: Padding( - padding: MzansiInnovationHub.of(context)!.theme.screenType == - "desktop" + return Consumer( + builder: (context, calculatorProvider, child) { + return MihSingleChildScroll( + child: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" ? EdgeInsets.symmetric(horizontal: width * 0.2) : EdgeInsets.symmetric(horizontal: width * 0.075), - child: Column( - children: [ - MihForm( - formKey: _formKey, - formFields: [ - MihTextFormField( - fillColor: MihColors.getSecondaryColor( + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: _fromAmountController, + multiLineInput: false, + requiredText: true, + hintText: "Currency Amount", + numberMode: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihDropdownField( + controller: _fromCurrencyController, + hintText: "From", + dropdownOptions: calculatorProvider.availableCurrencies, + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, + ), + const SizedBox(height: 10), + MihDropdownField( + controller: _toCurrencyController, + hintText: "To", + dropdownOptions: calculatorProvider.availableCurrencies, + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, + ), + const SizedBox(height: 15), + RichText( + textAlign: TextAlign.left, + text: TextSpan( + style: TextStyle( + fontSize: 15, + color: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: _fromAmountController, - multiLineInput: false, - requiredText: true, - hintText: "Currency Amount", - numberMode: true, - validator: (value) { - return MihValidationServices().isEmpty(value); - }, ), - const SizedBox(height: 10), - MihDropdownField( - controller: _fromCurrencyController, - hintText: "From", - dropdownOptions: snapshot.data!, - editable: true, - enableSearch: true, - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - requiredText: true, - ), - const SizedBox(height: 10), - MihDropdownField( - controller: _toCurrencyController, - hintText: "To", - dropdownOptions: snapshot.data!, - editable: true, - enableSearch: true, - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - requiredText: true, - ), - const SizedBox(height: 15), - RichText( - textAlign: TextAlign.left, - text: TextSpan( + children: [ + const TextSpan( + text: "* Experimental Feature: Please review "), + TextSpan( + text: "Diclaimer", style: TextStyle( - fontSize: 15, - color: MihColors.getRedColor( + decoration: TextDecoration.underline, + color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontWeight: FontWeight.bold, ), - children: [ - const TextSpan( - text: - "* Experimental Feature: Please review "), - TextSpan( - text: "Diclaimer", - style: TextStyle( - decoration: TextDecoration.underline, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - fontWeight: FontWeight.bold, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - displayDisclaimer(); - }, - ), - const TextSpan(text: " before use."), - ], + recognizer: TapGestureRecognizer() + ..onTap = () { + displayDisclaimer(); + }, ), - ), - const SizedBox(height: 25), - Center( - child: Wrap( - spacing: 10, - runSpacing: 10, - children: [ - MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - submitForm(); - FocusScope.of(context) - .requestFocus(FocusNode()); - } else { - MihAlertServices() - .formNotFilledCompletely(context); - } - }, - buttonColor: MihColors.getGreenColor( + const TextSpan(text: " before use."), + ], + ), + ), + const SizedBox(height: 25), + Center( + child: Wrap( + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm(); + FocusScope.of(context) + .requestFocus(FocusNode()); + } else { + MihAlertServices() + .formNotFilledCompletely(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Calculate", + style: TextStyle( + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)! .theme .mode == "Dark"), - width: 300, - child: Text( - "Calculate", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), + fontSize: 20, + fontWeight: FontWeight.bold, ), - MihButton( - onPressed: () { - clearInput(); - }, - buttonColor: MihColors.getRedColor( + ), + ), + MihButton( + onPressed: () { + clearInput(); + }, + buttonColor: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Clear", + style: TextStyle( + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)! .theme .mode == "Dark"), - width: 300, - child: Text( - "Clear", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), + fontSize: 20, + fontWeight: FontWeight.bold, ), - ], + ), ), - ), - ], + ], + ), ), ], ), - ), - ); - } else { - return Center( - child: Text( - "Error pulling Currency Exchange Data.", - style: TextStyle( - fontSize: 25, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark")), - textAlign: TextAlign.center, - ), - ); - } - }); + ], + ), + ), + ); + }, + ); } } diff --git a/Frontend/lib/mih_services/mih_currency_exchange_rate_services.dart b/Frontend/lib/mih_services/mih_currency_exchange_rate_services.dart index 2be8748e..02f5bd35 100644 --- a/Frontend/lib/mih_services/mih_currency_exchange_rate_services.dart +++ b/Frontend/lib/mih_services/mih_currency_exchange_rate_services.dart @@ -1,6 +1,9 @@ import 'dart:convert'; +import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/currency.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calculator_provider.dart'; +import 'package:provider/provider.dart'; import 'package:supertokens_flutter/http.dart' as http; class MihCurrencyExchangeRateServices { @@ -21,7 +24,7 @@ class MihCurrencyExchangeRateServices { } } - static Future> getCurrencyCodeList() async { + static Future getCurrencyCodeList(BuildContext context) async { final response = await http.get(Uri.parse( "https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies.min.json")); if (response.statusCode == 200) { @@ -32,7 +35,11 @@ class MihCurrencyExchangeRateServices { currencies.add("$code - $name"); }); currencies.sort(); - return currencies; + if (response.statusCode == 200) { + context + .read() + .setAvailableCurrencies(currencies: currencies); + } } else { throw Exception('failed to fatch currencies'); } From f828ba178686f5e6be61400de49aa5a7b6cfd514 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 13 Oct 2025 10:45:30 +0200 Subject: [PATCH 11/45] NEW: About MIH Provider Setup --- Frontend/lib/main.dart | 8 ++++ .../mih_providers/about_mih_provider.dart | 14 ++++++ Frontend/lib/mih_config/mih_go_router.dart | 19 +++++--- .../lib/mih_packages/about_mih/about_mih.dart | 43 +++++++------------ .../package_tile/about_mih_tile.dart | 6 +-- .../mih_home/components/mih_app_drawer.dart | 24 +++++++---- 6 files changed, 69 insertions(+), 45 deletions(-) create mode 100644 Frontend/lib/mih_components/mih_providers/about_mih_provider.dart diff --git a/Frontend/lib/main.dart b/Frontend/lib/main.dart index c3c12b52..a6d55038 100644 --- a/Frontend/lib/main.dart +++ b/Frontend/lib/main.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/about_mih_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calculator_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:provider/provider.dart'; @@ -81,6 +83,12 @@ class _MzansiInnovationHubState extends State { ChangeNotifierProvider( create: (context) => MihCalculatorProvider(), ), + ChangeNotifierProvider( + create: (context) => AboutMihProvider(), + ), + ChangeNotifierProvider( + create: (context) => MihMineSweeperProvider(), + ), ], child: MaterialApp.router( title: getTitle(), diff --git a/Frontend/lib/mih_components/mih_providers/about_mih_provider.dart b/Frontend/lib/mih_components/mih_providers/about_mih_provider.dart new file mode 100644 index 00000000..5ef994ba --- /dev/null +++ b/Frontend/lib/mih_components/mih_providers/about_mih_provider.dart @@ -0,0 +1,14 @@ +import 'package:flutter/foundation.dart'; + +class AboutMihProvider extends ChangeNotifier { + int toolIndex; + + AboutMihProvider({ + this.toolIndex = 0, + }); + + void setToolIndex(int index) { + toolIndex = index; + notifyListeners(); + } +} diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index 7ac1e756..856d61ff 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -13,6 +13,7 @@ import 'package:mzansi_innovation_hub/mih_packages/mih_authentication/mih_auth_p import 'package:mzansi_innovation_hub/mih_packages/mih_authentication/mih_authentication.dart'; import 'package:mzansi_innovation_hub/mih_packages/mih_home/mih_home.dart'; import 'package:mzansi_innovation_hub/mih_packages/mih_home/mih_route_error.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/mih_mine_sweeper.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_ai/mzansi_ai.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/mzansi_directory.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart'; @@ -63,6 +64,7 @@ class MihGoRouterPaths { static const String barcodeScanner = '/scanner'; static const String calculator = '/calculator'; static const String mzansiAi = '/mzansi-ai'; + static const String mihMineSweeper = '/mih-mine-sweeper'; static const String packageDevTest = '/package-dev'; } @@ -150,14 +152,12 @@ class MihGoRouter { path: MihGoRouterPaths.aboutMih, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: aboutMih"); - final AboutArguments? args = state.extra as AboutArguments?; - int index = 0; + final bool? args = state.extra as bool?; bool personalSelected = true; if (args != null) { - index = args.packageIndex ?? 0; - personalSelected = args.personalSelected; + personalSelected = args; } - return AboutMih(arguments: AboutArguments(personalSelected, index)); + return AboutMih(personalSelected: personalSelected); }, ), // ========================== Mzansi Profile Personal ================================== @@ -463,6 +463,15 @@ class MihGoRouter { return MIHPrintPreview(arguments: args!); }, ), + // ========================== MIH Calculator ================================== + GoRoute( + name: "mihMineSweeper", + path: MihGoRouterPaths.mihMineSweeper, + builder: (BuildContext context, GoRouterState state) { + KenLogger.success("MihGoRouter: mihMineSweeper"); + return MihMineSweeper(); + }, + ), // ========================== End ================================== // GoRoute( // name: "notifications", diff --git a/Frontend/lib/mih_packages/about_mih/about_mih.dart b/Frontend/lib/mih_packages/about_mih/about_mih.dart index e18dcf45..336885f9 100644 --- a/Frontend/lib/mih_packages/about_mih/about_mih.dart +++ b/Frontend/lib/mih_packages/about_mih/about_mih.dart @@ -1,19 +1,22 @@ import 'package:go_router/go_router.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/about_mih_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/about_mih/package_tools/mih_%20attributes.dart'; import 'package:mzansi_innovation_hub/mih_packages/about_mih/package_tools/mih_info.dart'; import 'package:mzansi_innovation_hub/mih_packages/about_mih/package_tools/mih_privacy_policy.dart'; import 'package:mzansi_innovation_hub/mih_packages/about_mih/package_tools/mih_terms_of_service.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class AboutMih extends StatefulWidget { - final AboutArguments? arguments; + final bool? personalSelected; + // final AboutArguments? arguments; const AboutMih({ super.key, - this.arguments, + // this.arguments, + this.personalSelected, }); @override @@ -21,19 +24,16 @@ class AboutMih extends StatefulWidget { } class _AboutMihState extends State { - late int _selcetedIndex; late bool _personalSelected; @override void initState() { super.initState(); setState(() { - if (widget.arguments == null) { - _selcetedIndex = 0; + if (widget.personalSelected == null) { _personalSelected = true; } else { - _selcetedIndex = widget.arguments!.packageIndex!; - _personalSelected = widget.arguments!.personalSelected; + _personalSelected = widget.personalSelected!; } }); } @@ -45,12 +45,9 @@ class _AboutMihState extends State { appTools: getTools(), appBody: getToolBody(), appToolTitles: getToolTitle(), - selectedbodyIndex: _selcetedIndex, - onIndexChange: (newValue) { - setState(() { - _selcetedIndex = newValue; - }); - // print("Index: $_selcetedIndex"); + selectedbodyIndex: context.watch().toolIndex, + onIndexChange: (newIndex) { + context.read().setToolIndex(newIndex); }, ); } @@ -72,28 +69,20 @@ class _AboutMihState extends State { MihPackageTools getTools() { Map temp = {}; temp[const Icon(Icons.info)] = () { - setState(() { - _selcetedIndex = 0; - }); + context.read().setToolIndex(0); }; temp[const Icon(Icons.policy)] = () { - setState(() { - _selcetedIndex = 1; - }); + context.read().setToolIndex(1); }; temp[const Icon(Icons.design_services)] = () { - setState(() { - _selcetedIndex = 2; - }); + context.read().setToolIndex(2); }; temp[const Icon(Icons.star_rounded)] = () { - setState(() { - _selcetedIndex = 3; - }); + context.read().setToolIndex(3); }; return MihPackageTools( tools: temp, - selcetedIndex: _selcetedIndex, + selcetedIndex: context.watch().toolIndex, ); } diff --git a/Frontend/lib/mih_packages/about_mih/package_tile/about_mih_tile.dart b/Frontend/lib/mih_packages/about_mih/package_tile/about_mih_tile.dart index 28b03444..edf7c351 100644 --- a/Frontend/lib/mih_packages/about_mih/package_tile/about_mih_tile.dart +++ b/Frontend/lib/mih_packages/about_mih/package_tile/about_mih_tile.dart @@ -1,6 +1,5 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; @@ -26,10 +25,7 @@ class _AboutMihTileState extends State { onTap: () { context.goNamed( "aboutMih", - extra: AboutArguments( - widget.personalSelected, - 0, - ), + extra: widget.personalSelected, ); // Navigator.of(context).pushNamed( // '/about', diff --git a/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart b/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart index ad15cbef..bd09514d 100644 --- a/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart +++ b/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart @@ -4,7 +4,9 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/about_mih_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:provider/provider.dart'; import '../../../main.dart'; import 'package:supertokens_flutter/supertokens.dart'; @@ -200,12 +202,15 @@ class _MIHAppDrawerState extends State { ], ), onTap: () { + WidgetsBinding.instance + .addPostFrameCallback((_) async { + context + .read() + .setToolIndex(1); + }); context.goNamed( "aboutMih", - extra: AboutArguments( - true, - 1, - ), + extra: true, ); }, ), @@ -236,12 +241,15 @@ class _MIHAppDrawerState extends State { ], ), onTap: () { + WidgetsBinding.instance + .addPostFrameCallback((_) async { + context + .read() + .setToolIndex(2); + }); context.goNamed( "aboutMih", - extra: AboutArguments( - true, - 2, - ), + extra: true, ); }, ), From ebd78eb72b484e003923fd391d86a80a294a45d4 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 13 Oct 2025 11:14:11 +0200 Subject: [PATCH 12/45] NEW: MIH Authentication Provider Setup --- Frontend/lib/main.dart | 4 ++ .../mih_authentication_provider.dart | 14 +++++++ .../mih_authentication.dart | 39 +++++-------------- .../package_tools/mih_register.dart | 10 +++-- .../package_tools/mih_sign_in.dart | 10 +++-- 5 files changed, 42 insertions(+), 35 deletions(-) create mode 100644 Frontend/lib/mih_components/mih_providers/mih_authentication_provider.dart diff --git a/Frontend/lib/main.dart b/Frontend/lib/main.dart index a6d55038..bffb4a3d 100644 --- a/Frontend/lib/main.dart +++ b/Frontend/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/about_mih_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_authentication_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calculator_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; @@ -74,6 +75,9 @@ class _MzansiInnovationHubState extends State { precacheImage(theme.loadingImage(), context); return MultiProvider( providers: [ + ChangeNotifierProvider( + create: (context) => MihAuthenticationProvider(), + ), ChangeNotifierProvider( create: (context) => MzansiWalletProvider(), ), diff --git a/Frontend/lib/mih_components/mih_providers/mih_authentication_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_authentication_provider.dart new file mode 100644 index 00000000..94d33ba3 --- /dev/null +++ b/Frontend/lib/mih_components/mih_providers/mih_authentication_provider.dart @@ -0,0 +1,14 @@ +import 'package:flutter/foundation.dart'; + +class MihAuthenticationProvider extends ChangeNotifier { + int toolIndex; + + MihAuthenticationProvider({ + this.toolIndex = 0, + }); + + void setToolIndex(int index) { + toolIndex = index; + notifyListeners(); + } +} diff --git a/Frontend/lib/mih_packages/mih_authentication/mih_authentication.dart b/Frontend/lib/mih_packages/mih_authentication/mih_authentication.dart index b255f91d..3511ed90 100644 --- a/Frontend/lib/mih_packages/mih_authentication/mih_authentication.dart +++ b/Frontend/lib/mih_packages/mih_authentication/mih_authentication.dart @@ -4,8 +4,10 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_authentication_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/mih_authentication/package_tools/mih_register.dart'; import 'package:mzansi_innovation_hub/mih_packages/mih_authentication/package_tools/mih_sign_in.dart'; +import 'package:provider/provider.dart'; class MihAuthentication extends StatefulWidget { const MihAuthentication({super.key}); @@ -15,56 +17,35 @@ class MihAuthentication extends StatefulWidget { } class _MihAuthenticationState extends State { - int _selcetedIndex = 0; - @override Widget build(BuildContext context) { return MihPackage( appActionButton: getAction(), appTools: getTools(), appBody: getToolBody(), - selectedbodyIndex: _selcetedIndex, - onIndexChange: (newValue) { - setState(() { - _selcetedIndex = newValue; - }); + selectedbodyIndex: context.watch().toolIndex, + onIndexChange: (newIndex) { + context.read().setToolIndex(newIndex); }, ); } List getToolBody() { - List toolBodies = [ - MihSignIn( - onNewUserButtonTap: () { - setState(() { - _selcetedIndex = 1; - }); - }, - ), - MihRegister(onExistingUserButtonTap: () { - setState(() { - _selcetedIndex = 0; - }); - }) - ]; + List toolBodies = [MihSignIn(), MihRegister()]; return toolBodies; } MihPackageTools getTools() { Map temp = {}; temp[const Icon(Icons.perm_identity)] = () { - setState(() { - _selcetedIndex = 0; - }); + context.read().setToolIndex(0); }; temp[const Icon(Icons.create)] = () { - setState(() { - _selcetedIndex = 1; - }); + context.read().setToolIndex(1); }; return MihPackageTools( tools: temp, - selcetedIndex: _selcetedIndex, + selcetedIndex: context.watch().toolIndex, ); } @@ -75,7 +56,7 @@ class _MihAuthenticationState extends State { icon: const Icon(MihIcons.mihLogo), iconSize: 45, onTap: () { - context.goNamed("aboutMih", extra: 0); + context.goNamed("aboutMih", extra: true); }, ), ); diff --git a/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_register.dart b/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_register.dart index 6fc9e0de..f97a0334 100644 --- a/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_register.dart +++ b/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_register.dart @@ -11,19 +11,19 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_authentication_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; import 'package:supertokens_flutter/http.dart' as http; import 'package:supertokens_flutter/supertokens.dart'; class MihRegister extends StatefulWidget { - final void Function()? onExistingUserButtonTap; const MihRegister({ super.key, - required this.onExistingUserButtonTap, }); @override @@ -366,7 +366,11 @@ class _MihRegisterState extends State { ), ), MihButton( - onPressed: widget.onExistingUserButtonTap, + onPressed: () { + context + .read() + .setToolIndex(0); + }, buttonColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), diff --git a/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart b/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart index c6bb47f2..d21ee78c 100644 --- a/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart +++ b/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart @@ -9,18 +9,18 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_authentication_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_authentication_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_install_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; class MihSignIn extends StatefulWidget { - final void Function()? onNewUserButtonTap; const MihSignIn({ super.key, - required this.onNewUserButtonTap, }); @override @@ -381,7 +381,11 @@ class _MihSignInState extends State { ), ), MihButton( - onPressed: widget.onNewUserButtonTap, + onPressed: () { + context + .read() + .setToolIndex(1); + }, buttonColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), From 22d8c649949a171c9641e5bb41238ca35af32a4d Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 16 Oct 2025 09:03:02 +0200 Subject: [PATCH 13/45] QOL: Change Users to People in About MIH --- Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart b/Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart index 98f090aa..eccbbc4d 100644 --- a/Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart +++ b/Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart @@ -610,7 +610,7 @@ class _MihInfoState extends State { ), const SizedBox(width: 10), Text( - "Users", + "People", textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.normal, From 6ecce1e9ff2789b69fad23de9d8f228d1b8c84f1 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 16 Oct 2025 09:45:17 +0200 Subject: [PATCH 14/45] NEW: MIH MineSweeper Package pt1 --- .../assets/fonts/Mih_Icons.ttf | Bin 44128 -> 45564 bytes .../assets/fonts/style.css | 56 +- .../mih_package_components/mih_icons.dart | 41 +- .../mine_sweeper/components/board_square.dart | 13 + .../mine_sweeper/components/mine_tile.dart | 111 ++++ .../mine_sweeper/mih_mine_sweeper.dart | 58 +- .../package_tiles/mih_mine_sweeper_tile.dart | 44 ++ .../package_tools/mine_sweeper_game.dart | 596 ++++++++++++++++++ 8 files changed, 873 insertions(+), 46 deletions(-) create mode 100644 Frontend/lib/mih_packages/mine_sweeper/components/board_square.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/components/mine_tile.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart diff --git a/Frontend/lib/mih_components/mih_package_components/assets/fonts/Mih_Icons.ttf b/Frontend/lib/mih_components/mih_package_components/assets/fonts/Mih_Icons.ttf index 71c04e155aa0042fcb72d33ab638b33a0cfd01d5..a908997c66d80100c9048237b82601bb02359778 100644 GIT binary patch delta 2118 zcmZuyON<;x8Ln4%b$4}l^{c8M(=$CiJ-y@cvfGZwvxBjh!59<>4?}Dv;gFD(@k?aA z3pU6gqzRWOf*gof3Qo=l85<`-MuI~Q8wptmB9J11asY%BAwcB71qq2IOU-(@xm(rs z{r~s>^*_|5|IhEBop;d;KmY&(&jJh%ojTnd=7By^nm5#X`t17JX8hROHvoXSlFwXN zyRxZvPs#J$xbVz3&cF56Q$JPmH306sbMf5TmzExPUk2c{&nbT8qEgV`<9{gmc_sHR zu3x=&>Y_s6wI8d`6VGg%J+byf_Dur7>uQ1J^|fo8V3pia@)0F>FR!hid-)ObKT1BM zf;_jmapkH?R6RfW!<+{g|NF)5DfF+yV~ZbD8VeWzsTYFo-~HYH?(WWQ6$X14?!Frn zP1Mp+;v+zmyWjKT1h2MvF;63;@ z{Hr>Ah*TtPJk<-tjjAD2I4YpvsG2lzN(HA?gE?%pLYtxjayY1!EjR1N8czzQ9LA#p z(Rwx|;|9%5XhFDE)eWAK292jE795HK2~OsAjX9ngD#8@b*QmgXZ4igCpeg~gni>tQ zI2DC4Qb#K*JjEk*1PLeO0WI)IQ)!X82G=ScRw<#X9yc>>QfTwE>jo;fy&9k@VINaf zjxi}zJ+Pjl!Bm+N5p#0i9I5l>7IadeQK3;)qA_oRHL2!J7^&3m=h_gCRJLR?uS^9& zDju?Hn z(+)bFqFm}0oh)!HL#G~>X)cn(ODxS}!(~B|^pb#k4wYHE|3`1Ngjud(_&uUy#yBN9 zaecbe$CNtNmHKESyfzjv}#`52HFL)1>*C z=^JLWP{^DdsM8OjDDVr{(y)$IYp5eVMh$ERf;c)Oh7@gxDYqCqk$HN%?6nk6YD0sL zPD~@t9c=5uK)L}q_ftbomxo8Lid?S(#cX(dF`W%{lv9GPqy?g zXguy}iz0$C5?LvmX|>$#TankqavJuFNVG!xsNZU5M@!jpgU^%)T4hfk1jBCpaF|BD zA}aDv2&7@gxs0M#+4*Ey_Hr3|2GQ-=6rn0IHLGH_gUA3vz7U>B)8WCvQl9#*OUWV3 zWl#3%y2#W832jR4FqLt3pi@OFG0hLJw}LUYshqL$1?-hKycuZ)sjSo`MO)T zF=1S)o<<}mVP}-M=ulzJ>iBUh?ZrW-Yg3o^)3N#=%?~3h5W3FX6f@IScTg80>r;Q= zIbL|Aj||=oLy^fkLCfw?eqQ*}wGff6aQw3FB@r{b*kq=s*%)k!w z7KvQXNuz@WKS?n`*jEvFwp95RzN%r5X~gLphICa$mhQDff(bVXaWzC!BpnJ*B9n28 z7%Wo%``tI;jbnG6mu`exFRo>GudKfEL^Yph>iO+goQJ>2kN*p>`D6j$FTpwY|NGW2 ze>8#e`mHlt-CJa3kG4PrI%vmu#J=hMTqdnwb??=09K7BSY=I1XXFisQ zsWh%)?qj6zg?)?_Ufst;;cw0HSUG4w&gbBsv#y9o_pt?zfFE2syRp8paT#0!XTb(o dS8D@Y-nw+VJorH7fy%Az+d@2;`RDD;{{di8BliFR delta 691 zcmaKpO=uHQ9K>g{o1{rGmBgkcR*g{{PaGfY@;Y=nb+&Y-AZu8yhXA3EdNwcX8tZQADr-kxUCi~`#-35%0G{+IS$Q@* z5qJ$eea!rXLc_T&ex-g-eOM_}7ABG;teIU>EoIKg>1)fEXqa}mATMZ$NnCKPN*yf9 zh3v{o_#X8GZgO8M=@lN7-}(ra=- zIktiST4?U{Nd7nemt4!dK8&0YuU&E8jn-B#Zp|2tP@s0;+*RKpGi39Pc^{^_Vn5I+ znWORf=C}TT)u?Qo6uOP|jpSe}b7K$o+f~=AUGIEDz2EnJ34J&k=-(QUB9~7`hPOvQ zT{s&*mGrds?KXy 0) { + // Display bomb count + return Center( + child: Text( + '${square.bombsAround}', + style: TextStyle( + fontWeight: FontWeight.bold, + color: _getTileColor(square.bombsAround, context), + ), + ), + ); + } else { + // Opened, but no bomb count (empty square) + return const SizedBox.shrink(); + } + } + + // Default: Unopened tile + return const SizedBox.shrink(); + } + + Color _getTileColor(int bombsAround, BuildContext context) { + // Choose colors based on standard Minesweeper appearance + switch (bombsAround) { + case 1: + return MihColors.getBluishPurpleColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark", + ); + // return Colors.blue; + case 2: + return MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark", + ); + // return Colors.green; + case 3: + return MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark", + ); + // return Colors.red; + case 4: + return MihColors.getPurpleColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark", + ); + // return Colors.purple; + case 5: + return MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark", + ); + // return Colors.brown; + default: + // return MihColors.getBluishPurpleColor( + // MzansiInnovationHub.of(context)!.theme.mode == "Dark", + // ); + return Colors.black; + } + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(1.0), + child: MihButton( + onPressed: onTap, + onLongPressed: onLongPress, + buttonColor: square.isOpened + ? MihColors.getGreyColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark", + ) + : MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark", + ), + width: 50, + height: 50, + borderRadius: 3, + child: _getTileContent(context), + ), + ); + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart b/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart index 98fd163f..b0659619 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart @@ -1,4 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart'; +import 'package:provider/provider.dart'; class MihMineSweeper extends StatefulWidget { const MihMineSweeper({super.key}); @@ -10,6 +18,54 @@ class MihMineSweeper extends StatefulWidget { class _MihMineSweeperState extends State { @override Widget build(BuildContext context) { - return const Placeholder(); + return MihPackage( + appActionButton: getAction(), + appTools: getTools(), + appToolTitles: getToolTitle(), + appBody: getToolBody(), + selectedbodyIndex: context.watch().toolIndex, + onIndexChange: (newIndex) { + context.read().setToolIndex(newIndex); + }, + ); + } + + MihPackageAction getAction() { + return MihPackageAction( + icon: const Icon(Icons.arrow_back), + iconSize: 35, + onTap: () { + context.goNamed( + 'mihHome', + extra: true, + ); + FocusScope.of(context).unfocus(); + }, + ); + } + + MihPackageTools getTools() { + Map temp = {}; + temp[const Icon(FontAwesomeIcons.bomb)] = () { + context.read().setToolIndex(0); + }; + return MihPackageTools( + tools: temp, + selcetedIndex: context.watch().toolIndex, + ); + } + + List getToolTitle() { + List toolTitles = [ + "MineSweeper", + ]; + return toolTitles; + } + + List getToolBody() { + List toolBodies = [ + const MineSweeperGame(), + ]; + return toolBodies; } } diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart new file mode 100644 index 00000000..81cab8fc --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; + +class MihMineSweeperTile extends StatefulWidget { + final bool personalSelected; + final double packageSize; + const MihMineSweeperTile({ + super.key, + required this.personalSelected, + required this.packageSize, + }); + + @override + State createState() => _MihMineSweeperTileState(); +} + +class _MihMineSweeperTileState extends State { + @override + Widget build(BuildContext context) { + return MihPackageTile( + onTap: () { + context.goNamed( + "mihMineSweeper", + ); + }, + appName: "MineSweeper", + appIcon: Icon( + MihIcons.mineSweeper, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // size: widget.packageSize, + ), + iconSize: widget.packageSize, + primaryColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + secondaryColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart new file mode 100644 index 00000000..be21f407 --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart @@ -0,0 +1,596 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_speed_dial/flutter_speed_dial.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/components/board_square.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/components/mine_tile.dart'; +import 'package:provider/provider.dart'; + +class MineSweeperGame extends StatefulWidget { + const MineSweeperGame({super.key}); + + @override + State createState() => _MineSweeperGameState(); +} + +class _MineSweeperGameState extends State { + TextEditingController modeController = TextEditingController(); + final _formKey = GlobalKey(); + List> board = []; + bool isGameOver = false; + bool isGameWon = false; + int squaresLeft = -1; + bool _isFirstLoad = true; + + void showStartGameWindow(MihMineSweeperProvider mihMineSweeperProvider) { + showDialog( + context: context, + builder: (context) { + return MihPackageWindow( + fullscreen: false, + windowTitle: "New Game Settings", + onWindowTapClose: () { + context.pop(); + }, + windowBody: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihDropdownField( + controller: modeController, + hintText: "Difficulty", + dropdownOptions: ["Easy", "Normal", "Hard"], + requiredText: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + setState( + () => initializeBoard(mihMineSweeperProvider)); + Navigator.of(context).pop(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Start Game", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ], + ), + ); + }); + } + +// --- GAME INITIALIZATION LOGIC --- + void initializeBoard(MihMineSweeperProvider mihMineSweeperProvider) { + // 1. Create a board of empty squares + board = List.generate( + mihMineSweeperProvider.rowCount, + (i) => List.generate( + mihMineSweeperProvider.columnCount, + (j) => BoardSquare(), + ), + ); + // 2. Place bombs randomly + placeBombs(mihMineSweeperProvider); + // 3. Calculate the number of bombs around each non-mine square + calculateBombsAround(mihMineSweeperProvider); + // Reset state variables + squaresLeft = + mihMineSweeperProvider.rowCount * mihMineSweeperProvider.columnCount; + isGameOver = false; + isGameWon = false; + // You'd typically add a call to setState here, but it's in initState. + } + + void placeBombs(MihMineSweeperProvider mihMineSweeperProvider) { + final Random random = Random(); + int bombsPlaced = 0; + + while (bombsPlaced < mihMineSweeperProvider.totalMines) { + int r = random.nextInt(mihMineSweeperProvider.rowCount); + int c = random.nextInt(mihMineSweeperProvider.columnCount); + + if (!board[r][c].hasBomb) { + board[r][c].hasBomb = true; + bombsPlaced++; + } + } + } + + void calculateBombsAround(MihMineSweeperProvider mihMineSweeperProvider) { + for (int r = 0; r < mihMineSweeperProvider.rowCount; r++) { + for (int c = 0; c < mihMineSweeperProvider.columnCount; c++) { + if (!board[r][c].hasBomb) { + int count = 0; + + // Check the 8 neighbors + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + if (i == 0 && j == 0) continue; // Skip the current square + + int neighborR = r + i; + int neighborC = c + j; + + // Check if neighbor is within bounds + if (neighborR >= 0 && + neighborR < mihMineSweeperProvider.rowCount && + neighborC >= 0 && + neighborC < mihMineSweeperProvider.columnCount) { + if (board[neighborR][neighborC].hasBomb) { + count++; + } + } + } + } + board[r][c].bombsAround = count; + } + } + } + } + + // Handles recursive opening of zero-squares + void _expandZeros( + MihMineSweeperProvider mihMineSweeperProvider, int r, int c) { + if (r < 0 || + r >= mihMineSweeperProvider.rowCount || + c < 0 || + c >= mihMineSweeperProvider.columnCount || + board[r][c].isOpened) { + return; + } + + BoardSquare square = board[r][c]; + + // Open the current square + square.isOpened = true; + squaresLeft--; + + // If it's a zero square, recursively call for neighbors + if (square.bombsAround == 0) { + // Check all 8 neighbors (not just 4 sides, for standard Minesweeper expansion) + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + _expandZeros(mihMineSweeperProvider, r + i, c + j); + } + } + } + } + + void handleTap(MihMineSweeperProvider mihMineSweeperProvider, int r, int c) { + if (isGameOver || board[r][c].isOpened || board[r][c].isFlagged) { + return; + } + // 1. Check for bomb (LOSS) + if (board[r][c].hasBomb) { + setState(() { + board[r][c].isOpened = true; + isGameOver = true; + // lose alert + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + FontAwesomeIcons.bomb, + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + size: 100, + ), + alertTitle: "Better Luck Next Time", + alertBody: Column( + children: [ + Text( + "Your lost this game of MIH MineSweeper!!!", + style: TextStyle( + fontSize: 15, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + const SizedBox(height: 20), + Wrap( + runAlignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + onPressed: () { + setState( + () => initializeBoard(mihMineSweeperProvider)); + Navigator.of(context).pop(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "New Game", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ], + ), + alertColour: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + ); + }); + return; + } + // 2. Open square and handle expansion (RECURSION) + if (board[r][c].bombsAround == 0) { + // Start recursive expansion + _expandZeros(mihMineSweeperProvider, r, c); + } else { + // Just open the single square + board[r][c].isOpened = true; + squaresLeft--; + } + // 3. Check for win + _checkWinCondition(mihMineSweeperProvider); + // Update the UI + setState(() {}); + } + + void handleLongPress(int r, int c) { + if (isGameOver || board[r][c].isOpened) { + return; + } + setState(() { + // Toggle the flag status + board[r][c].isFlagged = !board[r][c].isFlagged; + }); + } + + // --- GAME ACTION LOGIC --- + void _checkWinCondition(MihMineSweeperProvider mihMineSweeperProvider) { + // Game is won if all non-mine squares are opened. + if (squaresLeft <= mihMineSweeperProvider.totalMines) { + isGameWon = true; + isGameOver = true; + // win alert + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + Icons.celebration, + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + size: 100, + ), + alertTitle: "Congradulations", + alertBody: Column( + children: [ + Text( + "Your won this game of MIH MineSweeper!!!", + style: TextStyle( + fontSize: 15, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + const SizedBox(height: 20), + Wrap( + runAlignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + onPressed: () { + setState(() => initializeBoard(mihMineSweeperProvider)); + Navigator.of(context).pop(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "New Game", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ], + ), + alertColour: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + ); + } + } + + Color? getDifficultyColor() { + String mode = modeController.text; + switch (mode) { + case "Easy": + return MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark", + ); + case "Normal": + return MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark", + ); + case "Hard": + return MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark", + ); + default: + return null; + } + } + + @override + void initState() { + super.initState(); + modeController.text = "Easy"; + // showStartGameWindow(context.read()); + // initializeBoard(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // This method is safe for calling showDialog or reading provider values. + if (_isFirstLoad) { + // 1. Get the provider safely. + WidgetsBinding.instance.addPostFrameCallback((_) { + final mihMineSweeperProvider = context.read(); + // board = List.generate( + // mihMineSweeperProvider.rowCount, + // (i) => List.generate( + // mihMineSweeperProvider.columnCount, + // (j) => BoardSquare(), + // ), + // ); + // 2. Show the dialog to get initial game settings. + // The user selection in the dialog will call initializeBoard(). + showStartGameWindow(mihMineSweeperProvider); + }); + // 3. Set flag to prevent showing the dialog on subsequent dependency changes + _isFirstLoad = false; + } + } + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (BuildContext context, + MihMineSweeperProvider mihMineSweeperProvider, Widget? child) { + return Stack( + alignment: Alignment.topCenter, + children: [ + MihSingleChildScroll( + child: board.isEmpty && squaresLeft < 0 + // Start Up Message before setting up game + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.mineSweeper, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + const SizedBox(height: 10), + Text( + "Welcom to MIH MineSweeper, the first game of MIH.", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + const SizedBox(height: 25), + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + children: [ + TextSpan(text: "Press "), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + Icons.menu, + size: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + TextSpan(text: " to start a new game."), + ], + ), + ), + ), + ], + ), + ) + // Display Game Board when game started + : Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // Display game status + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Text( + 'Mines: ${mihMineSweeperProvider.totalMines}', + textAlign: TextAlign.left, + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Text( + modeController.text, + textAlign: TextAlign.right, + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: getDifficultyColor(), + ), + ), + ), + ), + ], + ), + // const SizedBox( + // height: 30, + // ), + // The Board Grid + SizedBox( + width: mihMineSweeperProvider.columnCount * + 40.0, // Control size based on columns + height: mihMineSweeperProvider.rowCount * + 40.0, // Control size based on rows + child: GridView.builder( + physics: + const NeverScrollableScrollPhysics(), // Prevent scrolling + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: + mihMineSweeperProvider.columnCount, + crossAxisSpacing: 0, + mainAxisSpacing: 0, + ), + itemCount: mihMineSweeperProvider.rowCount * + mihMineSweeperProvider.columnCount, + itemBuilder: (context, index) { + int r = index ~/ + mihMineSweeperProvider + .columnCount; // Integer division for row + int c = index % + mihMineSweeperProvider + .columnCount; // Remainder for column + + return MineTile( + square: board[r][c], + onTap: () => + handleTap(mihMineSweeperProvider, r, c), + onLongPress: () => handleLongPress(r, c), + ); + }, + ), + ), + ], + ), + ), + Positioned( + right: 10, + bottom: 10, + child: MihFloatingMenu( + animatedIcon: AnimatedIcons.menu_close, + children: [ + SpeedDialChild( + child: Icon( + Icons.add, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + label: board.isEmpty && squaresLeft < 0 + ? "Start Game" + : "Reset Game", + labelBackgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onTap: () { + showStartGameWindow(mihMineSweeperProvider); + }, + ) + ]), + ) + ], + ); + }, + ); + } +} From 5f5107ee997efa092d37fbc59511067356bab2b2 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 16 Oct 2025 09:46:02 +0200 Subject: [PATCH 15/45] QOL: Add Long Press to mih button --- .../lib/mih_components/mih_package_components/mih_button.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Frontend/lib/mih_components/mih_package_components/mih_button.dart b/Frontend/lib/mih_components/mih_package_components/mih_button.dart index 4166f475..6e76d55c 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_button.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_button.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; class MihButton extends StatelessWidget { final void Function()? onPressed; + final void Function()? onLongPressed; final Color buttonColor; final double? width; final double? height; @@ -12,6 +13,7 @@ class MihButton extends StatelessWidget { const MihButton({ super.key, required this.onPressed, + this.onLongPressed, required this.buttonColor, this.width, this.height, @@ -49,6 +51,7 @@ class MihButton extends StatelessWidget { highlightColor: rippleColor.withValues(alpha: 0.2), hoverColor: rippleColor.withValues(alpha: 0.3), onTap: onPressed, + onLongPress: onLongPressed, child: Container( width: width, height: height, From 553d22dd6bfb9378a99a70ece42c95fe918f2d3d Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 16 Oct 2025 09:59:52 +0200 Subject: [PATCH 16/45] BUG: Package Auth Loop --- .../main/kotlin/za/co/mzansiinnovationhub/mih/MainActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frontend/android/app/src/main/kotlin/za/co/mzansiinnovationhub/mih/MainActivity.kt b/Frontend/android/app/src/main/kotlin/za/co/mzansiinnovationhub/mih/MainActivity.kt index 7a5defbe..17f9c2bd 100644 --- a/Frontend/android/app/src/main/kotlin/za/co/mzansiinnovationhub/mih/MainActivity.kt +++ b/Frontend/android/app/src/main/kotlin/za/co/mzansiinnovationhub/mih/MainActivity.kt @@ -1,5 +1,5 @@ package za.co.mzansiinnovationhub.mih -import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.android.FlutterFragmentActivity -class MainActivity : FlutterActivity() +class MainActivity : FlutterFragmentActivity() From d51603ff5d7324eef43933d3c44df3be81ddf21d Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 16 Oct 2025 10:16:18 +0200 Subject: [PATCH 17/45] NEW: MIH Home & Mzansi Profile Provider Setup pt 1 --- Frontend/lib/main.dart | 4 + .../mih_image_display.dart | 22 +- .../mih_providers/mih_calendar_provider.dart | 14 + .../mih_mine_sweeper_provider.dart | 35 + .../mzansi_profile_provider.dart | 102 ++ Frontend/lib/mih_config/mih_colors.dart | 8 +- Frontend/lib/mih_config/mih_go_router.dart | 20 +- .../package_tiles/mih_calculator_tile.dart | 4 - .../calendar/mzansi_calendar.dart | 19 +- .../mih_home/components/mih_app_drawer.dart | 565 +++++----- .../lib/mih_packages/mih_home/mih_home.dart | 623 +++++------ .../package_tools/mih_personal_home.dart | 8 + .../builders/build_employee_list.dart | 66 +- .../mih_update_business_details_window.dart | 705 +++++++++++++ .../mzansi_business_profile.dart | 175 ++-- .../package_tools/mih_business_details.dart | 979 +++--------------- .../package_tools/mih_my_business_team.dart | 101 +- .../package_tools/mih_my_business_user.dart | 479 ++++----- .../personal_profile/mzansi_profile.dart | 37 +- .../package_tools/mih_personal_profile.dart | 929 ++++++++--------- .../package_tools/mih_personal_settings.dart | 135 +-- .../mih_business_details_services.dart | 39 +- .../lib/mih_services/mih_file_services.dart | 5 +- .../mih_my_business_user_services.dart | 57 +- .../lib/mih_services/mih_service_calls.dart | 8 +- .../mih_user_consent_services.dart | 27 +- .../lib/mih_services/mih_user_services.dart | 35 +- backend/routers/users.py | 1 + 28 files changed, 2687 insertions(+), 2515 deletions(-) create mode 100644 Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart create mode 100644 Frontend/lib/mih_components/mih_providers/mih_mine_sweeper_provider.dart create mode 100644 Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart create mode 100644 Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart diff --git a/Frontend/lib/main.dart b/Frontend/lib/main.dart index bffb4a3d..018c35ea 100644 --- a/Frontend/lib/main.dart +++ b/Frontend/lib/main.dart @@ -5,6 +5,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_authentic import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calculator_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:provider/provider.dart'; @@ -78,6 +79,9 @@ class _MzansiInnovationHubState extends State { ChangeNotifierProvider( create: (context) => MihAuthenticationProvider(), ), + ChangeNotifierProvider( + create: (context) => MzansiProfileProvider(), + ), ChangeNotifierProvider( create: (context) => MzansiWalletProvider(), ), diff --git a/Frontend/lib/mih_components/mih_package_components/mih_image_display.dart b/Frontend/lib/mih_components/mih_package_components/mih_image_display.dart index c33fe4f7..6d6d3145 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_image_display.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_image_display.dart @@ -32,19 +32,8 @@ class _MihImageDisplayState extends State { late ImageProvider? imagePreview; ImageProvider? getImage() { - Color dark = const Color(0XFF3A4454); if (widget.imageFile == null) { - if (MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark") == - dark) { - print("here in light icon"); - return const AssetImage( - 'lib/mih_components/mih_package_components/assets/images/i-dont-know-dark.png'); - } else { - print("here in dark icon"); - return const AssetImage( - 'lib/mih_components/mih_package_components/assets/images/i-dont-know-light.png'); - } + return null; } else { return widget.imageFile; } @@ -69,9 +58,12 @@ class _MihImageDisplayState extends State { child: Stack( alignment: Alignment.center, children: [ - ClipRRect( - borderRadius: BorderRadius.circular(widget.width * 0.1), - child: Image(image: imagePreview!), + Visibility( + visible: imagePreview != null, + child: ClipRRect( + borderRadius: BorderRadius.circular(widget.width * 0.1), + child: Image(image: imagePreview!), + ), ), Visibility( visible: widget.editable, diff --git a/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart new file mode 100644 index 00000000..7b80ab62 --- /dev/null +++ b/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart @@ -0,0 +1,14 @@ +import 'package:flutter/foundation.dart'; + +class MihCalendarProvider extends ChangeNotifier { + int toolIndex; + + MihCalendarProvider({ + this.toolIndex = 0, + }); + + void setToolIndex(int index) { + toolIndex = index; + notifyListeners(); + } +} diff --git a/Frontend/lib/mih_components/mih_providers/mih_mine_sweeper_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_mine_sweeper_provider.dart new file mode 100644 index 00000000..1d881fd9 --- /dev/null +++ b/Frontend/lib/mih_components/mih_providers/mih_mine_sweeper_provider.dart @@ -0,0 +1,35 @@ +import 'package:flutter/widgets.dart'; + +class MihMineSweeperProvider extends ChangeNotifier { + int toolIndex; + int rowCount; + int columnCount; + int totalMines; + + MihMineSweeperProvider({ + this.toolIndex = 0, + this.rowCount = 10, + this.columnCount = 10, + this.totalMines = 15, + }); + + void setToolIndex(int index) { + toolIndex = index; + notifyListeners(); + } + + void setRowCount(int rowCount) { + this.rowCount = rowCount; + notifyListeners(); + } + + void setCoulmnCount(int columnCount) { + this.columnCount = columnCount; + notifyListeners(); + } + + void setTotalMines(int totalMines) { + this.totalMines = totalMines; + notifyListeners(); + } +} diff --git a/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart b/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart new file mode 100644 index 00000000..8941a0a9 --- /dev/null +++ b/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_employee.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/user_consent.dart'; + +class MzansiProfileProvider extends ChangeNotifier { + bool personalHome; + int personalIndex; + int businessIndex; + AppUser? user; + String? userProfilePicUrl; + ImageProvider? userProfilePicture; + Business? business; + String? businessProfilePicUrl; + ImageProvider? businessProfilePicture; + BusinessUser? businessUser; + String? businessUserSignatureUrl; + ImageProvider? businessUserSignature; + UserConsent? userConsent; + List? employeeList; + + MzansiProfileProvider({ + this.personalHome = true, + this.personalIndex = 0, + this.businessIndex = 0, + }); + + void reset() { + personalHome = true; + personalIndex = 0; + businessIndex = 0; + user = null; + userProfilePicUrl = null; + userProfilePicture = null; + business = null; + businessProfilePicUrl = null; + businessProfilePicture = null; + businessUser = null; + businessUserSignatureUrl = null; + businessUserSignature = null; + userConsent = null; + } + + void setPersonalIndex(int index) { + personalIndex = index; + notifyListeners(); + } + + void setBusinessIndex(int index) { + businessIndex = index; + notifyListeners(); + } + + void setUser({ + required AppUser newUser, + }) { + user = newUser; + notifyListeners(); + } + + void setUserProfilePicUrl(String url) { + userProfilePicUrl = url; + userProfilePicture = url.isNotEmpty ? NetworkImage(url) : null; + notifyListeners(); + } + + void setBusiness({ + Business? newBusiness, + }) { + business = newBusiness; + notifyListeners(); + } + + void setBusinessProfilePicUrl(String url) { + businessProfilePicUrl = url; + businessProfilePicture = url.isNotEmpty ? NetworkImage(url) : null; + notifyListeners(); + } + + void setBusinessUser({required BusinessUser newBusinessUser}) { + businessUser = newBusinessUser; + notifyListeners(); + } + + void setBusinessUserSignatureUrl(String url) { + businessUserSignatureUrl = url; + businessUserSignature = url.isNotEmpty ? NetworkImage(url) : null; + notifyListeners(); + } + + void setUserConsent(UserConsent? newUserConsent) { + userConsent = newUserConsent; + notifyListeners(); + } + + void setEmployeeList({required List employeeList}) { + this.employeeList = employeeList; + notifyListeners(); + } +} diff --git a/Frontend/lib/mih_config/mih_colors.dart b/Frontend/lib/mih_config/mih_colors.dart index 6c69d0a9..398736af 100644 --- a/Frontend/lib/mih_config/mih_colors.dart +++ b/Frontend/lib/mih_config/mih_colors.dart @@ -37,7 +37,7 @@ class MihColors { if (darkMode == true) { return const Color(0xff8ae290); } else { - return const Color(0xffB0F2B4); + return const Color(0xFF41B349); } } @@ -63,7 +63,7 @@ class MihColors { return const Color(0xffd69d7d); } else { // Add a different shade of pink for light mode - return const Color(0xffd69d7d); + return const Color(0xFFBD7145); } } @@ -81,7 +81,7 @@ class MihColors { return const Color(0xff6e7dcc); } else { // Add a different shade of pink for light mode - return const Color(0xff6e7dcc); + return const Color(0xFF5567C0); } } @@ -90,7 +90,7 @@ class MihColors { return const Color(0xffb682e7); } else { // Add a different shade of pink for light mode - return const Color(0xffb682e7); + return const Color(0xFF9857D4); } } } diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index 856d61ff..25743e6d 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -4,6 +4,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_print_prevew import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/Example/package_test.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/about_mih/about_mih.dart'; import 'package:mzansi_innovation_hub/mih_packages/access_review/mih_access.dart'; import 'package:mzansi_innovation_hub/mih_packages/calculator/mih_calculator.dart'; @@ -29,6 +30,7 @@ import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/a import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/full_screen_file.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/patient_edit.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/patient_profile.dart'; +import 'package:provider/provider.dart'; import 'package:supertokens_flutter/supertokens.dart'; class MihGoRouterPaths { @@ -133,16 +135,8 @@ class MihGoRouter { path: MihGoRouterPaths.mihHome, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: mihHome"); - if (state.extra != null) { - final bool personalSelected = state.extra as bool; - return MihHome( - key: UniqueKey(), - personalSelected: personalSelected, - ); - } return MihHome( key: UniqueKey(), - personalSelected: true, ); }, ), @@ -166,15 +160,13 @@ class MihGoRouter { path: MihGoRouterPaths.mzansiProfileManage, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: mzansiProfileManage"); - final AppProfileUpdateArguments? args = - state.extra as AppProfileUpdateArguments?; - if (args == null) { + if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); return const SizedBox.shrink(); } - return MzansiProfile(arguments: args); + return MzansiProfile(); }, ), GoRoute( @@ -198,8 +190,7 @@ class MihGoRouter { path: MihGoRouterPaths.businessProfileManage, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: businessProfileManage"); - final BusinessArguments? args = state.extra as BusinessArguments?; - if (args == null) { + if (context.watch().business == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); @@ -207,7 +198,6 @@ class MihGoRouter { } return MzansiBusinessProfile( key: UniqueKey(), - arguments: args, ); }, ), diff --git a/Frontend/lib/mih_packages/calculator/package_tiles/mih_calculator_tile.dart b/Frontend/lib/mih_packages/calculator/package_tiles/mih_calculator_tile.dart index 58c42944..4011d6d1 100644 --- a/Frontend/lib/mih_packages/calculator/package_tiles/mih_calculator_tile.dart +++ b/Frontend/lib/mih_packages/calculator/package_tiles/mih_calculator_tile.dart @@ -28,10 +28,6 @@ class _MihCalculatorTileState extends State { "mihCalculator", extra: widget.personalSelected, ); - // Navigator.of(context).pushNamed( - // '/calculator', - // arguments: widget.personalSelected, - // ); }, appName: "Calculator", appIcon: Icon( diff --git a/Frontend/lib/mih_packages/calendar/mzansi_calendar.dart b/Frontend/lib/mih_packages/calendar/mzansi_calendar.dart index 2e5bbd51..fc148291 100644 --- a/Frontend/lib/mih_packages/calendar/mzansi_calendar.dart +++ b/Frontend/lib/mih_packages/calendar/mzansi_calendar.dart @@ -3,8 +3,10 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/calendar/package_tools/appointments.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class MzansiCalendar extends StatefulWidget { final CalendarArguments arguments; @@ -18,8 +20,6 @@ class MzansiCalendar extends StatefulWidget { } class _MzansiCalendarState extends State { - int _selcetedIndex = 0; - @override Widget build(BuildContext context) { return MihPackage( @@ -27,12 +27,9 @@ class _MzansiCalendarState extends State { appTools: getTools(), appBody: getToolBody(), appToolTitles: getToolTitle(), - selectedbodyIndex: _selcetedIndex, - onIndexChange: (newValue) { - setState(() { - _selcetedIndex = newValue; - }); - print("Index: $_selcetedIndex"); + selectedbodyIndex: context.watch().toolIndex, + onIndexChange: (newIndex) { + context.read().setToolIndex(newIndex); }, ); } @@ -55,14 +52,12 @@ class _MzansiCalendarState extends State { MihPackageTools getTools() { Map temp = {}; temp[const Icon(Icons.calendar_month)] = () { - setState(() { - _selcetedIndex = 0; - }); + context.read().setToolIndex(0); }; return MihPackageTools( tools: temp, - selcetedIndex: _selcetedIndex, + selcetedIndex: context.watch().toolIndex, ); } diff --git a/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart b/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart index bd09514d..3b3821ea 100644 --- a/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart +++ b/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart @@ -5,6 +5,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart' import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/about_mih_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:provider/provider.dart'; import '../../../main.dart'; @@ -78,293 +79,299 @@ class _MIHAppDrawerState extends State { Widget build(BuildContext context) { // precacheImage( // MzansiInnovationHub.of(context)!.theme.logoImage().image, context); - return SafeArea( - child: Drawer( - //backgroundColor: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return Stack( - //fit: StackFit.passthrough, - children: [ - Column( - // reverse: false, - // padding: EdgeInsets.zero, - mainAxisSize: MainAxisSize.max, + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return SafeArea( + child: Drawer( + //backgroundColor: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return Stack( + //fit: StackFit.passthrough, children: [ - DrawerHeader( - decoration: BoxDecoration( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - child: SizedBox( - height: 400, - width: constraints.maxWidth, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: [ - profilePictureLoaded, - Text( - "${widget.signedInUser.fname} ${widget.signedInUser.lname}", - style: TextStyle( - fontWeight: FontWeight.bold, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - ), + Column( + // reverse: false, + // padding: EdgeInsets.zero, + mainAxisSize: MainAxisSize.max, + children: [ + DrawerHeader( + decoration: BoxDecoration( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + child: SizedBox( + height: 400, + width: constraints.maxWidth, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + profilePictureLoaded, + Text( + "${widget.signedInUser.fname} ${widget.signedInUser.lname}", + style: TextStyle( + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + Text( + "@${widget.signedInUser.username}", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + Text( + widget.signedInUser.type.toUpperCase(), + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + ], ), - Text( - "@${widget.signedInUser.username}", - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), + ), + ), + // ListTile( + // title: Row( + // mainAxisSize: MainAxisSize.max, + // children: [ + // Icon( + // Icons.home_outlined, + // color: + // MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // ), + // const SizedBox(width: 25.0), + // Text( + // "Home", + // style: TextStyle( + // //fontWeight: FontWeight.bold, + // color: MzansiInnovationHub.of(context)! + // .theme + // .secondaryColor(), + // ), + // ), + // ], + // ), + // onTap: () { + // Navigator.of(context) + // .pushNamedAndRemoveUntil('/', (route) => false); + // }, + // ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + children: [ + ListTile( + title: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Icon( + Icons.policy, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + const SizedBox(width: 25.0), + Text( + "Privacy Policy", + style: TextStyle( + //fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + ], + ), + onTap: () { + WidgetsBinding.instance + .addPostFrameCallback((_) async { + context + .read() + .setToolIndex(1); + }); + context.goNamed( + "aboutMih", + extra: true, + ); + }, ), - ), - Text( - widget.signedInUser.type.toUpperCase(), - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), + ListTile( + title: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Icon( + Icons.design_services_rounded, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + const SizedBox(width: 25.0), + Text( + "Terms of Service", + style: TextStyle( + //fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + ], + ), + onTap: () { + WidgetsBinding.instance + .addPostFrameCallback((_) async { + context + .read() + .setToolIndex(2); + }); + context.goNamed( + "aboutMih", + extra: true, + ); + }, ), - ), - ], + ListTile( + title: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Icon( + Icons.logout, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + const SizedBox(width: 25.0), + Text( + "Sign Out", + style: TextStyle( + //fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + ], + ), + onTap: () async { + await SuperTokens.signOut( + completionHandler: (error) { + print(error); + }); + if (await SuperTokens.doesSessionExist() == + false) { + mzansiProfileProvider.reset(); + context.goNamed( + 'mihHome', + extra: true, + ); + // Navigator.of(context).pop(); + // Navigator.of(context).popAndPushNamed( + // '/', + // arguments: AuthArguments(true, false), + // ); + } + }, + ), + ], + ), + ), + ], + ), + Positioned( + top: 5, + right: 5, + width: 30, + height: 30, + child: InkWell( + onTap: () { + setState(() { + if (MzansiInnovationHub.of(context)?.theme.mode == + "Dark") { + //darkm = !darkm; + MzansiInnovationHub.of(context)! + .changeTheme(ThemeMode.light); + //print("Dark Mode: $darkm"); + } else { + //darkm = !darkm; + MzansiInnovationHub.of(context)! + .changeTheme(ThemeMode.dark); + //print("Dark Mode: $darkm"); + } + Navigator.of(context).pop(); + Navigator.of(context).popAndPushNamed( + '/', + arguments: AuthArguments(true, false), + ); + // Navigator.of(context).popAndPushNamed('/',); + }); + }, + child: Icon( + MihIcons.mihLogo, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), ), ), - ), - // ListTile( - // title: Row( - // mainAxisSize: MainAxisSize.max, - // children: [ - // Icon( - // Icons.home_outlined, - // color: - // MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // const SizedBox(width: 25.0), - // Text( - // "Home", - // style: TextStyle( - // //fontWeight: FontWeight.bold, - // color: MzansiInnovationHub.of(context)! - // .theme - // .secondaryColor(), - // ), - // ), - // ], - // ), - // onTap: () { - // Navigator.of(context) - // .pushNamedAndRemoveUntil('/', (route) => false); - // }, - // ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.max, - children: [ - ListTile( - title: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Icon( - Icons.policy, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - ), - const SizedBox(width: 25.0), - Text( - "Privacy Policy", - style: TextStyle( - //fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - ), - ), - ], - ), - onTap: () { - WidgetsBinding.instance - .addPostFrameCallback((_) async { - context - .read() - .setToolIndex(1); - }); - context.goNamed( - "aboutMih", - extra: true, - ); - }, - ), - ListTile( - title: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Icon( - Icons.design_services_rounded, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - ), - const SizedBox(width: 25.0), - Text( - "Terms of Service", - style: TextStyle( - //fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - ), - ), - ], - ), - onTap: () { - WidgetsBinding.instance - .addPostFrameCallback((_) async { - context - .read() - .setToolIndex(2); - }); - context.goNamed( - "aboutMih", - extra: true, - ); - }, - ), - ListTile( - title: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Icon( - Icons.logout, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - ), - const SizedBox(width: 25.0), - Text( - "Sign Out", - style: TextStyle( - //fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - ), - ), - ], - ), - onTap: () async { - await SuperTokens.signOut( - completionHandler: (error) { - print(error); - }); - if (await SuperTokens.doesSessionExist() == - false) { - context.goNamed( - 'mihHome', - extra: true, - ); - // Navigator.of(context).pop(); - // Navigator.of(context).popAndPushNamed( - // '/', - // arguments: AuthArguments(true, false), - // ); - } - }, - ), - ], - ), + // IconButton( + // onPressed: () { + // setState(() { + // if (MzansiInnovationHub.of(context)?.theme.mode == "Dark") { + // //darkm = !darkm; + // MzansiInnovationHub.of(context)!.changeTheme(ThemeMode.light); + // //print("Dark Mode: $darkm"); + // } else { + // //darkm = !darkm; + // MzansiInnovationHub.of(context)!.changeTheme(ThemeMode.dark); + // //print("Dark Mode: $darkm"); + // } + // Navigator.of(context).popAndPushNamed('/'); + // }); + // }, + // icon: Icon( + // Icons.light_mode, + // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // size: 35, + // ), + // ), ), ], - ), - Positioned( - top: 5, - right: 5, - width: 30, - height: 30, - child: InkWell( - onTap: () { - setState(() { - if (MzansiInnovationHub.of(context)?.theme.mode == - "Dark") { - //darkm = !darkm; - MzansiInnovationHub.of(context)! - .changeTheme(ThemeMode.light); - //print("Dark Mode: $darkm"); - } else { - //darkm = !darkm; - MzansiInnovationHub.of(context)! - .changeTheme(ThemeMode.dark); - //print("Dark Mode: $darkm"); - } - Navigator.of(context).pop(); - Navigator.of(context).popAndPushNamed( - '/', - arguments: AuthArguments(true, false), - ); - // Navigator.of(context).popAndPushNamed('/',); - }); - }, - child: Icon( - MihIcons.mihLogo, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - // IconButton( - // onPressed: () { - // setState(() { - // if (MzansiInnovationHub.of(context)?.theme.mode == "Dark") { - // //darkm = !darkm; - // MzansiInnovationHub.of(context)!.changeTheme(ThemeMode.light); - // //print("Dark Mode: $darkm"); - // } else { - // //darkm = !darkm; - // MzansiInnovationHub.of(context)!.changeTheme(ThemeMode.dark); - // //print("Dark Mode: $darkm"); - // } - // Navigator.of(context).popAndPushNamed('/'); - // }); - // }, - // icon: Icon( - // Icons.light_mode, - // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // size: 35, - // ), - // ), - ), - ], - ); - }, - ), - ), + ); + }, + ), + ), + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/mih_home/mih_home.dart b/Frontend/lib/mih_packages/mih_home/mih_home.dart index 1e90ccb0..61022390 100644 --- a/Frontend/lib/mih_packages/mih_home/mih_home.dart +++ b/Frontend/lib/mih_packages/mih_home/mih_home.dart @@ -1,7 +1,8 @@ import 'package:go_router/go_router.dart'; import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/user_consent.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; @@ -13,22 +14,24 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_scack_bar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/about_mih_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_packages/mih_home/components/mih_app_drawer.dart'; -import 'package:mzansi_innovation_hub/mih_packages/mih_home/mih_home_error.dart'; import 'package:mzansi_innovation_hub/mih_packages/mih_home/package_tools/mih_business_home.dart'; import 'package:mzansi_innovation_hub/mih_packages/mih_home/package_tools/mih_personal_home.dart'; import 'package:flutter/material.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_service_calls.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_my_business_user_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_user_consent_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; +import 'package:provider/provider.dart'; -// ignore: must_be_immutable class MihHome extends StatefulWidget { - final bool personalSelected; const MihHome({ super.key, - required this.personalSelected, }); @override @@ -38,12 +41,49 @@ class MihHome extends StatefulWidget { class _MihHomeState extends State { final proPicController = TextEditingController(); late int _selcetedIndex; - late bool _personalSelected; - late Future profileData; - late Future futureUserConsent; - bool showUserConsent = false; + late bool _personalHome; DateTime latestPrivacyPolicyDate = DateTime.parse("2024-12-01"); DateTime latestTermOfServiceDate = DateTime.parse("2024-12-01"); + bool _isLoadingInitialData = true; + + Future _loadInitialData() async { + // Note: getUserData sets user and userProfilePicUrl in the provider + await getUserData(); + // Note: getUserConsentStatus sets userConsent in the provider + await getUserConsentStatus(); + await getBusinessData(); + // 2. Set state after all data is loaded + if (mounted) { + setState(() { + _isLoadingInitialData = false; + }); + } + } + + Future getBusinessData() async { + Business? business = context.read().business; + AppUser? user = context.read().user; + String logoUrl; + String signatureUrl; + if (business == null && user!.type == "business") { + // Get Business + await MihBusinessDetailsServices().getBusinessDetailsByUser(context); + logoUrl = await MihFileApi.getMinioFileUrl( + context.read().business!.logo_path, + context, + ); + context.read().setBusinessProfilePicUrl(logoUrl); + // Get Business User + await MihMyBusinessUserServices().getBusinessUser(context); + signatureUrl = await MihFileApi.getMinioFileUrl( + context.read().businessUser!.sig_path, + context, + ); + context + .read() + .setBusinessUserSignatureUrl(signatureUrl); + } + } bool showPolicyWindow(UserConsent? userConsent) { if (userConsent == null) { @@ -60,20 +100,19 @@ class _MihHomeState extends State { } } - void createOrUpdateAccpetance(UserConsent? userConsent, String app_id) { + void createOrUpdateAccpetance(MzansiProfileProvider mzansiProfileProvider) { + UserConsent? userConsent = mzansiProfileProvider.userConsent; userConsent != null ? MihUserConsentServices() .updateUserConsentStatus( - app_id, DateTime.now().toIso8601String(), DateTime.now().toIso8601String(), + mzansiProfileProvider, + context, ) .then((value) { if (value == 200) { - // setState(() { - // showUserConsent = false; - // }); - context.goNamed("mihHome", extra: false); + context.goNamed("mihHome"); ScaffoldMessenger.of(context).showSnackBar( MihSnackBar( child: Text("Thank you for accepting our Policies"), @@ -89,16 +128,14 @@ class _MihHomeState extends State { }) : MihUserConsentServices() .insertUserConsentStatus( - app_id, DateTime.now().toIso8601String(), DateTime.now().toIso8601String(), + mzansiProfileProvider, + context, ) .then((value) { if (value == 201) { - // setState(() { - // showUserConsent = false; - // }); - context.goNamed("mihHome", extra: false); + context.goNamed("mihHome"); ScaffoldMessenger.of(context).showSnackBar( MihSnackBar( child: Text("Thank you for accepting our Policies"), @@ -114,6 +151,22 @@ class _MihHomeState extends State { }); } + Future getUserData() async { + String url; + await MihUserServices().getUserDetails( + context, + ); + url = await MihFileApi.getMinioFileUrl( + context.read().user!.pro_pic_path, + context, + ); + context.read().setUserProfilePicUrl(url); + } + + Future getUserConsentStatus() async { + await MihUserConsentServices().getUserConsentStatus(context); + } + @override void dispose() { super.dispose(); @@ -122,18 +175,15 @@ class _MihHomeState extends State { @override void initState() { super.initState(); - profileData = MIHApiCalls().getProfile(10, context); - futureUserConsent = MihUserConsentServices().getUserConsentStatus(); - if (widget.personalSelected == true) { - setState(() { - _selcetedIndex = 0; - _personalSelected = true; - }); + WidgetsBinding.instance.addPostFrameCallback((_) async { + _loadInitialData(); + }); + if (context.read().personalHome == true) { + _selcetedIndex = 0; + _personalHome = true; } else { - setState(() { - _selcetedIndex = 1; - _personalSelected = false; - }); + _selcetedIndex = 1; + _personalHome = false; } } @@ -147,278 +197,239 @@ class _MihHomeState extends State { @override Widget build(BuildContext context) { - return FutureBuilder( - future: profileData, - builder: (context, asyncSnapshot) { - if (asyncSnapshot.connectionState == ConnectionState.waiting) { + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + if (_isLoadingInitialData) { return Scaffold( - body: const Mihloadingcircle( - // message: "Fetching your Data...", - ), + body: Center( + child: Mihloadingcircle(), + ), ); - } else if (asyncSnapshot.connectionState == ConnectionState.done && - asyncSnapshot.hasData) { - return Stack( - children: [ - MihPackage( - appActionButton: getAction(asyncSnapshot.data!.profilePicUrl), - appTools: getTools( - asyncSnapshot.data!.signedInUser.type != "personal"), - appBody: getToolBody(asyncSnapshot.data!), - appToolTitles: getToolTitle(), - actionDrawer: getActionDrawer( - asyncSnapshot.data!.signedInUser, - asyncSnapshot.data!.profilePicUrl, - ), - selectedbodyIndex: _selcetedIndex, - onIndexChange: (newValue) { - if (_selcetedIndex == 0) { - setState(() { - _selcetedIndex = newValue; - _personalSelected = true; - }); - } else { - setState(() { - _selcetedIndex = newValue; - _personalSelected = false; - }); - } - }, - ), - FutureBuilder( - future: futureUserConsent, - builder: (context, asyncSnapshotUserConsent) { - if (asyncSnapshotUserConsent.connectionState == - ConnectionState.waiting) { - showUserConsent = false; - } else if (asyncSnapshotUserConsent.connectionState == - ConnectionState.done && - asyncSnapshotUserConsent.hasData) { - showUserConsent = - showPolicyWindow(asyncSnapshotUserConsent.data); - } else if (asyncSnapshotUserConsent.connectionState == - ConnectionState.done && - !asyncSnapshotUserConsent.hasData) { - showUserConsent = true; - } else { - showUserConsent = false; - } - return Visibility( - visible: showUserConsent, - child: Container( - color: Colors.black.withValues(alpha: 0.5), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - MihPackageWindow( - fullscreen: false, - windowTitle: - "Privacy Policy & Terms Of Service Alert!", - onWindowTapClose: () { - showDialog( - context: context, - builder: (context) { - return MihPackageAlert( - alertIcon: Icon( - Icons.warning_amber_rounded, - size: 100, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark", - ), - ), - alertTitle: - "Oops, Looks like you missed a step!", - alertBody: Text( - "We're excited for you to keep using the MIH app! Before you do, please take a moment to accept our Privacy Policy and Terms of Service. Thanks for helping us keep your experience great!", - textAlign: TextAlign.center, - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark", - ), - fontSize: 15, - fontWeight: FontWeight.normal, - ), - ), - alertColour: MihColors.getRedColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark", - ), - ); - }); - }, - windowBody: Column( - children: [ - Icon( - Icons.policy, - size: 150, + } + // bool showConsentWindow = + // showPolicyWindow(mzansiProfileProvider.userConsent); + return Stack( + children: [ + MihPackage( + appActionButton: + getAction(mzansiProfileProvider.userProfilePicUrl as String), + appTools: + getTools(mzansiProfileProvider.user!.type != "personal"), + appBody: getToolBody(), + appToolTitles: getToolTitle(), + actionDrawer: getActionDrawer(), + selectedbodyIndex: _selcetedIndex, + onIndexChange: (newValue) { + if (_selcetedIndex == 0) { + setState(() { + _selcetedIndex = newValue; + _personalHome = true; + }); + } else { + setState(() { + _selcetedIndex = newValue; + _personalHome = false; + }); + } + }, + ), + Visibility( + visible: showPolicyWindow(mzansiProfileProvider.userConsent), + child: Container( + color: Colors.black.withValues(alpha: 0.5), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + MihPackageWindow( + fullscreen: false, + windowTitle: "Privacy Policy & Terms Of Service Alert!", + onWindowTapClose: () { + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + Icons.warning_amber_rounded, + size: 100, + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark", + ), + ), + alertTitle: + "Oops, Looks like you missed a step!", + alertBody: Text( + "We're excited for you to keep using the MIH app! Before you do, please take a moment to accept our Privacy Policy and Terms of Service. Thanks for helping us keep your experience great!", + textAlign: TextAlign.center, + style: TextStyle( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)! .theme .mode == "Dark", ), + fontSize: 15, + fontWeight: FontWeight.normal, ), - const SizedBox(height: 10), - Text( - "Welcome to the MIH App", - textAlign: TextAlign.center, + ), + alertColour: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark", + ), + ); + }); + }, + windowBody: Column( + children: [ + Icon( + Icons.policy, + size: 150, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark", + ), + ), + const SizedBox(height: 10), + Text( + "Welcome to the MIH App", + textAlign: TextAlign.center, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark", + ), + fontSize: 30, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 10), + Text( + "To keep using the MIH app, please take a moment to review and accept our Policies. Our agreements helps us keep things running smoothly and securely.", + textAlign: TextAlign.center, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark", + ), + fontSize: 15, + fontWeight: FontWeight.normal, + ), + ), + const SizedBox(height: 20), + Center( + child: Wrap( + alignment: WrapAlignment.center, + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + onPressed: () { + WidgetsBinding.instance + .addPostFrameCallback((_) async { + context + .read() + .setToolIndex(1); + }); + context.goNamed("aboutMih", + extra: + mzansiProfileProvider.personalHome); + }, + buttonColor: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + elevation: 10, + width: 300, + child: Text( + "Privacy Policy", style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark", - ), - fontSize: 30, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, fontWeight: FontWeight.bold, ), ), - const SizedBox(height: 10), - Text( - "To keep using the MIH app, please take a moment to review and accept our Policies. Our agreements helps us keep things running smoothly and securely.", - textAlign: TextAlign.center, + ), + MihButton( + onPressed: () { + WidgetsBinding.instance + .addPostFrameCallback((_) async { + context + .read() + .setToolIndex(2); + }); + context.goNamed("aboutMih", + extra: + mzansiProfileProvider.personalHome); + }, + buttonColor: MihColors.getYellowColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + elevation: 10, + width: 300, + child: Text( + "Terms of Service", style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark", - ), - fontSize: 15, - fontWeight: FontWeight.normal, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, ), ), - const SizedBox(height: 20), - Center( - child: Wrap( - alignment: WrapAlignment.center, - spacing: 10, - runSpacing: 10, - children: [ - MihButton( - onPressed: () { - context.goNamed( - "aboutMih", - extra: AboutArguments( - widget.personalSelected, - 1, - ), - ); - }, - buttonColor: MihColors.getOrangeColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - elevation: 10, - width: 300, - child: Text( - "Privacy Policy", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of( - context)! - .theme - .mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - MihButton( - onPressed: () { - context.goNamed( - "aboutMih", - extra: AboutArguments( - widget.personalSelected, - 2, - ), - ); - }, - buttonColor: MihColors.getYellowColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - elevation: 10, - width: 300, - child: Text( - "Terms of Service", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of( - context)! - .theme - .mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - MihButton( - onPressed: () { - DateTime now = DateTime.now(); - KenLogger.success( - "Date Time Now: $now"); - createOrUpdateAccpetance( - asyncSnapshotUserConsent.data, - asyncSnapshot - .data!.signedInUser.app_id, - ); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - elevation: 10, - width: 300, - child: Text( - "Accept", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of( - context)! - .theme - .mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ], + ), + MihButton( + onPressed: () { + DateTime now = DateTime.now(); + KenLogger.success("Date Time Now: $now"); + createOrUpdateAccpetance( + mzansiProfileProvider); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + elevation: 10, + width: 300, + child: Text( + "Accept", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, ), ), - const SizedBox(height: 10), - ], - ), + ), + ], ), - ], - ), + ), + const SizedBox(height: 10), + ], ), - ); - }), - ], - ); - } else { - return MihHomeError( - errorMessage: asyncSnapshot.hasError - ? asyncSnapshot.error.toString() - : "An unknown error occurred", - ); - } + ), + ], + ), + ), + ), + ], + ); }, ); } @@ -464,7 +475,11 @@ class _MihHomeState extends State { }); } - MIHAppDrawer getActionDrawer(AppUser signedInUser, String proPicUrl) { + MIHAppDrawer getActionDrawer() { + AppUser signedInUser = + context.watch().user as AppUser; + String proPicUrl = + context.watch().userProfilePicUrl ?? ""; return MIHAppDrawer( signedInUser: signedInUser, propicFile: proPicUrl != "" ? NetworkImage(proPicUrl) : null, @@ -476,14 +491,14 @@ class _MihHomeState extends State { temp[const Icon(Icons.person)] = () { setState(() { _selcetedIndex = 0; - _personalSelected = true; + _personalHome = true; }); }; if (isBusinessUser) { temp[const Icon(Icons.business_center)] = () { setState(() { _selcetedIndex = 1; - _personalSelected = false; + _personalHome = false; }); }; } @@ -493,29 +508,35 @@ class _MihHomeState extends State { ); } - List getToolBody(HomeArguments profData) { + List getToolBody() { List toolBodies = []; + AppUser? user = context.watch().user; + Business? business = context.watch().business; + BusinessUser? businessUser = + context.watch().businessUser; + String userProfilePictureUrl = + context.watch().userProfilePicUrl ?? ""; toolBodies.add( MihPersonalHome( - signedInUser: profData.signedInUser, - personalSelected: _personalSelected, - business: profData.business, - businessUser: profData.businessUser, - propicFile: profData.profilePicUrl != "" - ? NetworkImage(profData.profilePicUrl) + signedInUser: user!, + personalSelected: _personalHome, + business: business, + businessUser: businessUser, + propicFile: userProfilePictureUrl != "" + ? NetworkImage(userProfilePictureUrl) : null, isDevActive: AppEnviroment.getEnv() == "Dev", - isUserNew: profData.signedInUser.username == "", + isUserNew: user.username == "", ), ); - if (profData.signedInUser.type != "personal") { + if (user.type != "personal") { toolBodies.add( MihBusinessHome( - signedInUser: profData.signedInUser, - personalSelected: _personalSelected, - businessUser: profData.businessUser, - business: profData.business, - isBusinessUserNew: profData.businessUser == null, + signedInUser: user, + personalSelected: _personalHome, + businessUser: businessUser, + business: business, + isBusinessUserNew: businessUser == null, ), ); } diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart index 8c17cf56..79120d66 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart @@ -14,6 +14,7 @@ import 'package:mzansi_innovation_hub/mih_packages/about_mih/package_tile/about_ import 'package:mzansi_innovation_hub/mih_packages/access_review/package_tile/mih_access_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/calculator/package_tiles/mih_calculator_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/calendar/package_tiles/mzansi_calendar_tile.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_ai/package_tiles/mzansi_ai_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/package_tiles/mzansi_directory_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/package_tiles/mzansi_profile_tile.dart'; @@ -153,6 +154,13 @@ class _MihPersonalHomeState extends State packageSize: packageSize, ) }); + //=============== Mine Sweeper =============== + temp.add({ + "Mine Sweeper": MihMineSweeperTile( + personalSelected: widget.personalSelected, + packageSize: packageSize, + ) + }); //=============== MIH Access =============== temp.add({ "MIH Access": MihAccessTile( diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart index edc2b570..d4268a57 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart @@ -4,6 +4,7 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; @@ -16,19 +17,17 @@ import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_del import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_employee.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:supertokens_flutter/http.dart' as http; class BuildEmployeeList extends StatefulWidget { final List employees; - final BusinessArguments arguments; const BuildEmployeeList({ super.key, required this.employees, - required this.arguments, }); @override @@ -369,36 +368,41 @@ class _BuildEmployeeListState extends State { @override Widget build(BuildContext context) { double screenWidth = MediaQuery.of(context).size.width; - return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (BuildContext context, index) { - return Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - }, - itemCount: widget.employees.length, - itemBuilder: (context, index) { - //final patient = widget.patients[index].id_no.contains(widget.searchString); - //print(index); - var isMe = ""; - if (widget.arguments.signedInUser.app_id == - widget.employees[index].app_id) { - isMe = "(You)"; - } - return ListTile( - title: Text( - "${widget.employees[index].fname} ${widget.employees[index].lname} - ${widget.employees[index].title} $isMe"), - subtitle: Text( - "${widget.employees[index].username}\n${widget.employees[index].email}\nAccess: ${widget.employees[index].access}", - style: TextStyle( + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (BuildContext context, index) { + return Divider( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - onTap: () { - updateEmployeePopUp(index, screenWidth); + ); + }, + itemCount: widget.employees.length, + itemBuilder: (context, index) { + //final patient = widget.patients[index].id_no.contains(widget.searchString); + //print(index); + var isMe = ""; + if (mzansiProfileProvider.user!.app_id == + widget.employees[index].app_id) { + isMe = "(You)"; + } + return ListTile( + title: Text( + "${widget.employees[index].fname} ${widget.employees[index].lname} - ${widget.employees[index].title} $isMe"), + subtitle: Text( + "${widget.employees[index].username}\n${widget.employees[index].email}\nAccess: ${widget.employees[index].access}", + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + onTap: () { + updateEmployeePopUp(index, screenWidth); + }, + ); }, ); }, diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart new file mode 100644 index 00000000..a5cef9de --- /dev/null +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart @@ -0,0 +1,705 @@ +import 'package:country_code_picker/country_code_picker.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_location_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; + +class MihUpdateBusinessDetailsWindow extends StatefulWidget { + final double width; + const MihUpdateBusinessDetailsWindow({ + super.key, + required this.width, + }); + + @override + State createState() => + _MihUpdateBusinessDetailsWindowState(); +} + +class _MihUpdateBusinessDetailsWindowState + extends State { + final _formKey = GlobalKey(); + PlatformFile? newSelectedLogoPic; + final fileNameController = TextEditingController(); + final regController = TextEditingController(); + final nameController = TextEditingController(); + final typeController = TextEditingController(); + final practiceNoController = TextEditingController(); + final vatNoController = TextEditingController(); + final countryCodeController = TextEditingController(); + final contactController = TextEditingController(); + final emailController = TextEditingController(); + final locationController = TextEditingController(); + final websiteController = TextEditingController(); + final ratingController = TextEditingController(); + final missionVisionController = TextEditingController(); + final ValueNotifier _counter = ValueNotifier(0); + late String env; + + void setContactNumberControllers( + MzansiProfileProvider mzansiProfileProvider) { + if (mzansiProfileProvider.business!.contact_no[0] == "+") { + List contactDetails = + mzansiProfileProvider.business!.contact_no.split("-"); + setState(() { + countryCodeController.text = contactDetails[0]; + contactController.text = contactDetails[1]; + }); + } else { + setState(() { + countryCodeController.text = "+27"; + contactController.text = mzansiProfileProvider.business!.contact_no; + }); + } + } + + void setControllers() { + MzansiProfileProvider mzansiProfileProvider = + context.read(); + setState(() { + fileNameController.text = + mzansiProfileProvider.business!.logo_path.split("/").last; + regController.text = mzansiProfileProvider.business!.registration_no; + nameController.text = mzansiProfileProvider.business!.Name; + typeController.text = mzansiProfileProvider.business!.type; + practiceNoController.text = mzansiProfileProvider.business!.practice_no; + vatNoController.text = mzansiProfileProvider.business!.vat_no; + emailController.text = mzansiProfileProvider.business!.bus_email; + locationController.text = mzansiProfileProvider.business!.gps_location; + websiteController.text = mzansiProfileProvider.business!.website; + ratingController.text = mzansiProfileProvider.business!.rating; + missionVisionController.text = + mzansiProfileProvider.business!.mission_vision; + }); + setContactNumberControllers(mzansiProfileProvider); + if (AppEnviroment.getEnv() == "Prod") { + env = "Prod"; + } else { + env = "Dev"; + } + } + + Color getMissionVisionLimitColor(int limit) { + if (_counter.value <= limit) { + return MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + } else { + return MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + } + } + + void _updateMissionVisionCounter() { + // New function name + // No need for setState since you are using a ValueNotifier for _counter + _counter.value = missionVisionController.text.characters.length; + } + + String getNumberWithCountryCode() { + String numberWithoutBeginingZero = ""; + if (contactController.text[0] == "0") { + numberWithoutBeginingZero = contactController.text + .replaceAll(" ", "") + .substring(1, contactController.text.length); + } else { + numberWithoutBeginingZero = contactController.text.replaceAll("-", " "); + } + return "${countryCodeController.text}-$numberWithoutBeginingZero"; + } + + bool isFormFilled() { + if (typeController.text.isEmpty) { + return false; + } else { + return true; + } + } + + void successPopUp(String message, bool stayOnPersonalSide) { + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + Icons.check_circle_outline_rounded, + size: 150, + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + alertTitle: "Successfully Updated Profile", + alertBody: Column( + children: [ + Text( + message, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + context.pop(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + elevation: 10, + width: 300, + child: Text( + "Dismiss", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ) + ], + ), + alertColour: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + // return MIHSuccessMessage( + // successType: "Success", + // successMessage: message, + // ); + }, + ); + } + + Future uploadFile(MzansiProfileProvider mzansiProfileProvider) async { + if (newSelectedLogoPic != null) { + int uploadStatusCode = 0; + uploadStatusCode = await MihFileApi.uploadFile( + mzansiProfileProvider.business!.business_id, + env, + "business_files", + newSelectedLogoPic!, + context, + ); + if (uploadStatusCode == 200) { + int deleteStatusCode = 0; + deleteStatusCode = await MihFileApi.deleteFile( + mzansiProfileProvider.business!.logo_path.split("/").first, + env, + "business_files", + mzansiProfileProvider.business!.logo_path.split("/").last, + context, + ); + if (deleteStatusCode == 200) { + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return true; // No file selected, so no upload needed + } + } + + Future submitForm(MzansiProfileProvider mzansiProfileProvider) async { + KenLogger.success("Start Submit Form"); + if (isFormFilled()) { + KenLogger.success("Form Filled"); + KenLogger.success("Start File Upload"); + bool successfullyUploadedFile = await uploadFile(mzansiProfileProvider); + KenLogger.success( + "File Upload Complete: outcome $successfullyUploadedFile"); + if (!mounted) return; + KenLogger.success("is mounted"); + if (successfullyUploadedFile) { + KenLogger.success("Start Details Update"); + int statusCode = 0; + statusCode = await MihBusinessDetailsServices().updateBusinessDetailsV2( + mzansiProfileProvider.business!.business_id, + nameController.text, + typeController.text, + regController.text, + practiceNoController.text, + vatNoController.text, + emailController.text, + getNumberWithCountryCode(), + // contactController.text, + locationController.text, + fileNameController.text, + websiteController.text, + ratingController.text.isEmpty ? "0" : ratingController.text, + missionVisionController.text, + mzansiProfileProvider, + context, + ); + KenLogger.success("Details Update Complete: status code $statusCode"); + if (!mounted) return; + KenLogger.success("is mounted"); + if (statusCode == 200) { + KenLogger.success("Start Success Message"); + //You left of here + String message = "Your information has been updated successfully!"; + context.pop(); + successPopUp(message, false); + // File uploaded successfully + } else { + context.pop(); + // File upload failed + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + Icons.warning_rounded, + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + alertTitle: "Error Updating Business Details", + alertBody: Column( + children: [ + Text( + "An error occurred while updating the business details. Please check internet connection and try again.", + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ], + ), + alertColour: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + ); + } + } else { + context.pop(); + if (!mounted) return; + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Internet Connection"); + }, + ); + } + } else { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Input Error"); + }, + ); + } + } + + @override + void initState() { + super.initState(); + setControllers(); + missionVisionController.addListener(_updateMissionVisionCounter); + } + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return MihPackageWindow( + fullscreen: false, + windowTitle: 'Edit Profile', + onWindowTapClose: () { + context.pop(); + }, + windowBody: MihSingleChildScroll( + child: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: widget.width * 0.05) + : EdgeInsets.symmetric(horizontal: widget.width * 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Center( + child: MihCircleAvatar( + imageFile: newSelectedLogoPic != null + ? MemoryImage(newSelectedLogoPic!.bytes!) + : mzansiProfileProvider.businessProfilePicture, + width: 150, + editable: true, + fileNameController: fileNameController, + userSelectedfile: newSelectedLogoPic, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: (selectedfile) { + setState(() { + newSelectedLogoPic = selectedfile; + }); + }, + ), + ), + Visibility( + visible: false, + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: fileNameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Selected File Name", + ), + ), + const SizedBox(height: 20), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: nameController, + multiLineInput: false, + requiredText: true, + hintText: "Business Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: typeController, + multiLineInput: false, + requiredText: true, + hintText: "Business Type", + validator: (value) { + return MihValidationServices() + .validateNoSpecialChars(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: emailController, + multiLineInput: false, + requiredText: true, + hintText: "Business Email", + validator: (value) { + return MihValidationServices().validateEmail(value); + }, + ), + const SizedBox(height: 10), + Container( + width: 300, + alignment: Alignment.topLeft, + child: const Text( + "Contact Number:", + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + CountryCodePicker( + padding: EdgeInsetsGeometry.all(0), + onChanged: (selectedCode) { + setState(() { + countryCodeController.text = + selectedCode.toString(); + }); + debugPrint( + "Selected Country Code: ${countryCodeController.text}"); + }, + initialSelection: countryCodeController.text, + showDropDownButton: false, + pickerStyle: PickerStyle.bottomSheet, + dialogBackgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + barrierColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + Expanded( + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: contactController, + numberMode: true, + multiLineInput: false, + requiredText: true, + hintText: null, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + ), + ], + ), + const SizedBox(height: 10), + MihTextFormField( + height: 250, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: missionVisionController, + multiLineInput: true, + requiredText: true, + hintText: "Business Mission & Vision", + validator: (value) { + return MihValidationServices().validateLength( + missionVisionController.text, 256); + }, + ), + SizedBox( + height: 15, + child: ValueListenableBuilder( + valueListenable: _counter, + builder: + (BuildContext context, int value, Widget? child) { + return Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "$value", + style: TextStyle( + color: getMissionVisionLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 5), + Text( + "/256", + style: TextStyle( + color: getMissionVisionLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + ], + ); + }, + ), + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: websiteController, + multiLineInput: false, + requiredText: false, + hintText: "Business Website", + validator: (value) { + return MihValidationServices() + .validateWebsite(value, false); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: regController, + multiLineInput: false, + requiredText: false, + hintText: "Registration No.", + validator: (value) { + // return MihValidationServices().isEmpty(value); + return null; + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: practiceNoController, + multiLineInput: false, + requiredText: false, + hintText: "Practice Number", + validator: (validateValue) { + return null; + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: vatNoController, + multiLineInput: false, + requiredText: false, + hintText: "VAT Number", + validator: (value) { + // return MihValidationServices().isEmpty(value); + return null; + }, + ), + const SizedBox(height: 10), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Flexible( + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: locationController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "GPS Location", + ), + ), + const SizedBox(width: 10.0), + MihButton( + onPressed: () { + showDialog( + context: context, + builder: (context) { + return const Mihloadingcircle( + message: "Getting your location", + ); + }, + ); + MIHLocationAPI() + .getGPSPosition(context) + .then((position) { + if (position != null) { + setState(() { + locationController.text = + "${position.latitude}, ${position.longitude}"; + }); + } + //Dismiss loading indicator + context.pop(); + }); + }, + buttonColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 100, + child: Text( + "Set", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm(mzansiProfileProvider); + } else { + MihAlertServices() + .formNotFilledCompletely(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(height: 20), + ], + ), + ], + ), + ), + ), + ); + }, + ); + } +} diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart index f106ec95..1baef840 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart @@ -1,23 +1,22 @@ +import 'dart:convert'; + import 'package:go_router/go_router.dart'; -import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart'; -import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_reviews.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_employee.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart'; -import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart'; -import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_team.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_team.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart'; +import 'package:provider/provider.dart'; +import 'package:supertokens_flutter/http.dart' as http; class MzansiBusinessProfile extends StatefulWidget { - final BusinessArguments arguments; const MzansiBusinessProfile({ super.key, - required this.arguments, }); @override @@ -25,26 +24,38 @@ class MzansiBusinessProfile extends StatefulWidget { } class _MzansiBusinessProfileState extends State { - int _selcetedIndex = 0; - late Future futureLogoUrl; - late Future futureProPicUrl; - late Future futureUserSignatureUrl; + String errorCode = ""; + String errorBody = ""; + + Future fetchEmployees() async { + //print("Patien manager page: $endpoint"); + MzansiProfileProvider mzansiProfileProvider = + context.read(); + final response = await http.get(Uri.parse( + "${AppEnviroment.baseApiUrl}/business-user/employees/${mzansiProfileProvider.businessUser!.business_id}")); + errorCode = response.statusCode.toString(); + errorBody = response.body; + if (response.statusCode == 200) { + //print("Here1"); + Iterable l = jsonDecode(response.body); + //print("Here2"); + List employeeList = List.from( + l.map((model) => BusinessEmployee.fromJson(model))); + mzansiProfileProvider.setEmployeeList(employeeList: employeeList); + //print("Here3"); + //print(patientQueue); + // return patientQueue; + } else { + throw Exception('failed to load employees'); + } + } @override void initState() { super.initState(); - futureLogoUrl = MihFileApi.getMinioFileUrl( - widget.arguments.business!.logo_path, - context, - ); - futureProPicUrl = MihFileApi.getMinioFileUrl( - widget.arguments.signedInUser.pro_pic_path, - context, - ); - futureUserSignatureUrl = MihFileApi.getMinioFileUrl( - widget.arguments.businessUser!.sig_path, - context, - ); + WidgetsBinding.instance.addPostFrameCallback((_) async { + await fetchEmployees(); + }); } @override @@ -54,11 +65,9 @@ class _MzansiBusinessProfileState extends State { appTools: getTools(), appBody: getToolBody(), appToolTitles: getToolTitle(), - selectedbodyIndex: _selcetedIndex, - onIndexChange: (newValue) { - setState(() { - _selcetedIndex = newValue; - }); + selectedbodyIndex: context.watch().businessIndex, + onIndexChange: (newIndex) { + context.read().setBusinessIndex(newIndex); }, ); } @@ -80,96 +89,40 @@ class _MzansiBusinessProfileState extends State { MihPackageTools getTools() { Map temp = {}; temp[const Icon(Icons.business)] = () { - setState(() { - _selcetedIndex = 0; - }); + context.read().setBusinessIndex(0); }; temp[const Icon(Icons.person)] = () { - setState(() { - _selcetedIndex = 1; - }); + context.read().setBusinessIndex(1); }; - // temp[const Icon(Icons.warning)] = () { - // setState(() { - // _selcetedIndex = 2; - // }); - // }; temp[const Icon(Icons.people)] = () { - setState(() { - _selcetedIndex = 2; - }); - }; - temp[const Icon(Icons.add)] = () { - setState(() { - _selcetedIndex = 3; - }); - }; - temp[const Icon(Icons.star_rate_rounded)] = () { - setState(() { - _selcetedIndex = 4; - }); - }; - temp[const Icon(Icons.qr_code_rounded)] = () { - setState(() { - _selcetedIndex = 5; - }); + context.read().setBusinessIndex(2); }; + // temp[const Icon(Icons.add)] = () { + // context.read().setBusinessIndex(3); + // }; + // temp[const Icon(Icons.star_rate_rounded)] = () { + // context.read().setBusinessIndex(4); + // }; + // temp[const Icon(Icons.qr_code_rounded)] = () { + // context.read().setBusinessIndex(5); + // }; return MihPackageTools( tools: temp, - selcetedIndex: _selcetedIndex, + selcetedIndex: context.watch().businessIndex, ); } List getToolBody() { List toolBodies = [ - FutureBuilder( - future: futureLogoUrl, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: Mihloadingcircle()); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - final logoUrl = snapshot.data!.isNotEmpty - ? NetworkImage(snapshot.data!) - : null; - return MihBusinessDetails( - arguments: widget.arguments, - logoImage: logoUrl, - ); - } else { - return Text("Error: ${snapshot.error}"); - } - }), - FutureBuilder>( - future: Future.wait([futureProPicUrl, futureUserSignatureUrl]), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: Mihloadingcircle()); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - final proPicUrl = NetworkImage(snapshot.data![0]); - print("=============== Signature URL: ${snapshot.data![1]}"); - final signatureUrl = snapshot.data![1].isNotEmpty - ? NetworkImage(snapshot.data![1]) - : null; - return MihMyBusinessUser( - arguments: widget.arguments, - userProPicImage: proPicUrl, - userSignatureImage: signatureUrl, - ); - } else { - return Text("Error: ${snapshot.error}"); - } - }, - ), - // MihBusinessProfile(arguments: widget.arguments), - MihMyBusinessTeam(arguments: widget.arguments), - MihBusinessUserSearch(arguments: widget.arguments), - MihBusinessReviews(business: widget.arguments.business!), - MihBusinessQrCode( - business: widget.arguments.business!, - startUpSearch: "", - ), + MihBusinessDetails(), + MihMyBusinessUser(), + MihMyBusinessTeam(), + // MihBusinessUserSearch(arguments: widget.arguments), + // MihBusinessReviews(business: widget.arguments.business!), + // MihBusinessQrCode( + // business: widget.arguments.business!, + // startUpSearch: "", + // ), ]; return toolBodies; } @@ -179,9 +132,9 @@ class _MzansiBusinessProfileState extends State { "Profile", "User", "Team", - "Add", - "Reviews", - "Share", + // "Add", + // "Reviews", + // "Share", ]; return toolTitles; } diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart index 4399f5ea..b682df21 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart @@ -1,35 +1,19 @@ -import 'package:country_code_picker/country_code_picker.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_business_info_card.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_location_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; +import 'package:provider/provider.dart'; class MihBusinessDetails extends StatefulWidget { - final BusinessArguments arguments; - final ImageProvider? logoImage; const MihBusinessDetails({ super.key, - required this.arguments, - required this.logoImage, }); @override @@ -37,696 +21,25 @@ class MihBusinessDetails extends StatefulWidget { } class _MihBusinessDetailsState extends State { - PlatformFile? imageFile; + PlatformFile? newSelectedLogoPic; final fileNameController = TextEditingController(); - final regController = TextEditingController(); - final nameController = TextEditingController(); - final typeController = TextEditingController(); - final practiceNoController = TextEditingController(); - final vatNoController = TextEditingController(); - final countryCodeController = TextEditingController(); - final contactController = TextEditingController(); - final emailController = TextEditingController(); - final locationController = TextEditingController(); - final websiteController = TextEditingController(); - final ratingController = TextEditingController(); - final missionVisionController = TextEditingController(); - final _formKey = GlobalKey(); - final ValueNotifier _counter = ValueNotifier(0); - late String env; - void successPopUp(String message, bool stayOnPersonalSide) { + void editBizProfileWindow( + MzansiProfileProvider mzansiProfileProvider, double width) { showDialog( context: context, - builder: (context) { - return MihPackageAlert( - alertIcon: Icon( - Icons.check_circle_outline_rounded, - size: 150, - color: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - alertTitle: "Successfully Updated Profile", - alertBody: Column( - children: [ - Text( - message, - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 25), - Center( - child: MihButton( - onPressed: () { - context.goNamed( - 'mihHome', - extra: stayOnPersonalSide, - ); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - elevation: 10, - width: 300, - child: Text( - "Dismiss", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ) - ], - ), - alertColour: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - // return MIHSuccessMessage( - // successType: "Success", - // successMessage: message, - // ); - }, + builder: (context) => MihUpdateBusinessDetailsWindow(width: width), ); } - Future submitForm() async { - if (isFormFilled()) { - int statusCode = 0; - statusCode = await MihBusinessDetailsServices().updateBusinessDetailsV2( - widget.arguments.business!.business_id, - nameController.text, - typeController.text, - regController.text, - practiceNoController.text, - vatNoController.text, - emailController.text, - getNumberWithCountryCode(), - // contactController.text, - locationController.text, - fileNameController.text, - websiteController.text, - ratingController.text.isEmpty ? "0" : ratingController.text, - missionVisionController.text, - context, - ); - if (statusCode == 200) { - bool successfullyUploadedFile = await uploadFile(); - if (successfullyUploadedFile) { - //You left of here - String message = "Your information has been updated successfully!"; - successPopUp(message, false); - // File uploaded successfully - } else { - // File upload failed - showDialog( - context: context, - builder: (context) { - return MihPackageAlert( - alertIcon: Icon( - Icons.warning_rounded, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - alertTitle: "Error Updating Business Details", - alertBody: Column( - children: [ - Text( - "An error occurred while updating the business details. Please check internet connection and try again.", - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ], - ), - alertColour: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - }, - ); - } - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Internet Connection"); - }, - ); - } - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); - } - } - - Future uploadFile() async { - if (imageFile != null) { - int uploadStatusCode = 0; - uploadStatusCode = await MihFileApi.uploadFile( - widget.arguments.business!.business_id, - env, - "business_files", - imageFile!, - context, - ); - if (uploadStatusCode == 200) { - int deleteStatusCode = 0; - deleteStatusCode = await MihFileApi.deleteFile( - widget.arguments.business!.logo_path.split("/").first, - env, - "business_files", - widget.arguments.business!.logo_path.split("/").last, - context, - ); - if (deleteStatusCode == 200) { - return true; - } else { - return false; - } - } else { - return false; - } - } else { - return true; // No file selected, so no upload needed - } - } - - bool isFileSelected() { - if (imageFile != null) { - return true; - } else { - return false; - } - } - - bool isEmailValid() { - String text = emailController.text; - var regex = RegExp(r'^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$'); - return regex.hasMatch(text); - } - - bool isFormFilled() { - if (typeController.text.isEmpty) { - return false; - } else { - return true; - } - } - - void setContactNumberControllers() { - if (widget.arguments.business!.contact_no[0] == "+") { - List contactDetails = - widget.arguments.business!.contact_no.split("-"); - setState(() { - countryCodeController.text = contactDetails[0]; - contactController.text = contactDetails[1]; - }); - } else { - setState(() { - countryCodeController.text = "+27"; - contactController.text = widget.arguments.business!.contact_no; - }); - } - } - - String getNumberWithCountryCode() { - String numberWithoutBeginingZero = ""; - if (contactController.text[0] == "0") { - numberWithoutBeginingZero = contactController.text - .replaceAll(" ", "") - .substring(1, contactController.text.length); - } else { - numberWithoutBeginingZero = contactController.text.replaceAll("-", " "); - } - return "${countryCodeController.text}-$numberWithoutBeginingZero"; - } - - void editBizProfileWindow(double width) { - showDialog( - context: context, - builder: (context) => MihPackageWindow( - fullscreen: false, - windowTitle: 'Edit Profile', - onWindowTapClose: () { - context.pop(); - resetControllers(); - }, - windowBody: MihSingleChildScroll( - child: Padding( - padding: MzansiInnovationHub.of(context)!.theme.screenType == - "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.05) - : EdgeInsets.symmetric(horizontal: width * 0), - child: Column( - children: [ - MihForm( - formKey: _formKey, - formFields: [ - Center( - child: MihCircleAvatar( - imageFile: widget.logoImage, - width: 150, - editable: true, - fileNameController: fileNameController, - userSelectedfile: imageFile, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: (selectedfile) { - setState(() { - imageFile = selectedfile; - }); - }, - ), - ), - Visibility( - visible: false, - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: fileNameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Selected File Name", - ), - ), - const SizedBox(height: 20), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: nameController, - multiLineInput: false, - requiredText: true, - hintText: "Business Name", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: typeController, - multiLineInput: false, - requiredText: true, - hintText: "Business Type", - validator: (value) { - return MihValidationServices() - .validateNoSpecialChars(value); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: emailController, - multiLineInput: false, - requiredText: true, - hintText: "Business Email", - validator: (value) { - return MihValidationServices() - .validateEmail(value); - }, - ), - const SizedBox(height: 10), - Container( - width: 300, - alignment: Alignment.topLeft, - child: const Text( - "Contact Number:", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - ), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - CountryCodePicker( - padding: EdgeInsetsGeometry.all(0), - onChanged: (selectedCode) { - setState(() { - countryCodeController.text = - selectedCode.toString(); - }); - debugPrint( - "Selected Country Code: ${countryCodeController.text}"); - }, - initialSelection: countryCodeController.text, - showDropDownButton: false, - pickerStyle: PickerStyle.bottomSheet, - dialogBackgroundColor: - MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - barrierColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - ), - Expanded( - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - controller: contactController, - numberMode: true, - multiLineInput: false, - requiredText: true, - hintText: null, - validator: (value) { - return MihValidationServices() - .isEmpty(value); - }, - ), - ), - ], - ), - const SizedBox(height: 10), - MihTextFormField( - height: 250, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: missionVisionController, - multiLineInput: true, - requiredText: true, - hintText: "Business Mission & Vision", - validator: (value) { - return MihValidationServices().validateLength( - missionVisionController.text, 256); - }, - ), - SizedBox( - height: 15, - child: ValueListenableBuilder( - valueListenable: _counter, - builder: (BuildContext context, int value, - Widget? child) { - return Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - "$value", - style: TextStyle( - color: getMissionVisionLimitColor(256), - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(width: 5), - Text( - "/256", - style: TextStyle( - color: getMissionVisionLimitColor(256), - fontWeight: FontWeight.bold, - ), - ), - ], - ); - }, - ), - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: websiteController, - multiLineInput: false, - requiredText: false, - hintText: "Business Website", - validator: (value) { - return MihValidationServices() - .validateWebsite(value, false); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: regController, - multiLineInput: false, - requiredText: false, - hintText: "Registration No.", - validator: (value) { - // return MihValidationServices().isEmpty(value); - return null; - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: practiceNoController, - multiLineInput: false, - requiredText: false, - hintText: "Practice Number", - validator: (validateValue) { - return null; - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: vatNoController, - multiLineInput: false, - requiredText: false, - hintText: "VAT Number", - validator: (value) { - // return MihValidationServices().isEmpty(value); - return null; - }, - ), - const SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Flexible( - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - controller: locationController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "GPS Location", - ), - ), - const SizedBox(width: 10.0), - MihButton( - onPressed: () { - showDialog( - context: context, - builder: (context) { - return const Mihloadingcircle( - message: "Getting your location", - ); - }, - ); - MIHLocationAPI() - .getGPSPosition(context) - .then((position) { - if (position != null) { - setState(() { - locationController.text = - "${position.latitude}, ${position.longitude}"; - }); - } - //Dismiss loading indicator - Navigator.of(context).pop(); - }); - }, - buttonColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - width: 100, - child: Text( - "Set", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - const SizedBox(height: 25), - Center( - child: MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - submitForm(); - } else { - MihAlertServices() - .formNotFilledCompletely(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - const SizedBox(height: 20), - ], - ), - ], - ), - ), - ), - )); - } - - Color getMissionVisionLimitColor(int limit) { - if (_counter.value <= limit) { - return MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"); - } else { - return MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"); - } - } - - void resetControllers() { - setState(() { - fileNameController.text = - widget.arguments.business!.logo_path.split("/").last; - regController.text = widget.arguments.business!.registration_no; - nameController.text = widget.arguments.business!.Name; - typeController.text = widget.arguments.business!.type; - practiceNoController.text = widget.arguments.business!.practice_no; - vatNoController.text = widget.arguments.business!.vat_no; - emailController.text = widget.arguments.business!.bus_email; - locationController.text = widget.arguments.business!.gps_location; - websiteController.text = widget.arguments.business!.website; - ratingController.text = widget.arguments.business!.rating; - missionVisionController.text = widget.arguments.business!.mission_vision; - }); - setContactNumberControllers(); - if (AppEnviroment.getEnv() == "Prod") { - env = "Prod"; - } else { - env = "Dev"; - } - missionVisionController.addListener(() { - setState(() { - _counter.value = missionVisionController.text.characters.length; - }); - }); - } - @override void dispose() { super.dispose(); - fileNameController.dispose(); - regController.dispose(); - nameController.dispose(); - typeController.dispose(); - practiceNoController.dispose(); - vatNoController.dispose(); - contactController.dispose(); - emailController.dispose(); - locationController.dispose(); - websiteController.dispose(); - ratingController.dispose(); - missionVisionController.dispose(); - imageFile = null; } @override void initState() { super.initState(); - resetControllers(); } @override @@ -740,161 +53,149 @@ class _MihBusinessDetailsState extends State { } Widget getBody(double width, BuildContext context) { - return Stack( - children: [ - MihSingleChildScroll( - child: Padding( - padding: - MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return Stack( + children: [ + MihSingleChildScroll( + child: Padding( + padding: MzansiInnovationHub.of(context)!.theme.screenType == + "desktop" ? EdgeInsets.symmetric(horizontal: width * 0.2) : EdgeInsets.symmetric(horizontal: width * 0.075), - child: Column( - children: [ - Center( - child: MihCircleAvatar( - imageFile: widget.logoImage, - width: 150, - editable: false, - fileNameController: fileNameController, - userSelectedfile: imageFile, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onChange: (selectedfile) { - setState(() { - imageFile = selectedfile; - }); - }, - ), - ), - FittedBox( - child: Text( - widget.arguments.business!.Name, - style: TextStyle( - fontSize: 35, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ), - FittedBox( - child: Text( - widget.arguments.business!.type, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w600, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ), - const SizedBox(height: 5), - // FittedBox( - // child: Text( - // "Mission & Vision", - // style: TextStyle( - // fontSize: 15, - // fontWeight: FontWeight.bold, - // color: MzansiInnovationHub.of(context)! - // .theme - // .secondaryColor(), - // ), - // ), - // ), - Center( - child: SizedBox( - width: 700, - child: Text( - widget.arguments.business!.mission_vision.isNotEmpty - ? widget.arguments.business!.mission_vision - : "No Mission & Vision added yet", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( + child: Column( + children: [ + Center( + child: MihCircleAvatar( + imageFile: mzansiProfileProvider.businessProfilePicture, + width: 150, + editable: false, + fileNameController: fileNameController, + userSelectedfile: newSelectedLogoPic, + frameColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - ), - ), - const SizedBox(height: 20), - SizedBox( - width: 700, - child: MihBusinessCard( - // businessid: widget.arguments.business!.business_id, - // businessName: widget.arguments.business!.Name, - // cellNumber: widget.arguments.business!.contact_no, - // email: widget.arguments.business!.bus_email, - // gpsLocation: widget.arguments.business!.gps_location, - // rating: widget.arguments.business!.rating.isNotEmpty - // ? double.parse(widget.arguments.business!.rating) - // : 0, - // website: widget.arguments.business!.website, - business: widget.arguments.business!, - startUpSearch: null, - width: width, - ), - ), - const SizedBox(height: 30.0), - Center( - child: MihButton( - onPressed: () { - // Connect with the user - editBizProfileWindow(width); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 300, - child: Text( - "Edit Profile", - style: TextStyle( - color: MihColors.getPrimaryColor( + backgroundColor: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, + onChange: (selectedfile) { + setState(() { + newSelectedLogoPic = selectedfile; + }); + }, ), ), - ), + FittedBox( + child: Text( + mzansiProfileProvider.business!.Name, + style: TextStyle( + fontSize: 35, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + FittedBox( + child: Text( + mzansiProfileProvider.business!.type, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + const SizedBox(height: 5), + Center( + child: SizedBox( + width: 700, + child: Text( + mzansiProfileProvider + .business!.mission_vision.isNotEmpty + ? mzansiProfileProvider.business!.mission_vision + : "No Mission & Vision added yet", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + ), + const SizedBox(height: 20), + SizedBox( + width: 700, + child: MihBusinessCard( + business: mzansiProfileProvider.business!, + startUpSearch: null, + width: width, + ), + ), + const SizedBox(height: 30.0), + Center( + child: MihButton( + onPressed: () { + // Connect with the user + editBizProfileWindow(mzansiProfileProvider, width); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Edit Profile", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], ), - ], + ), ), - ), - ), - // Positioned( - // right: 5, - // bottom: 10, - // child: MihFloatingMenu( - // animatedIcon: AnimatedIcons.menu_close, - // children: [ - // SpeedDialChild( - // child: Icon( - // Icons.edit, - // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // label: "Edit Profile", - // labelBackgroundColor: - // MihColors.getGreenColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // labelStyle: TextStyle( - // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // fontWeight: FontWeight.bold, - // ), - // backgroundColor: - // MihColors.getGreenColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // onTap: () { - // editBizProfileWindow(width); - // }, - // ) - // ], - // ), - // ), - ], + // Positioned( + // right: 5, + // bottom: 10, + // child: MihFloatingMenu( + // animatedIcon: AnimatedIcons.menu_close, + // children: [ + // SpeedDialChild( + // child: Icon( + // Icons.edit, + // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // ), + // label: "Edit Profile", + // labelBackgroundColor: + // MihColors.getGreenColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // labelStyle: TextStyle( + // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // fontWeight: FontWeight.bold, + // ), + // backgroundColor: + // MihColors.getGreenColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // onTap: () { + // editBizProfileWindow(width); + // }, + // ) + // ], + // ), + // ), + ], + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_team.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_team.dart index 651d7d21..4fb5696f 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_team.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_team.dart @@ -3,19 +3,18 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_employee.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:supertokens_flutter/http.dart' as http; class MihMyBusinessTeam extends StatefulWidget { - final BusinessArguments arguments; const MihMyBusinessTeam({ super.key, - required this.arguments, }); @override @@ -23,36 +22,35 @@ class MihMyBusinessTeam extends StatefulWidget { } class _MihMyBusinessTeamState extends State { - late Future> employeeList; - String errorCode = ""; String errorBody = ""; - Future> fetchEmployees() async { - //print("Patien manager page: $endpoint"); - final response = await http.get(Uri.parse( - "${AppEnviroment.baseApiUrl}/business-user/employees/${widget.arguments.businessUser!.business_id}")); - errorCode = response.statusCode.toString(); - errorBody = response.body; - if (response.statusCode == 200) { - //print("Here1"); - Iterable l = jsonDecode(response.body); - //print("Here2"); - List patientQueue = List.from( - l.map((model) => BusinessEmployee.fromJson(model))); - //print("Here3"); - //print(patientQueue); - return patientQueue; - } else { - throw Exception('failed to load employees'); - } - } + // Future fetchEmployees( + // MzansiProfileProvider mzansiProfileProvider) async { + // //print("Patien manager page: $endpoint"); + // final response = await http.get(Uri.parse( + // "${AppEnviroment.baseApiUrl}/business-user/employees/${mzansiProfileProvider.businessUser!.business_id}")); + // errorCode = response.statusCode.toString(); + // errorBody = response.body; + // if (response.statusCode == 200) { + // //print("Here1"); + // Iterable l = jsonDecode(response.body); + // //print("Here2"); + // List employeeList = List.from( + // l.map((model) => BusinessEmployee.fromJson(model))); + // mzansiProfileProvider.setEmployeeList(employeeList: employeeList); + // //print("Here3"); + // //print(patientQueue); + // // return patientQueue; + // } else { + // throw Exception('failed to load employees'); + // } + // } Widget displayEmployeeList(List employeeList) { if (employeeList.isNotEmpty) { return BuildEmployeeList( employees: employeeList, - arguments: widget.arguments, ); } return Center( @@ -70,7 +68,10 @@ class _MihMyBusinessTeamState extends State { @override void initState() { super.initState(); - employeeList = fetchEmployees(); + // fetchEmployees(context.read()).catchError((e) { + // // Handle the error thrown in fetchEmployees + // print('Error fetching employees: $e'); + // }); } @override @@ -82,40 +83,20 @@ class _MihMyBusinessTeamState extends State { } Widget getBody() { - return MihSingleChildScroll( - child: Column(mainAxisSize: MainAxisSize.max, children: [ - FutureBuilder( - future: employeeList, - builder: (context, snapshot) { - //print("patient Queue List ${snapshot.hasData}"); - if (snapshot.connectionState == ConnectionState.waiting) { - return const Mihloadingcircle(); - } else if (snapshot.connectionState == ConnectionState.done) { - //List employeeListResults; - // if (searchString == "") { - // patientQueueList = []; - // } else { - - // print(patientQueueList); - // } - - return displayEmployeeList(snapshot.requireData); - } else { - return Center( - child: Text( - "$errorCode: Error pulling Patients Data\n${AppEnviroment.baseApiUrl}/business-user/users/${widget.arguments.businessUser!.business_id}\n$errorBody", - style: TextStyle( - fontSize: 25, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark")), - textAlign: TextAlign.center, - ), - ); - } - }, - ), - ]), + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + if (mzansiProfileProvider.employeeList == null) { + return Center( + child: Mihloadingcircle(), + ); + } + return MihSingleChildScroll( + child: Column(mainAxisSize: MainAxisSize.max, children: [ + displayEmployeeList(mzansiProfileProvider.employeeList!), + ]), + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart index 45e87a65..8bc78d59 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart @@ -1,7 +1,9 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; @@ -17,18 +19,11 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; +import 'package:provider/provider.dart'; class MihMyBusinessUser extends StatefulWidget { - final BusinessArguments arguments; - final ImageProvider? userProPicImage; - final ImageProvider? userSignatureImage; - const MihMyBusinessUser({ super.key, - required this.arguments, - required this.userProPicImage, - required this.userSignatureImage, }); @override @@ -37,7 +32,7 @@ class MihMyBusinessUser extends StatefulWidget { class _MihMyBusinessUserState extends State { PlatformFile? userPicFile; - PlatformFile? userSignatureFile; + PlatformFile? newSelectedSignaturePic; final fileNameController = TextEditingController(); final titleTextController = TextEditingController(); final fnameController = TextEditingController(); @@ -55,23 +50,24 @@ class _MihMyBusinessUserState extends State { } } - Future uploadFile() async { - if (userSignatureFile != null) { + Future uploadFile(MzansiProfileProvider mzansiProfileProvider) async { + if (newSelectedSignaturePic != null) { int uploadStatusCode = 0; uploadStatusCode = await MihFileApi.uploadFile( - widget.arguments.signedInUser.app_id, + mzansiProfileProvider.user!.app_id, env, "business_files", - userSignatureFile!, + newSelectedSignaturePic!, context, ); if (uploadStatusCode == 200) { + signtureController.text = newSelectedSignaturePic!.name; int deleteStatusCode = 0; deleteStatusCode = await MihFileApi.deleteFile( - widget.arguments.signedInUser.app_id, + mzansiProfileProvider.user!.app_id, env, "business_files", - widget.arguments.businessUser!.sig_path.split("/").last, + mzansiProfileProvider.businessUser!.sig_path.split("/").last, context, ); if (deleteStatusCode == 200) { @@ -87,42 +83,34 @@ class _MihMyBusinessUserState extends State { } } - Future submitForm() async { + Future submitForm(MzansiProfileProvider mzansiProfileProvider) async { + KenLogger.success("Start Submit Form"); if (isFormFilled()) { - int statusCode = await MihMyBusinessUserServices().updateBusinessUser( - widget.arguments.signedInUser.app_id, - widget.arguments.businessUser!.business_id, - titleTextController.text, - accessController.text, - signtureController.text, - context, - ); - if (statusCode == 200) { - bool successfullyUploadedFile = await uploadFile(); - if (successfullyUploadedFile) { - // Navigator.of(context).pop(); - // Navigator.of(context).pop(); - // Navigator.of(context).pushNamed( - // '/', - // arguments: AuthArguments( - // false, - // false, - // ), - // ); - // File uploaded successfully + KenLogger.success("Form Filled"); + KenLogger.success("Start File Upload"); + bool successfullyUploadedFile = await uploadFile(mzansiProfileProvider); + KenLogger.success( + "File Upload Complete: outcome $successfullyUploadedFile"); + if (!mounted) return; + KenLogger.success("is mounted"); + if (successfullyUploadedFile) { + int statusCode = await MihMyBusinessUserServices().updateBusinessUser( + mzansiProfileProvider.user!.app_id, + mzansiProfileProvider.businessUser!.business_id, + titleTextController.text, + accessController.text, + signtureController.text, + mzansiProfileProvider, + context, + ); + KenLogger.success("Details Update Complete: status code $statusCode"); + if (!mounted) return; + KenLogger.success("is mounted"); + if (statusCode == 200) { + KenLogger.success("Start Success Message"); String message = "Business details updated successfully"; successPopUp(message, false); - // showDialog( - // context: context, - // builder: (context) { - // return const MIHSuccessMessage( - // successType: "Success", - // successMessage: "Business details updated successfully", - // ); - // }, - // ); } else { - // File upload failed showDialog( context: context, builder: (context) { @@ -196,10 +184,7 @@ class _MihMyBusinessUserState extends State { Center( child: MihButton( onPressed: () { - context.goNamed( - 'mihHome', - extra: stayOnPersonalSide, - ); + context.pop(); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -230,6 +215,29 @@ class _MihMyBusinessUserState extends State { ); } + void setControllers() { + MzansiProfileProvider mzansiProfileProvider = + context.read(); + setState(() { + fileNameController.text = + mzansiProfileProvider.user!.pro_pic_path.split("/").last; + signtureController.text = + mzansiProfileProvider.businessUser!.sig_path.split("/").last; + KenLogger.success("title: ${mzansiProfileProvider.businessUser!.title}"); + KenLogger.success( + "sig url: ${mzansiProfileProvider.businessUser!.sig_path}"); + titleTextController.text = mzansiProfileProvider.businessUser!.title; + fnameController.text = mzansiProfileProvider.user!.fname; + lnameController.text = mzansiProfileProvider.user!.lname; + accessController.text = mzansiProfileProvider.businessUser!.access; + }); + if (AppEnviroment.getEnv() == "Prod") { + env = "Prod"; + } else { + env = "Dev"; + } + } + @override void dispose() { super.dispose(); @@ -240,27 +248,13 @@ class _MihMyBusinessUserState extends State { accessController.dispose(); signtureController.dispose(); userPicFile = null; - userSignatureFile = null; + newSelectedSignaturePic = null; } @override void initState() { super.initState(); - setState(() { - fileNameController.text = - widget.arguments.signedInUser.pro_pic_path.split("/").last; - signtureController.text = - widget.arguments.businessUser!.sig_path.split("/").last; - titleTextController.text = widget.arguments.businessUser!.title; - fnameController.text = widget.arguments.signedInUser.fname; - lnameController.text = widget.arguments.signedInUser.lname; - accessController.text = widget.arguments.businessUser!.access; - }); - if (AppEnviroment.getEnv() == "Prod") { - env = "Prod"; - } else { - env = "Dev"; - } + setControllers(); } @override @@ -274,177 +268,200 @@ class _MihMyBusinessUserState extends State { } Widget getBody(double width) { - return MihSingleChildScroll( - child: Padding( - padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.2) - : EdgeInsets.symmetric(horizontal: width * 0.075), - child: Column( - children: [ - MihForm( - formKey: _formKey, - formFields: [ - Center( - child: MihCircleAvatar( - imageFile: widget.userProPicImage, - width: 150, - editable: false, - fileNameController: fileNameController, - userSelectedfile: userPicFile, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onChange: (_) {}, - ), - ), - Visibility( - visible: false, - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: fileNameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Selected File Name", - ), - ), - const SizedBox(height: 20), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: titleTextController, - multiLineInput: false, - requiredText: true, - readOnly: false, - hintText: "Title", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: fnameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "First Name", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: lnameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Surname", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: accessController, - multiLineInput: false, - requiredText: true, - hintText: "Access Level", - readOnly: true, - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - Container( - width: 300, - alignment: Alignment.topLeft, - child: const Text( - "Signature:", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - ), - Center( - child: MihImageDisplay( - imageFile: widget.userSignatureImage, - width: 300, - height: 200, - editable: true, - fileNameController: signtureController, - userSelectedfile: userSignatureFile, - onChange: (selectedFile) { - setState(() { - userSignatureFile = selectedFile; - }); - }, - ), - ), - const SizedBox(height: 10), - Visibility( - visible: false, - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: fileNameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Selected Signature File", - ), - ), - const SizedBox(height: 15), - Center( - child: MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - submitForm(); - } else { - MihAlertServices().formNotFilledCompletely(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MihColors.getPrimaryColor( + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return MihSingleChildScroll( + child: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Center( + child: MihCircleAvatar( + imageFile: mzansiProfileProvider.userProfilePicture, + width: 150, + editable: false, + fileNameController: fileNameController, + userSelectedfile: userPicFile, + frameColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: (_) {}, ), ), - ), + Visibility( + visible: false, + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: fileNameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Selected File Name", + ), + ), + const SizedBox(height: 20), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: titleTextController, + multiLineInput: false, + requiredText: true, + readOnly: false, + hintText: "Title", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: fnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: lnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Surname", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: accessController, + multiLineInput: false, + requiredText: true, + hintText: "Access Level", + readOnly: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + Container( + width: 300, + alignment: Alignment.topLeft, + child: const Text( + "Signature:", + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + Center( + child: MihImageDisplay( + imageFile: newSelectedSignaturePic != null + ? MemoryImage(newSelectedSignaturePic!.bytes!) + : mzansiProfileProvider.businessUserSignature, + width: 300, + height: 200, + editable: true, + fileNameController: signtureController, + userSelectedfile: newSelectedSignaturePic, + onChange: (selectedFile) { + setState(() { + newSelectedSignaturePic = selectedFile; + }); + }, + ), + ), + const SizedBox(height: 10), + Visibility( + visible: false, + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: fileNameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Selected Signature File", + ), + ), + const SizedBox(height: 15), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm(mzansiProfileProvider); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(height: 20), + ], ), - const SizedBox(height: 20), ], ), - ], - ), - ), + ), + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart index 46dea907..e1692b51 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart @@ -2,16 +2,15 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class MzansiProfile extends StatefulWidget { - final AppProfileUpdateArguments arguments; const MzansiProfile({ super.key, - required this.arguments, }); @override @@ -19,8 +18,6 @@ class MzansiProfile extends StatefulWidget { } class _MzansiProfileState extends State { - int _selcetedIndex = 0; - @override Widget build(BuildContext context) { return MihPackage( @@ -28,11 +25,9 @@ class _MzansiProfileState extends State { appTools: getTools(), appBody: getToolBody(), appToolTitles: getToolTitle(), - selectedbodyIndex: _selcetedIndex, - onIndexChange: (newValue) { - setState(() { - _selcetedIndex = newValue; - }); + selectedbodyIndex: context.watch().personalIndex, + onIndexChange: (newIndex) { + context.read().setPersonalIndex(newIndex); }, ); } @@ -55,29 +50,25 @@ class _MzansiProfileState extends State { MihPackageTools getTools() { Map temp = {}; temp[const Icon(Icons.person)] = () { - setState(() { - _selcetedIndex = 0; - }); + context.read().setPersonalIndex(0); }; + // temp[const Icon(Icons.person)] = () { + // context.read().setPersonalIndex(1); + // }; temp[const Icon(Icons.settings)] = () { - setState(() { - _selcetedIndex = 1; - }); + context.read().setPersonalIndex(1); }; return MihPackageTools( tools: temp, - selcetedIndex: _selcetedIndex, + selcetedIndex: context.watch().personalIndex, ); } List getToolBody() { List toolBodies = []; - toolBodies.add(MihPersonalProfile( - arguments: widget.arguments, - )); - toolBodies.add(MihPersonalSettings( - signedInUser: widget.arguments.signedInUser, - )); + toolBodies.add(MihPersonalProfile()); + // toolBodies.add(MihPersonalProfile()); + toolBodies.add(MihPersonalSettings()); return toolBodies; } diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart index 97f3900b..965ad532 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart @@ -1,146 +1,322 @@ +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:file_picker/file_picker.dart'; -import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class MihPersonalProfile extends StatefulWidget { - final AppProfileUpdateArguments arguments; - const MihPersonalProfile({ - super.key, - required this.arguments, - }); + const MihPersonalProfile({super.key}); @override State createState() => _MihPersonalProfileState(); } class _MihPersonalProfileState extends State { - final proPicController = TextEditingController(); - final usernameController = TextEditingController(); - final fnameController = TextEditingController(); - final lnameController = TextEditingController(); - final purposeController = TextEditingController(); + TextEditingController proPicController = TextEditingController(); + TextEditingController usernameController = TextEditingController(); + TextEditingController fnameController = TextEditingController(); + TextEditingController lnameController = TextEditingController(); + TextEditingController purposeController = TextEditingController(); final ValueNotifier _counter = ValueNotifier(0); - PlatformFile? proPic; - late ImageProvider? propicPreview; - late bool originalProfileTypeIsBusiness; - late bool businessUser; - late String oldProPicName; - late String env; + PlatformFile? newSelectedProPic; + bool businessUser = false; + bool _controllersInitialized = false; + String env = ""; + String oldProPicName = ""; final _formKey = GlobalKey(); - void notUniqueAlert() { + void initializeControllers(MzansiProfileProvider mzansiProfileProvider) { + if (!_controllersInitialized && mzansiProfileProvider.user != null) { + usernameController.text = mzansiProfileProvider.user!.username; + fnameController.text = mzansiProfileProvider.user!.fname; + lnameController.text = mzansiProfileProvider.user!.lname; + purposeController.text = mzansiProfileProvider.user!.purpose; + proPicController.text = + mzansiProfileProvider.user!.pro_pic_path.isNotEmpty + ? mzansiProfileProvider.user!.pro_pic_path.split("/").last + : ""; + businessUser = mzansiProfileProvider.user!.type == "business"; + _controllersInitialized = true; + } + } + + void editProfileWindow(double width) { showDialog( context: context, - builder: (context) { - return MihPackageAlert( - alertIcon: Icon( - Icons.warning_amber_rounded, - size: 100, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - alertTitle: "Too Slow, That Username is Taken", - alertBody: const Text( - "The username you have entered is already taken by another member of Mzansi. Please choose a different username and try again.", - style: TextStyle( - fontSize: 15, + builder: (context) => Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + // usernameController.text = mzansiProfileProvider.user!.username; + // fnameController.text = mzansiProfileProvider.user!.fname; + // lnameController.text = mzansiProfileProvider.user!.lname; + // purposeController.text = mzansiProfileProvider.user!.purpose; + // proPicController.text = + // mzansiProfileProvider.user!.pro_pic_path.isNotEmpty + // ? mzansiProfileProvider.user!.pro_pic_path.split("/").last + // : ""; + initializeControllers(mzansiProfileProvider); + return MihPackageWindow( + fullscreen: false, + windowTitle: "Edit Profile", + onWindowTapClose: () { + Navigator.of(context).pop(); + }, + windowBody: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : EdgeInsets.symmetric(horizontal: width * 0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Center( + child: MihCircleAvatar( + imageFile: newSelectedProPic != null + ? MemoryImage(newSelectedProPic!.bytes!) + : mzansiProfileProvider.userProfilePicture, + width: 150, + editable: true, + fileNameController: proPicController, + userSelectedfile: newSelectedProPic, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: (selectedImage) { + setState(() { + newSelectedProPic = selectedImage; + }); + }, + ), + ), + // const SizedBox(height: 25.0), + Visibility( + visible: false, + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: proPicController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Selected File Name", + ), + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: usernameController, + multiLineInput: false, + requiredText: true, + hintText: "Username", + validator: (value) { + return MihValidationServices() + .validateUsername(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: fnameController, + multiLineInput: false, + requiredText: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: lnameController, + multiLineInput: false, + requiredText: true, + hintText: "Last Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + height: 250, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: purposeController, + multiLineInput: true, + requiredText: true, + hintText: "Your Personal Mission", + validator: (value) { + return MihValidationServices() + .validateLength(purposeController.text, 256); + }, + ), + SizedBox( + height: 15, + child: ValueListenableBuilder( + valueListenable: _counter, + builder: + (BuildContext context, int value, Widget? child) { + return Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "$value", + style: TextStyle( + color: getPurposeLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 5), + Text( + "/256", + style: TextStyle( + color: getPurposeLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + ], + ); + }, + ), + ), + const SizedBox(height: 10.0), + MihToggle( + hintText: "Activate Business Account", + initialPostion: businessUser, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + secondaryFillColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: (value) { + setState(() { + businessUser = value; + }); + }, + ), + const SizedBox(height: 30.0), + Center( + child: MihButton( + onPressed: () { + //Add validation here + if (_formKey.currentState!.validate()) { + submitForm(mzansiProfileProvider); + } else { + MihAlertServices() + .formNotFilledCompletely(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ], + ), ), - ), - alertColour: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - }, + ); + }, + ), ); } - Future submitForm() async { - // print("============\nsubmiit form\n================="); - if (widget.arguments.signedInUser.username != usernameController.text) { + Future submitForm(MzansiProfileProvider mzansiProfileProvider) async { + if (mzansiProfileProvider.user!.username != usernameController.text) { bool isUsernameUnique = await MihUserServices.isUsernameUnique( usernameController.text, context); - print("isUsernameUnique: $isUsernameUnique"); if (isUsernameUnique == false) { notUniqueAlert(); return; } } if (oldProPicName != proPicController.text) { - await uploadSelectedFile(proPic); + await uploadSelectedFile(mzansiProfileProvider, newSelectedProPic); } - await updateUserApiCall(); + await updateUserApiCall(mzansiProfileProvider); } - bool isBusinessUser() { - if (widget.arguments.signedInUser.type == "personal") { - return false; - } else { - return true; - } - } - - bool isUsernameValid(String username) { - return RegExp(r'^[a-zA-Z][a-zA-Z0-9_]{5,19}$').hasMatch(username); - } - - Future uploadSelectedFile(PlatformFile? file) async { + Future uploadSelectedFile( + MzansiProfileProvider mzansiProfileProvider, PlatformFile? file) async { var response = await MihFileApi.uploadFile( - widget.arguments.signedInUser.app_id, + mzansiProfileProvider.user!.app_id, env, "profile_files", file, context, ); if (response == 200) { - deleteFileApiCall(oldProPicName); + deleteFileApiCall(mzansiProfileProvider, oldProPicName); } else { internetConnectionPopUp(); } } - Future updateUserApiCall() async { - int responseCode = await MihUserServices().updateUserV2( - widget.arguments.signedInUser, - fnameController.text, - lnameController.text, - usernameController.text, - proPicController.text, - purposeController.text, - businessUser, - context, - ); - if (responseCode == 200) { - bool stayOnPersonalSide = true; - if (originalProfileTypeIsBusiness == false && businessUser == true) { - stayOnPersonalSide = false; - } - String message = "Your information has been updated successfully!"; - successPopUp(message, stayOnPersonalSide); - } else { - internetConnectionPopUp(); - } - } - - Future deleteFileApiCall(String filename) async { + Future deleteFileApiCall( + MzansiProfileProvider mzansiProfileProvider, String filename) async { var response = await MihFileApi.deleteFile( - widget.arguments.signedInUser.app_id, + mzansiProfileProvider.user!.app_id, env, "profile_files", filename, @@ -153,6 +329,53 @@ class _MihPersonalProfileState extends State { } } + Future updateUserApiCall( + MzansiProfileProvider mzansiProfileProvider) async { + int responseCode = await MihUserServices().updateUserV2( + mzansiProfileProvider.user!, + fnameController.text, + lnameController.text, + usernameController.text, + proPicController.text, + purposeController.text, + businessUser, + context, + ); + if (responseCode == 200) { + setState(() { + setProfileVariables(mzansiProfileProvider); + newSelectedProPic = null; + }); + bool stayOnPersonalSide = true; + // if (originalProfileTypeIsBusiness == false && businessUser == true) { + // stayOnPersonalSide = false; + // } + String message = "Your information has been updated successfully!"; + context.pop(); + successPopUp(message, stayOnPersonalSide); + } else { + internetConnectionPopUp(); + } + } + + Color getPurposeLimitColor(int limit) { + if (_counter.value <= limit) { + return MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + } else { + return MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + } + } + + void setProfileVariables(MzansiProfileProvider mzansiProfileProvider) { + businessUser = mzansiProfileProvider.user!.type == "business"; + oldProPicName = mzansiProfileProvider.user!.pro_pic_path.isNotEmpty + ? mzansiProfileProvider.user!.pro_pic_path.split("/").last + : ""; + env = AppEnviroment.getEnv() == "Prod" ? env = "Prod" : env = "Dev"; + } + void successPopUp(String message, bool stayOnPersonalSide) { showDialog( context: context, @@ -180,10 +403,7 @@ class _MihPersonalProfileState extends State { Center( child: MihButton( onPressed: () { - context.goNamed( - 'mihHome', - extra: stayOnPersonalSide, - ); + context.pop(); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -223,264 +443,31 @@ class _MihPersonalProfileState extends State { ); } - void usernamePopUp() { + void notUniqueAlert() { showDialog( context: context, builder: (context) { - return const MIHErrorMessage(errorType: "Invalid Username"); + return MihPackageAlert( + alertIcon: Icon( + Icons.warning_amber_rounded, + size: 100, + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + alertTitle: "Too Slow, That Username is Taken", + alertBody: const Text( + "The username you have entered is already taken by another member of Mzansi. Please choose a different username and try again.", + style: TextStyle( + fontSize: 15, + ), + ), + alertColour: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); }, ); } - Color getPurposeLimitColor(int limit) { - if (_counter.value <= limit) { - return MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"); - } else { - return MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"); - } - } - - void editProfileWindow(double width) { - showDialog( - context: context, - builder: (context) => MihPackageWindow( - fullscreen: false, - windowTitle: "Edit Profile", - onWindowTapClose: () { - Navigator.of(context).pop(); - }, - windowBody: Padding( - padding: - MzansiInnovationHub.of(context)!.theme.screenType == "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.05) - : EdgeInsets.symmetric(horizontal: width * 0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - MihForm( - formKey: _formKey, - formFields: [ - Center( - child: MihCircleAvatar( - imageFile: propicPreview, - width: 150, - editable: true, - fileNameController: proPicController, - userSelectedfile: proPic, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: (selectedImage) { - setState(() { - proPic = selectedImage; - }); - }, - ), - ), - // const SizedBox(height: 25.0), - Visibility( - visible: false, - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: proPicController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Selected File Name", - ), - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: usernameController, - multiLineInput: false, - requiredText: true, - hintText: "Username", - validator: (value) { - return MihValidationServices().validateUsername(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: fnameController, - multiLineInput: false, - requiredText: true, - hintText: "First Name", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: lnameController, - multiLineInput: false, - requiredText: true, - hintText: "Last Name", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - height: 250, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: purposeController, - multiLineInput: true, - requiredText: true, - hintText: "Your Personal Mission", - validator: (value) { - return MihValidationServices() - .validateLength(purposeController.text, 256); - }, - ), - SizedBox( - height: 15, - child: ValueListenableBuilder( - valueListenable: _counter, - builder: - (BuildContext context, int value, Widget? child) { - return Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - "$value", - style: TextStyle( - color: getPurposeLimitColor(256), - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(width: 5), - Text( - "/256", - style: TextStyle( - color: getPurposeLimitColor(256), - fontWeight: FontWeight.bold, - ), - ), - ], - ); - }, - ), - ), - const SizedBox(height: 10.0), - MihToggle( - hintText: "Activate Business Account", - initialPostion: businessUser, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - secondaryFillColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onChange: (value) { - setState(() { - businessUser = value; - }); - }, - ), - const SizedBox(height: 30.0), - Center( - child: MihButton( - onPressed: () { - //Add validation here - if (_formKey.currentState!.validate()) { - submitForm(); - } else { - MihAlertServices().formNotFilledCompletely(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), - ], - ), - ), - ), - ); - } - - @override - void dispose() { - proPicController.dispose(); - usernameController.dispose(); - fnameController.dispose(); - lnameController.dispose(); - purposeController.dispose(); - super.dispose(); - } - - @override - void initState() { - super.initState(); - var proPicName = ""; - if (widget.arguments.signedInUser.pro_pic_path.isNotEmpty) { - proPicName = widget.arguments.signedInUser.pro_pic_path.split("/").last; - } - if (AppEnviroment.getEnv() == "Prod") { - env = "Prod"; - } else { - env = "Dev"; - } - purposeController.addListener(() { - setState(() { - _counter.value = purposeController.text.characters.length; - }); - }); - setState(() { - propicPreview = widget.arguments.propicFile; - oldProPicName = proPicName; - proPicController.text = proPicName; - fnameController.text = widget.arguments.signedInUser.fname; - lnameController.text = widget.arguments.signedInUser.lname; - usernameController.text = widget.arguments.signedInUser.username; - purposeController.text = widget.arguments.signedInUser.purpose; - businessUser = isBusinessUser(); - if (businessUser) { - originalProfileTypeIsBusiness = true; - } else { - originalProfileTypeIsBusiness = false; - } - }); - } - @override Widget build(BuildContext context) { double screenWidth = MediaQuery.of(context).size.width; @@ -492,84 +479,87 @@ class _MihPersonalProfileState extends State { } Widget getBody(double width) { - return Stack( - children: [ - MihSingleChildScroll( - child: Padding( - padding: - MzansiInnovationHub.of(context)!.theme.screenType == "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.2) - : EdgeInsets.symmetric(horizontal: width * 0.075), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Center( - child: MihCircleAvatar( - imageFile: propicPreview, - width: 150, - editable: false, - fileNameController: proPicController, - userSelectedfile: proPic, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onChange: (selectedImage) { - setState(() { - proPic = selectedImage; - }); - }, - ), - ), - FittedBox( - child: Text( - widget.arguments.signedInUser.username.isNotEmpty - ? widget.arguments.signedInUser.username - : "username", - style: TextStyle( - fontSize: 35, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + if (mzansiProfileProvider.user == null) { + //Change to new user flow + return Center( + child: Mihloadingcircle(), + ); + } + // else if (mzansiProfileProvider.user!.username.isEmpty) { + // editProfileWindow(width); + // } + else { + businessUser = mzansiProfileProvider.user!.type == "business"; + oldProPicName = mzansiProfileProvider.user!.pro_pic_path.isNotEmpty + ? mzansiProfileProvider.user!.pro_pic_path.split("/").last + : ""; + env = AppEnviroment.getEnv() == "Prod" ? env = "Prod" : env = "Dev"; + KenLogger.success( + mzansiProfileProvider.userProfilePicture.toString()); + return MihSingleChildScroll( + child: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Center( + child: MihCircleAvatar( + imageFile: mzansiProfileProvider.userProfilePicture, + width: 150, + editable: false, + fileNameController: proPicController, + userSelectedfile: newSelectedProPic, + frameColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - ), - FittedBox( - child: Text( - widget.arguments.signedInUser.fname.isNotEmpty - ? "${widget.arguments.signedInUser.fname} ${widget.arguments.signedInUser.lname}" - : "Name Surname", - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( + backgroundColor: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onChange: (selectedImage) { + setState(() { + newSelectedProPic = selectedImage; + }); + }, + key: ValueKey(mzansiProfileProvider.userProfilePicUrl), ), ), - ), - FittedBox( - child: Text( - businessUser ? "Business" : "Personal", - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ), - const SizedBox(height: 10.0), - Center( - child: SizedBox( - width: 700, + FittedBox( child: Text( - widget.arguments.signedInUser.purpose.isNotEmpty - ? widget.arguments.signedInUser.purpose - : "No Personal Mission added yet", - textAlign: TextAlign.center, + mzansiProfileProvider.user!.username.isNotEmpty + ? mzansiProfileProvider.user!.username + : "username", + style: TextStyle( + fontSize: 35, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + FittedBox( + child: Text( + mzansiProfileProvider.user!.fname.isNotEmpty + ? "${mzansiProfileProvider.user!.fname} ${mzansiProfileProvider.user!.lname}" + : "Name Surname", + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + FittedBox( + child: Text( + businessUser == true ? "Business" : "Personal", style: TextStyle( fontSize: 15, fontWeight: FontWeight.bold, @@ -579,63 +569,56 @@ class _MihPersonalProfileState extends State { ), ), ), - ), - const SizedBox(height: 30.0), - Center( - child: MihButton( - onPressed: () { - // Connect with the user - editProfileWindow(width); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 300, - child: Text( - widget.arguments.signedInUser.username.isEmpty - ? "Set Up Profile" - : "Edit Profile", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, + const SizedBox(height: 10.0), + Center( + child: SizedBox( + width: 700, + child: Text( + mzansiProfileProvider.user!.purpose.isNotEmpty + ? mzansiProfileProvider.user!.purpose + : "No Personal Mission added yet", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), ), ), ), - ), - ], + const SizedBox(height: 30.0), + Center( + child: MihButton( + onPressed: () { + // Connect with the user + editProfileWindow(width); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + mzansiProfileProvider.user!.username.isEmpty + ? "Set Up Profile" + : "Edit Profile", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), ), - ), - ), - // Positioned( - // right: 5, - // bottom: 10, - // child: MihFloatingMenu( - // animatedIcon: AnimatedIcons.menu_close, - // children: [ - // SpeedDialChild( - // child: Icon( - // Icons.edit, - // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // label: "Edit Profile", - // labelBackgroundColor: - // MihColors.getGreenColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // labelStyle: TextStyle( - // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // fontWeight: FontWeight.bold, - // ), - // backgroundColor: - // MihColors.getGreenColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // onTap: () { - // editProfileWindow(width); - // }, - // ) - // ], - // ), - // ), - ], + ); + } + }, ); } } diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart index 7a7eeac9..1427074d 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart @@ -1,19 +1,18 @@ import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:provider/provider.dart'; class MihPersonalSettings extends StatefulWidget { - final AppUser signedInUser; const MihPersonalSettings({ super.key, - required this.signedInUser, }); @override @@ -35,75 +34,83 @@ class _MihPersonalSettingsState extends State { context: context, barrierDismissible: false, builder: (context) { - return MihPackageAlert( - alertIcon: Icon( - Icons.warning_amber_rounded, - size: 100, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - alertTitle: - "Are you sure you want to permanently delete your MIH account?", - alertBody: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "This action will remove all of your data, and it cannot be recovered. We understand this is a big decision, so please take a moment to double-check.\n\nIf you're certain, please confirm below. If you've changed your mind, you can simply close this window.", - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 15, - fontWeight: FontWeight.bold, - ), + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return MihPackageAlert( + alertIcon: Icon( + Icons.warning_amber_rounded, + size: 100, + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), - const SizedBox(height: 15), - Wrap( - spacing: 10, - runSpacing: 10, + alertTitle: + "Are you sure you want to permanently delete your MIH account?", + alertBody: Column( + mainAxisSize: MainAxisSize.min, children: [ - MihButton( - onPressed: () { - MihUserServices.deleteAccount( - widget.signedInUser.app_id, context); - }, - buttonColor: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 300, - child: Text( - "Delete", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + Text( + "This action will remove all of your data, and it cannot be recovered. We understand this is a big decision, so please take a moment to double-check.\n\nIf you're certain, please confirm below. If you've changed your mind, you can simply close this window.", + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 15, + fontWeight: FontWeight.bold, ), ), - MihButton( - onPressed: () { - Navigator.pop(context); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 300, - child: Text( - "Cancel", - style: TextStyle( - color: MihColors.getPrimaryColor( + const SizedBox(height: 15), + Wrap( + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + onPressed: () { + MihUserServices.deleteAccount( + mzansiProfileProvider, context); + }, + buttonColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, + width: 300, + child: Text( + "Delete", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), ), - ), - ), + MihButton( + onPressed: () { + Navigator.pop(context); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Cancel", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ) ], - ) - ], - ), - alertColour: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + alertColour: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, ); }, ); diff --git a/Frontend/lib/mih_services/mih_business_details_services.dart b/Frontend/lib/mih_services/mih_business_details_services.dart index b59840c1..6b976cb9 100644 --- a/Frontend/lib/mih_services/mih_business_details_services.dart +++ b/Frontend/lib/mih_services/mih_business_details_services.dart @@ -1,10 +1,15 @@ import 'dart:convert'; +import 'package:go_router/go_router.dart'; import 'package:http/http.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; +import 'package:provider/provider.dart'; +import 'package:supertokens_flutter/supertokens.dart'; import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:supertokens_flutter/http.dart' as http; @@ -75,8 +80,9 @@ class MihBusinessDetailsServices { } Future getBusinessDetailsByUser( - String app_id, + BuildContext context, ) async { + String app_id = await SuperTokens.getUserId(); var response = await http.get( Uri.parse("${AppEnviroment.baseApiUrl}/business/app_id/$app_id"), headers: { @@ -86,7 +92,9 @@ class MihBusinessDetailsServices { if (response.statusCode == 200) { String body = response.body; var jsonBody = jsonDecode(body); - return Business.fromJson(jsonBody); + Business? business = Business.fromJson(jsonBody); + context.read().setBusiness(newBusiness: business); + return business; } else { return null; } @@ -175,6 +183,7 @@ class MihBusinessDetailsServices { String businessWebsite, String businessRating, String businessMissionVision, + MzansiProfileProvider provider, BuildContext context, ) async { showDialog( @@ -183,6 +192,7 @@ class MihBusinessDetailsServices { return const Mihloadingcircle(); }, ); + var filePath = "$business_id/business_files/$business_logo_name"; var response = await http.put( Uri.parse("${AppEnviroment.baseApiUrl}/business/update/v2/"), headers: { @@ -194,7 +204,7 @@ class MihBusinessDetailsServices { "type": business_type, "registration_no": business_registration_no, "logo_name": business_logo_name, - "logo_path": "$business_id/business_files/$business_logo_name", + "logo_path": filePath, "contact_no": business_phone_number, "bus_email": business_email, "gps_location": business_location, @@ -205,8 +215,29 @@ class MihBusinessDetailsServices { "mission_vision": businessMissionVision, }), ); - Navigator.of(context).pop(); + context.pop(); if (response.statusCode == 200) { + provider.setBusiness( + newBusiness: Business( + business_id, + business_name, + business_type, + business_registration_no, + business_logo_name, + filePath, + business_phone_number, + business_email, + provider.business!.app_id, + business_location, + business_practice_no, + business_vat_no, + businessWebsite, + businessRating, + businessMissionVision, + ), + ); + String newProPicUrl = await MihFileApi.getMinioFileUrl(filePath, context); + provider.setBusinessProfilePicUrl(newProPicUrl); return 200; } else { return 500; diff --git a/Frontend/lib/mih_services/mih_file_services.dart b/Frontend/lib/mih_services/mih_file_services.dart index fa983869..88746f66 100644 --- a/Frontend/lib/mih_services/mih_file_services.dart +++ b/Frontend/lib/mih_services/mih_file_services.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:file_picker/file_picker.dart'; +import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; @@ -75,7 +76,7 @@ class MihFileApi { request.files.add(await http2.MultipartFile.fromBytes('file', file!.bytes!, filename: file.name.replaceAll(RegExp(r' '), '-'))); var response = await request.send(); - Navigator.of(context).pop(); // Pop loading dialog + context.pop(); // Pop loading dialog return response.statusCode; } @@ -99,7 +100,7 @@ class MihFileApi { "env": env, }), ); - Navigator.of(context).pop(); // Pop loading dialog + context.pop(); // Pop loading dialog return response.statusCode; } diff --git a/Frontend/lib/mih_services/mih_my_business_user_services.dart b/Frontend/lib/mih_services/mih_my_business_user_services.dart index e1481493..5b0f5349 100644 --- a/Frontend/lib/mih_services/mih_my_business_user_services.dart +++ b/Frontend/lib/mih_services/mih_my_business_user_services.dart @@ -1,15 +1,22 @@ import 'dart:convert'; +import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; +import 'package:provider/provider.dart'; +import 'package:supertokens_flutter/supertokens.dart'; import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:supertokens_flutter/http.dart' as http; class MihMyBusinessUserServices { Future getBusinessUser( - String app_id, + BuildContext context, ) async { + String app_id = await SuperTokens.getUserId(); var response = await http.get( Uri.parse("${AppEnviroment.baseApiUrl}/business-user/$app_id"), headers: { @@ -17,7 +24,13 @@ class MihMyBusinessUserServices { }, ); if (response.statusCode == 200) { - return BusinessUser.fromJson(jsonDecode(response.body)); + KenLogger.success(response.body); + BusinessUser? businessUser = + BusinessUser.fromJson(jsonDecode(response.body)); + context + .read() + .setBusinessUser(newBusinessUser: businessUser); + return businessUser; } else { return null; } @@ -51,7 +64,7 @@ class MihMyBusinessUserServices { "access": access, }), ); - Navigator.of(context).pop(); + context.pop(); if (response.statusCode == 201) { return 201; } else { @@ -67,6 +80,7 @@ class MihMyBusinessUserServices { String bUserTitle, String bUserAccess, String signatureFileName, + MzansiProfileProvider provider, BuildContext context, ) async { showDialog( @@ -75,6 +89,7 @@ class MihMyBusinessUserServices { return const Mihloadingcircle(); }, ); + var filePath = "$app_id/business_files/$signatureFileName"; var response = await http.put( Uri.parse("${AppEnviroment.baseApiUrl}/business-user/update/"), headers: { @@ -84,32 +99,26 @@ class MihMyBusinessUserServices { "business_id": business_id, "app_id": app_id, "signature": signatureFileName, - "sig_path": "$app_id/business_files/$signatureFileName", + "sig_path": filePath, "title": bUserTitle, "access": bUserAccess, }), ); - // var response = await http.put( - // Uri.parse("${AppEnviroment.baseApiUrl}/business/update/"), - // headers: { - // "Content-Type": "application/json; charset=UTF-8" - // }, - // body: jsonEncode({ - // "business_id": business_id, - // "Name": business_name, - // "type": business_type, - // "registration_no": business_registration_no, - // "logo_name": business_logo_name, - // "logo_path": "$business_id/business_files/$business_logo_name", - // "contact_no": business_phone_number, - // "bus_email": business_email, - // "gps_location": business_location, - // "practice_no": business_practice_no, - // "vat_no": business_vat_no, - // }), - // ); - Navigator.of(context).pop(); + context.pop(); if (response.statusCode == 200) { + provider.setBusinessUser( + newBusinessUser: BusinessUser( + provider.businessUser!.idbusiness_users, + business_id, + app_id, + signatureFileName, + filePath, + bUserTitle, + bUserAccess, + ), + ); + String newProPicUrl = await MihFileApi.getMinioFileUrl(filePath, context); + provider.setBusinessUserSignatureUrl(newProPicUrl); return 200; } else { internetConnectionPopUp(context); diff --git a/Frontend/lib/mih_services/mih_service_calls.dart b/Frontend/lib/mih_services/mih_service_calls.dart index 411ec8c7..9375c2ec 100644 --- a/Frontend/lib/mih_services/mih_service_calls.dart +++ b/Frontend/lib/mih_services/mih_service_calls.dart @@ -61,7 +61,7 @@ class MIHApiCalls { // Get Userdata var uid = await SuperTokens.getUserId(); - AppUser? user = await MihUserServices().getUserDetails(uid, context); + AppUser? user = await MihUserServices().getUserDetails(context); if (user != null) { userData = user; } else { @@ -70,7 +70,7 @@ class MIHApiCalls { // Get BusinessUserdata BusinessUser? businessUser = - await MihMyBusinessUserServices().getBusinessUser(uid); + await MihMyBusinessUserServices().getBusinessUser(context); if (businessUser != null) { bUserData = businessUser; } else { @@ -79,9 +79,7 @@ class MIHApiCalls { // Get Businessdata Business? business = - await MihBusinessDetailsServices().getBusinessDetailsByUser( - uid, - ); + await MihBusinessDetailsServices().getBusinessDetailsByUser(context); if (business != null) { busData = business; } else { diff --git a/Frontend/lib/mih_services/mih_user_consent_services.dart b/Frontend/lib/mih_services/mih_user_consent_services.dart index f4246916..f55424f6 100644 --- a/Frontend/lib/mih_services/mih_user_consent_services.dart +++ b/Frontend/lib/mih_services/mih_user_consent_services.dart @@ -1,31 +1,39 @@ import 'dart:convert'; +import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/user_consent.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:provider/provider.dart'; import 'package:supertokens_flutter/http.dart' as http; import 'package:supertokens_flutter/supertokens.dart'; class MihUserConsentServices { - Future getUserConsentStatus() async { + Future getUserConsentStatus( + BuildContext context, + ) async { var app_id = await SuperTokens.getUserId(); final response = await http.get( Uri.parse("${AppEnviroment.baseApiUrl}/user-consent/user/$app_id")); if (response.statusCode == 200) { Map userMap = jsonDecode(response.body); UserConsent userConsent = UserConsent.fromJson(userMap); - return userConsent; - } else { - return null; + context.read().setUserConsent(userConsent); + // return userConsent; } + // else { + // return null; + // } } Future insertUserConsentStatus( - String app_id, String latestPrivacyPolicyDate, String latestTermOfServiceDate, + MzansiProfileProvider provider, + BuildContext context, ) async { UserConsent userConsent = UserConsent( - app_id: app_id, + app_id: provider.user!.app_id, privacy_policy_accepted: DateTime.parse(latestPrivacyPolicyDate), terms_of_services_accepted: DateTime.parse(latestTermOfServiceDate), ); @@ -34,16 +42,18 @@ class MihUserConsentServices { headers: {"Content-Type": "application/json"}, body: jsonEncode(userConsent.toJson()), ); + provider.setUserConsent(userConsent); return response.statusCode; } Future updateUserConsentStatus( - String app_id, String latestPrivacyPolicyDate, String latestTermOfServiceDate, + MzansiProfileProvider provider, + BuildContext context, ) async { UserConsent userConsent = UserConsent( - app_id: app_id, + app_id: provider.user!.app_id, privacy_policy_accepted: DateTime.parse(latestPrivacyPolicyDate), terms_of_services_accepted: DateTime.parse(latestTermOfServiceDate), ); @@ -52,6 +62,7 @@ class MihUserConsentServices { headers: {"Content-Type": "application/json"}, body: jsonEncode(userConsent.toJson()), ); + provider.setUserConsent(userConsent); return response.statusCode; } } diff --git a/Frontend/lib/mih_services/mih_user_services.dart b/Frontend/lib/mih_services/mih_user_services.dart index 44f83c87..ff74e988 100644 --- a/Frontend/lib/mih_services/mih_user_services.dart +++ b/Frontend/lib/mih_services/mih_user_services.dart @@ -7,9 +7,12 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; +import 'package:provider/provider.dart'; import 'package:supertokens_flutter/http.dart' as http; import 'package:supertokens_flutter/supertokens.dart'; @@ -94,9 +97,9 @@ class MihUserServices { } Future getUserDetails( - String app_id, BuildContext context, ) async { + String app_id = await SuperTokens.getUserId(); var response = await http.get( Uri.parse("${AppEnviroment.baseApiUrl}/user/$app_id"), headers: { @@ -107,6 +110,9 @@ class MihUserServices { if (response.statusCode == 200) { String body = response.body; var jsonBody = jsonDecode(body); + context.read().setUser( + newUser: AppUser.fromJson(jsonBody), + ); return AppUser.fromJson(jsonBody); } else { return null; @@ -147,6 +153,21 @@ class MihUserServices { }), ); if (response.statusCode == 200) { + context.read().setUser( + newUser: AppUser( + signedInUser.idUser, + signedInUser.email, + firstName, + lastName, + profileType, + signedInUser.app_id, + username, + filePath, + purpose, + ), + ); + String newProPicUrl = await MihFileApi.getMinioFileUrl(filePath, context); + context.read().setUserProfilePicUrl(newProPicUrl); return response.statusCode; } else { return response.statusCode; @@ -192,7 +213,7 @@ class MihUserServices { } static Future deleteAccount( - String app_id, + MzansiProfileProvider provider, BuildContext context, ) async { loadingPopUp(context); @@ -202,7 +223,7 @@ class MihUserServices { "Content-Type": "application/json; charset=UTF-8" }, body: jsonEncode({ - "app_id": app_id, + "app_id": provider.user!.app_id, "env": AppEnviroment.getEnv(), }), ); @@ -212,18 +233,12 @@ class MihUserServices { print(error); }); if (await SuperTokens.doesSessionExist() == false) { - // Navigator.of(context).pop(); // Pop loading dialog - // Navigator.of(context).pop(); // Pop delete account dialog - // Navigator.of(context).pop(); // Pop Mzansi Profile - // Navigator.of(context).popAndPushNamed( - // '/', - // arguments: AuthArguments(true, false), - // ); //Pop and push to login page successPopUp( "Account Deleted Successfully", "Your account has been successfully deleted. We are sorry to see you go, but we respect your decision.", context, ); // Show success message. + provider.dispose(); } } else { Navigator.of(context).pop(); // Pop loading dialog diff --git a/backend/routers/users.py b/backend/routers/users.py index 5aede146..a065e41b 100644 --- a/backend/routers/users.py +++ b/backend/routers/users.py @@ -249,6 +249,7 @@ async def delete_users_data_by_app_id(itemRequest: userDeleteRequest, session: "DELETE FROM patient_manager.patient_notes where app_id = %s", "DELETE FROM patient_manager.patient_files where app_id = %s", "DELETE FROM patient_manager.claim_statement_file where app_id = %s", + "DELETE FROM app_data.user_consent where app_id = %s", "DELETE FROM app_data.users where app_id = %s", ] # Delete user from all tables From 540e13dfe045c08ea7728735af3604c35e98f244 Mon Sep 17 00:00:00 2001 From: yaso Date: Fri, 17 Oct 2025 08:24:23 +0200 Subject: [PATCH 18/45] mine sweeper pt2 --- .../mine_sweeper/components/mine_tile.dart | 1 + .../package_tools/mine_sweeper_game.dart | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/Frontend/lib/mih_packages/mine_sweeper/components/mine_tile.dart b/Frontend/lib/mih_packages/mine_sweeper/components/mine_tile.dart index 4e877c4b..f6e653d8 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/components/mine_tile.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/components/mine_tile.dart @@ -36,6 +36,7 @@ class MineTile extends StatelessWidget { child: Text( '${square.bombsAround}', style: TextStyle( + fontSize: 25, fontWeight: FontWeight.bold, color: _getTileColor(square.bombsAround, context), ), diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart index be21f407..01b16f05 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart @@ -35,7 +35,23 @@ class _MineSweeperGameState extends State { int squaresLeft = -1; bool _isFirstLoad = true; + String getModeConfig() { + switch (modeController.text) { + case ("Easy"): + return "Columns: 10\nRows: 10\nBomds: 15"; + case ("Normal"): + return "Columns: 10\nRows: 15\nBomds: 23"; + case ("Hard"): + return "Columns: 10\nRows: 20\nBomds: 30"; + default: + return "Error"; + } + } + void showStartGameWindow(MihMineSweeperProvider mihMineSweeperProvider) { + // easy - 10 * 10 & 15 bombs + // Normal - 10 * 15 & 23 bombs + // Hard - 10 * 20 & 30 bombs showDialog( context: context, builder: (context) { @@ -58,6 +74,17 @@ class _MineSweeperGameState extends State { editable: true, enableSearch: false, ), + const SizedBox(height: 10), + Text( + getModeConfig(), + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), const SizedBox(height: 25), Center( child: MihButton( From c89932755ff3b6d255436992c983ef8e9713da1a Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 20 Oct 2025 11:18:06 +0200 Subject: [PATCH 19/45] BUG: Tab movement on password fields --- .../mih_text_form_field.dart | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart b/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart index 03d44871..176d26bb 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_text_form_field.dart @@ -191,18 +191,21 @@ class _MihTextFormFieldState extends State { ), decoration: InputDecoration( suffixIcon: widget.passwordMode == true - ? IconButton( - icon: Icon( - _obscureText - ? Icons.visibility_off - : Icons.visibility, - color: widget.inputColor, + ? FocusScope( + canRequestFocus: false, + child: IconButton( + icon: Icon( + _obscureText + ? Icons.visibility_off + : Icons.visibility, + color: widget.inputColor, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }, ), - onPressed: () { - setState(() { - _obscureText = !_obscureText; - }); - }, ) : null, errorStyle: const TextStyle( From 2e69e1dd92c46db24a7aa6afd5e8052d7165d7c2 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 20 Oct 2025 16:41:24 +0200 Subject: [PATCH 20/45] NEW: MIH Home & Mzansi Profile Provider Setup pt 2 done --- .../mih_circle_avatar.dart | 8 +- .../mih_image_display.dart | 31 +- .../mzansi_profile_provider.dart | 27 + Frontend/lib/mih_config/mih_go_router.dart | 5 +- .../about_mih/package_tools/mih_info.dart | 4 +- .../lib/mih_packages/mih_home/mih_home.dart | 123 +++-- .../package_tools/mih_business_home.dart | 282 +++++----- .../builders/build_employee_list.dart | 361 +------------ .../builders/build_user_list.dart | 347 ++----------- .../components/mih_add_employee_window.dart | 250 +++++++++ .../mih_edit_employee_details_window.dart | 319 ++++++++++++ .../mzansi_business_profile.dart | 80 +-- .../mzansi_set_up_business_profile.dart | 72 +++ .../mzansi_business_profile_tile.dart | 4 - .../mih_business_details_set_up.dart} | 487 +++++++++--------- .../package_tools/mih_business_qr_code.dart | 35 +- .../mih_business_user_search.dart | 16 - .../package_tools/mih_my_business_team.dart | 15 +- .../mih_edit_personal_profile_window.dart | 470 +++++++++++++++++ .../package_tools/mih_personal_profile.dart | 438 +--------------- .../mih_business_details_services.dart | 54 +- .../mih_business_employee_services.dart | 142 +++++ .../lib/mih_services/mih_file_services.dart | 6 +- .../mih_my_business_user_services.dart | 11 +- .../lib/mih_services/mih_user_services.dart | 3 + 25 files changed, 1937 insertions(+), 1653 deletions(-) create mode 100644 Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_add_employee_window.dart create mode 100644 Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_edit_employee_details_window.dart create mode 100644 Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_set_up_business_profile.dart rename Frontend/lib/mih_packages/mzansi_profile/business_profile/{profile_business_add.dart => package_tools/mih_business_details_set_up.dart} (81%) create mode 100644 Frontend/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart create mode 100644 Frontend/lib/mih_services/mih_business_employee_services.dart diff --git a/Frontend/lib/mih_components/mih_package_components/mih_circle_avatar.dart b/Frontend/lib/mih_components/mih_package_components/mih_circle_avatar.dart index 4f0c3e71..c64aaa75 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_circle_avatar.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_circle_avatar.dart @@ -10,7 +10,7 @@ class MihCircleAvatar extends StatefulWidget { final ImageProvider? imageFile; final double width; final bool editable; - final TextEditingController fileNameController; + final TextEditingController? fileNameController; final onChange; final PlatformFile? userSelectedfile; final Color frameColor; @@ -130,7 +130,7 @@ class _MihCircleAvatarState extends State { }); setState(() { - widget.fileNameController.text = selectedFile.name; + widget.fileNameController!.text = selectedFile.name; }); } else { if (result != null) { @@ -148,7 +148,7 @@ class _MihCircleAvatarState extends State { }); setState(() { - widget.fileNameController.text = + widget.fileNameController!.text = file.path.split('/').last; }); } else { @@ -157,7 +157,7 @@ class _MihCircleAvatarState extends State { } } } catch (e) { - print("Error: $e"); + print("Here Error: $e"); } }, icon: Icon( diff --git a/Frontend/lib/mih_components/mih_package_components/mih_image_display.dart b/Frontend/lib/mih_components/mih_package_components/mih_image_display.dart index 6d6d3145..509fcc59 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_image_display.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_image_display.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; @@ -32,6 +33,7 @@ class _MihImageDisplayState extends State { late ImageProvider? imagePreview; ImageProvider? getImage() { + KenLogger.success(widget.imageFile.toString()); if (widget.imageFile == null) { return null; } else { @@ -58,13 +60,26 @@ class _MihImageDisplayState extends State { child: Stack( alignment: Alignment.center, children: [ - Visibility( - visible: imagePreview != null, - child: ClipRRect( - borderRadius: BorderRadius.circular(widget.width * 0.1), - child: Image(image: imagePreview!), - ), - ), + imagePreview != null + ? ClipRRect( + borderRadius: BorderRadius.circular(widget.width * 0.1), + child: Image(image: imagePreview!), + ) + : Container( + width: widget.width, + height: widget.height, + decoration: BoxDecoration( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + borderRadius: BorderRadius.circular(widget.width * 0.1), + ), + child: Icon( + Icons.image_not_supported_rounded, + size: widget.width * 0.3, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), Visibility( visible: widget.editable, child: Positioned( @@ -125,7 +140,7 @@ class _MihImageDisplayState extends State { } } } catch (e) { - print("Error: $e"); + print("here 2 Error: $e"); } }, icon: const Icon( diff --git a/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart b/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart index 8941a0a9..109aedf2 100644 --- a/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart @@ -99,4 +99,31 @@ class MzansiProfileProvider extends ChangeNotifier { this.employeeList = employeeList; notifyListeners(); } + + void addLoyaltyCard({required BusinessEmployee newEmployee}) { + employeeList!.add(newEmployee); + notifyListeners(); + } + + void updateEmplyeeDetails({required BusinessEmployee updatedEmployee}) { + int index = employeeList!.indexWhere((employee) => + employee.business_id == updatedEmployee.business_id && + employee.app_id == updatedEmployee.app_id); + if (index != -1) { + employeeList![index] = updatedEmployee; + notifyListeners(); + } + } + + void deleteEmplyee({required BusinessEmployee deletedEmployee}) { + employeeList!.removeWhere((employee) => + employee.business_id == deletedEmployee.business_id && + employee.app_id == deletedEmployee.app_id); + notifyListeners(); + } + + void addEmployee({required BusinessEmployee newEmployee}) { + employeeList!.add(newEmployee); + notifyListeners(); + } } diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index 25743e6d..86211a8f 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -19,7 +19,7 @@ import 'package:mzansi_innovation_hub/mih_packages/mzansi_ai/mzansi_ai.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/mzansi_directory.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/mzansi_business_profile_view.dart'; -import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/profile_business_add.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/mzansi_set_up_business_profile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/mzansi_profile_view.dart'; import 'package:ken_logger/ken_logger.dart'; @@ -228,8 +228,7 @@ class MihGoRouter { path: MihGoRouterPaths.businessProfileSetup, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: businessProfileSetup"); - final AppUser? signedInUser = state.extra as AppUser?; - return ProfileBusinessAdd(signedInUser: signedInUser!); + return MzansiSetUpBusinessProfile(); }, ), // ========================== MIH Calculator ================================== diff --git a/Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart b/Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart index eccbbc4d..d3456a20 100644 --- a/Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart +++ b/Frontend/lib/mih_packages/about_mih/package_tools/mih_info.dart @@ -506,8 +506,8 @@ class _MihInfoState extends State { void shareMIHLink(BuildContext context, String message, String link) { String shareText = "$message: $link"; - Share.share( - shareText, + SharePlus.instance.share( + ShareParams(text: shareText), ); } diff --git a/Frontend/lib/mih_packages/mih_home/mih_home.dart b/Frontend/lib/mih_packages/mih_home/mih_home.dart index 61022390..92a4ea8a 100644 --- a/Frontend/lib/mih_packages/mih_home/mih_home.dart +++ b/Frontend/lib/mih_packages/mih_home/mih_home.dart @@ -39,7 +39,6 @@ class MihHome extends StatefulWidget { } class _MihHomeState extends State { - final proPicController = TextEditingController(); late int _selcetedIndex; late bool _personalHome; DateTime latestPrivacyPolicyDate = DateTime.parse("2024-12-01"); @@ -47,11 +46,30 @@ class _MihHomeState extends State { bool _isLoadingInitialData = true; Future _loadInitialData() async { + if (mounted) { + setState(() { + _isLoadingInitialData = true; + }); + } + MzansiProfileProvider mzansiProfileProvider = + context.read(); // Note: getUserData sets user and userProfilePicUrl in the provider - await getUserData(); + if (mzansiProfileProvider.user == null) { + await getUserData(); + } // Note: getUserConsentStatus sets userConsent in the provider - await getUserConsentStatus(); - await getBusinessData(); + if (mzansiProfileProvider.userConsent == null) { + await getUserConsentStatus(); + } + // 1. Get Business Data + if (mzansiProfileProvider.user != null && + mzansiProfileProvider.user!.type == "business" && + mzansiProfileProvider.business == null) { + KenLogger.success(mzansiProfileProvider.business == null + ? "Business is null, fetching business data..." + : "Business data already loaded."); + await getBusinessData(); + } // 2. Set state after all data is loaded if (mounted) { setState(() { @@ -61,13 +79,23 @@ class _MihHomeState extends State { } Future getBusinessData() async { - Business? business = context.read().business; AppUser? user = context.read().user; String logoUrl; String signatureUrl; - if (business == null && user!.type == "business") { + Business? responseBusiness = + await MihBusinessDetailsServices().getBusinessDetailsByUser(context); + if (responseBusiness == null && user!.type == "business") { + if (mounted) { + context.goNamed( + 'businessProfileSetup', + extra: user, + ); + } + } + + if (responseBusiness != null && user!.type == "business") { // Get Business - await MihBusinessDetailsServices().getBusinessDetailsByUser(context); + // Business Profile Set Up aleary logoUrl = await MihFileApi.getMinioFileUrl( context.read().business!.logo_path, context, @@ -152,10 +180,12 @@ class _MihHomeState extends State { } Future getUserData() async { + if (!mounted) return; String url; await MihUserServices().getUserDetails( context, ); + if (!mounted) return; url = await MihFileApi.getMinioFileUrl( context.read().user!.pro_pic_path, context, @@ -164,6 +194,7 @@ class _MihHomeState extends State { } Future getUserConsentStatus() async { + if (!mounted) return; await MihUserConsentServices().getUserConsentStatus(context); } @@ -175,9 +206,6 @@ class _MihHomeState extends State { @override void initState() { super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) async { - _loadInitialData(); - }); if (context.read().personalHome == true) { _selcetedIndex = 0; _personalHome = true; @@ -185,6 +213,7 @@ class _MihHomeState extends State { _selcetedIndex = 1; _personalHome = false; } + _loadInitialData(); } List getToolTitle() { @@ -211,28 +240,39 @@ class _MihHomeState extends State { // showPolicyWindow(mzansiProfileProvider.userConsent); return Stack( children: [ - MihPackage( - appActionButton: - getAction(mzansiProfileProvider.userProfilePicUrl as String), - appTools: - getTools(mzansiProfileProvider.user!.type != "personal"), - appBody: getToolBody(), - appToolTitles: getToolTitle(), - actionDrawer: getActionDrawer(), - selectedbodyIndex: _selcetedIndex, - onIndexChange: (newValue) { - if (_selcetedIndex == 0) { - setState(() { - _selcetedIndex = newValue; - _personalHome = true; - }); - } else { - setState(() { - _selcetedIndex = newValue; - _personalHome = false; - }); - } + RefreshIndicator( + onRefresh: () async { + await _loadInitialData(); }, + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: MihPackage( + appActionButton: getAction( + mzansiProfileProvider.userProfilePicUrl as String), + appTools: getTools( + mzansiProfileProvider.user!.type != "personal"), + appBody: getToolBody(), + appToolTitles: getToolTitle(), + actionDrawer: getActionDrawer(), + selectedbodyIndex: _selcetedIndex, + onIndexChange: (newValue) { + if (_selcetedIndex == 0) { + setState(() { + _selcetedIndex = newValue; + _personalHome = true; + }); + } else { + setState(() { + _selcetedIndex = newValue; + _personalHome = false; + }); + } + }, + ), + ), + ), ), Visibility( visible: showPolicyWindow(mzansiProfileProvider.userConsent), @@ -443,7 +483,7 @@ class _MihHomeState extends State { imageFile: proPicUrl != "" ? NetworkImage(proPicUrl) : null, width: 50, editable: false, - fileNameController: proPicController, + fileNameController: null, userSelectedfile: null, // frameColor: frameColor, frameColor: MihColors.getSecondaryColor( @@ -452,17 +492,6 @@ class _MihHomeState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onChange: (_) {}, ), - // MIHProfilePicture( - // profilePictureFile: widget.propicFile, - // proPicController: proPicController, - // proPic: null, - // width: 45, - // radius: 21, - // drawerMode: false, - // editable: false, - // frameColor: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // onChange: (newProPic) {}, - // ), ), iconSize: 45, onTap: () { @@ -531,13 +560,7 @@ class _MihHomeState extends State { ); if (user.type != "personal") { toolBodies.add( - MihBusinessHome( - signedInUser: user, - personalSelected: _personalHome, - businessUser: businessUser, - business: business, - isBusinessUserNew: businessUser == null, - ), + MihBusinessHome(), ); } return toolBodies; diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart index b9b1ae12..140544f2 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart @@ -4,10 +4,9 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/about_mih/package_tile/about_mih_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/calculator/package_tiles/mih_calculator_tile.dart'; @@ -18,20 +17,11 @@ import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profi import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tiles/mzansi_setup_business_profile_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_manager/package_tiles/pat_manager_tile.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class MihBusinessHome extends StatefulWidget { - final AppUser signedInUser; - final bool personalSelected; - final Business? business; - final BusinessUser? businessUser; - final bool isBusinessUserNew; const MihBusinessHome({ super.key, - required this.signedInUser, - required this.personalSelected, - required this.business, - required this.businessUser, - required this.isBusinessUserNew, }); @override @@ -70,7 +60,7 @@ class _MihBusinessHomeState extends State List> temp = []; temp.add({ "Setup Business": MzansiSetupBusinessProfileTile( - signedInUser: widget.signedInUser, + signedInUser: context.read().user!, packageSize: packageSize, ) }); @@ -78,15 +68,17 @@ class _MihBusinessHomeState extends State } List> setBusinessPackages() { + MzansiProfileProvider mzansiProfileProvider = + context.read(); + if (mzansiProfileProvider.user == null || + mzansiProfileProvider.business == null || + mzansiProfileProvider.businessUser == null) { + return []; // Return empty list if data isn't ready + } List> temp = []; //=============== Biz Profile =============== temp.add({ "Business Profile": MzansiBusinessProfileTile( - arguments: BusinessArguments( - widget.signedInUser, - widget.businessUser, - widget.business, - ), packageSize: packageSize, ) }); @@ -94,10 +86,10 @@ class _MihBusinessHomeState extends State temp.add({ "Patient Manager": PatManagerTile( arguments: PatManagerArguments( - widget.signedInUser, + mzansiProfileProvider.user!, false, - widget.business, - widget.businessUser, + mzansiProfileProvider.business!, + mzansiProfileProvider.businessUser!, ), packageSize: packageSize, ) @@ -106,10 +98,10 @@ class _MihBusinessHomeState extends State temp.add({ "Calendar": MzansiCalendarTile( arguments: CalendarArguments( - widget.signedInUser, + mzansiProfileProvider.user!, false, - widget.business, - widget.businessUser, + mzansiProfileProvider.business!, + mzansiProfileProvider.businessUser!, ), packageSize: packageSize, ) @@ -124,7 +116,7 @@ class _MihBusinessHomeState extends State //=============== Calculator =============== temp.add({ "Calculator": MihCalculatorTile( - personalSelected: widget.personalSelected, + personalSelected: mzansiProfileProvider.personalHome, packageSize: packageSize, ) }); @@ -132,7 +124,7 @@ class _MihBusinessHomeState extends State temp.add({ "Mzansi AI": MzansiAiTile( arguments: MzansiAiArguments( - widget.signedInUser, + mzansiProfileProvider.user!, "", false, ), @@ -194,19 +186,11 @@ class _MihBusinessHomeState extends State void initState() { super.initState(); searchController.addListener(searchPackage); - if (widget.isBusinessUserNew) { - businessPackagesMap = setNewBusinessUserPackages(); - } else { + + WidgetsBinding.instance.addPostFrameCallback((_) { businessPackagesMap = setBusinessPackages(); - } - searchPackage(); - //Scrolling Banner message - // _marqueeController = AnimationController( - // vsync: this, - // duration: const Duration(seconds: 12), - // ); - // _scrollController = ScrollController(); - // WidgetsBinding.instance.addPostFrameCallback((_) => _startMarquee()); + searchPackage(); + }); } @override @@ -221,123 +205,113 @@ class _MihBusinessHomeState extends State } Widget getBody(double width, double height) { - return MihSingleChildScroll( - child: Column( - children: [ - // Icon( - // MihIcons.mihLogo, - // size: width / 2, - // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // const SizedBox(height: 10), - // Text( - // // "Welcome, ${widget.signedInUser.fname}!", - // "Mzansi Innovation Hub", - // textAlign: TextAlign.center, - // style: TextStyle( - // fontSize: 30, - // fontWeight: FontWeight.bold, - // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // ), - // const SizedBox(height: 20), - Visibility( - visible: !widget.isBusinessUserNew, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: width / 20), - child: MihSearchBar( - controller: searchController, - hintText: "Ask Mzansi", - prefixIcon: Icons.search, - prefixAltIcon: MihIcons.mzansiAi, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - hintColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onPrefixIconTap: () { - context.goNamed( - "mzansiAi", - extra: MzansiAiArguments( - widget.signedInUser, - searchController.text.isEmpty - ? null - : searchController.text, - false, - ), - ); - // Navigator.of(context).pushNamed( - // '/mzansi-ai', - // arguments: MzansiAiArguments( - // widget.signedInUser, - // searchController.text.isEmpty - // ? null - // : searchController.text, - // ), - // ); - searchController.clear(); - }, - searchFocusNode: _searchFocusNode, - ), - ), - ), - const SizedBox(height: 20), - ValueListenableBuilder( - valueListenable: searchPackageName, - builder: (context, value, child) { - List filteredPackages = value - .where((package) => package.keys.first - .toLowerCase() - .contains(searchController.text.toLowerCase())) - .map((package) => package.values.first) - .toList(); - if (filteredPackages.isNotEmpty) { - return GridView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: getPadding(width, height), - // shrinkWrap: true, - itemCount: filteredPackages.length, - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: packageSize, - crossAxisSpacing: 5, - ), - itemBuilder: (context, index) { - return filteredPackages[index]; - }, - ); - } else { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 50), - Icon( - MihIcons.mzansiAi, - size: 165, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - const SizedBox(height: 10), - Text( - "Mzansi AI is here to help you!", - textAlign: TextAlign.center, - overflow: TextOverflow.visible, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + if (mzansiProfileProvider.business == null) { + return Center( + child: Mihloadingcircle(), + ); + } + return MihSingleChildScroll( + child: Column( + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: searchController, + hintText: "Ask Mzansi", + prefixIcon: Icons.search, + prefixAltIcon: MihIcons.mzansiAi, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + hintColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onPrefixIconTap: () { + context.goNamed( + "mzansiAi", + extra: MzansiAiArguments( + mzansiProfileProvider.user!, + searchController.text.isEmpty + ? null + : searchController.text, + false, ), - ), - ], - ); - } - }, + ); + // Navigator.of(context).pushNamed( + // '/mzansi-ai', + // arguments: MzansiAiArguments( + // widget.signedInUser, + // searchController.text.isEmpty + // ? null + // : searchController.text, + // ), + // ); + searchController.clear(); + }, + searchFocusNode: _searchFocusNode, + ), + ), + const SizedBox(height: 20), + ValueListenableBuilder( + valueListenable: searchPackageName, + builder: (context, value, child) { + List filteredPackages = value + .where((package) => package.keys.first + .toLowerCase() + .contains(searchController.text.toLowerCase())) + .map((package) => package.values.first) + .toList(); + if (filteredPackages.isNotEmpty) { + return GridView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: getPadding(width, height), + // shrinkWrap: true, + itemCount: filteredPackages.length, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: packageSize, + crossAxisSpacing: 5, + ), + itemBuilder: (context, index) { + return filteredPackages[index]; + }, + ); + } else { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.mzansiAi, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + const SizedBox(height: 10), + Text( + "Mzansi AI is here to help you!", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ], + ); + } + }, + ), + ], ), - ], - ), + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart index d4268a57..fa7fe96a 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart @@ -1,33 +1,15 @@ -import 'dart:convert'; - -import 'package:flutter_speed_dial/flutter_speed_dial.dart'; -import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_employee.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_delete_message.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_edit_employee_details_window.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_employee.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:supertokens_flutter/http.dart' as http; class BuildEmployeeList extends StatefulWidget { - final List employees; - const BuildEmployeeList({ super.key, - required this.employees, }); @override @@ -35,339 +17,20 @@ class BuildEmployeeList extends StatefulWidget { } class _BuildEmployeeListState extends State { - TextEditingController accessController = TextEditingController(); - TextEditingController typeController = TextEditingController(); - TextEditingController fnameController = TextEditingController(); - TextEditingController lnameController = TextEditingController(); - - final _formKey = GlobalKey(); final baseAPI = AppEnviroment.baseApiUrl; - Future updateEmployeeAPICall(int index) async { - showDialog( - context: context, - builder: (context) { - return const Mihloadingcircle(); - }, - ); - - var response = await http.put( - Uri.parse("$baseAPI/business-user/employees/update/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "business_id": widget.employees[index].business_id, - "app_id": widget.employees[index].app_id, - "title": typeController.text, - "access": accessController.text, - }), - ); - if (response.statusCode == 200) { - // Navigator.of(context).pop(); - // Navigator.of(context).pop(); - // Navigator.of(context).pop(); - // //setState(() {}); - // Navigator.of(context).pushNamed( - // '/business-profile/manage', - // arguments: BusinessArguments( - // widget.arguments.signedInUser, - // widget.arguments.businessUser, - // widget.arguments.business, - // ), - // ); - String message = "Your employees details have been updated."; - successPopUp(message, false); - } else { - internetConnectionPopUp(); - } - } - - Future deleteNoteApiCall(int index) async { - var response = await http.delete( - Uri.parse("$baseAPI/business-user/employees/delete/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "business_id": widget.employees[index].business_id, - "app_id": widget.employees[index].app_id, - }), - ); - //print("Here4"); - //print(response.statusCode); - if (response.statusCode == 200) { - // Navigator.of(context).pop(); - // Navigator.of(context).pop(); - // Navigator.of(context).pop(); - // Navigator.of(context).pushNamed( - // '/business-profile/manage', - // arguments: BusinessArguments( - // widget.arguments.signedInUser, - // widget.arguments.businessUser, - // widget.arguments.business, - // ), - // ); - String message = - "The employee has been deleted successfully. This means they will no longer have access to your business profile"; - successPopUp(message, false); - } else { - internetConnectionPopUp(); - } - } - - void successPopUp(String message, bool stayOnPersonalSide) { - showDialog( - context: context, - builder: (context) { - return MihPackageAlert( - alertIcon: Icon( - Icons.check_circle_outline_rounded, - size: 150, - color: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - alertTitle: "Successfully Updated Profile", - alertBody: Column( - children: [ - Text( - message, - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 25), - Center( - child: MihButton( - onPressed: () { - context.goNamed( - 'mihHome', - extra: stayOnPersonalSide, - ); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - elevation: 10, - width: 300, - child: Text( - "Dismiss", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ) - ], - ), - alertColour: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - // return MIHSuccessMessage( - // successType: "Success", - // successMessage: message, - // ); - }, - ); - } - - void internetConnectionPopUp() { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Internet Connection"); - }, - ); - } - - bool isRequiredFieldsCaptured() { - if (accessController.text.isEmpty || typeController.text.isEmpty) { - return false; - } else { - return true; - } - } - - void updateEmployeePopUp(int index, double width) { - setState(() { - accessController.text = widget.employees[index].access; - typeController.text = widget.employees[index].title; - fnameController.text = widget.employees[index].fname; - lnameController.text = widget.employees[index].lname; - }); + void updateEmployeePopUp(BusinessEmployee employee) { showDialog( context: context, barrierDismissible: false, - builder: (context) => MihPackageWindow( - fullscreen: false, - windowTitle: "Employee Details", - menuOptions: [ - SpeedDialChild( - child: Icon( - Icons.delete, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - label: "Delete Employee", - labelBackgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - labelStyle: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontWeight: FontWeight.bold, - ), - backgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onTap: () { - showDeleteWarning(index); - }, - ), - ], - onWindowTapClose: () { - Navigator.pop(context); - }, - windowBody: Padding( - padding: - MzansiInnovationHub.of(context)!.theme.screenType == "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.05) - : const EdgeInsets.symmetric(horizontal: 0), - child: Column( - children: [ - MihForm( - formKey: _formKey, - formFields: [ - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: fnameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "First Name", - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: lnameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Surname", - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: typeController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Title", - ), - // MihDropdownField( - // controller: typeController, - // hintText: "Title", - // dropdownOptions: const ["Doctor", "Assistant", "Other"], - // editable: true, - // enableSearch: true, - // validator: (value) { - // return MihValidationServices().isEmpty(value); - // }, - // requiredText: true, - // ), - const SizedBox(height: 10.0), - MihDropdownField( - controller: accessController, - hintText: "Access Type", - dropdownOptions: const ["Full", "Partial"], - editable: true, - enableSearch: true, - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - requiredText: true, - ), - const SizedBox(height: 20.0), - Center( - child: MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - if (isRequiredFieldsCaptured()) { - updateEmployeeAPICall(index); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage( - errorType: "Input Error"); - }, - ); - } - } else { - MihAlertServices().formNotFilledCompletely(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), - ], - ), - ), + builder: (context) => MihEditEmployeeDetailsWindow( + employee: employee, ), ); } - void showDeleteWarning(int index) { - showDialog( - context: context, - barrierDismissible: false, - builder: (context) => MIHDeleteMessage( - deleteType: "Employee", - onTap: () { - deleteNoteApiCall(index); - })); - } - - @override - void dispose() { - accessController.dispose(); - typeController.dispose(); - fnameController.dispose(); - lnameController.dispose(); - super.dispose(); - } - @override Widget build(BuildContext context) { - double screenWidth = MediaQuery.of(context).size.width; return Consumer( builder: (BuildContext context, MzansiProfileProvider mzansiProfileProvider, Widget? child) { @@ -380,27 +43,29 @@ class _BuildEmployeeListState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ); }, - itemCount: widget.employees.length, + itemCount: mzansiProfileProvider.employeeList!.length, itemBuilder: (context, index) { //final patient = widget.patients[index].id_no.contains(widget.searchString); //print(index); - var isMe = ""; + BusinessEmployee employee = + mzansiProfileProvider.employeeList![index]; + String isMe = ""; if (mzansiProfileProvider.user!.app_id == - widget.employees[index].app_id) { + mzansiProfileProvider.employeeList![index].app_id) { isMe = "(You)"; } return ListTile( title: Text( - "${widget.employees[index].fname} ${widget.employees[index].lname} - ${widget.employees[index].title} $isMe"), + "${mzansiProfileProvider.employeeList![index].fname} ${mzansiProfileProvider.employeeList![index].lname} - ${mzansiProfileProvider.employeeList![index].title} $isMe"), subtitle: Text( - "${widget.employees[index].username}\n${widget.employees[index].email}\nAccess: ${widget.employees[index].access}", + "${mzansiProfileProvider.employeeList![index].username}\n${mzansiProfileProvider.employeeList![index].email}\nAccess: ${mzansiProfileProvider.employeeList![index].access}", style: TextStyle( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), ), onTap: () { - updateEmployeePopUp(index, screenWidth); + updateEmployeePopUp(employee); }, ); }, diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart index c1c6e870..2bfa71d1 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart @@ -1,32 +1,18 @@ -import 'dart:convert'; - -import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_add_employee_window.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:flutter/material.dart'; -import 'package:supertokens_flutter/http.dart' as http; +import 'package:provider/provider.dart'; class BuildUserList extends StatefulWidget { final List users; - final BusinessArguments arguments; const BuildUserList({ super.key, required this.users, - required this.arguments, }); @override @@ -34,133 +20,8 @@ class BuildUserList extends StatefulWidget { } class _BuildUserListState extends State { - TextEditingController accessController = TextEditingController(); - TextEditingController typeController = TextEditingController(); - TextEditingController usernameController = TextEditingController(); - TextEditingController emailController = TextEditingController(); - - final _formKey = GlobalKey(); final baseAPI = AppEnviroment.baseApiUrl; - Future createBusinessUserAPICall(int index) async { - showDialog( - context: context, - builder: (context) { - return const Mihloadingcircle(); - }, - ); - var response = await http.post( - Uri.parse("$baseAPI/business-user/insert/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "business_id": widget.arguments.business!.business_id, - "app_id": widget.users[index].app_id, - "signature": "", - "sig_path": "", - "title": "", - "access": accessController.text, - }), - ); - if (response.statusCode == 201) { - // Navigator.of(context).pop(); - // Navigator.of(context).pop(); - // Navigator.of(context).pop(); - // Navigator.of(context).pushNamed( - // '/business-profile/manage', - // arguments: BusinessArguments( - // widget.arguments.signedInUser, - // widget.arguments.businessUser, - // widget.arguments.business, - // ), - // ); - String message = - "${widget.users[index].username} is now apart of your team with ${accessController.text} access to ${widget.arguments.business!.Name}"; - successPopUp(message, false); - } else { - internetConnectionPopUp(); - } - } - - void successPopUp(String message, bool stayOnPersonalSide) { - showDialog( - context: context, - builder: (context) { - return MihPackageAlert( - alertIcon: Icon( - Icons.check_circle_outline_rounded, - size: 150, - color: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - alertTitle: "Successfully Updated Profile", - alertBody: Column( - children: [ - Text( - message, - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 25), - Center( - child: MihButton( - onPressed: () { - context.goNamed( - 'mihHome', - extra: stayOnPersonalSide, - ); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - elevation: 10, - width: 300, - child: Text( - "Dismiss", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ) - ], - ), - alertColour: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - // return MIHSuccessMessage( - // successType: "Success", - // successMessage: message, - // ); - }, - ); - } - - bool isRequiredFieldsCaptured() { - if (accessController.text.isEmpty) { - return false; - } else { - return true; - } - } - - void internetConnectionPopUp() { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Internet Connection"); - }, - ); - } - String hideEmail(String email) { var firstLetter = email[0]; var end = email.split("@")[1]; @@ -168,180 +29,50 @@ class _BuildUserListState extends State { } void addEmployeePopUp(int index, double width) { - setState(() { - //accessController.text = widget.users[index].access; - //typeController.text = widget.users[index].title; - // var fnameInitial = widget.users[index].fname[0]; - // var lnameInitial = widget.users[index].lname[0]; - usernameController.text = widget.users[index].username; - emailController.text = hideEmail(widget.users[index].email); - }); showDialog( - context: context, - barrierDismissible: false, - builder: (context) => MihPackageWindow( - fullscreen: false, - windowTitle: "Add Employee", - windowBody: Padding( - padding: - MzansiInnovationHub.of(context)!.theme.screenType == "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.05) - : const EdgeInsets.symmetric(horizontal: 0), - child: Column( - children: [ - MihForm( - formKey: _formKey, - formFields: [ - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: usernameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Username", - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: emailController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Email", - ), - const SizedBox(height: 10.0), - // MihTextFormField( - // fillColor: MihColors.getSecondaryColor( - // MzansiInnovationHub.of(context)!.theme.mode == - // "Dark"), - // inputColor: MihColors.getPrimaryColor( - // MzansiInnovationHub.of(context)!.theme.mode == - // "Dark"), - // controller: typeController, - // multiLineInput: false, - // requiredText: true, - // readOnly: true, - // hintText: "Title", - // ), - // MihDropdownField( - // controller: typeController, - // hintText: "Title", - // dropdownOptions: const ["Doctor", "Assistant", "Other"], - // editable: true, - // enableSearch: true, - // validator: (value) { - // return MihValidationServices().isEmpty(value); - // }, - // requiredText: true, - // ), - // const SizedBox(height: 10.0), - MihDropdownField( - controller: accessController, - hintText: "Access Type", - dropdownOptions: const ["Full", "Partial"], - editable: true, - enableSearch: true, - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - requiredText: true, - ), - const SizedBox(height: 15.0), - Center( - child: MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - if (isRequiredFieldsCaptured()) { - createBusinessUserAPICall(index); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage( - errorType: "Input Error"); - }, - ); - } - } else { - MihAlertServices() - .formNotFilledCompletely(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Add", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), - ], - ), - ), - onWindowTapClose: () { - Navigator.pop(context); - })); - } - - @override - void dispose() { - accessController.dispose(); - typeController.dispose(); - usernameController.dispose(); - emailController.dispose(); - super.dispose(); + context: context, + barrierDismissible: false, + builder: (context) => MihAddEmployeeWindow( + user: widget.users[index], + ), + ); } @override Widget build(BuildContext context) { double screenWidth = MediaQuery.of(context).size.width; - return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (BuildContext context, index) { - return Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - }, - itemCount: widget.users.length, - itemBuilder: (context, index) { - var isYou = ""; - if (widget.arguments.signedInUser.app_id == - widget.users[index].app_id) { - isYou = "(You)"; - } - return ListTile( - title: Text("@${widget.users[index].username} $isYou"), - subtitle: Text( - "Email: ${hideEmail(widget.users[index].email)}", - style: TextStyle( + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (BuildContext context, index) { + return Divider( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - onTap: () { - addEmployeePopUp(index, screenWidth); + ); + }, + itemCount: widget.users.length, + itemBuilder: (context, index) { + var isYou = ""; + if (mzansiProfileProvider.user!.app_id == + widget.users[index].app_id) { + isYou = "(You)"; + } + return ListTile( + title: Text("@${widget.users[index].username} $isYou"), + subtitle: Text( + "Email: ${hideEmail(widget.users[index].email)}", + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + onTap: () { + addEmployeePopUp(index, screenWidth); + }, + ); }, ); }, diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_add_employee_window.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_add_employee_window.dart new file mode 100644 index 00000000..daf43813 --- /dev/null +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_add_employee_window.dart @@ -0,0 +1,250 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_business_employee_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; + +class MihAddEmployeeWindow extends StatefulWidget { + final AppUser user; + const MihAddEmployeeWindow({ + super.key, + required this.user, + }); + + @override + State createState() => _MihAddEmployeeWindowState(); +} + +class _MihAddEmployeeWindowState extends State { + TextEditingController accessController = TextEditingController(); + TextEditingController usernameController = TextEditingController(); + TextEditingController emailController = TextEditingController(); + final _formKey = GlobalKey(); + + Future createBusinessUserAPICall( + MzansiProfileProvider mzansiProfileProvider) async { + int statusCode = await MihBusinessEmployeeServices().addEmployee( + mzansiProfileProvider, + widget.user, + accessController.text, + context, + ); + if (statusCode == 201) { + String message = + "${widget.user.username} is now apart of your team with ${accessController.text} access to ${mzansiProfileProvider.business!.Name}"; + successPopUp(message, false); + } else { + internetConnectionPopUp(); + } + } + + void successPopUp(String message, bool stayOnPersonalSide) { + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + Icons.check_circle_outline_rounded, + size: 150, + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + alertTitle: "Successfully Updated Profile", + alertBody: Column( + children: [ + Text( + message, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + context.pop(); + context.pop(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + elevation: 10, + width: 300, + child: Text( + "Dismiss", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ) + ], + ), + alertColour: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + // return MIHSuccessMessage( + // successType: "Success", + // successMessage: message, + // ); + }, + ); + } + + void internetConnectionPopUp() { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Internet Connection"); + }, + ); + } + + bool isRequiredFieldsCaptured() { + if (accessController.text.isEmpty) { + return false; + } else { + return true; + } + } + + @override + void dispose() { + super.dispose(); + accessController.dispose(); + usernameController.dispose(); + emailController.dispose(); + } + + @override + void initState() { + super.initState(); + usernameController.text = widget.user.username; + emailController.text = widget.user.email; + } + + @override + Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return MihPackageWindow( + fullscreen: false, + windowTitle: "Add Employee", + windowBody: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: screenWidth * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: usernameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Username", + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: emailController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Email", + ), + const SizedBox(height: 10.0), + MihDropdownField( + controller: accessController, + hintText: "Access Type", + dropdownOptions: const ["Full", "Partial"], + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, + ), + const SizedBox(height: 15.0), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + if (isRequiredFieldsCaptured()) { + createBusinessUserAPICall(mzansiProfileProvider); + } else { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage( + errorType: "Input Error"); + }, + ); + } + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Add", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ], + ), + ), + onWindowTapClose: () { + Navigator.pop(context); + }, + ); + }, + ); + } +} diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_edit_employee_details_window.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_edit_employee_details_window.dart new file mode 100644 index 00000000..0b2bd362 --- /dev/null +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_edit_employee_details_window.dart @@ -0,0 +1,319 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_speed_dial/flutter_speed_dial.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_employee.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_delete_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_business_employee_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; + +class MihEditEmployeeDetailsWindow extends StatefulWidget { + final BusinessEmployee employee; + const MihEditEmployeeDetailsWindow({ + super.key, + required this.employee, + }); + + @override + State createState() => + _MihEditEmployeeDetailsWindowState(); +} + +class _MihEditEmployeeDetailsWindowState + extends State { + TextEditingController accessController = TextEditingController(); + TextEditingController titleController = TextEditingController(); + TextEditingController fnameController = TextEditingController(); + TextEditingController lnameController = TextEditingController(); + final _formKey = GlobalKey(); + + void updateEmployeeAPICall( + MzansiProfileProvider mzansiProfileProvider) async { + int statusCode = await MihBusinessEmployeeServices().updateEmployeeDetails( + mzansiProfileProvider, + widget.employee, + titleController.text, + accessController.text, + context); + if (statusCode == 200) { + String message = "Your employees details have been updated."; + successPopUp(message, false); + } else { + internetConnectionPopUp(); + } + } + + Future deleteNoteApiCall() async { + int statusCode = await MihBusinessEmployeeServices().deleteEmployee( + context.read(), + widget.employee, + context, + ); + if (statusCode == 200) { + String message = + "The employee has been deleted successfully. This means they will no longer have access to your business profile"; + successPopUp(message, false); + } else { + internetConnectionPopUp(); + } + } + + void showDeleteWarning() { + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => MIHDeleteMessage( + deleteType: "Employee", + onTap: () { + deleteNoteApiCall(); + })); + } + + void successPopUp(String message, bool stayOnPersonalSide) { + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + Icons.check_circle_outline_rounded, + size: 150, + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + alertTitle: "Successfully Updated Profile", + alertBody: Column( + children: [ + Text( + message, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + context.pop(); + context.pop(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + elevation: 10, + width: 300, + child: Text( + "Dismiss", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ) + ], + ), + alertColour: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + // return MIHSuccessMessage( + // successType: "Success", + // successMessage: message, + // ); + }, + ); + } + + void internetConnectionPopUp() { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Internet Connection"); + }, + ); + } + + bool isRequiredFieldsCaptured() { + if (accessController.text.isEmpty || titleController.text.isEmpty) { + return false; + } else { + return true; + } + } + + @override + void dispose() { + accessController.dispose(); + titleController.dispose(); + fnameController.dispose(); + lnameController.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + fnameController.text = widget.employee.fname; + lnameController.text = widget.employee.lname; + titleController.text = widget.employee.title; + accessController.text = widget.employee.access; + } + + @override + Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return MihPackageWindow( + fullscreen: false, + windowTitle: "Employee Details", + menuOptions: [ + SpeedDialChild( + child: Icon( + Icons.delete, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + label: "Delete Employee", + labelBackgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onTap: () { + showDeleteWarning(); + }, + ), + ], + onWindowTapClose: () { + Navigator.pop(context); + }, + windowBody: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: screenWidth * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: fnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "First Name", + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: lnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Surname", + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: titleController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Title", + ), + const SizedBox(height: 10.0), + MihDropdownField( + controller: accessController, + hintText: "Access Type", + dropdownOptions: const ["Full", "Partial"], + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, + ), + const SizedBox(height: 20.0), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + if (isRequiredFieldsCaptured()) { + updateEmployeeAPICall(mzansiProfileProvider); + } else { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage( + errorType: "Input Error"); + }, + ); + } + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart index 1baef840..de297b57 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart @@ -1,18 +1,16 @@ -import 'dart:convert'; - import 'package:go_router/go_router.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_employee.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; -import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_reviews.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_team.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart'; import 'package:provider/provider.dart'; -import 'package:supertokens_flutter/http.dart' as http; class MzansiBusinessProfile extends StatefulWidget { const MzansiBusinessProfile({ @@ -24,40 +22,6 @@ class MzansiBusinessProfile extends StatefulWidget { } class _MzansiBusinessProfileState extends State { - String errorCode = ""; - String errorBody = ""; - - Future fetchEmployees() async { - //print("Patien manager page: $endpoint"); - MzansiProfileProvider mzansiProfileProvider = - context.read(); - final response = await http.get(Uri.parse( - "${AppEnviroment.baseApiUrl}/business-user/employees/${mzansiProfileProvider.businessUser!.business_id}")); - errorCode = response.statusCode.toString(); - errorBody = response.body; - if (response.statusCode == 200) { - //print("Here1"); - Iterable l = jsonDecode(response.body); - //print("Here2"); - List employeeList = List.from( - l.map((model) => BusinessEmployee.fromJson(model))); - mzansiProfileProvider.setEmployeeList(employeeList: employeeList); - //print("Here3"); - //print(patientQueue); - // return patientQueue; - } else { - throw Exception('failed to load employees'); - } - } - - @override - void initState() { - super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) async { - await fetchEmployees(); - }); - } - @override Widget build(BuildContext context) { return MihPackage( @@ -82,6 +46,7 @@ class _MzansiBusinessProfileState extends State { extra: false, ); FocusScope.of(context).unfocus(); + context.read().setBusinessIndex(0); }, ); } @@ -97,15 +62,15 @@ class _MzansiBusinessProfileState extends State { temp[const Icon(Icons.people)] = () { context.read().setBusinessIndex(2); }; - // temp[const Icon(Icons.add)] = () { - // context.read().setBusinessIndex(3); - // }; - // temp[const Icon(Icons.star_rate_rounded)] = () { - // context.read().setBusinessIndex(4); - // }; - // temp[const Icon(Icons.qr_code_rounded)] = () { - // context.read().setBusinessIndex(5); - // }; + temp[const Icon(Icons.add)] = () { + context.read().setBusinessIndex(3); + }; + temp[const Icon(Icons.star_rate_rounded)] = () { + context.read().setBusinessIndex(4); + }; + temp[const Icon(Icons.qr_code_rounded)] = () { + context.read().setBusinessIndex(5); + }; return MihPackageTools( tools: temp, selcetedIndex: context.watch().businessIndex, @@ -117,12 +82,13 @@ class _MzansiBusinessProfileState extends State { MihBusinessDetails(), MihMyBusinessUser(), MihMyBusinessTeam(), - // MihBusinessUserSearch(arguments: widget.arguments), - // MihBusinessReviews(business: widget.arguments.business!), - // MihBusinessQrCode( - // business: widget.arguments.business!, - // startUpSearch: "", - // ), + MihBusinessUserSearch(), + MihBusinessReviews( + business: context.watch().business!), + MihBusinessQrCode( + business: context.watch().business!, + startUpSearch: "", + ), ]; return toolBodies; } @@ -132,9 +98,9 @@ class _MzansiBusinessProfileState extends State { "Profile", "User", "Team", - // "Add", - // "Reviews", - // "Share", + "Add", + "Reviews", + "Share", ]; return toolTitles; } diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_set_up_business_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_set_up_business_profile.dart new file mode 100644 index 00000000..4449a393 --- /dev/null +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_set_up_business_profile.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_set_up.dart'; +import 'package:provider/provider.dart'; + +class MzansiSetUpBusinessProfile extends StatefulWidget { + const MzansiSetUpBusinessProfile({super.key}); + + @override + State createState() => + _MzansiSetUpBusinessProfileState(); +} + +class _MzansiSetUpBusinessProfileState + extends State { + @override + Widget build(BuildContext context) { + return MihPackage( + appActionButton: getAction(), + appTools: getTools(), + appBody: getToolBody(), + appToolTitles: getToolTitle(), + selectedbodyIndex: context.watch().businessIndex, + onIndexChange: (newIndex) { + context.read().setBusinessIndex(newIndex); + }, + ); + } + + MihPackageAction getAction() { + return MihPackageAction( + icon: const Icon(Icons.arrow_back), + iconSize: 35, + onTap: () { + context.goNamed( + 'mihHome', + ); + FocusScope.of(context).unfocus(); + context.read().setBusinessIndex(0); + }, + ); + } + + MihPackageTools getTools() { + Map temp = {}; + temp[const Icon(Icons.business)] = () { + context.read().setBusinessIndex(0); + }; + return MihPackageTools( + tools: temp, + selcetedIndex: context.watch().businessIndex, + ); + } + + List getToolTitle() { + List toolTitles = [ + "Set Up Profile", + ]; + return toolTitles; + } + + List getToolBody() { + List toolBodies = [ + MihBusinessDetailsSetUp(), + ]; + return toolBodies; + } +} diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tiles/mzansi_business_profile_tile.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tiles/mzansi_business_profile_tile.dart index abd349c7..96d782bf 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tiles/mzansi_business_profile_tile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tiles/mzansi_business_profile_tile.dart @@ -2,16 +2,13 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; class MzansiBusinessProfileTile extends StatefulWidget { - final BusinessArguments arguments; final double packageSize; const MzansiBusinessProfileTile({ super.key, - required this.arguments, required this.packageSize, }); @@ -27,7 +24,6 @@ class _MzansiBusinessProfileTileState extends State { onTap: () { context.goNamed( "businessProfileManage", - extra: widget.arguments, ); // Navigator.of(context).pushNamed( // '/business-profile/manage', diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/profile_business_add.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_set_up.dart similarity index 81% rename from Frontend/lib/mih_packages/mzansi_profile/business_profile/profile_business_add.dart rename to Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_set_up.dart index 550d5fd0..ab37bd22 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/profile_business_add.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_set_up.dart @@ -1,53 +1,43 @@ -import 'dart:convert'; - import 'package:country_code_picker/country_code_picker.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:http/http.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_image_display.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_location_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_my_business_user_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_action.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_body.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_header.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_layout_builder.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:file_picker/file_picker.dart'; +import 'package:provider/provider.dart'; -class ProfileBusinessAdd extends StatefulWidget { - //final BusinessUserScreenArguments arguments; - final AppUser signedInUser; - const ProfileBusinessAdd({ - super.key, - required this.signedInUser, - }); +class MihBusinessDetailsSetUp extends StatefulWidget { + const MihBusinessDetailsSetUp({super.key}); @override - State createState() => _ProfileBusinessAddState(); + State createState() => + _MihBusinessDetailsSetUpState(); } -class _ProfileBusinessAddState extends State { - final FocusNode _focusNode = FocusNode(); - final baseAPI = AppEnviroment.baseApiUrl; - +class _MihBusinessDetailsSetUpState extends State { final nameController = TextEditingController(); final typeController = TextEditingController(); final regController = TextEditingController(); final addressController = TextEditingController(); - final logonameController = TextEditingController(); final fnameController = TextEditingController(); final lnameController = TextEditingController(); final titleController = TextEditingController(); @@ -62,65 +52,33 @@ class _ProfileBusinessAddState extends State { final websiteController = TextEditingController(); final ratingController = TextEditingController(); final missionVisionController = TextEditingController(); - - ImageProvider? logoPreview; - ImageProvider? signaturePreview; - PlatformFile? selectedLogo; - PlatformFile? selectedSignature; - + final logoFileNameController = TextEditingController(); + PlatformFile? newSelectedLogoPic; + PlatformFile? newSelectedSignaturePic; + final FocusNode _focusNode = FocusNode(); + final _formKey = GlobalKey(); final ValueNotifier _counter = ValueNotifier(0); final ValueNotifier busType = ValueNotifier(""); - final _formKey = GlobalKey(); late String env; - Future uploadFile(String id, PlatformFile? selectedFile) async { - print("Inside uploud file method"); - int uploadStatusCode = 0; - uploadStatusCode = await MihFileApi.uploadFile( - id, - env, - "business_files", - selectedFile, - context, - ); - print("Status code: $uploadStatusCode"); - if (uploadStatusCode == 200) { - return true; + void submitForm(MzansiProfileProvider mzansiProfileProvider) { + if (isFieldsFilled()) { + createBusinessProfileAPICall(mzansiProfileProvider); } else { - return false; + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Input Error"); + }, + ); } } - Future createBusinessUserAPICall(String business_id) async { - print("Inside create bus user method"); - int statusCode = await MihMyBusinessUserServices().createBusinessUser( - business_id, - widget.signedInUser.app_id, - signtureController.text, - titleController.text, - accessController.text, - context, - ); - print("Status code: $statusCode"); - if (statusCode == 201) { - // Navigator.of(context).pop(); - // Navigator.of(context).popAndPushNamed( - // '/', - // arguments: AuthArguments(false, false), - // ); - String message = - "Your business profile is now live! You can now start connecting with customers and growing your business."; - successPopUp(message, false); - } else { - internetConnectionPopUp(); - } - } - - Future createBusinessProfileAPICall() async { - print("Inside create business profile method"); + Future createBusinessProfileAPICall( + MzansiProfileProvider mzansiProfileProvider) async { Response response = await MihBusinessDetailsServices().createBusinessDetails( - widget.signedInUser.app_id, + mzansiProfileProvider, nameController.text, typeController.text, regController.text, @@ -128,23 +86,87 @@ class _ProfileBusinessAddState extends State { vatNoController.text, emailController.text, getNumberWithCountryCode(), - // "${countryCodeController.text}-${contactController.text}", locationController.text, - logonameController.text, + logoFileNameController.text, websiteController.text, "0", missionVisionController.text, context, ); - print(response.body); if (response.statusCode == 201) { - var businessResponse = jsonDecode(response.body); - createBusinessUserAPICall(businessResponse['business_id']); + bool successUpload = + await uploadFile(mzansiProfileProvider, newSelectedLogoPic); + if (successUpload) { + String logoUrl = await MihFileApi.getMinioFileUrl( + mzansiProfileProvider.business!.logo_path, context); + mzansiProfileProvider.setBusinessProfilePicUrl(logoUrl); + } + await createBusinessUserAPICall(mzansiProfileProvider); } else { internetConnectionPopUp(); } } + Future createBusinessUserAPICall( + MzansiProfileProvider mzansiProfileProvider) async { + int statusCode = await MihMyBusinessUserServices().createBusinessUser( + mzansiProfileProvider.business!.business_id, + mzansiProfileProvider.user!.app_id, + signtureController.text, + titleController.text, + accessController.text, + mzansiProfileProvider, + context, + ); + if (statusCode == 201) { + bool successUpload = + await uploadFile(mzansiProfileProvider, newSelectedSignaturePic); + if (successUpload) { + String sigUrl = await MihFileApi.getMinioFileUrl( + mzansiProfileProvider.businessUser!.sig_path, context); + mzansiProfileProvider.setBusinessUserSignatureUrl(sigUrl); + String message = + "Your business profile is now live! You can now start connecting with customers and growing your business."; + successPopUp(message, false); + } else { + internetConnectionPopUp(); + } + } else { + internetConnectionPopUp(); + } + } + + Future uploadFile( + MzansiProfileProvider mzansiProfileProvider, PlatformFile? image) async { + if (newSelectedLogoPic != null) { + int uploadStatusCode = 0; + uploadStatusCode = await MihFileApi.uploadFile( + mzansiProfileProvider.business!.business_id, + env, + "business_files", + image, + context, + ); + if (uploadStatusCode == 200) { + return true; + } else { + return false; + } + } else { + return true; // No file selected, so no upload needed + } + } + + bool isFieldsFilled() { + if (typeController.text.isEmpty || + titleController.text.isEmpty || + accessController.text.isEmpty) { + return false; + } else { + return true; + } + } + String getNumberWithCountryCode() { String numberWithoutBeginingZero = ""; if (contactController.text[0] == "0") { @@ -157,13 +179,22 @@ class _ProfileBusinessAddState extends State { return "${countryCodeController.text}-$numberWithoutBeginingZero"; } - void internetConnectionPopUp() { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Internet Connection"); - }, - ); + Color getMissionVisionLimitColor(int limit) { + if (_counter.value <= limit) { + return MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + } else { + return MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + } + } + + void typeSelected() { + if (typeController.text.isNotEmpty) { + busType.value = typeController.text; + } else { + busType.value = ""; + } } void successPopUp(String message, bool stayOnPersonalSide) { @@ -227,110 +258,90 @@ class _ProfileBusinessAddState extends State { ); } - bool isFieldsFilled() { - if (typeController.text.isEmpty || - titleController.text.isEmpty || - accessController.text.isEmpty) { - return false; - } else { - return true; - } - } - - void submitForm() { - if (isFieldsFilled()) { - print("Inside submit method"); - createBusinessProfileAPICall(); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Input Error"); - }, - ); - } - } - - void emailError() { + void internetConnectionPopUp() { showDialog( context: context, builder: (context) { - return const MIHErrorMessage(errorType: "Invalid Email"); + return const MIHErrorMessage(errorType: "Internet Connection"); }, ); } - bool isEmailValid() { - String text = emailController.text; - var regex = RegExp(r'^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$'); - return regex.hasMatch(text); - } - - // bool validEmail() { - // String text = emailController.text; - // var regex = RegExp(r'^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$'); - // return regex.hasMatch(text); - // } - - void typeSelected() { - if (typeController.text.isNotEmpty) { - busType.value = typeController.text; + void initialiseControlers(MzansiProfileProvider mzansiProfileProvider) { + typeController.addListener(typeSelected); + setState(() { + fnameController.text = mzansiProfileProvider.user!.fname; + lnameController.text = mzansiProfileProvider.user!.lname; + accessController.text = "Full"; + countryCodeController.text = "+27"; + }); + if (AppEnviroment.getEnv() == "Prod") { + env = "Prod"; } else { - busType.value = ""; + env = "Dev"; } + missionVisionController.addListener(() { + setState(() { + _counter.value = missionVisionController.text.characters.length; + }); + }); } - MIHAction getActionButton() { - return MIHAction( - icon: const Icon(Icons.arrow_back), - iconSize: 35, - onTap: () { - // Navigator.of(context).pop(); - context.goNamed( - 'mihHome', - extra: true, - ); - }, - ); + @override + void dispose() { + typeController.removeListener(typeSelected); + nameController.dispose(); + typeController.dispose(); + regController.dispose(); + addressController.dispose(); + fnameController.dispose(); + lnameController.dispose(); + titleController.dispose(); + signtureController.dispose(); + accessController.dispose(); + countryCodeController.dispose(); + contactController.dispose(); + emailController.dispose(); + locationController.dispose(); + practiceNoController.dispose(); + vatNoController.dispose(); + websiteController.dispose(); + ratingController.dispose(); + missionVisionController.dispose(); + logoFileNameController.dispose(); + busType.dispose(); + _focusNode.dispose(); + _counter.dispose(); + super.dispose(); } - MIHHeader getHeader() { - return const MIHHeader( - headerAlignment: MainAxisAlignment.center, - headerItems: [ - Text( - "Set Up Business Profile", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 25, - ), - ), - ], - ); + @override + void initState() { + super.initState(); + initialiseControlers(context.read()); } - Color getMissionVisionLimitColor(int limit) { - if (_counter.value <= limit) { - return MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"); - } else { - return MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"); - } - } - - MIHBody getBody(double width) { - return MIHBody( + @override + Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; + return MihPackageToolBody( borderOn: false, - bodyItems: [ - KeyboardListener( + bodyItem: getBody(screenWidth), + ); + } + + Widget getBody(double width) { + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return KeyboardListener( focusNode: _focusNode, autofocus: true, onKeyEvent: (event) async { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.enter) { if (_formKey.currentState!.validate()) { - submitForm(); + submitForm(mzansiProfileProvider); } else { MihAlertServices().formNotFilledCompletely(context); } @@ -345,7 +356,7 @@ class _ProfileBusinessAddState extends State { child: Column( children: [ const Text( - "My Business Details", + "Business Details", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 25, @@ -359,6 +370,29 @@ class _ProfileBusinessAddState extends State { MihForm( formKey: _formKey, formFields: [ + Center( + child: MihCircleAvatar( + imageFile: newSelectedLogoPic != null + ? MemoryImage(newSelectedLogoPic!.bytes!) + : mzansiProfileProvider.businessProfilePicture, + width: 150, + editable: true, + fileNameController: logoFileNameController, + userSelectedfile: newSelectedLogoPic, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: (selectedfile) { + setState(() { + newSelectedLogoPic = selectedfile; + }); + }, + ), + ), + const SizedBox(height: 20), MihTextFormField( fillColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == @@ -644,7 +678,7 @@ class _ProfileBusinessAddState extends State { //const SizedBox(height: 15.0), const Center( child: Text( - "My Business User", + "Business User", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 22, @@ -716,7 +750,7 @@ class _ProfileBusinessAddState extends State { return MihValidationServices().isEmpty(value); }, ), - const SizedBox(height: 15.0), + const SizedBox(height: 10.0), MihTextFormField( fillColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == @@ -733,23 +767,41 @@ class _ProfileBusinessAddState extends State { return MihValidationServices().isEmpty(value); }, ), - // MihDropdownField( - // controller: accessController, - // hintText: "Access Type", - // dropdownOptions: const ["Full", "Partial"], - // editable: false, - // enableSearch: true, - // validator: (value) { - // return MihValidationServices().isEmpty(value); - // }, - // requiredText: true, - // ), + const SizedBox(height: 10), + Container( + width: 300, + alignment: Alignment.topLeft, + child: const Text( + "Signature:", + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + Center( + child: MihImageDisplay( + imageFile: newSelectedSignaturePic != null + ? MemoryImage(newSelectedSignaturePic!.bytes!) + : mzansiProfileProvider.businessUserSignature, + width: 300, + height: 200, + editable: true, + fileNameController: signtureController, + userSelectedfile: newSelectedSignaturePic, + onChange: (selectedFile) { + setState(() { + newSelectedSignaturePic = selectedFile; + }); + }, + ), + ), const SizedBox(height: 20.0), Center( child: MihButton( onPressed: () { if (_formKey.currentState!.validate()) { - submitForm(); + submitForm(mzansiProfileProvider); } else { MihAlertServices() .formNotFilledCompletely(context); @@ -771,72 +823,15 @@ class _ProfileBusinessAddState extends State { ), ), ), + const SizedBox(height: 30), ], ), ], ), ), ), - ), - ], - ); - } - - @override - void dispose() { - nameController.dispose(); - typeController.dispose(); - regController.dispose(); - logonameController.dispose(); - fnameController.dispose(); - lnameController.dispose(); - titleController.dispose(); - signtureController.dispose(); - accessController.dispose(); - contactController.dispose(); - emailController.dispose(); - locationController.dispose(); - practiceNoController.dispose(); - vatNoController.dispose(); - _focusNode.dispose(); - super.dispose(); - } - - @override - void initState() { - super.initState(); - typeController.addListener(typeSelected); - setState(() { - fnameController.text = widget.signedInUser.fname; - lnameController.text = widget.signedInUser.lname; - accessController.text = "Full"; - countryCodeController.text = "+27"; - }); - if (AppEnviroment.getEnv() == "Prod") { - env = "Prod"; - } else { - env = "Dev"; - } - missionVisionController.addListener(() { - setState(() { - _counter.value = missionVisionController.text.characters.length; - }); - }); - } - - @override - Widget build(BuildContext context) { - double screenWidth = MediaQuery.of(context).size.width; - return MIHLayoutBuilder( - actionButton: getActionButton(), - secondaryActionButton: null, - header: getHeader(), - body: getBody(screenWidth), - actionDrawer: null, - secondaryActionDrawer: null, - bottomNavBar: null, - pullDownToRefresh: false, - onPullDown: () async {}, + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart index 96592644..577efd23 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart @@ -1,4 +1,3 @@ -import 'dart:typed_data'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:file_picker/file_picker.dart'; import 'package:file_saver/file_saver.dart'; @@ -21,6 +20,7 @@ import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:screenshot/screenshot.dart'; +import 'package:share_plus/share_plus.dart'; import 'package:supertokens_flutter/supertokens.dart'; class MihBusinessQrCode extends StatefulWidget { @@ -320,6 +320,13 @@ class _MihBusinessQrCodeState extends State { ); } + void shareMIHLink(BuildContext context, String message, String link) { + String shareText = "$message: $link"; + SharePlus.instance.share( + ShareParams(text: shareText), + ); + } + @override void dispose() { super.dispose(); @@ -391,7 +398,31 @@ class _MihBusinessQrCodeState extends State { onTap: () { downloadQrCode(); }, - ) + ), + SpeedDialChild( + child: Icon( + Icons.share_rounded, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + label: "Share Business", + labelBackgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onTap: () { + shareMIHLink( + context, + "Check out ${widget.business.Name} on the MIH app", + "$qrCodedata${widget.business.business_id}", + ); + }, + ), ]), ) ], diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart index dd129042..e15563b8 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart @@ -5,17 +5,14 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; class MihBusinessUserSearch extends StatefulWidget { - final BusinessArguments arguments; const MihBusinessUserSearch({ super.key, - required this.arguments, }); @override @@ -33,18 +30,6 @@ class _MihBusinessUserSearchState extends State { Future> fetchUsers(String search) async { return MihUserServices().searchUsers(search, context); - // final response = await http - // .get(Uri.parse("${AppEnviroment.baseApiUrl}/users/search/$search")); - // errorCode = response.statusCode.toString(); - // errorBody = response.body; - // if (response.statusCode == 200) { - // Iterable l = jsonDecode(response.body); - // List users = - // List.from(l.map((model) => AppUser.fromJson(model))); - // return users; - // } else { - // throw Exception('failed to load patients'); - // } } void submitUserForm() { @@ -61,7 +46,6 @@ class _MihBusinessUserSearchState extends State { if (userList.isNotEmpty) { return BuildUserList( users: userList, - arguments: widget.arguments, ); } if (hasSearchedBefore && userSearch.isNotEmpty) { diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_team.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_team.dart index 4fb5696f..3dc774a9 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_team.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_team.dart @@ -1,16 +1,14 @@ -import 'dart:convert'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; -import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_employee.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/builders/build_employee_list.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_business_employee_services.dart'; import 'package:provider/provider.dart'; -import 'package:supertokens_flutter/http.dart' as http; class MihMyBusinessTeam extends StatefulWidget { const MihMyBusinessTeam({ @@ -25,6 +23,12 @@ class _MihMyBusinessTeamState extends State { String errorCode = ""; String errorBody = ""; + void getEmployeeData(MzansiProfileProvider mzansiProfileProvider) { + WidgetsBinding.instance.addPostFrameCallback((_) async { + await MihBusinessEmployeeServices() + .fetchEmployees(mzansiProfileProvider, context); + }); + } // Future fetchEmployees( // MzansiProfileProvider mzansiProfileProvider) async { // //print("Patien manager page: $endpoint"); @@ -49,9 +53,7 @@ class _MihMyBusinessTeamState extends State { Widget displayEmployeeList(List employeeList) { if (employeeList.isNotEmpty) { - return BuildEmployeeList( - employees: employeeList, - ); + return BuildEmployeeList(); } return Center( child: Text( @@ -87,6 +89,7 @@ class _MihMyBusinessTeamState extends State { builder: (BuildContext context, MzansiProfileProvider mzansiProfileProvider, Widget? child) { if (mzansiProfileProvider.employeeList == null) { + getEmployeeData(mzansiProfileProvider); return Center( child: Mihloadingcircle(), ); diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart new file mode 100644 index 00000000..c4b47711 --- /dev/null +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart @@ -0,0 +1,470 @@ +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; + +class MihEditPersonalProfileWindow extends StatefulWidget { + const MihEditPersonalProfileWindow({super.key}); + + @override + State createState() => + _MihEditPersonalProfileWindowState(); +} + +class _MihEditPersonalProfileWindowState + extends State { + TextEditingController proPicController = TextEditingController(); + TextEditingController usernameController = TextEditingController(); + TextEditingController fnameController = TextEditingController(); + TextEditingController lnameController = TextEditingController(); + TextEditingController purposeController = TextEditingController(); + bool _controllersInitialized = false; + final ValueNotifier _counter = ValueNotifier(0); + final _formKey = GlobalKey(); + PlatformFile? newSelectedProPic; + String oldProPicName = ""; + String env = ""; + bool businessUser = false; + + void initializeControllers(MzansiProfileProvider mzansiProfileProvider) { + businessUser = mzansiProfileProvider.user!.type == "business"; + oldProPicName = mzansiProfileProvider.user!.pro_pic_path.isNotEmpty + ? mzansiProfileProvider.user!.pro_pic_path.split("/").last + : ""; + env = AppEnviroment.getEnv() == "Prod" ? env = "Prod" : env = "Dev"; + if (!_controllersInitialized && mzansiProfileProvider.user != null) { + usernameController.text = mzansiProfileProvider.user!.username; + fnameController.text = mzansiProfileProvider.user!.fname; + lnameController.text = mzansiProfileProvider.user!.lname; + purposeController.text = mzansiProfileProvider.user!.purpose; + proPicController.text = + mzansiProfileProvider.user!.pro_pic_path.isNotEmpty + ? mzansiProfileProvider.user!.pro_pic_path.split("/").last + : ""; + businessUser = mzansiProfileProvider.user!.type == "business"; + _controllersInitialized = true; + } + } + + Future submitForm(MzansiProfileProvider mzansiProfileProvider) async { + if (mzansiProfileProvider.user!.username != usernameController.text) { + bool isUsernameUnique = await MihUserServices.isUsernameUnique( + usernameController.text, context); + if (isUsernameUnique == false) { + notUniqueAlert(); + return; + } + } + if (oldProPicName != proPicController.text) { + await uploadSelectedFile(mzansiProfileProvider, newSelectedProPic); + } + await updateUserApiCall(mzansiProfileProvider); + } + + Future updateUserApiCall( + MzansiProfileProvider mzansiProfileProvider) async { + KenLogger.success("businessUser: $businessUser"); + int responseCode = await MihUserServices().updateUserV2( + mzansiProfileProvider.user!, + fnameController.text, + lnameController.text, + usernameController.text, + proPicController.text, + purposeController.text, + businessUser, + context, + ); + if (responseCode == 200) { + setState(() { + setProfileVariables(mzansiProfileProvider); + newSelectedProPic = null; + }); + bool stayOnPersonalSide = true; + // if (originalProfileTypeIsBusiness == false && businessUser == true) { + // stayOnPersonalSide = false; + // } + String message = "Your information has been updated successfully!"; + context.pop(); + successPopUp(message, stayOnPersonalSide); + } else { + internetConnectionPopUp(); + } + } + + Future uploadSelectedFile( + MzansiProfileProvider mzansiProfileProvider, PlatformFile? file) async { + var response = await MihFileApi.uploadFile( + mzansiProfileProvider.user!.app_id, + env, + "profile_files", + file, + context, + ); + if (response == 200) { + deleteFileApiCall(mzansiProfileProvider, oldProPicName); + } else { + internetConnectionPopUp(); + } + } + + Future deleteFileApiCall( + MzansiProfileProvider mzansiProfileProvider, String filename) async { + var response = await MihFileApi.deleteFile( + mzansiProfileProvider.user!.app_id, + env, + "profile_files", + filename, + context, + ); + if (response == 200) { + //SQL delete + } else { + internetConnectionPopUp(); + } + } + + void setProfileVariables(MzansiProfileProvider mzansiProfileProvider) { + businessUser = mzansiProfileProvider.user!.type == "business"; + oldProPicName = mzansiProfileProvider.user!.pro_pic_path.isNotEmpty + ? mzansiProfileProvider.user!.pro_pic_path.split("/").last + : ""; + env = AppEnviroment.getEnv() == "Prod" ? env = "Prod" : env = "Dev"; + } + + Color getPurposeLimitColor(int limit) { + if (_counter.value <= limit) { + return MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + } else { + return MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + } + } + + void successPopUp(String message, bool stayOnPersonalSide) { + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + Icons.check_circle_outline_rounded, + size: 150, + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + alertTitle: "Successfully Updated Profile", + alertBody: Column( + children: [ + Text( + message, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + context.pop(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + elevation: 10, + width: 300, + child: Text( + "Dismiss", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ) + ], + ), + alertColour: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + // return MIHSuccessMessage( + // successType: "Success", + // successMessage: message, + // ); + }, + ); + } + + void internetConnectionPopUp() { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Internet Connection"); + }, + ); + } + + void notUniqueAlert() { + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + Icons.warning_amber_rounded, + size: 100, + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + alertTitle: "Too Slow, That Username is Taken", + alertBody: const Text( + "The username you have entered is already taken by another member of Mzansi. Please choose a different username and try again.", + style: TextStyle( + fontSize: 15, + ), + ), + alertColour: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + ); + } + + @override + void initState() { + super.initState(); + initializeControllers(context.read()); + } + + @override + Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return MihPackageWindow( + fullscreen: false, + windowTitle: "Edit Profile", + onWindowTapClose: () { + Navigator.of(context).pop(); + }, + windowBody: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: screenWidth * 0.05) + : EdgeInsets.symmetric(horizontal: screenWidth * 0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Center( + child: MihCircleAvatar( + imageFile: newSelectedProPic != null + ? MemoryImage(newSelectedProPic!.bytes!) + : mzansiProfileProvider.userProfilePicture, + width: 150, + editable: true, + fileNameController: proPicController, + userSelectedfile: newSelectedProPic, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: (selectedImage) { + setState(() { + newSelectedProPic = selectedImage; + }); + }, + ), + ), + // const SizedBox(height: 25.0), + Visibility( + visible: false, + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: proPicController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Selected File Name", + ), + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: usernameController, + multiLineInput: false, + requiredText: true, + hintText: "Username", + validator: (value) { + return MihValidationServices().validateUsername(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: fnameController, + multiLineInput: false, + requiredText: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: lnameController, + multiLineInput: false, + requiredText: true, + hintText: "Last Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + height: 250, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: purposeController, + multiLineInput: true, + requiredText: true, + hintText: "Your Personal Mission", + validator: (value) { + return MihValidationServices() + .validateLength(purposeController.text, 256); + }, + ), + SizedBox( + height: 15, + child: ValueListenableBuilder( + valueListenable: _counter, + builder: + (BuildContext context, int value, Widget? child) { + return Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "$value", + style: TextStyle( + color: getPurposeLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 5), + Text( + "/256", + style: TextStyle( + color: getPurposeLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + ], + ); + }, + ), + ), + const SizedBox(height: 10.0), + MihToggle( + hintText: "Activate Business Account", + initialPostion: businessUser, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + secondaryFillColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: (value) { + setState(() { + businessUser = value; + }); + KenLogger.success("Business User: $businessUser"); + }, + ), + const SizedBox(height: 30.0), + Center( + child: MihButton( + onPressed: () { + //Add validation here + if (_formKey.currentState!.validate()) { + submitForm(mzansiProfileProvider); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart index 965ad532..c47af691 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart @@ -1,26 +1,15 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; -import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart'; import 'package:provider/provider.dart'; class MihPersonalProfile extends StatefulWidget { @@ -32,32 +21,7 @@ class MihPersonalProfile extends StatefulWidget { class _MihPersonalProfileState extends State { TextEditingController proPicController = TextEditingController(); - TextEditingController usernameController = TextEditingController(); - TextEditingController fnameController = TextEditingController(); - TextEditingController lnameController = TextEditingController(); - TextEditingController purposeController = TextEditingController(); - final ValueNotifier _counter = ValueNotifier(0); PlatformFile? newSelectedProPic; - bool businessUser = false; - bool _controllersInitialized = false; - String env = ""; - String oldProPicName = ""; - final _formKey = GlobalKey(); - - void initializeControllers(MzansiProfileProvider mzansiProfileProvider) { - if (!_controllersInitialized && mzansiProfileProvider.user != null) { - usernameController.text = mzansiProfileProvider.user!.username; - fnameController.text = mzansiProfileProvider.user!.fname; - lnameController.text = mzansiProfileProvider.user!.lname; - purposeController.text = mzansiProfileProvider.user!.purpose; - proPicController.text = - mzansiProfileProvider.user!.pro_pic_path.isNotEmpty - ? mzansiProfileProvider.user!.pro_pic_path.split("/").last - : ""; - businessUser = mzansiProfileProvider.user!.type == "business"; - _controllersInitialized = true; - } - } void editProfileWindow(double width) { showDialog( @@ -73,401 +37,12 @@ class _MihPersonalProfileState extends State { // mzansiProfileProvider.user!.pro_pic_path.isNotEmpty // ? mzansiProfileProvider.user!.pro_pic_path.split("/").last // : ""; - initializeControllers(mzansiProfileProvider); - return MihPackageWindow( - fullscreen: false, - windowTitle: "Edit Profile", - onWindowTapClose: () { - Navigator.of(context).pop(); - }, - windowBody: Padding( - padding: - MzansiInnovationHub.of(context)!.theme.screenType == "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.05) - : EdgeInsets.symmetric(horizontal: width * 0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - MihForm( - formKey: _formKey, - formFields: [ - Center( - child: MihCircleAvatar( - imageFile: newSelectedProPic != null - ? MemoryImage(newSelectedProPic!.bytes!) - : mzansiProfileProvider.userProfilePicture, - width: 150, - editable: true, - fileNameController: proPicController, - userSelectedfile: newSelectedProPic, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: (selectedImage) { - setState(() { - newSelectedProPic = selectedImage; - }); - }, - ), - ), - // const SizedBox(height: 25.0), - Visibility( - visible: false, - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: proPicController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Selected File Name", - ), - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: usernameController, - multiLineInput: false, - requiredText: true, - hintText: "Username", - validator: (value) { - return MihValidationServices() - .validateUsername(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: fnameController, - multiLineInput: false, - requiredText: true, - hintText: "First Name", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: lnameController, - multiLineInput: false, - requiredText: true, - hintText: "Last Name", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - height: 250, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: purposeController, - multiLineInput: true, - requiredText: true, - hintText: "Your Personal Mission", - validator: (value) { - return MihValidationServices() - .validateLength(purposeController.text, 256); - }, - ), - SizedBox( - height: 15, - child: ValueListenableBuilder( - valueListenable: _counter, - builder: - (BuildContext context, int value, Widget? child) { - return Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - "$value", - style: TextStyle( - color: getPurposeLimitColor(256), - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(width: 5), - Text( - "/256", - style: TextStyle( - color: getPurposeLimitColor(256), - fontWeight: FontWeight.bold, - ), - ), - ], - ); - }, - ), - ), - const SizedBox(height: 10.0), - MihToggle( - hintText: "Activate Business Account", - initialPostion: businessUser, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - secondaryFillColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: (value) { - setState(() { - businessUser = value; - }); - }, - ), - const SizedBox(height: 30.0), - Center( - child: MihButton( - onPressed: () { - //Add validation here - if (_formKey.currentState!.validate()) { - submitForm(mzansiProfileProvider); - } else { - MihAlertServices() - .formNotFilledCompletely(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), - ], - ), - ), - ); + return MihEditPersonalProfileWindow(); }, ), ); } - Future submitForm(MzansiProfileProvider mzansiProfileProvider) async { - if (mzansiProfileProvider.user!.username != usernameController.text) { - bool isUsernameUnique = await MihUserServices.isUsernameUnique( - usernameController.text, context); - if (isUsernameUnique == false) { - notUniqueAlert(); - return; - } - } - if (oldProPicName != proPicController.text) { - await uploadSelectedFile(mzansiProfileProvider, newSelectedProPic); - } - await updateUserApiCall(mzansiProfileProvider); - } - - Future uploadSelectedFile( - MzansiProfileProvider mzansiProfileProvider, PlatformFile? file) async { - var response = await MihFileApi.uploadFile( - mzansiProfileProvider.user!.app_id, - env, - "profile_files", - file, - context, - ); - if (response == 200) { - deleteFileApiCall(mzansiProfileProvider, oldProPicName); - } else { - internetConnectionPopUp(); - } - } - - Future deleteFileApiCall( - MzansiProfileProvider mzansiProfileProvider, String filename) async { - var response = await MihFileApi.deleteFile( - mzansiProfileProvider.user!.app_id, - env, - "profile_files", - filename, - context, - ); - if (response == 200) { - //SQL delete - } else { - internetConnectionPopUp(); - } - } - - Future updateUserApiCall( - MzansiProfileProvider mzansiProfileProvider) async { - int responseCode = await MihUserServices().updateUserV2( - mzansiProfileProvider.user!, - fnameController.text, - lnameController.text, - usernameController.text, - proPicController.text, - purposeController.text, - businessUser, - context, - ); - if (responseCode == 200) { - setState(() { - setProfileVariables(mzansiProfileProvider); - newSelectedProPic = null; - }); - bool stayOnPersonalSide = true; - // if (originalProfileTypeIsBusiness == false && businessUser == true) { - // stayOnPersonalSide = false; - // } - String message = "Your information has been updated successfully!"; - context.pop(); - successPopUp(message, stayOnPersonalSide); - } else { - internetConnectionPopUp(); - } - } - - Color getPurposeLimitColor(int limit) { - if (_counter.value <= limit) { - return MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"); - } else { - return MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"); - } - } - - void setProfileVariables(MzansiProfileProvider mzansiProfileProvider) { - businessUser = mzansiProfileProvider.user!.type == "business"; - oldProPicName = mzansiProfileProvider.user!.pro_pic_path.isNotEmpty - ? mzansiProfileProvider.user!.pro_pic_path.split("/").last - : ""; - env = AppEnviroment.getEnv() == "Prod" ? env = "Prod" : env = "Dev"; - } - - void successPopUp(String message, bool stayOnPersonalSide) { - showDialog( - context: context, - builder: (context) { - return MihPackageAlert( - alertIcon: Icon( - Icons.check_circle_outline_rounded, - size: 150, - color: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - alertTitle: "Successfully Updated Profile", - alertBody: Column( - children: [ - Text( - message, - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 25), - Center( - child: MihButton( - onPressed: () { - context.pop(); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - elevation: 10, - width: 300, - child: Text( - "Dismiss", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ) - ], - ), - alertColour: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - // return MIHSuccessMessage( - // successType: "Success", - // successMessage: message, - // ); - }, - ); - } - - void internetConnectionPopUp() { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Internet Connection"); - }, - ); - } - - void notUniqueAlert() { - showDialog( - context: context, - builder: (context) { - return MihPackageAlert( - alertIcon: Icon( - Icons.warning_amber_rounded, - size: 100, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - alertTitle: "Too Slow, That Username is Taken", - alertBody: const Text( - "The username you have entered is already taken by another member of Mzansi. Please choose a different username and try again.", - style: TextStyle( - fontSize: 15, - ), - ), - alertColour: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - }, - ); - } - @override Widget build(BuildContext context) { double screenWidth = MediaQuery.of(context).size.width; @@ -492,11 +67,6 @@ class _MihPersonalProfileState extends State { // editProfileWindow(width); // } else { - businessUser = mzansiProfileProvider.user!.type == "business"; - oldProPicName = mzansiProfileProvider.user!.pro_pic_path.isNotEmpty - ? mzansiProfileProvider.user!.pro_pic_path.split("/").last - : ""; - env = AppEnviroment.getEnv() == "Prod" ? env = "Prod" : env = "Dev"; KenLogger.success( mzansiProfileProvider.userProfilePicture.toString()); return MihSingleChildScroll( @@ -559,7 +129,9 @@ class _MihPersonalProfileState extends State { ), FittedBox( child: Text( - businessUser == true ? "Business" : "Personal", + mzansiProfileProvider.user!.type == "business" + ? "Business".toUpperCase() + : "Personal".toUpperCase(), style: TextStyle( fontSize: 15, fontWeight: FontWeight.bold, diff --git a/Frontend/lib/mih_services/mih_business_details_services.dart b/Frontend/lib/mih_services/mih_business_details_services.dart index 6b976cb9..f12e1282 100644 --- a/Frontend/lib/mih_services/mih_business_details_services.dart +++ b/Frontend/lib/mih_services/mih_business_details_services.dart @@ -120,7 +120,7 @@ class MihBusinessDetailsServices { } Future createBusinessDetails( - String appId, + MzansiProfileProvider provider, String busineName, String businessType, String businessRegistrationNo, @@ -141,9 +141,6 @@ class MihBusinessDetailsServices { return const Mihloadingcircle(); }, ); - String logoPath = businessLogoFilename.isNotEmpty - ? "$appId/business_files/$businessLogoFilename" - : ""; var response = await http.post( Uri.parse("${AppEnviroment.baseApiUrl}/business/insert/"), headers: { @@ -154,7 +151,7 @@ class MihBusinessDetailsServices { "type": businessType, "registration_no": businessRegistrationNo, "logo_name": businessLogoFilename, - "logo_path": logoPath, + "logo_path": "", "contact_no": businessPhoneNumber, "bus_email": businessEmail, "gps_location": businessLocation, @@ -165,7 +162,50 @@ class MihBusinessDetailsServices { "mission_vision": businessMissionVision, }), ); - Navigator.of(context).pop(); + context.pop(); + if (response.statusCode == 201) { + int finalStatusCode = await updateBusinessDetailsV2( + jsonDecode(response.body)['business_id'], + busineName, + businessType, + businessRegistrationNo, + businessPracticeNo, + businessVatNo, + businessEmail, + businessPhoneNumber, + businessLocation, + businessLogoFilename, + businessWebsite, + businessRating, + businessMissionVision, + provider, + context, + ); + if (finalStatusCode == 200) { + String logoPath = businessLogoFilename.isNotEmpty + ? "${jsonDecode(response.body)['business_id']}/business_files/$businessLogoFilename" + : ""; + provider.setBusiness( + newBusiness: Business( + jsonDecode(response.body)['business_id'], + busineName, + businessType, + businessRegistrationNo, + businessLogoFilename, + logoPath, + businessPhoneNumber, + businessEmail, + provider.user!.app_id, + businessLocation, + businessPracticeNo, + businessVatNo, + businessWebsite, + businessRating, + businessMissionVision, + ), + ); + } + } return response; } @@ -227,7 +267,7 @@ class MihBusinessDetailsServices { filePath, business_phone_number, business_email, - provider.business!.app_id, + business_id, business_location, business_practice_no, business_vat_no, diff --git a/Frontend/lib/mih_services/mih_business_employee_services.dart b/Frontend/lib/mih_services/mih_business_employee_services.dart new file mode 100644 index 00000000..4518437b --- /dev/null +++ b/Frontend/lib/mih_services/mih_business_employee_services.dart @@ -0,0 +1,142 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_employee.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:supertokens_flutter/http.dart' as http; + +class MihBusinessEmployeeServices { + Future fetchEmployees( + MzansiProfileProvider mzansiProfileProvider, BuildContext context) async { + final response = await http.get(Uri.parse( + "${AppEnviroment.baseApiUrl}/business-user/employees/${mzansiProfileProvider.businessUser!.business_id}")); + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List employeeList = List.from( + l.map((model) => BusinessEmployee.fromJson(model))); + mzansiProfileProvider.setEmployeeList(employeeList: employeeList); + } else { + throw Exception('failed to load employees'); + } + return response.statusCode; + } + + Future addEmployee( + MzansiProfileProvider provider, + AppUser newEmployee, + String access, + BuildContext context, + ) async { + showDialog( + context: context, + builder: (context) { + return const Mihloadingcircle(); + }, + ); + var response = await http.post( + Uri.parse("${AppEnviroment.baseApiUrl}/business-user/insert/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "business_id": provider.business!.business_id, + "app_id": newEmployee.app_id, + "signature": "", + "sig_path": "", + "title": "", + "access": access, + }), + ); + if (response.statusCode == 201) { + provider.addEmployee( + newEmployee: BusinessEmployee( + provider.business!.business_id, + newEmployee.app_id, + "", + access, + newEmployee.fname, + newEmployee.lname, + newEmployee.email, + newEmployee.username, + ), + ); + provider.setBusinessIndex(2); + } + context.pop(); + return response.statusCode; + } + + Future updateEmployeeDetails( + MzansiProfileProvider provider, + BusinessEmployee employee, + String newTitle, + String newAccess, + BuildContext context) async { + showDialog( + context: context, + builder: (context) { + return const Mihloadingcircle(); + }, + ); + var response = await http.put( + Uri.parse("${AppEnviroment.baseApiUrl}/business-user/employees/update/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "business_id": employee.business_id, + "app_id": employee.app_id, + "title": newTitle, + "access": newAccess, + }), + ); + if (response.statusCode == 200) { + provider.updateEmplyeeDetails( + updatedEmployee: BusinessEmployee( + employee.business_id, + employee.app_id, + newTitle, + newAccess, + employee.fname, + employee.lname, + employee.email, + employee.username, + ), + ); + } + context.pop(); + return response.statusCode; + } + + Future deleteEmployee( + MzansiProfileProvider provider, + BusinessEmployee employee, + BuildContext context, + ) async { + showDialog( + context: context, + builder: (context) { + return const Mihloadingcircle(); + }, + ); + var response = await http.delete( + Uri.parse("${AppEnviroment.baseApiUrl}/business-user/employees/delete/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "business_id": employee.business_id, + "app_id": employee.app_id, + }), + ); + if (response.statusCode == 200) { + provider.deleteEmplyee(deletedEmployee: employee); + } + context.pop(); + return response.statusCode; + } +} diff --git a/Frontend/lib/mih_services/mih_file_services.dart b/Frontend/lib/mih_services/mih_file_services.dart index 88746f66..e3eec301 100644 --- a/Frontend/lib/mih_services/mih_file_services.dart +++ b/Frontend/lib/mih_services/mih_file_services.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:file_picker/file_picker.dart'; import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; @@ -44,8 +45,9 @@ class MihFileApi { fileUrl = decodedData['minioURL']; } else { // internetConnectionPopUp(context); - print("Error: ${response.statusCode}"); - print("Error: ${response.body}"); + KenLogger.error("Get File Error: $url"); + KenLogger.error("Get File Error: ${response.statusCode}"); + KenLogger.error("Get File Error: ${response.body}"); } } catch (e) { // internetConnectionPopUp(context); diff --git a/Frontend/lib/mih_services/mih_my_business_user_services.dart b/Frontend/lib/mih_services/mih_my_business_user_services.dart index 5b0f5349..bb927b5f 100644 --- a/Frontend/lib/mih_services/mih_my_business_user_services.dart +++ b/Frontend/lib/mih_services/mih_my_business_user_services.dart @@ -1,6 +1,5 @@ import 'dart:convert'; import 'package:go_router/go_router.dart'; -import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:flutter/material.dart'; @@ -24,7 +23,7 @@ class MihMyBusinessUserServices { }, ); if (response.statusCode == 200) { - KenLogger.success(response.body); + // KenLogger.success(response.body); BusinessUser? businessUser = BusinessUser.fromJson(jsonDecode(response.body)); context @@ -42,6 +41,7 @@ class MihMyBusinessUserServices { String signatureFilename, String title, String access, + MzansiProfileProvider provider, BuildContext context, ) async { showDialog( @@ -50,6 +50,7 @@ class MihMyBusinessUserServices { return const Mihloadingcircle(); }, ); + String sigPath = "$business_id/business_files/$signatureFilename"; var response = await http.post( Uri.parse("${AppEnviroment.baseApiUrl}/business-user/insert/"), headers: { @@ -59,13 +60,17 @@ class MihMyBusinessUserServices { "business_id": business_id, "app_id": app_id, "signature": signatureFilename, - "sig_path": "$business_id/business_files/$signatureFilename", + "sig_path": sigPath, "title": title, "access": access, }), ); context.pop(); if (response.statusCode == 201) { + provider.setBusinessUser( + newBusinessUser: BusinessUser( + 0, business_id, app_id, signatureFilename, sigPath, title, access), + ); return 201; } else { internetConnectionPopUp(context); diff --git a/Frontend/lib/mih_services/mih_user_services.dart b/Frontend/lib/mih_services/mih_user_services.dart index ff74e988..3467f7f0 100644 --- a/Frontend/lib/mih_services/mih_user_services.dart +++ b/Frontend/lib/mih_services/mih_user_services.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; @@ -132,11 +133,13 @@ class MihUserServices { var fileName = profilePicture.replaceAll(RegExp(r' '), '-'); var filePath = "${signedInUser.app_id}/profile_files/$fileName"; String profileType; + KenLogger.success("is Busines User: $isBusinessUser"); if (isBusinessUser) { profileType = "business"; } else { profileType = "personal"; } + KenLogger.success("Profile Type: $profileType"); var response = await http.put( Uri.parse("${AppEnviroment.baseApiUrl}/user/update/v2/"), headers: { From 15106d0a005cb720bf0c33340cd9889f2ffdd5b9 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 21 Oct 2025 09:53:37 +0200 Subject: [PATCH 21/45] NEW: fix home nav --- .../mzansi_profile_provider.dart | 5 + Frontend/lib/mih_config/mih_go_router.dart | 14 +- .../lib/mih_packages/about_mih/about_mih.dart | 14 -- .../access_review/mih_access.dart | 1 - .../calculator/mih_calculator.dart | 3 - .../mih_home/components/mih_app_drawer.dart | 115 ++++++++++------ .../lib/mih_packages/mih_home/mih_home.dart | 128 ++++++++---------- .../lib/mih_packages/mzansi_ai/mzansi_ai.dart | 1 - .../mzansi_directory/mzansi_directory.dart | 1 - .../mzansi_business_profile.dart | 1 - .../personal_profile/mzansi_profile.dart | 1 - .../mzansi_wallet/mih_wallet.dart | 1 - .../pat_manager/pat_manager.dart | 1 - .../pat_profile/patient_profile.dart | 1 - 14 files changed, 138 insertions(+), 149 deletions(-) diff --git a/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart b/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart index 109aedf2..cf6e6d8d 100644 --- a/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart @@ -43,6 +43,11 @@ class MzansiProfileProvider extends ChangeNotifier { userConsent = null; } + void setPersonalHome(bool isPersonalHome) { + personalHome = isPersonalHome; + notifyListeners(); + } + void setPersonalIndex(int index) { personalIndex = index; notifyListeners(); diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index 86211a8f..ae242b82 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -146,12 +146,7 @@ class MihGoRouter { path: MihGoRouterPaths.aboutMih, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: aboutMih"); - final bool? args = state.extra as bool?; - bool personalSelected = true; - if (args != null) { - personalSelected = args; - } - return AboutMih(personalSelected: personalSelected); + return AboutMih(); }, ), // ========================== Mzansi Profile Personal ================================== @@ -237,12 +232,7 @@ class MihGoRouter { path: MihGoRouterPaths.calculator, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: mihCalculator"); - final bool? personalSelected = state.extra as bool?; - bool personal = true; - if (personalSelected != null) { - personal = personalSelected; - } - return MIHCalculator(personalSelected: personal); + return MIHCalculator(); }, ), // ========================== MIH Calculator ================================== diff --git a/Frontend/lib/mih_packages/about_mih/about_mih.dart b/Frontend/lib/mih_packages/about_mih/about_mih.dart index 336885f9..07f69340 100644 --- a/Frontend/lib/mih_packages/about_mih/about_mih.dart +++ b/Frontend/lib/mih_packages/about_mih/about_mih.dart @@ -11,12 +11,8 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class AboutMih extends StatefulWidget { - final bool? personalSelected; - // final AboutArguments? arguments; const AboutMih({ super.key, - // this.arguments, - this.personalSelected, }); @override @@ -24,18 +20,9 @@ class AboutMih extends StatefulWidget { } class _AboutMihState extends State { - late bool _personalSelected; - @override void initState() { super.initState(); - setState(() { - if (widget.personalSelected == null) { - _personalSelected = true; - } else { - _personalSelected = widget.personalSelected!; - } - }); } @override @@ -59,7 +46,6 @@ class _AboutMihState extends State { onTap: () { context.goNamed( 'mihHome', - extra: _personalSelected, ); FocusScope.of(context).unfocus(); }, diff --git a/Frontend/lib/mih_packages/access_review/mih_access.dart b/Frontend/lib/mih_packages/access_review/mih_access.dart index 3812784a..bd456813 100644 --- a/Frontend/lib/mih_packages/access_review/mih_access.dart +++ b/Frontend/lib/mih_packages/access_review/mih_access.dart @@ -43,7 +43,6 @@ class _MihAccessState extends State { onTap: () { context.goNamed( 'mihHome', - extra: true, ); FocusScope.of(context).unfocus(); }, diff --git a/Frontend/lib/mih_packages/calculator/mih_calculator.dart b/Frontend/lib/mih_packages/calculator/mih_calculator.dart index 96fcbcee..e0ed5add 100644 --- a/Frontend/lib/mih_packages/calculator/mih_calculator.dart +++ b/Frontend/lib/mih_packages/calculator/mih_calculator.dart @@ -12,10 +12,8 @@ import 'package:mzansi_innovation_hub/mih_services/mih_currency_exchange_rate_se import 'package:provider/provider.dart'; class MIHCalculator extends StatefulWidget { - final bool personalSelected; const MIHCalculator({ super.key, - required this.personalSelected, }); @override @@ -57,7 +55,6 @@ class _MIHCalculatorState extends State { onTap: () { context.goNamed( 'mihHome', - extra: widget.personalSelected, ); FocusScope.of(context).unfocus(); }, diff --git a/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart b/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart index 3b3821ea..c74fe1c8 100644 --- a/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart +++ b/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; @@ -12,13 +11,8 @@ import '../../../main.dart'; import 'package:supertokens_flutter/supertokens.dart'; class MIHAppDrawer extends StatefulWidget { - final AppUser signedInUser; - final ImageProvider? propicFile; - const MIHAppDrawer({ super.key, - required this.signedInUser, - required this.propicFile, }); @override @@ -35,19 +29,23 @@ class _MIHAppDrawerState extends State { return true; } - Widget displayProPic() { + Widget displayProPic(MzansiProfileProvider mzansiProfileProvider) { return GestureDetector( onTap: () { - context.goNamed( - 'mzansiProfileManage', - extra: AppProfileUpdateArguments( - widget.signedInUser, - widget.propicFile, - ), - ); + if (mzansiProfileProvider.personalHome) { + context.goNamed( + 'mzansiProfileManage', + ); + } else { + context.goNamed( + "businessProfileManage", + ); + } }, child: MihCircleAvatar( - imageFile: widget.propicFile, + imageFile: mzansiProfileProvider.personalHome + ? mzansiProfileProvider.userProfilePicture + : mzansiProfileProvider.businessProfilePicture, width: 60, editable: false, fileNameController: proPicController, @@ -69,9 +67,6 @@ class _MIHAppDrawerState extends State { @override void initState() { - setState(() { - profilePictureLoaded = displayProPic(); - }); super.initState(); } @@ -102,38 +97,74 @@ class _MIHAppDrawerState extends State { "Dark"), ), child: SizedBox( - height: 400, + // height: 300, width: constraints.maxWidth, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: [ - profilePictureLoaded, - Text( - "${widget.signedInUser.fname} ${widget.signedInUser.lname}", - style: TextStyle( - fontWeight: FontWeight.bold, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), + displayProPic(mzansiProfileProvider), + Visibility( + visible: !mzansiProfileProvider.personalHome, + child: Text( + mzansiProfileProvider.business!.Name, + style: TextStyle( + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + ), + Visibility( + visible: mzansiProfileProvider.personalHome, + child: Text( + "${mzansiProfileProvider.user!.fname} ${mzansiProfileProvider.user!.lname}", + style: TextStyle( + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + ), + Visibility( + visible: !mzansiProfileProvider.personalHome, + child: Text( + mzansiProfileProvider.business!.type, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + ), + Visibility( + visible: mzansiProfileProvider.personalHome, + child: Text( + "@${mzansiProfileProvider.user!.username}", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), ), ), Text( - "@${widget.signedInUser.username}", - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - ), - ), - Text( - widget.signedInUser.type.toUpperCase(), + mzansiProfileProvider.user!.type + .toUpperCase(), style: TextStyle( fontSize: 10, fontWeight: FontWeight.bold, diff --git a/Frontend/lib/mih_packages/mih_home/mih_home.dart b/Frontend/lib/mih_packages/mih_home/mih_home.dart index 92a4ea8a..b294cc37 100644 --- a/Frontend/lib/mih_packages/mih_home/mih_home.dart +++ b/Frontend/lib/mih_packages/mih_home/mih_home.dart @@ -39,8 +39,6 @@ class MihHome extends StatefulWidget { } class _MihHomeState extends State { - late int _selcetedIndex; - late bool _personalHome; DateTime latestPrivacyPolicyDate = DateTime.parse("2024-12-01"); DateTime latestTermOfServiceDate = DateTime.parse("2024-12-01"); bool _isLoadingInitialData = true; @@ -206,13 +204,6 @@ class _MihHomeState extends State { @override void initState() { super.initState(); - if (context.read().personalHome == true) { - _selcetedIndex = 0; - _personalHome = true; - } else { - _selcetedIndex = 1; - _personalHome = false; - } _loadInitialData(); } @@ -249,26 +240,16 @@ class _MihHomeState extends State { child: SizedBox( height: MediaQuery.of(context).size.height, child: MihPackage( - appActionButton: getAction( - mzansiProfileProvider.userProfilePicUrl as String), - appTools: getTools( + appActionButton: getAction(), + appTools: getTools(mzansiProfileProvider, mzansiProfileProvider.user!.type != "personal"), - appBody: getToolBody(), + appBody: getToolBody(mzansiProfileProvider), appToolTitles: getToolTitle(), actionDrawer: getActionDrawer(), - selectedbodyIndex: _selcetedIndex, + selectedbodyIndex: + mzansiProfileProvider.personalHome ? 0 : 1, onIndexChange: (newValue) { - if (_selcetedIndex == 0) { - setState(() { - _selcetedIndex = newValue; - _personalHome = true; - }); - } else { - setState(() { - _selcetedIndex = newValue; - _personalHome = false; - }); - } + mzansiProfileProvider.setPersonalHome(newValue == 0); }, ), ), @@ -474,81 +455,88 @@ class _MihHomeState extends State { ); } - Widget getAction(String proPicUrl) { + Widget getAction() { return Builder(builder: (context) { - return MihPackageAction( - icon: Padding( - padding: const EdgeInsets.only(left: 5.0), - child: MihCircleAvatar( - imageFile: proPicUrl != "" ? NetworkImage(proPicUrl) : null, - width: 50, - editable: false, - fileNameController: null, - userSelectedfile: null, - // frameColor: frameColor, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onChange: (_) {}, - ), - ), - iconSize: 45, - onTap: () { - Scaffold.of(context).openDrawer(); - FocusScope.of(context) - .requestFocus(FocusNode()); // Fully unfocus all fields - // FocusScope.of(context).unfocus(); // Unfocus any text fields + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + ImageProvider? currentImage; + String imageKey; + if (mzansiProfileProvider.personalHome) { + currentImage = mzansiProfileProvider.userProfilePicture; + imageKey = 'user_${mzansiProfileProvider.userProfilePicUrl}'; + } else { + currentImage = mzansiProfileProvider.businessProfilePicture; + imageKey = + 'business_${mzansiProfileProvider.businessProfilePicUrl}'; + } + return MihPackageAction( + icon: Padding( + padding: const EdgeInsets.only(left: 5.0), + child: MihCircleAvatar( + key: Key(imageKey), + imageFile: currentImage, + width: 50, + editable: false, + fileNameController: null, + userSelectedfile: null, + // frameColor: frameColor, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onChange: (_) {}, + ), + ), + iconSize: 45, + onTap: () { + Scaffold.of(context).openDrawer(); + FocusScope.of(context) + .requestFocus(FocusNode()); // Fully unfocus all fields + // FocusScope.of(context).unfocus(); // Unfocus any text fields + }, + ); }, ); }); } MIHAppDrawer getActionDrawer() { - AppUser signedInUser = - context.watch().user as AppUser; - String proPicUrl = - context.watch().userProfilePicUrl ?? ""; - return MIHAppDrawer( - signedInUser: signedInUser, - propicFile: proPicUrl != "" ? NetworkImage(proPicUrl) : null, - ); + return MIHAppDrawer(); } - MihPackageTools getTools(bool isBusinessUser) { + MihPackageTools getTools( + MzansiProfileProvider mzansiProfileProvider, bool isBusinessUser) { Map temp = {}; temp[const Icon(Icons.person)] = () { setState(() { - _selcetedIndex = 0; - _personalHome = true; + mzansiProfileProvider.setPersonalHome(true); }); }; if (isBusinessUser) { temp[const Icon(Icons.business_center)] = () { setState(() { - _selcetedIndex = 1; - _personalHome = false; + mzansiProfileProvider.setPersonalHome(false); }); }; } return MihPackageTools( tools: temp, - selcetedIndex: _selcetedIndex, + selcetedIndex: mzansiProfileProvider.personalHome ? 0 : 1, ); } - List getToolBody() { + List getToolBody(MzansiProfileProvider mzansiProfileProvider) { List toolBodies = []; - AppUser? user = context.watch().user; - Business? business = context.watch().business; - BusinessUser? businessUser = - context.watch().businessUser; + AppUser? user = mzansiProfileProvider.user; + Business? business = mzansiProfileProvider.business; + BusinessUser? businessUser = mzansiProfileProvider.businessUser; String userProfilePictureUrl = - context.watch().userProfilePicUrl ?? ""; + mzansiProfileProvider.userProfilePicUrl ?? ""; toolBodies.add( MihPersonalHome( signedInUser: user!, - personalSelected: _personalHome, + personalSelected: mzansiProfileProvider.personalHome, business: business, businessUser: businessUser, propicFile: userProfilePictureUrl != "" diff --git a/Frontend/lib/mih_packages/mzansi_ai/mzansi_ai.dart b/Frontend/lib/mih_packages/mzansi_ai/mzansi_ai.dart index ccb43d38..715b0519 100644 --- a/Frontend/lib/mih_packages/mzansi_ai/mzansi_ai.dart +++ b/Frontend/lib/mih_packages/mzansi_ai/mzansi_ai.dart @@ -31,7 +31,6 @@ class _MzansiAiState extends State { onTap: () { context.goNamed( 'mihHome', - extra: widget.arguments.personalSelected, ); FocusScope.of(context).unfocus(); }, diff --git a/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart b/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart index eb390b29..403c62c8 100644 --- a/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart +++ b/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart @@ -100,7 +100,6 @@ class _MzansiDirectoryState extends State { onTap: () { context.goNamed( 'mihHome', - extra: widget.arguments.personalSearch, ); FocusScope.of(context).unfocus(); }, diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart index de297b57..3e3736ab 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart @@ -43,7 +43,6 @@ class _MzansiBusinessProfileState extends State { onTap: () { context.goNamed( 'mihHome', - extra: false, ); FocusScope.of(context).unfocus(); context.read().setBusinessIndex(0); diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart index e1692b51..a03b4364 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart @@ -40,7 +40,6 @@ class _MzansiProfileState extends State { // Navigator.of(context).pop(); context.goNamed( 'mihHome', - extra: true, ); FocusScope.of(context).unfocus(); }, diff --git a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart index 60d3c0e2..c29bbe4c 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart @@ -81,7 +81,6 @@ class _MihWalletState extends State { onTap: () { context.goNamed( 'mihHome', - extra: true, ); FocusScope.of(context).unfocus(); }, diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/pat_manager.dart b/Frontend/lib/mih_packages/patient_profile/pat_manager/pat_manager.dart index 77003af1..ed5d077f 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_manager/pat_manager.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_manager/pat_manager.dart @@ -52,7 +52,6 @@ class _PatManagerState extends State { // Navigator.of(context).pop(); context.goNamed( 'mihHome', - extra: false, ); FocusScope.of(context).unfocus(); }, diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_profile.dart b/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_profile.dart index 01f3d6b6..623d4787 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_profile.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_profile.dart @@ -48,7 +48,6 @@ class _PatientProfileState extends State { } else { context.goNamed( 'mihHome', - extra: true, ); } FocusScope.of(context).unfocus(); From c79904d13200234849ba7ed2d96972e09a741045 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 21 Oct 2025 10:22:20 +0200 Subject: [PATCH 22/45] NEW: complete provider mzansi wallet --- Frontend/lib/mih_config/mih_go_router.dart | 4 +- .../package_tools/mih_personal_home.dart | 4 - .../package_tiles/mzansi_profile_tile.dart | 10 - .../mzansi_setup_profile_tile.dart | 10 - .../builder/build_loyalty_card_list.dart | 113 +++-- .../components/mih_add_card_window.dart | 394 +++++++++--------- .../mzansi_wallet/mih_wallet.dart | 34 +- .../package_tools/mih_card_favourites.dart | 4 - .../package_tools/mih_cards.dart | 8 +- docker-compose.yml | 16 +- 10 files changed, 295 insertions(+), 302 deletions(-) diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index ae242b82..c59ad602 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -276,8 +276,7 @@ class MihGoRouter { path: MihGoRouterPaths.mzansiWallet, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: mzansiWallet"); - final WalletArguments? args = state.extra as WalletArguments?; - if (args == null) { + if (context.watch().business == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); @@ -285,7 +284,6 @@ class MihGoRouter { } return MihWallet( key: UniqueKey(), - arguments: args, ); }, ), diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart index 79120d66..55c42822 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart @@ -79,8 +79,6 @@ class _MihPersonalHomeState extends State List> temp = []; temp.add({ "Setup Profile": MzansiSetupProfileTile( - signedInUser: widget.signedInUser, - propicFile: widget.propicFile, packageSize: packageSize, ) }); @@ -92,8 +90,6 @@ class _MihPersonalHomeState extends State //=============== Mzansi Profile =============== temp.add({ "Mzansi Profile": MzansiProfileTile( - signedInUser: widget.signedInUser, - propicFile: widget.propicFile, packageSize: packageSize, ) }); diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tiles/mzansi_profile_tile.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tiles/mzansi_profile_tile.dart index 730b1f0e..3707b877 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tiles/mzansi_profile_tile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tiles/mzansi_profile_tile.dart @@ -2,20 +2,14 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; class MzansiProfileTile extends StatefulWidget { - final AppUser signedInUser; - final ImageProvider? propicFile; final double packageSize; const MzansiProfileTile({ super.key, - required this.signedInUser, - required this.propicFile, required this.packageSize, }); @@ -31,10 +25,6 @@ class _MzansiProfileTileState extends State { onTap: () { context.goNamed( 'mzansiProfileManage', - extra: AppProfileUpdateArguments( - widget.signedInUser, - widget.propicFile, - ), ); }, appName: "Mzansi Profile", diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tiles/mzansi_setup_profile_tile.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tiles/mzansi_setup_profile_tile.dart index 37fff79c..abfdf4bf 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tiles/mzansi_setup_profile_tile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tiles/mzansi_setup_profile_tile.dart @@ -2,20 +2,14 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; class MzansiSetupProfileTile extends StatefulWidget { - final AppUser signedInUser; - final ImageProvider? propicFile; final double packageSize; const MzansiSetupProfileTile({ super.key, - required this.signedInUser, - required this.propicFile, required this.packageSize, }); @@ -30,10 +24,6 @@ class _MzansiSetupProfileTileState extends State { onTap: () { context.goNamed( 'mzansiProfileManage', - extra: AppProfileUpdateArguments( - widget.signedInUser, - widget.propicFile, - ), ); }, appName: "Set Up Profile", diff --git a/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart b/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart index 90ea7719..f44e7afb 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart @@ -7,6 +7,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; @@ -18,7 +19,6 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_delete_message.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/loyalty_card.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_card_display.dart'; import 'package:flutter/material.dart'; @@ -27,7 +27,6 @@ import 'package:provider/provider.dart'; import 'package:screen_brightness/screen_brightness.dart'; class BuildLoyaltyCardList extends StatefulWidget { - final AppUser signedInUser; final List cardList; final int navIndex; final bool favouritesMode; @@ -35,7 +34,6 @@ class BuildLoyaltyCardList extends StatefulWidget { const BuildLoyaltyCardList({ super.key, - required this.signedInUser, required this.cardList, required this.navIndex, required this.favouritesMode, @@ -60,7 +58,8 @@ class _BuildLoyaltyCardListState extends State { ); } - void editCardWindow(BuildContext ctxt, int index, double width) { + void editCardWindow(MzansiProfileProvider mzansiProfileProvider, + BuildContext ctxt, int index, double width) { showDialog( context: context, barrierDismissible: false, @@ -145,7 +144,7 @@ class _BuildLoyaltyCardListState extends State { if (_formKey.currentState!.validate()) { int statusCode = await MIHMzansiWalletApis .updateLoyaltyCardAPICall( - widget.signedInUser, + mzansiProfileProvider.user!, widget.cardList[index].idloyalty_cards, widget.cardList[index].shop_name, widget.cardList[index].favourite, @@ -211,7 +210,8 @@ class _BuildLoyaltyCardListState extends State { ); } - void deleteCardWindow(BuildContext ctxt, int index) { + void deleteCardWindow(MzansiProfileProvider mzansiProfileProvider, + BuildContext ctxt, int index) { showDialog( context: context, barrierDismissible: false, @@ -221,7 +221,7 @@ class _BuildLoyaltyCardListState extends State { onTap: () async { int statusCode = await MIHMzansiWalletApis.deleteLoyaltyCardAPICall( - widget.signedInUser, + mzansiProfileProvider.user!, widget.cardList[index].idloyalty_cards, context, ); @@ -237,7 +237,8 @@ class _BuildLoyaltyCardListState extends State { ); } - void addToFavCardWindow(BuildContext ctxt, int index) { + void addToFavCardWindow(MzansiProfileProvider mzansiProfileProvider, + BuildContext ctxt, int index) { showDialog( context: context, barrierDismissible: false, @@ -269,7 +270,7 @@ class _BuildLoyaltyCardListState extends State { onPressed: () async { int statusCode = await MIHMzansiWalletApis.updateLoyaltyCardAPICall( - widget.signedInUser, + mzansiProfileProvider.user!, widget.cardList[index].idloyalty_cards, widget.cardList[index].shop_name, "Yes", @@ -282,7 +283,9 @@ class _BuildLoyaltyCardListState extends State { context.pop(); context.pop(); await MIHMzansiWalletApis.getFavouriteLoyaltyCards( - widget.signedInUser.app_id, context); + mzansiProfileProvider.user!.app_id, + context, + ); context.read().setToolIndex(1); } else { internetConnectionPopUp(); @@ -319,7 +322,8 @@ class _BuildLoyaltyCardListState extends State { ); } - void removeFromFavCardWindow(BuildContext ctxt, int index) { + void removeFromFavCardWindow(MzansiProfileProvider mzansiProfileProvider, + BuildContext ctxt, int index) { showDialog( context: context, barrierDismissible: false, @@ -351,7 +355,7 @@ class _BuildLoyaltyCardListState extends State { onPressed: () async { int statusCode = await MIHMzansiWalletApis.updateLoyaltyCardAPICall( - widget.signedInUser, + mzansiProfileProvider.user!, widget.cardList[index].idloyalty_cards, widget.cardList[index].shop_name, "", @@ -364,7 +368,9 @@ class _BuildLoyaltyCardListState extends State { context.pop(); context.pop(); await MIHMzansiWalletApis.getFavouriteLoyaltyCards( - widget.signedInUser.app_id, context); + mzansiProfileProvider.user!.app_id, + context, + ); context.read().setToolIndex(0); } else { internetConnectionPopUp(); @@ -390,7 +396,8 @@ class _BuildLoyaltyCardListState extends State { ); } - void viewCardWindow(int index, double width) { + void viewCardWindow( + MzansiProfileProvider mzansiProfileProvider, int index, double width) { //print(widget.cardList[index].card_number); String formattedCardNumber = ""; for (int i = 0; i <= widget.cardList[index].card_number.length - 1; i++) { @@ -432,9 +439,17 @@ class _BuildLoyaltyCardListState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { if (widget.cardList[index].favourite == "") { - addToFavCardWindow(context, index); + addToFavCardWindow( + mzansiProfileProvider, + context, + index, + ); } else { - removeFromFavCardWindow(context, index); + removeFromFavCardWindow( + mzansiProfileProvider, + context, + index, + ); } }, ), @@ -459,7 +474,12 @@ class _BuildLoyaltyCardListState extends State { _cardNumberController.text = widget.cardList[index].card_number; _nicknameController.text = widget.cardList[index].nickname; }); - editCardWindow(context, index, width); + editCardWindow( + mzansiProfileProvider, + context, + index, + width, + ); }, ), SpeedDialChild( @@ -479,7 +499,11 @@ class _BuildLoyaltyCardListState extends State { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - deleteCardWindow(context, index); + deleteCardWindow( + mzansiProfileProvider, + context, + index, + ); }, ), ], @@ -681,29 +705,38 @@ class _BuildLoyaltyCardListState extends State { // final double width = size.width; //final double height = size.height; if (widget.cardList.isNotEmpty) { - return GridView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: EdgeInsets.only( - left: getHorizontalPaddingSize(size), - right: getHorizontalPaddingSize(size), - ), - itemCount: widget.cardList.length, - gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 0, - crossAxisSpacing: 5, - maxCrossAxisExtent: 200, - ), - itemBuilder: (context, index) { - return GestureDetector( - child: MihCardDisplay( - shopName: widget.cardList[index].shop_name, - nickname: widget.cardList[index].nickname, - height: 100, + return Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return GridView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.only( + left: getHorizontalPaddingSize(size), + right: getHorizontalPaddingSize(size), ), - onTap: () { - setScreenBrightness(1.0); - viewCardWindow(index, size.width); + itemCount: widget.cardList.length, + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + mainAxisSpacing: 0, + crossAxisSpacing: 5, + maxCrossAxisExtent: 200, + ), + itemBuilder: (context, index) { + return GestureDetector( + child: MihCardDisplay( + shopName: widget.cardList[index].shop_name, + nickname: widget.cardList[index].nickname, + height: 100, + ), + onTap: () { + setScreenBrightness(1.0); + viewCardWindow( + mzansiProfileProvider, + index, + size.width, + ); + }, + ); }, ); }, diff --git a/Frontend/lib/mih_packages/mzansi_wallet/components/mih_add_card_window.dart b/Frontend/lib/mih_packages/mzansi_wallet/components/mih_add_card_window.dart index 9d990cf2..b1e69c35 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/components/mih_add_card_window.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/components/mih_add_card_window.dart @@ -2,8 +2,6 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; @@ -11,18 +9,17 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_card_display.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_wallet_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; class MihAddCardWindow extends StatefulWidget { - final AppUser signedInUser; - const MihAddCardWindow({ super.key, - required this.signedInUser, }); @override @@ -77,7 +74,6 @@ class _MihAddCardWindowState extends State { context.pop(); context.goNamed( 'mzansiWallet', - extra: WalletArguments(widget.signedInUser, 0), ); }, buttonColor: MihColors.getGreenColor( @@ -145,207 +141,217 @@ class _MihAddCardWindowState extends State { padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" ? EdgeInsets.symmetric(horizontal: width * 0.05) : EdgeInsets.symmetric(horizontal: width * 0), - child: Column( - children: [ - MihForm( - formKey: _formKey, - formFields: [ - MihDropdownField( - controller: _shopController, - hintText: "Shop Name", - editable: true, - enableSearch: true, - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - requiredText: true, - dropdownOptions: const [ - "+More", - "Apple Tree", - "+More", - "Apple Tree", - "Auchan", - "Best Before", - "Big Save", - "Boxer", - "BP", - "Builders Warehouse", - "Checkers", - "Choppies", - "Clicks", - "Continente", - "Cotton:On", - "Carrefour", - "Dis-Chem", - "Edgars", - "Engen", - "Eskom", - "Exclusive Books", - "Fresh Stop", - "Fresmart", - "Infinity", - "Jet", - "Justrite", - "Kero", - "Leroy Merlin", - "Makro", - "Naivas", - "OK Foods", - "Panarottis", - "Pick n Pay", - "PnA", - "PQ Clothing", - "Rage", - "Sefalana", - "Sasol", - "Shell", - "Shoprite", - "Signature Cosmetics & Fragrances", - "Spar", - "Spur", - "TFG Group", - "Total Energies", - "Toys R Us", - "Woermann Brock", - "Woolworths" - ], - ), - ValueListenableBuilder( - valueListenable: _shopName, - builder: (BuildContext context, String value, Widget? child) { - return Visibility( - visible: value != "", - child: Column( - children: [ - const SizedBox(height: 10), - MihCardDisplay( - shopName: _shopName.value, - nickname: "", - height: 200), - ], - ), - ); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: _nicknameController, - multiLineInput: false, - requiredText: false, - hintText: "Card Title", - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.max, - children: [ - Flexible( - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: _cardNumberController, - multiLineInput: false, - requiredText: true, - hintText: "Card Number", - numberMode: true, - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), + child: Consumer( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, Widget? child) { + return Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihDropdownField( + controller: _shopController, + hintText: "Shop Name", + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + requiredText: true, + dropdownOptions: const [ + "+More", + "Apple Tree", + "+More", + "Apple Tree", + "Auchan", + "Best Before", + "Big Save", + "Boxer", + "BP", + "Builders Warehouse", + "Checkers", + "Choppies", + "Clicks", + "Continente", + "Cotton:On", + "Carrefour", + "Dis-Chem", + "Edgars", + "Engen", + "Eskom", + "Exclusive Books", + "Fresh Stop", + "Fresmart", + "Infinity", + "Jet", + "Justrite", + "Kero", + "Leroy Merlin", + "Makro", + "Naivas", + "OK Foods", + "Panarottis", + "Pick n Pay", + "PnA", + "PQ Clothing", + "Rage", + "Sefalana", + "Sasol", + "Shell", + "Shoprite", + "Signature Cosmetics & Fragrances", + "Spar", + "Spur", + "TFG Group", + "Total Energies", + "Toys R Us", + "Woermann Brock", + "Woolworths" + ], ), - const SizedBox(width: 20), - MihButton( - onPressed: () { - context.pushNamed( - "barcodeScanner", - extra: _cardNumberController, // Use local controller + ValueListenableBuilder( + valueListenable: _shopName, + builder: + (BuildContext context, String value, Widget? child) { + return Visibility( + visible: value != "", + child: Column( + children: [ + const SizedBox(height: 10), + MihCardDisplay( + shopName: _shopName.value, + nickname: "", + height: 200), + ], + ), ); }, - buttonColor: MihColors.getSecondaryColor( + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 100, - child: Text( - "Scan", - style: TextStyle( - color: MihColors.getPrimaryColor( + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: _nicknameController, + multiLineInput: false, + requiredText: false, + hintText: "Card Title", + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: _cardNumberController, + multiLineInput: false, + requiredText: true, + hintText: "Card Number", + numberMode: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + ), + const SizedBox(width: 20), + MihButton( + onPressed: () { + context.pushNamed( + "barcodeScanner", + extra: + _cardNumberController, // Use local controller + ); + }, + buttonColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, + width: 100, + child: Text( + "Scan", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 15), + Center( + child: MihButton( + onPressed: () async { + if (_formKey.currentState!.validate()) { + if (_shopController.text == "") { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage( + errorType: "Input Error"); + }, + ); + } else { + int statusCode = await MIHMzansiWalletApis + .addLoyaltyCardAPICall( + mzansiProfileProvider.user!, + mzansiProfileProvider.user!.app_id, + _shopController.text, + _cardNumberController.text, + "", + 0, + _nicknameController.text, + context, + ); + if (statusCode == 201) { + context.pop(); + KenLogger.error("Card Added Successfully"); + successPopUp( + "Successfully Added Card", + "The loyalty card has been added to your favourites.", + 0, + ); + } else { + internetConnectionPopUp(); + } + } + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Add", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), ), ), ), ], ), - const SizedBox(height: 15), - Center( - child: MihButton( - onPressed: () async { - if (_formKey.currentState!.validate()) { - if (_shopController.text == "") { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage( - errorType: "Input Error"); - }, - ); - } else { - int statusCode = - await MIHMzansiWalletApis.addLoyaltyCardAPICall( - widget.signedInUser, - widget.signedInUser.app_id, - _shopController.text, - _cardNumberController.text, - "", - 0, - _nicknameController.text, - context, - ); - if (statusCode == 201) { - context.pop(); - KenLogger.error("Card Added Successfully"); - successPopUp( - "Successfully Added Card", - "The loyalty card has been added to your favourites.", - 0, - ); - } else { - internetConnectionPopUp(); - } - } - } else { - MihAlertServices().formNotFilledCompletely(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 300, - child: Text( - "Add", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ), ], - ), - ], + ); + }, ), ), ); diff --git a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart index c29bbe4c..bfc58d34 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/mih_wallet.dart @@ -2,9 +2,9 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart'; @@ -13,10 +13,8 @@ import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_wallet_services.da import 'package:provider/provider.dart'; class MihWallet extends StatefulWidget { - final WalletArguments arguments; const MihWallet({ super.key, - required this.arguments, }); @override @@ -26,29 +24,25 @@ class MihWallet extends StatefulWidget { class _MihWalletState extends State { bool isLoading = true; - void setPackageIndex() { - if (widget.arguments.index >= 0 && widget.arguments.index <= 3) { - context.read().setToolIndex(widget.arguments.index); - } - } - - Future setLoyaltyCards() async { + Future setLoyaltyCards( + MzansiProfileProvider mzansiProfileProvider) async { await MIHMzansiWalletApis.getLoyaltyCards( - widget.arguments.signedInUser.app_id, context); + mzansiProfileProvider.user!.app_id, context); } - Future setFavouritesCards() async { + Future setFavouritesCards( + MzansiProfileProvider mzansiProfileProvider) async { await MIHMzansiWalletApis.getFavouriteLoyaltyCards( - widget.arguments.signedInUser.app_id, context); + mzansiProfileProvider.user!.app_id, context); } @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { - setPackageIndex(); - await setLoyaltyCards(); - await setFavouritesCards(); + var mzansiProfileProvider = context.read(); + await setLoyaltyCards(mzansiProfileProvider); + await setFavouritesCards(mzansiProfileProvider); context.read().loadBannerAd(); setState(() { isLoading = false; @@ -104,12 +98,8 @@ class _MihWalletState extends State { List getToolBody() { List toolBodies = [ - MihCards( - signedInUser: widget.arguments.signedInUser, - ), - MihCardFavourites( - signedInUser: widget.arguments.signedInUser, - ), + MihCards(), + MihCardFavourites(), ]; if (isLoading) { return [ diff --git a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart index 1d1a19c2..5df6695c 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_card_favourites.dart @@ -2,16 +2,13 @@ import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/loyalty_card.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart'; import 'package:provider/provider.dart'; class MihCardFavourites extends StatefulWidget { - final AppUser signedInUser; const MihCardFavourites({ super.key, - required this.signedInUser, }); @override @@ -50,7 +47,6 @@ class _MihCardFavouritesState extends State { children: [ BuildLoyaltyCardList( cardList: listOfCards, - signedInUser: widget.signedInUser, navIndex: 0, favouritesMode: true, searchText: TextEditingController(), diff --git a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart index 32658638..089a382d 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart @@ -11,7 +11,6 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/loyalty_card.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart'; import 'package:flutter/material.dart'; @@ -19,10 +18,8 @@ import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:provider/provider.dart'; class MihCards extends StatefulWidget { - final AppUser signedInUser; const MihCards({ super.key, - required this.signedInUser, }); @override @@ -127,9 +124,7 @@ class _MihCardsState extends State { showDialog( context: context, barrierDismissible: false, - builder: (context) => MihAddCardWindow( - signedInUser: widget.signedInUser, - ), + builder: (context) => MihAddCardWindow(), ); } @@ -198,7 +193,6 @@ class _MihCardsState extends State { builder: (context, filteredCards, child) { return BuildLoyaltyCardList( cardList: filteredCards, //listOfCards, - signedInUser: widget.signedInUser, navIndex: 0, favouritesMode: false, searchText: cardSearchController, diff --git a/docker-compose.yml b/docker-compose.yml index ccdadd2e..f42cb4e8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -171,14 +171,14 @@ services: networks: - MIH-network # === Added section for NVIDIA GPU acceleration === - runtime: nvidia - deploy: - resources: - reservations: - devices: - - driver: nvidia - count: all # or specify a number of GPUs - capabilities: [ gpu ] + # runtime: nvidia + # deploy: + # resources: + # reservations: + # devices: + # - driver: nvidia + # count: all # or specify a number of GPUs + # capabilities: [ gpu ] #============== Firebaase ==================================================================== # firebase: # container_name: MIH-firebase-emulator From 91241aa3992926a28440aa6dbcb885e32c8899bf Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 21 Oct 2025 10:40:40 +0200 Subject: [PATCH 23/45] NEW: Mzansi AI Provider Setup --- Frontend/lib/main.dart | 4 + .../mih_providers/mzansi_ai_provider.dart | 20 ++ Frontend/lib/mih_config/mih_go_router.dart | 5 +- .../package_tools/mih_business_home.dart | 29 +-- .../package_tools/mih_personal_home.dart | 228 +++++++++--------- .../lib/mih_packages/mzansi_ai/mzansi_ai.dart | 30 +-- .../package_tiles/mzansi_ai_tile.dart | 4 - .../mzansi_ai/package_tools/ai_chat.dart | 22 +- docker-compose.yml | 16 +- 9 files changed, 169 insertions(+), 189 deletions(-) create mode 100644 Frontend/lib/mih_components/mih_providers/mzansi_ai_provider.dart diff --git a/Frontend/lib/main.dart b/Frontend/lib/main.dart index 018c35ea..05ab1dc3 100644 --- a/Frontend/lib/main.dart +++ b/Frontend/lib/main.dart @@ -5,6 +5,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_authentic import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calculator_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_ai_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; @@ -85,6 +86,9 @@ class _MzansiInnovationHubState extends State { ChangeNotifierProvider( create: (context) => MzansiWalletProvider(), ), + ChangeNotifierProvider( + create: (context) => MzansiAiProvider(), + ), ChangeNotifierProvider( create: (context) => MihBannerAdProvider(), ), diff --git a/Frontend/lib/mih_components/mih_providers/mzansi_ai_provider.dart b/Frontend/lib/mih_components/mih_providers/mzansi_ai_provider.dart new file mode 100644 index 00000000..fc6b31fb --- /dev/null +++ b/Frontend/lib/mih_components/mih_providers/mzansi_ai_provider.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +class MzansiAiProvider extends ChangeNotifier { + int toolIndex; + String? startUpQuestion; + + MzansiAiProvider({ + this.toolIndex = 0, + }); + + void setToolIndex(int index) { + toolIndex = index; + notifyListeners(); + } + + void setStartUpQuestion(String? question) { + startUpQuestion = question; + notifyListeners(); + } +} diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index c59ad602..fb7429ce 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -260,14 +260,13 @@ class MihGoRouter { path: MihGoRouterPaths.mzansiAi, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: mzansiAi"); - final MzansiAiArguments? args = state.extra as MzansiAiArguments?; - if (args == null) { + if (context.watch().business == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); return const SizedBox.shrink(); } - return MzansiAi(arguments: args); + return MzansiAi(); }, ), // ========================== Mzansi Wallet ================================== diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart index 140544f2..cbfc1bad 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart @@ -6,6 +6,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_ai_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/about_mih/package_tile/about_mih_tile.dart'; @@ -123,11 +124,6 @@ class _MihBusinessHomeState extends State //=============== Mzansi AI =============== temp.add({ "Mzansi AI": MzansiAiTile( - arguments: MzansiAiArguments( - mzansiProfileProvider.user!, - "", - false, - ), packageSize: packageSize, ) }); @@ -205,9 +201,11 @@ class _MihBusinessHomeState extends State } Widget getBody(double width, double height) { - return Consumer( + return Consumer2( builder: (BuildContext context, - MzansiProfileProvider mzansiProfileProvider, Widget? child) { + MzansiProfileProvider mzansiProfileProvider, + MzansiAiProvider mzansiAiProvider, + Widget? child) { if (mzansiProfileProvider.business == null) { return Center( child: Mihloadingcircle(), @@ -228,25 +226,10 @@ class _MihBusinessHomeState extends State hintColor: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onPrefixIconTap: () { + mzansiAiProvider.setStartUpQuestion(searchController.text); context.goNamed( "mzansiAi", - extra: MzansiAiArguments( - mzansiProfileProvider.user!, - searchController.text.isEmpty - ? null - : searchController.text, - false, - ), ); - // Navigator.of(context).pushNamed( - // '/mzansi-ai', - // arguments: MzansiAiArguments( - // widget.signedInUser, - // searchController.text.isEmpty - // ? null - // : searchController.text, - // ), - // ); searchController.clear(); }, searchFocusNode: _searchFocusNode, diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart index 55c42822..6bc80728 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart @@ -9,6 +9,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_ai_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/about_mih/package_tile/about_mih_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/access_review/package_tile/mih_access_tile.dart'; @@ -22,6 +23,7 @@ import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profi import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/package_tiles/mih_wallet_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/package_tiles/patient_profile_tile.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class MihPersonalHome extends StatefulWidget { final AppUser signedInUser; @@ -135,11 +137,6 @@ class _MihPersonalHomeState extends State //=============== Mzansi AI =============== temp.add({ "Mzansi AI": MzansiAiTile( - arguments: MzansiAiArguments( - widget.signedInUser, - "", - true, - ), packageSize: packageSize, ) }); @@ -263,124 +260,115 @@ class _MihPersonalHomeState extends State } Widget getBody(double width, double height) { - return MihSingleChildScroll( - child: Column( - children: [ - // Icon( - // MihIcons.mihLogo, - // size: 200, - // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // const SizedBox(height: 10), - // Text( - // // "Welcome, ${widget.signedInUser.fname}!", - // "Mzansi Innovation Hub", - // textAlign: TextAlign.center, - // style: TextStyle( - // fontSize: 30, - // fontWeight: FontWeight.bold, - // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // ), - // const SizedBox(height: 20), - Visibility( - visible: !widget.isUserNew, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: width / 20), - child: MihSearchBar( - controller: searchController, - hintText: "Ask Mzansi", - prefixIcon: Icons.search, - prefixAltIcon: MihIcons.mzansiAi, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - hintColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onPrefixIconTap: () { - context.goNamed( - "mzansiAi", - extra: MzansiAiArguments( - widget.signedInUser, - searchController.text.isEmpty - ? null - : searchController.text, - true, - ), - ); - // Navigator.of(context).pushNamed( - // '/mzansi-ai', - // arguments: MzansiAiArguments( - // widget.signedInUser, - // searchController.text.isEmpty - // ? null - // : searchController.text, - // ), - // ); - searchController.clear(); - }, - searchFocusNode: _searchFocusNode, - ), - ), - ), - const SizedBox(height: 20), - ValueListenableBuilder( - valueListenable: searchPackageName, - builder: (context, value, child) { - List filteredPackages = value - .where((package) => package.keys.first - .toLowerCase() - .contains(searchController.text.toLowerCase())) - .map((package) => package.values.first) - .toList(); - if (filteredPackages.isNotEmpty) { - return GridView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: getPadding(width, height), - // shrinkWrap: true, - itemCount: filteredPackages.length, - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: packageSize, - crossAxisSpacing: 5, + return Consumer( + builder: (BuildContext context, MzansiAiProvider mzansiAiProvider, + Widget? child) { + return MihSingleChildScroll( + child: Column( + children: [ + // Icon( + // MihIcons.mihLogo, + // size: 200, + // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // ), + // const SizedBox(height: 10), + // Text( + // // "Welcome, ${widget.signedInUser.fname}!", + // "Mzansi Innovation Hub", + // textAlign: TextAlign.center, + // style: TextStyle( + // fontSize: 30, + // fontWeight: FontWeight.bold, + // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // ), + // ), + // const SizedBox(height: 20), + Visibility( + visible: !widget.isUserNew, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: searchController, + hintText: "Ask Mzansi", + prefixIcon: Icons.search, + prefixAltIcon: MihIcons.mzansiAi, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + hintColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onPrefixIconTap: () { + mzansiAiProvider + .setStartUpQuestion(searchController.text); + context.goNamed( + "mzansiAi", + ); + searchController.clear(); + }, + searchFocusNode: _searchFocusNode, ), - itemBuilder: (context, index) { - return filteredPackages[index]; - // return personalPackages[index]; - }, - ); - } else { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 50), - Icon( - MihIcons.mzansiAi, - size: 165, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - const SizedBox(height: 10), - Text( - "Mzansi AI is here to help you!", - textAlign: TextAlign.center, - overflow: TextOverflow.visible, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), + ), + ), + const SizedBox(height: 20), + ValueListenableBuilder( + valueListenable: searchPackageName, + builder: (context, value, child) { + List filteredPackages = value + .where((package) => package.keys.first + .toLowerCase() + .contains(searchController.text.toLowerCase())) + .map((package) => package.values.first) + .toList(); + if (filteredPackages.isNotEmpty) { + return GridView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: getPadding(width, height), + // shrinkWrap: true, + itemCount: filteredPackages.length, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: packageSize, + crossAxisSpacing: 5, ), - ), - ], - ); - } - }, + itemBuilder: (context, index) { + return filteredPackages[index]; + // return personalPackages[index]; + }, + ); + } else { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.mzansiAi, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + const SizedBox(height: 10), + Text( + "Mzansi AI is here to help you!", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ], + ); + } + }, + ), + ], ), - ], - ), + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/mzansi_ai/mzansi_ai.dart b/Frontend/lib/mih_packages/mzansi_ai/mzansi_ai.dart index 715b0519..1d694165 100644 --- a/Frontend/lib/mih_packages/mzansi_ai/mzansi_ai.dart +++ b/Frontend/lib/mih_packages/mzansi_ai/mzansi_ai.dart @@ -2,19 +2,14 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_ai_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_ai/package_tools/ai_chat.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class MzansiAi extends StatefulWidget { - // final AppUser signedInUser; - // final String? startUpQuestion; - final MzansiAiArguments arguments; const MzansiAi({ super.key, - required this.arguments, - // required this.signedInUser, - // this.startUpQuestion, }); @override @@ -22,13 +17,12 @@ class MzansiAi extends StatefulWidget { } class _MzansiAiState extends State { - int _selcetedIndex = 0; - MihPackageAction getAction() { return MihPackageAction( icon: const Icon(Icons.arrow_back), iconSize: 35, onTap: () { + context.read().setStartUpQuestion(null); context.goNamed( 'mihHome', ); @@ -40,23 +34,18 @@ class _MzansiAiState extends State { MihPackageTools getTools() { Map temp = {}; temp[const Icon(Icons.chat)] = () { - setState(() { - _selcetedIndex = 0; - }); + context.read().setToolIndex(0); }; return MihPackageTools( tools: temp, - selcetedIndex: _selcetedIndex, + selcetedIndex: context.watch().toolIndex, ); } List getToolBody() { List toolBodies = [ - AiChat( - signedInUser: widget.arguments.signedInUser, - startUpQuestion: widget.arguments.startUpQuestion, - ), + AiChat(), ]; return toolBodies; } @@ -80,12 +69,9 @@ class _MzansiAiState extends State { appTools: getTools(), appBody: getToolBody(), appToolTitles: getToolTitle(), - selectedbodyIndex: _selcetedIndex, + selectedbodyIndex: context.watch().toolIndex, onIndexChange: (newValue) { - setState(() { - _selcetedIndex = newValue; - }); - print("Index: $_selcetedIndex"); + context.read().setToolIndex(newValue); }, ); } diff --git a/Frontend/lib/mih_packages/mzansi_ai/package_tiles/mzansi_ai_tile.dart b/Frontend/lib/mih_packages/mzansi_ai/package_tiles/mzansi_ai_tile.dart index 24633b33..de331e7a 100644 --- a/Frontend/lib/mih_packages/mzansi_ai/package_tiles/mzansi_ai_tile.dart +++ b/Frontend/lib/mih_packages/mzansi_ai/package_tiles/mzansi_ai_tile.dart @@ -3,16 +3,13 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:flutter/material.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; class MzansiAiTile extends StatefulWidget { - final MzansiAiArguments arguments; final double packageSize; const MzansiAiTile({ super.key, - required this.arguments, required this.packageSize, }); @@ -27,7 +24,6 @@ class _MzansiAiTileState extends State { onTap: () { context.goNamed( 'mzansiAi', - extra: widget.arguments, ); // Navigator.of(context).pushNamed( // '/mzansi-ai', diff --git a/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart b/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart index 8f789669..c380456f 100644 --- a/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart +++ b/Frontend/lib/mih_packages/mzansi_ai/package_tools/ai_chat.dart @@ -4,6 +4,8 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:gpt_markdown/gpt_markdown.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_ai_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; @@ -14,22 +16,18 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_radio_options.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:flutter/material.dart'; import 'package:flutter_chat_ui/flutter_chat_ui.dart'; import 'package:flutter_chat_types/flutter_chat_types.dart' as types; import 'package:flutter/services.dart' show rootBundle; import 'package:flutter_tts/flutter_tts.dart'; import 'package:ollama_dart/ollama_dart.dart' as ollama; +import 'package:provider/provider.dart'; import 'package:uuid/uuid.dart'; class AiChat extends StatefulWidget { - final AppUser signedInUser; - final String? startUpQuestion; const AiChat({ super.key, - required this.signedInUser, - this.startUpQuestion, }); @override @@ -615,9 +613,13 @@ class _AiChatState extends State { @override void initState() { super.initState(); + MzansiAiProvider mzansiAiProvider = context.read(); + MzansiProfileProvider mzansiProfileProvider = + context.read(); _user = types.User( - firstName: widget.signedInUser.fname, - id: widget.signedInUser.app_id, //'82091008-a484-4a89-ae75-a22bf8d6f3ac', + firstName: mzansiProfileProvider.user!.fname, + id: mzansiProfileProvider + .user!.app_id, //'82091008-a484-4a89-ae75-a22bf8d6f3ac', ); _mihAI = types.User( firstName: "Mzansi AI", @@ -634,8 +636,10 @@ class _AiChatState extends State { ); initTTS(); _ttsVoiceController.addListener(voiceSelected); - if (widget.startUpQuestion != null && widget.startUpQuestion!.isNotEmpty) { - final partialText = types.PartialText(text: widget.startUpQuestion!); + if (mzansiAiProvider.startUpQuestion != null && + mzansiAiProvider.startUpQuestion!.isNotEmpty) { + final partialText = + types.PartialText(text: mzansiAiProvider.startUpQuestion!); WidgetsBinding.instance.addPostFrameCallback((_) { _handleSendPressed(partialText); }); diff --git a/docker-compose.yml b/docker-compose.yml index f42cb4e8..ccdadd2e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -171,14 +171,14 @@ services: networks: - MIH-network # === Added section for NVIDIA GPU acceleration === - # runtime: nvidia - # deploy: - # resources: - # reservations: - # devices: - # - driver: nvidia - # count: all # or specify a number of GPUs - # capabilities: [ gpu ] + runtime: nvidia + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all # or specify a number of GPUs + capabilities: [ gpu ] #============== Firebaase ==================================================================== # firebase: # container_name: MIH-firebase-emulator From 3dc9ce30e685ab676c886eac5f4cbae2078eab0c Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 21 Oct 2025 10:45:15 +0200 Subject: [PATCH 24/45] NEW: MIH Calc Provider Setup pt2 --- .../calculator/package_tiles/mih_calculator_tile.dart | 3 --- .../mih_packages/mih_home/package_tools/mih_business_home.dart | 1 - .../mih_packages/mih_home/package_tools/mih_personal_home.dart | 1 - 3 files changed, 5 deletions(-) diff --git a/Frontend/lib/mih_packages/calculator/package_tiles/mih_calculator_tile.dart b/Frontend/lib/mih_packages/calculator/package_tiles/mih_calculator_tile.dart index 4011d6d1..a771df6b 100644 --- a/Frontend/lib/mih_packages/calculator/package_tiles/mih_calculator_tile.dart +++ b/Frontend/lib/mih_packages/calculator/package_tiles/mih_calculator_tile.dart @@ -6,12 +6,10 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; class MihCalculatorTile extends StatefulWidget { - final bool personalSelected; final double packageSize; const MihCalculatorTile({ super.key, - required this.personalSelected, required this.packageSize, }); @@ -26,7 +24,6 @@ class _MihCalculatorTileState extends State { onTap: () { context.goNamed( "mihCalculator", - extra: widget.personalSelected, ); }, appName: "Calculator", diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart index cbfc1bad..34713af8 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart @@ -117,7 +117,6 @@ class _MihBusinessHomeState extends State //=============== Calculator =============== temp.add({ "Calculator": MihCalculatorTile( - personalSelected: mzansiProfileProvider.personalHome, packageSize: packageSize, ) }); diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart index 6bc80728..0729704e 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart @@ -143,7 +143,6 @@ class _MihPersonalHomeState extends State //=============== Calculator =============== temp.add({ "Calculator": MihCalculatorTile( - personalSelected: widget.personalSelected, packageSize: packageSize, ) }); From b2ed1e0b5113f49f9e5a1772d017c94fd6cd2dcc Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 21 Oct 2025 10:46:50 +0200 Subject: [PATCH 25/45] NEW: About MIH Provider Setup pt2 --- .../mih_packages/about_mih/package_tile/about_mih_tile.dart | 3 --- .../mih_packages/mih_home/package_tools/mih_business_home.dart | 1 - .../mih_packages/mih_home/package_tools/mih_personal_home.dart | 1 - 3 files changed, 5 deletions(-) diff --git a/Frontend/lib/mih_packages/about_mih/package_tile/about_mih_tile.dart b/Frontend/lib/mih_packages/about_mih/package_tile/about_mih_tile.dart index edf7c351..945a4122 100644 --- a/Frontend/lib/mih_packages/about_mih/package_tile/about_mih_tile.dart +++ b/Frontend/lib/mih_packages/about_mih/package_tile/about_mih_tile.dart @@ -7,11 +7,9 @@ import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; class AboutMihTile extends StatefulWidget { final double packageSize; - final bool personalSelected; const AboutMihTile({ super.key, required this.packageSize, - required this.personalSelected, }); @override @@ -25,7 +23,6 @@ class _AboutMihTileState extends State { onTap: () { context.goNamed( "aboutMih", - extra: widget.personalSelected, ); // Navigator.of(context).pushNamed( // '/about', diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart index 34713af8..7c3c49bd 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart @@ -130,7 +130,6 @@ class _MihBusinessHomeState extends State temp.add({ "About MIH": AboutMihTile( packageSize: packageSize, - personalSelected: false, ) }); return temp; diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart index 0729704e..0b879fc2 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart @@ -164,7 +164,6 @@ class _MihPersonalHomeState extends State temp.add({ "About MIH": AboutMihTile( packageSize: packageSize, - personalSelected: true, ) }); //=============== Dev =============== From 926b749fa8ab9b0f465232d52f139e3f156d7228 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 21 Oct 2025 13:00:52 +0200 Subject: [PATCH 26/45] NEW: MIH Calendar Provider Setup --- Frontend/lib/main.dart | 4 + .../mih_package_components/mih_calendar.dart | 18 +- .../mih_providers/mih_calendar_provider.dart | 66 ++++ Frontend/lib/mih_config/mih_go_router.dart | 6 +- .../builder/build_appointment_list.dart | 262 ++++++++------- .../calendar/mzansi_calendar.dart | 17 +- .../package_tiles/mzansi_calendar_tile.dart | 4 - .../calendar/package_tools/appointments.dart | 306 +++++++++--------- .../package_tools/mih_business_home.dart | 6 - .../package_tools/mih_personal_home.dart | 6 - .../package_tools/waiting_room.dart | 214 ++++++------ .../mih_mzansi_calendar_services.dart | 151 ++++----- 12 files changed, 576 insertions(+), 484 deletions(-) diff --git a/Frontend/lib/main.dart b/Frontend/lib/main.dart index 05ab1dc3..efee465d 100644 --- a/Frontend/lib/main.dart +++ b/Frontend/lib/main.dart @@ -4,6 +4,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_providers/about_mih_pro import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_authentication_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calculator_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_ai_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; @@ -95,6 +96,9 @@ class _MzansiInnovationHubState extends State { ChangeNotifierProvider( create: (context) => MihCalculatorProvider(), ), + ChangeNotifierProvider( + create: (context) => MihCalendarProvider(), + ), ChangeNotifierProvider( create: (context) => AboutMihProvider(), ), diff --git a/Frontend/lib/mih_components/mih_package_components/mih_calendar.dart b/Frontend/lib/mih_components/mih_package_components/mih_calendar.dart index 01fc2f18..8989da51 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_calendar.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_calendar.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:provider/provider.dart'; import 'package:table_calendar/table_calendar.dart'; class MIHCalendar extends StatefulWidget { @@ -19,16 +22,29 @@ class MIHCalendar extends StatefulWidget { } class _MIHCalendarState extends State { - DateTime selectedDay = DateTime.now(); + late DateTime selectedDay; CalendarFormat _calendarFormat = CalendarFormat.week; void onDaySelected(DateTime day, DateTime focusedDay) { + KenLogger.success("Selected Day: $day"); setState(() { selectedDay = day; }); widget.setDate(selectedDay.toString().split(" ")[0]); } + @override + void initState() { + super.initState(); + MihCalendarProvider mihCalendarProvider = + context.read(); + if (mihCalendarProvider.selectedDay.isNotEmpty) { + selectedDay = DateTime.parse(mihCalendarProvider.selectedDay); + } else { + selectedDay = DateTime.now(); + } + } + @override Widget build(BuildContext context) { return SizedBox( diff --git a/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart index 7b80ab62..57cb2e92 100644 --- a/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart @@ -1,7 +1,11 @@ import 'package:flutter/foundation.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/appointment.dart'; class MihCalendarProvider extends ChangeNotifier { int toolIndex; + String selectedDay = DateTime.now().toString().split(" ")[0]; + List? personalAppointments; + List? businessAppointments; MihCalendarProvider({ this.toolIndex = 0, @@ -11,4 +15,66 @@ class MihCalendarProvider extends ChangeNotifier { toolIndex = index; notifyListeners(); } + + void setSelectedDay(String day) { + selectedDay = day; + notifyListeners(); + } + + void resetSelectedDay() { + selectedDay = DateTime.now().toString().split(" ")[0]; + notifyListeners(); + } + + void setPersonalAppointments({required List appointments}) { + personalAppointments = appointments; + notifyListeners(); + } + + void setBusinessAppointments({required List appointments}) { + businessAppointments = appointments; + notifyListeners(); + } + + void addPersonalAppointment({required Appointment newAppointment}) { + personalAppointments?.add(newAppointment); + notifyListeners(); + } + + void addBusinessAppointment({required Appointment newAppointment}) { + businessAppointments?.add(newAppointment); + notifyListeners(); + } + + void editPersonalAppointment({required Appointment updatedAppointment}) { + int index = personalAppointments?.indexWhere((appointment) => + appointment.idappointments == updatedAppointment.idappointments) ?? + -1; + if (index != -1) { + personalAppointments?[index] = updatedAppointment; + notifyListeners(); + } + } + + void editBusinessAppointment({required Appointment updatedAppointment}) { + int index = businessAppointments?.indexWhere((appointment) => + appointment.idappointments == updatedAppointment.idappointments) ?? + -1; + if (index != -1) { + businessAppointments?[index] = updatedAppointment; + notifyListeners(); + } + } + + void deletePersonalAppointment({required int appointmentId}) { + personalAppointments?.removeWhere( + (appointment) => appointment.idappointments == appointmentId); + notifyListeners(); + } + + void deleteBusinessAppointment({required int appointmentId}) { + businessAppointments?.removeWhere( + (appointment) => appointment.idappointments == appointmentId); + notifyListeners(); + } } diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index fb7429ce..69732265 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -241,8 +241,7 @@ class MihGoRouter { path: MihGoRouterPaths.calendar, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: mihCalendar"); - final CalendarArguments? args = state.extra as CalendarArguments?; - if (args == null) { + if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); @@ -250,7 +249,6 @@ class MihGoRouter { } return MzansiCalendar( key: UniqueKey(), - arguments: args, ); }, ), @@ -260,7 +258,7 @@ class MihGoRouter { path: MihGoRouterPaths.mzansiAi, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: mzansiAi"); - if (context.watch().business == null) { + if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); diff --git a/Frontend/lib/mih_packages/calendar/builder/build_appointment_list.dart b/Frontend/lib/mih_packages/calendar/builder/build_appointment_list.dart index b195fb75..d56ef908 100644 --- a/Frontend/lib/mih_packages/calendar/builder/build_appointment_list.dart +++ b/Frontend/lib/mih_packages/calendar/builder/build_appointment_list.dart @@ -2,8 +2,11 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:go_router/go_router.dart'; import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/appointment.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_calendar_services.dart'; @@ -17,18 +20,10 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_delete_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/appointment.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class BuildAppointmentList extends StatefulWidget { - final List appointmentList; - final AppUser signedInUser; - final Business? business; - final BusinessUser? businessUser; - final bool personalSelected; final bool inWaitingRoom; final TextEditingController titleController; final TextEditingController descriptionIDController; @@ -38,11 +33,6 @@ class BuildAppointmentList extends StatefulWidget { const BuildAppointmentList({ super.key, - required this.appointmentList, - required this.signedInUser, - required this.business, - required this.businessUser, - required this.personalSelected, required this.inWaitingRoom, required this.titleController, required this.descriptionIDController, @@ -77,22 +67,39 @@ class _BuildAppointmentListState extends State { } } - Widget displayAppointment(int index, double bodyWidth) { - String heading = - "${widget.appointmentList[index].date_time.split('T')[1].substring(0, 5)} - ${widget.appointmentList[index].title.toUpperCase()}"; - String description = widget.appointmentList[index].description; - DateTime now = new DateTime.now(); - int hourNow = int.parse(now.toString().split(' ')[1].substring(0, 2)); - String date = - new DateTime(now.year, now.month, now.day).toString().split(' ')[0]; - String appointDate = widget.appointmentList[index].date_time.split('T')[0]; - int appointHour = int.parse( - widget.appointmentList[index].date_time.split('T')[1].substring(0, 2)); - // print("Date Time Now: $now"); - // print("Hour Now: $hourNow"); - // print("Date: $date"); - // print("Appointment Date: $appointDate"); - // print("Appointment Hour: $appointHour"); + Widget displayAppointment(MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider, int index, double bodyWidth) { + List appointmentList = mzansiProfileProvider.personalHome + ? mihCalendarProvider.personalAppointments! + : mihCalendarProvider.businessAppointments!; + String heading = ""; + String description = ""; + DateTime now; + int hourNow = 0; + String date = ""; + int appointHour = 0; + String appointDate = ""; + if (appointmentList[index].date_time.contains("T")) { + heading = + "${appointmentList[index].date_time.split('T')[1].substring(0, 5)} - ${appointmentList[index].title.toUpperCase()}"; + description = appointmentList[index].description; + now = DateTime.now(); + hourNow = int.parse(now.toString().split(' ')[1].substring(0, 2)); + date = DateTime(now.year, now.month, now.day).toString().split(' ')[0]; + appointDate = appointmentList[index].date_time.split('T')[0]; + appointHour = int.parse( + appointmentList[index].date_time.split('T')[1].substring(0, 2)); + } else { + heading = + "${appointmentList[index].date_time.split(' ')[1].substring(0, 5)} - ${appointmentList[index].title.toUpperCase()}"; + description = appointmentList[index].description; + now = DateTime.now(); + hourNow = int.parse(now.toString().split(' ')[1].substring(0, 2)); + date = DateTime(now.year, now.month, now.day).toString().split(' ')[0]; + appointDate = appointmentList[index].date_time.split(' ')[0]; + appointHour = int.parse( + appointmentList[index].date_time.split(' ')[1].substring(0, 2)); + } Color appointmentColor = MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"); if (date == appointDate) { @@ -132,26 +139,28 @@ class _BuildAppointmentListState extends State { ), onTap: () { setState(() { - widget.titleController.text = widget.appointmentList[index].title; + widget.titleController.text = appointmentList[index].title; widget.descriptionIDController.text = - widget.appointmentList[index].description; + appointmentList[index].description; widget.dateController.text = - widget.appointmentList[index].date_time.split('T')[0]; - widget.timeController.text = widget.appointmentList[index].date_time - .split('T')[1] - .substring(0, 5); + appointmentList[index].date_time.split('T')[0]; + widget.timeController.text = + appointmentList[index].date_time.split('T')[1].substring(0, 5); }); if (widget.inWaitingRoom == false) { - appointmentDetailsWindow(index, bodyWidth); + appointmentDetailsWindow( + mzansiProfileProvider, mihCalendarProvider, index, bodyWidth); } else { - waitingRiinAppointmentDetailsWindow(index, bodyWidth); + waitingRoomAppointmentDetailsWindow( + mzansiProfileProvider, mihCalendarProvider, index, bodyWidth); } }, ), ); } - void appointmentDetailsWindow(int index, double bodyWidth) { + void appointmentDetailsWindow(MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider, int index, double bodyWidth) { showDialog( context: context, barrierDismissible: false, @@ -177,7 +186,8 @@ class _BuildAppointmentListState extends State { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - appointmentUpdateWindow(index, bodyWidth); + appointmentUpdateWindow(mzansiProfileProvider, + mihCalendarProvider, index, bodyWidth); }, ), SpeedDialChild( @@ -197,7 +207,8 @@ class _BuildAppointmentListState extends State { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - deleteAppointmentConfirmationWindow(index); + deleteAppointmentConfirmationWindow( + mzansiProfileProvider, mihCalendarProvider, index); }, ), ], @@ -273,7 +284,11 @@ class _BuildAppointmentListState extends State { ); } - void waitingRiinAppointmentDetailsWindow(int index, double bodyWidth) { + void waitingRoomAppointmentDetailsWindow( + MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider, + int index, + double bodyWidth) { showDialog( context: context, barrierDismissible: false, @@ -299,7 +314,8 @@ class _BuildAppointmentListState extends State { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - appointmentUpdateWindow(index, bodyWidth); + appointmentUpdateWindow(mzansiProfileProvider, + mihCalendarProvider, index, bodyWidth); }, ), SpeedDialChild( @@ -319,7 +335,8 @@ class _BuildAppointmentListState extends State { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - deleteAppointmentConfirmationWindow(index); + deleteAppointmentConfirmationWindow( + mzansiProfileProvider, mihCalendarProvider, index); }, ), ], @@ -405,7 +422,11 @@ class _BuildAppointmentListState extends State { ); } - void appointmentUpdateWindow(int index, double bodyWidth) { + void appointmentUpdateWindow(MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider, int index, double bodyWidth) { + List appointmentList = mzansiProfileProvider.personalHome + ? mihCalendarProvider.personalAppointments! + : mihCalendarProvider.businessAppointments!; showDialog( context: context, barrierDismissible: false, @@ -415,13 +436,13 @@ class _BuildAppointmentListState extends State { windowTitle: "Update Appointment", onWindowTapClose: () { setState(() { - widget.titleController.text = widget.appointmentList[index].title; + widget.titleController.text = appointmentList[index].title; widget.descriptionIDController.text = - widget.appointmentList[index].description; + appointmentList[index].description; widget.dateController.text = - widget.appointmentList[index].date_time.split('T')[0]; - widget.timeController.text = widget - .appointmentList[index].date_time + appointmentList[index].date_time.split('T')[0]; + widget.timeController.text = appointmentList[index] + .date_time .split('T')[1] .substring(0, 5); }); @@ -497,7 +518,8 @@ class _BuildAppointmentListState extends State { MihButton( onPressed: () { if (_formKey.currentState!.validate()) { - updateAppointmentCall(index); + updateAppointmentCall(mzansiProfileProvider, + mihCalendarProvider, index); } else { MihAlertServices() .formNotFilledCompletely(context); @@ -542,7 +564,10 @@ class _BuildAppointmentListState extends State { } } - void deleteAppointmentConfirmationWindow(int index) { + void deleteAppointmentConfirmationWindow( + MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider, + int index) { showDialog( context: context, barrierDismissible: false, @@ -550,46 +575,55 @@ class _BuildAppointmentListState extends State { return MIHDeleteMessage( deleteType: "Appointment", onTap: () { - deleteAppointmentCall(index); + deleteAppointmentCall( + mzansiProfileProvider, mihCalendarProvider, index); }); }, ); } - Future updateAppointmentCall(int index) async { + Future updateAppointmentCall( + MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider, + int index) async { int statusCode; if (isAppointmentInputValid()) { - if (widget.personalSelected == true) { + List appointmentList = mzansiProfileProvider.personalHome + ? mihCalendarProvider.personalAppointments! + : mihCalendarProvider.businessAppointments!; + if (mzansiProfileProvider.personalHome == true) { statusCode = await MihMzansiCalendarApis.updatePersonalAppointment( - widget.signedInUser, - widget.business, + mzansiProfileProvider.user!, + mzansiProfileProvider.business, null, - widget.appointmentList[index].idappointments, + appointmentList[index].idappointments, widget.titleController.text, widget.descriptionIDController.text, widget.dateController.text, widget.timeController.text, + mihCalendarProvider, context, ); - } else if (widget.personalSelected == false && + } else if (mzansiProfileProvider.personalHome == false && widget.inWaitingRoom == false) { statusCode = await MihMzansiCalendarApis.updateBusinessAppointment( - widget.signedInUser, - widget.business, - widget.businessUser, - widget.appointmentList[index].idappointments, + mzansiProfileProvider.user!, + mzansiProfileProvider.business, + mzansiProfileProvider.businessUser, + appointmentList[index].idappointments, widget.titleController.text, widget.descriptionIDController.text, widget.dateController.text, widget.timeController.text, + mihCalendarProvider, context, ); } else { statusCode = await MihMzansiCalendarApis.updatePatientAppointment( - widget.signedInUser, - widget.business, - widget.businessUser, - widget.appointmentList[index].idappointments, + mzansiProfileProvider.user!, + mzansiProfileProvider.business, + mzansiProfileProvider.businessUser, + appointmentList[index].idappointments, widget.titleController.text, widget.descriptionIDController.text, widget.dateController.text, @@ -604,27 +638,20 @@ class _BuildAppointmentListState extends State { KenLogger.warning("calendar route"); context.goNamed( "mihCalendar", - extra: CalendarArguments( - widget.signedInUser, - widget.personalSelected, - widget.business, - widget.businessUser, - ), ); } else { KenLogger.warning("waiting room route"); // GoRouter.of(context).refresh(); context.goNamed( 'mihHome', - extra: false, ); context.goNamed( 'patientManager', extra: PatManagerArguments( - widget.signedInUser, + mzansiProfileProvider.user!, false, - widget.business, - widget.businessUser, + mzansiProfileProvider.business, + mzansiProfileProvider.businessUser, ), ); // context.pop(); @@ -642,22 +669,26 @@ class _BuildAppointmentListState extends State { } } - Future deleteAppointmentCall(int index) async { + Future deleteAppointmentCall( + MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider, + int index) async { + List appointmentList = mzansiProfileProvider.personalHome + ? mihCalendarProvider.personalAppointments! + : mihCalendarProvider.businessAppointments!; int statucCode = await MihMzansiCalendarApis.deleteAppointmentAPICall( - widget.signedInUser, - widget.personalSelected, - widget.business, - widget.businessUser, + mzansiProfileProvider.user!, + mzansiProfileProvider.personalHome, + mzansiProfileProvider.business, + mzansiProfileProvider.businessUser, widget.inWaitingRoom, - widget.appointmentList[index].idappointments, + appointmentList[index].idappointments, + mihCalendarProvider, context, ); if (statucCode == 200) { context.pop(); context.pop(); - setState(() { - widget.appointmentList.removeAt(index); - }); successPopUp("Successfully Deleted Appointment", "You appointment has been successfully deleted from your calendar."); } else { @@ -730,20 +761,24 @@ class _BuildAppointmentListState extends State { ); } - bool canEditAppointment(int index) { - if (widget.personalSelected == true && - widget.appointmentList[index].app_id == widget.signedInUser.app_id && - widget.appointmentList[index].business_id == "") { + bool canEditAppointment(MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider, int index) { + List appointmentList = mzansiProfileProvider.personalHome + ? mihCalendarProvider.personalAppointments! + : mihCalendarProvider.businessAppointments!; + if (mzansiProfileProvider.personalHome == true && + appointmentList[index].app_id == mzansiProfileProvider.user!.app_id && + appointmentList[index].business_id == "") { return true; - } else if (widget.personalSelected == false && - widget.appointmentList[index].business_id == - widget.business!.business_id && - widget.appointmentList[index].app_id.isEmpty) { + } else if (mzansiProfileProvider.personalHome == false && + appointmentList[index].business_id == + mzansiProfileProvider.business!.business_id && + appointmentList[index].app_id.isEmpty) { return true; - } else if (widget.personalSelected == false && - widget.appointmentList[index].business_id == - widget.business!.business_id && - widget.appointmentList[index].app_id.isNotEmpty) { + } else if (mzansiProfileProvider.personalHome == false && + appointmentList[index].business_id == + mzansiProfileProvider.business!.business_id && + appointmentList[index].app_id.isNotEmpty) { return true; } else { return false; @@ -765,16 +800,27 @@ class _BuildAppointmentListState extends State { width = size.width; height = size.height; }); - return Padding( - padding: EdgeInsets.symmetric(horizontal: getPaddingSize()), - child: ListView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: widget.appointmentList.length, - itemBuilder: (context, index) { - return displayAppointment(index, width); - }, - ), + return Consumer2( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider, + Widget? child) { + List appointmentList = mzansiProfileProvider.personalHome + ? mihCalendarProvider.personalAppointments! + : mihCalendarProvider.businessAppointments!; + return Padding( + padding: EdgeInsets.symmetric(horizontal: getPaddingSize()), + child: ListView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: appointmentList.length, + itemBuilder: (context, index) { + return displayAppointment( + mzansiProfileProvider, mihCalendarProvider, index, width); + }, + ), + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/calendar/mzansi_calendar.dart b/Frontend/lib/mih_packages/calendar/mzansi_calendar.dart index fc148291..cb0687e4 100644 --- a/Frontend/lib/mih_packages/calendar/mzansi_calendar.dart +++ b/Frontend/lib/mih_packages/calendar/mzansi_calendar.dart @@ -2,17 +2,15 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/calendar/package_tools/appointments.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class MzansiCalendar extends StatefulWidget { - final CalendarArguments arguments; const MzansiCalendar({ super.key, - required this.arguments, }); @override @@ -40,9 +38,9 @@ class _MzansiCalendarState extends State { iconSize: 35, onTap: () { // Navigator.of(context).pop(); + context.read().resetSelectedDay(); context.goNamed( 'mihHome', - extra: widget.arguments.personalSelected, ); FocusScope.of(context).unfocus(); }, @@ -64,19 +62,16 @@ class _MzansiCalendarState extends State { List getToolBody() { List toolBodies = [ //appointment here - Appointments( - signedInUser: widget.arguments.signedInUser, - business: widget.arguments.business, - businessUser: widget.arguments.businessUser, - personalSelected: widget.arguments.personalSelected, - ), + Appointments(), ]; return toolBodies; } List getToolTitle() { + MzansiProfileProvider mzansiProfileProvider = + context.read(); List toolTitles = [ - widget.arguments.personalSelected == true ? "Personal" : "Business", + mzansiProfileProvider.personalHome == true ? "Personal" : "Business", ]; return toolTitles; } diff --git a/Frontend/lib/mih_packages/calendar/package_tiles/mzansi_calendar_tile.dart b/Frontend/lib/mih_packages/calendar/package_tiles/mzansi_calendar_tile.dart index 7abb6097..545aac53 100644 --- a/Frontend/lib/mih_packages/calendar/package_tiles/mzansi_calendar_tile.dart +++ b/Frontend/lib/mih_packages/calendar/package_tiles/mzansi_calendar_tile.dart @@ -2,17 +2,14 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; class MzansiCalendarTile extends StatefulWidget { - final CalendarArguments arguments; final double packageSize; const MzansiCalendarTile({ super.key, - required this.arguments, required this.packageSize, }); @@ -27,7 +24,6 @@ class _MzansiCalendarTileState extends State { onTap: () { context.goNamed( "mihCalendar", - extra: widget.arguments, ); // Navigator.of(context).pushNamed( // '/calendar', diff --git a/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart b/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart index db9bb941..1d198a82 100644 --- a/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart +++ b/Frontend/lib/mih_packages/calendar/package_tools/appointments.dart @@ -1,7 +1,13 @@ +import 'package:flutter/material.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_calendar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_calendar_services.dart'; @@ -17,29 +23,12 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_time_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/appointment.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_packages/calendar/builder/build_appointment_list.dart'; -import 'package:flutter/material.dart'; -import '../../../main.dart'; - -import '../../../mih_components/mih_package_components/mih_calendar.dart'; -import '../../../mih_components/mih_pop_up_messages/mih_loading_circle.dart'; -import '../../../mih_config/mih_env.dart'; -import '../../../mih_components/mih_objects/app_user.dart'; +import 'package:provider/provider.dart'; class Appointments extends StatefulWidget { - final AppUser signedInUser; - final Business? business; - final BusinessUser? businessUser; - final bool personalSelected; - const Appointments({ super.key, - required this.signedInUser, - required this.business, - required this.businessUser, - required this.personalSelected, }); @override @@ -57,25 +46,18 @@ class _PatientAccessRequestState extends State { TextEditingController(); final TextEditingController _appointmentTimeController = TextEditingController(); - String baseUrl = AppEnviroment.baseApiUrl; - - String selectedDay = DateTime.now().toString().split(" ")[0]; - - late Future> personalAppointmentResults; - late Future> businessAppointmentResults; - late Future> appointmentResults; + bool isLoading = true; final _formKey = GlobalKey(); - Widget displayAppointmentList(List appointmentList) { + Widget displayAppointmentList(MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider) { + List appointmentList = mzansiProfileProvider.personalHome + ? mihCalendarProvider.personalAppointments! + : mihCalendarProvider.businessAppointments!; if (appointmentList.isNotEmpty) { return Expanded( child: BuildAppointmentList( - appointmentList: appointmentList, - signedInUser: widget.signedInUser, - business: widget.business, - businessUser: widget.businessUser, - personalSelected: widget.personalSelected, inWaitingRoom: false, titleController: _appointmentTitleController, descriptionIDController: _appointmentDescriptionIDController, @@ -101,7 +83,7 @@ class _PatientAccessRequestState extends State { ), const SizedBox(height: 10), Text( - "No appointments for $selectedDay", + "No appointments for ${mihCalendarProvider.selectedDay}", textAlign: TextAlign.center, overflow: TextOverflow.visible, style: TextStyle( @@ -147,7 +129,8 @@ class _PatientAccessRequestState extends State { ); } - void addAppointmentWindow(double width) { + void addAppointmentWindow(MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider, double width) { showDialog( context: context, barrierDismissible: false, @@ -227,7 +210,8 @@ class _PatientAccessRequestState extends State { child: MihButton( onPressed: () { if (_formKey.currentState!.validate()) { - addAppointmentCall(); + addAppointmentCall( + mzansiProfileProvider, mihCalendarProvider); } else { MihAlertServices().formNotFilledCompletely(context); } @@ -269,28 +253,33 @@ class _PatientAccessRequestState extends State { } } - Future addAppointmentCall() async { + Future addAppointmentCall( + MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider, + ) async { if (isAppointmentInputValid()) { int statusCode; - if (widget.personalSelected == false) { + if (mzansiProfileProvider.personalHome == false) { statusCode = await MihMzansiCalendarApis.addBusinessAppointment( - widget.signedInUser, - widget.business!, - widget.businessUser!, + mzansiProfileProvider.user!, + mzansiProfileProvider.business!, + mzansiProfileProvider.businessUser!, false, _appointmentTitleController.text, _appointmentDescriptionIDController.text, _appointmentDateController.text, _appointmentTimeController.text, + mihCalendarProvider, context, ); } else { statusCode = await MihMzansiCalendarApis.addPersonalAppointment( - widget.signedInUser, + mzansiProfileProvider.user!, _appointmentTitleController.text, _appointmentDescriptionIDController.text, _appointmentDateController.text, _appointmentTimeController.text, + mihCalendarProvider, context, ); } @@ -298,20 +287,20 @@ class _PatientAccessRequestState extends State { context.pop(); successPopUp("Successfully Added Appointment", "You appointment has been successfully added to your calendar."); - setState(() { - if (widget.personalSelected) { - appointmentResults = MihMzansiCalendarApis.getPersonalAppointments( - widget.signedInUser.app_id, - selectedDay, - ); - } else { - appointmentResults = MihMzansiCalendarApis.getBusinessAppointments( - widget.business!.business_id, - false, - selectedDay, - ); - } - }); + if (mzansiProfileProvider.personalHome == true) { + await MihMzansiCalendarApis.getPersonalAppointments( + mzansiProfileProvider.user!.app_id, + mihCalendarProvider.selectedDay, + mihCalendarProvider, + ); + } else { + await MihMzansiCalendarApis.getBusinessAppointments( + mzansiProfileProvider.business!.business_id, + false, + mihCalendarProvider.selectedDay, + mihCalendarProvider, + ); + } } else { internetConnectionPopUp(); } @@ -397,8 +386,8 @@ class _PatientAccessRequestState extends State { ); } - String getTitle() { - if (widget.personalSelected == false) { + String getTitle(MzansiProfileProvider mzansiProfileProvider) { + if (mzansiProfileProvider.personalHome == false) { return "Business Appointments"; } else { return "Personal Appointments"; @@ -407,108 +396,114 @@ class _PatientAccessRequestState extends State { void checkforchange() { setState(() { - if (widget.personalSelected == false) { - appointmentResults = MihMzansiCalendarApis.getBusinessAppointments( - widget.business!.business_id, - false, - selectedDay, - ); - } else { - appointmentResults = MihMzansiCalendarApis.getPersonalAppointments( - widget.signedInUser.app_id, - selectedDay, - ); - } + isLoading = true; }); + _loadInitialAppointments(); } Widget getBody(double width) { - return Stack( - children: [ - MihSingleChildScroll( - child: Column( - children: [ - MIHCalendar( - calendarWidth: 500, - rowHeight: 35, - setDate: (value) { - setState(() { - selectedDay = value; - selectedAppointmentDateController.text = selectedDay; - }); - }), - // Divider( - // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - Row( - mainAxisSize: MainAxisSize.max, + if (isLoading) { + return const Center( + child: Mihloadingcircle(), + ); + } + return Consumer2( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, + MihCalendarProvider mihCalendarProvider, + Widget? child) { + return Stack( + children: [ + MihSingleChildScroll( + child: Column( children: [ - FutureBuilder( - future: appointmentResults, - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.waiting) { - return const Expanded( - child: Center(child: Mihloadingcircle())); - } else if (snapshot.connectionState == - ConnectionState.done && - snapshot.hasData) { - return displayAppointmentList(snapshot.requireData); - } else { - return Center( - child: Text( - "Error pulling appointments", - style: TextStyle( - fontSize: 25, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark")), - textAlign: TextAlign.center, - ), - ); - } + MIHCalendar( + calendarWidth: 500, + rowHeight: 35, + setDate: (value) { + mihCalendarProvider.setSelectedDay(value); + setState(() { + selectedAppointmentDateController.text = value; + }); }), + // Divider( + // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // ), + Row( + mainAxisSize: MainAxisSize.max, + children: [ + displayAppointmentList( + mzansiProfileProvider, + mihCalendarProvider, + ), + ], + ) ], - ) - ], - ), - ), - Positioned( - right: 10, - bottom: 10, - child: MihFloatingMenu( - icon: Icons.add, - animatedIcon: AnimatedIcons.menu_close, - children: [ - SpeedDialChild( - child: Icon( - Icons.add, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - label: "Add Appointment", - labelBackgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - labelStyle: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontWeight: FontWeight.bold, - ), - backgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onTap: () { - addAppointmentWindow(width); - }, - ) - ], - ), - ), - ], + ), + ), + Positioned( + right: 10, + bottom: 10, + child: MihFloatingMenu( + icon: Icons.add, + animatedIcon: AnimatedIcons.menu_close, + children: [ + SpeedDialChild( + child: Icon( + Icons.add, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + label: "Add Appointment", + labelBackgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onTap: () { + addAppointmentWindow( + mzansiProfileProvider, mihCalendarProvider, width); + }, + ) + ], + ), + ), + ], + ); + }, ); } + Future _loadInitialAppointments() async { + MzansiProfileProvider mzansiProfileProvider = + context.read(); + MihCalendarProvider mihCalendarProvider = + context.read(); + if (mzansiProfileProvider.personalHome == false) { + await MihMzansiCalendarApis.getBusinessAppointments( + mzansiProfileProvider.business!.business_id, + false, + mihCalendarProvider.selectedDay, + mihCalendarProvider, + ); + } else { + await MihMzansiCalendarApis.getPersonalAppointments( + mzansiProfileProvider.user!.app_id, + mihCalendarProvider.selectedDay, + mihCalendarProvider, + ); + } + setState(() { + isLoading = false; + }); + } + @override void dispose() { selectedAppointmentDateController.dispose(); @@ -522,19 +517,8 @@ class _PatientAccessRequestState extends State { @override void initState() { selectedAppointmentDateController.addListener(checkforchange); - setState(() { - if (widget.personalSelected == false) { - appointmentResults = MihMzansiCalendarApis.getBusinessAppointments( - widget.business!.business_id, - false, - selectedDay, - ); - } else { - appointmentResults = MihMzansiCalendarApis.getPersonalAppointments( - widget.signedInUser.app_id, - selectedDay, - ); - } + WidgetsBinding.instance.addPostFrameCallback((_) async { + _loadInitialAppointments(); }); super.initState(); } diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart index 7c3c49bd..6b19a4c2 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart @@ -98,12 +98,6 @@ class _MihBusinessHomeState extends State //=============== Calendar =============== temp.add({ "Calendar": MzansiCalendarTile( - arguments: CalendarArguments( - mzansiProfileProvider.user!, - false, - mzansiProfileProvider.business!, - mzansiProfileProvider.businessUser!, - ), packageSize: packageSize, ) }); diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart index 0b879fc2..dac8ef6c 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart @@ -125,12 +125,6 @@ class _MihPersonalHomeState extends State //=============== Calendar =============== temp.add({ "Calendar": MzansiCalendarTile( - arguments: CalendarArguments( - widget.signedInUser, - true, - widget.business, - widget.businessUser, - ), packageSize: packageSize, ) }); diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/waiting_room.dart b/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/waiting_room.dart index 9dfe5cbf..89e737ef 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/waiting_room.dart +++ b/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/waiting_room.dart @@ -3,6 +3,8 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_calendar_services.dart'; @@ -26,6 +28,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_packages/calendar/builder/build_appointment_list.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class WaitingRoom extends StatefulWidget { final AppUser signedInUser; @@ -60,113 +63,91 @@ class _WaitingRoomState extends State { final TextEditingController _patientController = TextEditingController(); String baseUrl = AppEnviroment.baseApiUrl; - String selectedDay = DateTime.now().toString().split(" ")[0]; - late Future> businessAppointmentResults; late Future> appointmentResults; bool inWaitingRoom = true; + bool isLoading = true; final _formKey = GlobalKey(); // Business Appointment Tool Widget getBusinessAppointmentsTool(double width) { - return Stack( - children: [ - MihSingleChildScroll( - child: Column( - children: [ - MIHCalendar( - calendarWidth: 500, - rowHeight: 35, - setDate: (value) { - setState(() { - selectedDay = value; - selectedAppointmentDateController.text = selectedDay; - }); - }), - // Divider( - // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - Row( - mainAxisSize: MainAxisSize.max, + return Consumer( + builder: (BuildContext context, MihCalendarProvider mihCalendarProvider, + Widget? child) { + if (isLoading) { + return const Center( + child: Mihloadingcircle(), + ); + } + return Stack( + children: [ + MihSingleChildScroll( + child: Column( children: [ - FutureBuilder( - future: appointmentResults, - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.waiting) { - return const Expanded( - child: Center(child: Mihloadingcircle())); - } else if (snapshot.connectionState == - ConnectionState.done && - snapshot.hasData) { - return - // Container(child: const Placeholder()); - displayAppointmentList(snapshot.requireData); - } else { - return Center( - child: Text( - "Error pulling appointments", - style: TextStyle( - fontSize: 25, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark")), - textAlign: TextAlign.center, - ), - ); - } + MIHCalendar( + calendarWidth: 500, + rowHeight: 35, + setDate: (value) { + mihCalendarProvider.setSelectedDay(value); + setState(() { + selectedAppointmentDateController.text = value; + }); }), + // Divider( + // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // ), + Row( + mainAxisSize: MainAxisSize.max, + children: [ + displayAppointmentList(mihCalendarProvider), + ], + ) ], - ) - ], - ), - ), - Positioned( - right: 10, - bottom: 10, - child: MihFloatingMenu( - icon: Icons.add, - animatedIcon: AnimatedIcons.menu_close, - children: [ - SpeedDialChild( - child: Icon( - Icons.add, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - label: "Add Appointment", - labelBackgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - labelStyle: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontWeight: FontWeight.bold, - ), - backgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onTap: () { - // addAppointmentWindow(); - appointmentTypeSelection(width); - }, - ) - ], - ), - ), - ], + ), + ), + Positioned( + right: 10, + bottom: 10, + child: MihFloatingMenu( + icon: Icons.add, + animatedIcon: AnimatedIcons.menu_close, + children: [ + SpeedDialChild( + child: Icon( + Icons.add, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + label: "Add Appointment", + labelBackgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onTap: () { + // addAppointmentWindow(); + appointmentTypeSelection(mihCalendarProvider, width); + }, + ) + ], + ), + ), + ], + ); + }, ); } - Widget displayAppointmentList(List appointmentList) { - if (appointmentList.isNotEmpty) { + Widget displayAppointmentList(MihCalendarProvider mihCalendarProvider) { + if (mihCalendarProvider.businessAppointments!.isNotEmpty) { return Expanded( child: BuildAppointmentList( - appointmentList: appointmentList, - signedInUser: widget.signedInUser, - business: widget.business, - businessUser: widget.businessUser, - personalSelected: widget.personalSelected, inWaitingRoom: true, titleController: _appointmentTitleController, descriptionIDController: _appointmentDescriptionIDController, @@ -192,7 +173,7 @@ class _WaitingRoomState extends State { ), const SizedBox(height: 10), Text( - "No Appointments for $selectedDay", + "No Appointments for ${mihCalendarProvider.selectedDay}", textAlign: TextAlign.center, overflow: TextOverflow.visible, style: TextStyle( @@ -255,7 +236,8 @@ class _WaitingRoomState extends State { // ); } - void appointmentTypeSelection(double width) { + void appointmentTypeSelection( + MihCalendarProvider mihCalendarProvider, double width) { String question = "What type of appointment would you like to add?"; question += "\n\nExisting Patient: Add an appointment for an patient your practice has access to."; @@ -325,7 +307,7 @@ class _WaitingRoomState extends State { MihButton( onPressed: () { Navigator.pop(context); - addAppointmentWindow(width); + addAppointmentWindow(mihCalendarProvider, width); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -347,7 +329,8 @@ class _WaitingRoomState extends State { ); } - void addAppointmentWindow(double width) { + void addAppointmentWindow( + MihCalendarProvider mihCalendarProvider, double width) { showDialog( context: context, barrierDismissible: false, @@ -428,7 +411,7 @@ class _WaitingRoomState extends State { child: MihButton( onPressed: () { if (_formKey.currentState!.validate()) { - addAppointmentCall(); + addAppointmentCall(mihCalendarProvider); } else { MihAlertServices().formNotFilledCompletely(context); } @@ -459,7 +442,8 @@ class _WaitingRoomState extends State { ); } - Future addAppointmentCall() async { + Future addAppointmentCall( + MihCalendarProvider mihCalendarProvider) async { if (isAppointmentInputValid()) { int statusCode; if (widget.personalSelected == false) { @@ -472,6 +456,7 @@ class _WaitingRoomState extends State { _appointmentDescriptionIDController.text, _appointmentDateController.text, _appointmentTimeController.text, + mihCalendarProvider, context, ); } else { @@ -481,6 +466,7 @@ class _WaitingRoomState extends State { _appointmentDescriptionIDController.text, _appointmentDateController.text, _appointmentTimeController.text, + mihCalendarProvider, context, ); } @@ -488,6 +474,7 @@ class _WaitingRoomState extends State { context.pop(); successPopUp("Successfully Added Appointment", "You appointment has been successfully added to your calendar."); + _loadInitialAppointments(); } else { internetConnectionPopUp(); } @@ -585,11 +572,24 @@ class _WaitingRoomState extends State { void checkforchange() { setState(() { - appointmentResults = MihMzansiCalendarApis.getBusinessAppointments( - widget.business!.business_id, - true, - selectedDay, - ); + isLoading = true; + }); + _loadInitialAppointments(); + } + + Future _loadInitialAppointments() async { + MzansiProfileProvider mzansiProfileProvider = + context.read(); + MihCalendarProvider mihCalendarProvider = + context.read(); + await MihMzansiCalendarApis.getBusinessAppointments( + mzansiProfileProvider.business!.business_id, + false, + mihCalendarProvider.selectedDay, + mihCalendarProvider, + ); + setState(() { + isLoading = false; }); } @@ -606,12 +606,8 @@ class _WaitingRoomState extends State { @override void initState() { selectedAppointmentDateController.addListener(checkforchange); - setState(() { - appointmentResults = MihMzansiCalendarApis.getBusinessAppointments( - widget.business!.business_id, - true, - selectedDay, - ); + WidgetsBinding.instance.addPostFrameCallback((_) { + _loadInitialAppointments(); }); super.initState(); } diff --git a/Frontend/lib/mih_services/mih_mzansi_calendar_services.dart b/Frontend/lib/mih_services/mih_mzansi_calendar_services.dart index d01785aa..3acbeeea 100644 --- a/Frontend/lib/mih_services/mih_mzansi_calendar_services.dart +++ b/Frontend/lib/mih_services/mih_mzansi_calendar_services.dart @@ -8,6 +8,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart' import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; import 'package:supertokens_flutter/http.dart' as http; import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; import '../mih_components/mih_pop_up_messages/mih_success_message.dart'; @@ -23,9 +24,10 @@ class MihMzansiCalendarApis { /// date (yyyy-mm-dd), /// /// Returns Future>. - static Future> getPersonalAppointments( + static Future getPersonalAppointments( String app_id, String date, + MihCalendarProvider mihCalendarProvider, ) async { final response = await http.get(Uri.parse( "${AppEnviroment.baseApiUrl}/appointments/personal/$app_id?date=$date")); @@ -33,7 +35,9 @@ class MihMzansiCalendarApis { Iterable l = jsonDecode(response.body); List personalAppointments = List.from(l.map((model) => Appointment.fromJson(model))); - return personalAppointments; + mihCalendarProvider.setPersonalAppointments( + appointments: personalAppointments); + return response.statusCode; } else { throw Exception('failed to fatch personal appointments'); } @@ -46,38 +50,21 @@ class MihMzansiCalendarApis { /// date (yyyy-mm-dd), /// /// Returns Future>. - static Future> getBusinessAppointments( + static Future getBusinessAppointments( String business_id, bool waitingRoom, String date, + MihCalendarProvider mihCalendarProvider, ) async { - //print("Patien manager page: $endpoint"); final response = await http.get(Uri.parse( "${AppEnviroment.baseApiUrl}/appointments/business/$business_id?date=$date")); - // print("Here"); - // print("Body: ${response.body}"); - // print("Code: ${response.statusCode}"); - // errorCode = response.statusCode.toString(); - // errorBody = response.body; - if (response.statusCode == 200) { - //print("Here1"); Iterable l = jsonDecode(response.body); - //print("Here2"); List businessAppointments = List.from(l.map((model) => Appointment.fromJson(model))); - //print("Here3"); - //print(patientQueue); - // if (waitingRoom == true) { - // businessAppointments = businessAppointments - // .where((element) => element.app_id != "") - // .toList(); - // } else { - // businessAppointments = businessAppointments - // .where((element) => element.app_id == "") - // .toList(); - // } - return businessAppointments; + mihCalendarProvider.setBusinessAppointments( + appointments: businessAppointments); + return response.statusCode; } else { throw Exception('failed to fatch business appointments'); } @@ -98,6 +85,7 @@ class MihMzansiCalendarApis { BusinessUser? businessUser, bool inWaitingRoom, int idappointments, + MihCalendarProvider mihCalendarProvider, BuildContext context, ) async { loadingPopUp(context); @@ -109,6 +97,19 @@ class MihMzansiCalendarApis { body: jsonEncode({"idappointments": idappointments}), ); context.pop(); + if (response.statusCode == 200) { + if (personalSelected == true) { + mihCalendarProvider.deletePersonalAppointment( + appointmentId: idappointments); + getPersonalAppointments(signedInUser.app_id, + mihCalendarProvider.selectedDay, mihCalendarProvider); + } else { + mihCalendarProvider.deleteBusinessAppointment( + appointmentId: idappointments); + getBusinessAppointments(business!.business_id, inWaitingRoom, + mihCalendarProvider.selectedDay, mihCalendarProvider); + } + } return response.statusCode; //print("Here4"); //print(response.statusCode); @@ -163,6 +164,7 @@ class MihMzansiCalendarApis { String description, String date, String time, + MihCalendarProvider mihCalendarProvider, BuildContext context, ) async { loadingPopUp(context); @@ -181,6 +183,18 @@ class MihMzansiCalendarApis { }), ); context.pop(); + if (response.statusCode == 201) { + mihCalendarProvider.addPersonalAppointment( + newAppointment: Appointment( + idappointments: 0, + app_id: signedInUser.app_id, + business_id: "", + date_time: "$date $time", + title: title, + description: description, + ), + ); + } return response.statusCode; // if (response.statusCode == 201) { // Navigator.pop(context); @@ -227,6 +241,7 @@ class MihMzansiCalendarApis { String description, String date, String time, + MihCalendarProvider mihCalendarProvider, BuildContext context, ) async { loadingPopUp(context); @@ -245,43 +260,19 @@ class MihMzansiCalendarApis { }), ); context.pop(); + if (response.statusCode == 201) { + mihCalendarProvider.addBusinessAppointment( + newAppointment: Appointment( + idappointments: 0, + app_id: "", + business_id: business.business_id, + date_time: "$date $time", + title: title, + description: description, + ), + ); + } return response.statusCode; - // if (response.statusCode == 201) { - // // Navigator.pop(context); - // Navigator.pop(context); - // Navigator.pop(context); - // Navigator.pop(context); - // String message = - // "Your appointment \"$title\" for the $date $title has been deleted."; - - // // Navigator.pop(context); - // if (inWaitingRoom) { - // Navigator.of(context).pushNamed( - // '/patient-manager', - // arguments: PatManagerArguments( - // signedInUser, - // false, - // business, - // businessUser, - // ), - // ); - // } else { - // Navigator.of(context).pushNamed( - // '/calendar', - // arguments: CalendarArguments( - // signedInUser, - // false, - // business, - // businessUser, - // ), - // ); - // } - - // successPopUp(message, context); - // } else { - // Navigator.pop(context); - // internetConnectionPopUp(context); - // } } /// This function is used to add an appointment to users mzansi Calendar. @@ -324,20 +315,6 @@ class MihMzansiCalendarApis { ); context.pop(); return response.statusCode; - // if (response.statusCode == 201) { - // MihNotificationApis.addNewAppointmentNotificationAPICall( - // patientAppId, - // personalSelected, - // date, - // time, - // businessArgs, - // context, - // ); - // // Navigator.pop(context); - // } else { - // Navigator.pop(context); - // internetConnectionPopUp(context); - // } } /// This function is used to update an appointment to users mzansi Calendar. @@ -362,6 +339,7 @@ class MihMzansiCalendarApis { String description, String date, String time, + MihCalendarProvider mihCalendarProvider, BuildContext context, ) async { loadingPopUp(context); @@ -379,6 +357,18 @@ class MihMzansiCalendarApis { }), ); context.pop(); + if (response.statusCode == 200) { + mihCalendarProvider.editPersonalAppointment( + updatedAppointment: Appointment( + idappointments: idappointments, + app_id: signedInUser.app_id, + business_id: "", + date_time: "$date $time", + title: title, + description: description, + ), + ); + } return response.statusCode; // if (response.statusCode == 200) { // Navigator.pop(context); @@ -426,6 +416,7 @@ class MihMzansiCalendarApis { String description, String date, String time, + MihCalendarProvider mihCalendarProvider, BuildContext context, ) async { loadingPopUp(context); @@ -443,6 +434,18 @@ class MihMzansiCalendarApis { }), ); context.pop(); + if (response.statusCode == 200) { + mihCalendarProvider.editBusinessAppointment( + updatedAppointment: Appointment( + idappointments: idappointments, + app_id: "", + business_id: business!.business_id, + date_time: "$date $time", + title: title, + description: description, + ), + ); + } return response.statusCode; // if (response.statusCode == 200) { // Navigator.pop(context); From b0d38b4b117e6c508194c599ecebea1c53b4f742 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 21 Oct 2025 15:42:38 +0200 Subject: [PATCH 27/45] NEW: MIH Access Controlls Provider Setup --- Frontend/lib/main.dart | 4 + .../mih_access_controlls_provider.dart | 31 ++ Frontend/lib/mih_config/mih_go_router.dart | 4 +- .../access_review/mih_access.dart | 23 +- .../package_tile/mih_access_tile.dart | 4 - .../package_tools/mih_access_requests.dart | 296 ++++++------------ .../calendar/mzansi_calendar.dart | 1 - .../package_tools/mih_personal_home.dart | 2 - .../package_tiles/mih_wallet_tile.dart | 5 - .../mih_access_controls_services.dart | 25 ++ .../lib/mih_services/mih_service_calls.dart | 36 --- 11 files changed, 167 insertions(+), 264 deletions(-) create mode 100644 Frontend/lib/mih_components/mih_providers/mih_access_controlls_provider.dart diff --git a/Frontend/lib/main.dart b/Frontend/lib/main.dart index efee465d..9e9925f6 100644 --- a/Frontend/lib/main.dart +++ b/Frontend/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/about_mih_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_access_controlls_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_authentication_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calculator_provider.dart'; @@ -96,6 +97,9 @@ class _MzansiInnovationHubState extends State { ChangeNotifierProvider( create: (context) => MihCalculatorProvider(), ), + ChangeNotifierProvider( + create: (context) => MihAccessControllsProvider(), + ), ChangeNotifierProvider( create: (context) => MihCalendarProvider(), ), diff --git a/Frontend/lib/mih_components/mih_providers/mih_access_controlls_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_access_controlls_provider.dart new file mode 100644 index 00000000..4fb1c2b6 --- /dev/null +++ b/Frontend/lib/mih_components/mih_providers/mih_access_controlls_provider.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; + +class MihAccessControllsProvider extends ChangeNotifier { + int toolIndex; + List? accessList; + + MihAccessControllsProvider({ + this.toolIndex = 0, + }); + + void setToolIndex(int index) { + toolIndex = index; + } + + void setAccessList(List accesses) { + accessList = accesses; + notifyListeners(); + } + + void editAccessItem(PatientAccess updatedAccess) { + if (accessList == null) return; + int index = accessList!.indexWhere((access) => + access.app_id == updatedAccess.app_id && + access.business_id == updatedAccess.business_id); + if (index != -1) { + accessList![index] = updatedAccess; + notifyListeners(); + } + } +} diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index 69732265..b315cc52 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -321,8 +321,7 @@ class MihGoRouter { name: "mihAccess", path: MihGoRouterPaths.mihAccess, builder: (BuildContext context, GoRouterState state) { - final AppUser? signedInUser = state.extra as AppUser?; - if (signedInUser == null) { + if (context.watch().business == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); @@ -330,7 +329,6 @@ class MihGoRouter { } return MihAccess( key: UniqueKey(), - signedInUser: signedInUser, ); }, ), diff --git a/Frontend/lib/mih_packages/access_review/mih_access.dart b/Frontend/lib/mih_packages/access_review/mih_access.dart index bd456813..73d4e325 100644 --- a/Frontend/lib/mih_packages/access_review/mih_access.dart +++ b/Frontend/lib/mih_packages/access_review/mih_access.dart @@ -2,15 +2,14 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_access_controlls_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/access_review/package_tools/mih_access_requests.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class MihAccess extends StatefulWidget { - final AppUser signedInUser; const MihAccess({ super.key, - required this.signedInUser, }); @override @@ -18,7 +17,6 @@ class MihAccess extends StatefulWidget { } class _MihAccessState extends State { - int _selcetedIndex = 0; @override Widget build(BuildContext context) { return MihPackage( @@ -26,12 +24,9 @@ class _MihAccessState extends State { appTools: getTools(), appBody: getToolBody(), appToolTitles: getToolTitle(), - selectedbodyIndex: _selcetedIndex, + selectedbodyIndex: context.watch().toolIndex, onIndexChange: (newValue) { - setState(() { - _selcetedIndex = newValue; - }); - print("Index: $_selcetedIndex"); + context.read().setToolIndex(newValue); }, ); } @@ -52,21 +47,17 @@ class _MihAccessState extends State { MihPackageTools getTools() { Map temp = {}; temp[const Icon(Icons.people)] = () { - setState(() { - _selcetedIndex = 0; - }); + context.read().setToolIndex(0); }; return MihPackageTools( tools: temp, - selcetedIndex: _selcetedIndex, + selcetedIndex: context.watch().toolIndex, ); } List getToolBody() { List toolBodies = [ - MihAccessRequest( - signedInUser: widget.signedInUser, - ), + MihAccessRequest(), ]; return toolBodies; } diff --git a/Frontend/lib/mih_packages/access_review/package_tile/mih_access_tile.dart b/Frontend/lib/mih_packages/access_review/package_tile/mih_access_tile.dart index 1e5a4ea7..8574ef9e 100644 --- a/Frontend/lib/mih_packages/access_review/package_tile/mih_access_tile.dart +++ b/Frontend/lib/mih_packages/access_review/package_tile/mih_access_tile.dart @@ -2,17 +2,14 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; class MihAccessTile extends StatefulWidget { - final AppUser signedInUser; final double packageSize; const MihAccessTile({ super.key, - required this.signedInUser, required this.packageSize, }); @@ -28,7 +25,6 @@ class _MihAccessTileState extends State { onTap: () { context.goNamed( "mihAccess", - extra: widget.signedInUser, ); // Navigator.of(context).pushNamed( // '/mih-access', diff --git a/Frontend/lib/mih_packages/access_review/package_tools/mih_access_requests.dart b/Frontend/lib/mih_packages/access_review/package_tools/mih_access_requests.dart index aca607c2..1fc2f9d8 100644 --- a/Frontend/lib/mih_packages/access_review/package_tools/mih_access_requests.dart +++ b/Frontend/lib/mih_packages/access_review/package_tools/mih_access_requests.dart @@ -1,28 +1,24 @@ import 'package:go_router/go_router.dart'; import 'package:ken_logger/ken_logger.dart'; -import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; -import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_action.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_header.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_access_controlls_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:mzansi_innovation_hub/mih_packages/access_review/builder/build_business_access_list.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_access_controls_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:flutter/material.dart'; -import '../../../mih_services/mih_service_calls.dart'; -import '../../../mih_components/mih_layout/mih_action.dart'; -import '../../../mih_components/mih_layout/mih_header.dart'; -import '../../../mih_components/mih_pop_up_messages/mih_loading_circle.dart'; -import '../../../mih_config/mih_env.dart'; -import '../../../mih_components/mih_objects/app_user.dart'; -import '../../../mih_components/mih_objects/patient_access.dart'; -import '../builder/build_business_access_list.dart'; +import 'package:provider/provider.dart'; class MihAccessRequest extends StatefulWidget { - final AppUser signedInUser; - const MihAccessRequest({ super.key, - required this.signedInUser, }); @override @@ -31,7 +27,7 @@ class MihAccessRequest extends StatefulWidget { class _MihAccessRequestState extends State { TextEditingController filterController = TextEditingController(); - + bool isLoading = true; String baseUrl = AppEnviroment.baseApiUrl; String errorCode = ""; @@ -41,35 +37,8 @@ class _MihAccessRequestState extends State { bool forceRefresh = false; late String selectedDropdown; - late Future> accessList; - - // Future> fetchAccessRequests() async { - // //print("Patien manager page: $endpoint"); - // final response = await http.get( - // Uri.parse("$baseUrl/access-requests/${widget.signedInUser.app_id}")); - // // print("Here"); - // // print("Body: ${response.body}"); - // // print("Code: ${response.statusCode}"); - // errorCode = response.statusCode.toString(); - // errorBody = response.body; - - // if (response.statusCode == 200) { - // //print("Here1"); - // Iterable l = jsonDecode(response.body); - // //print("Here2"); - // List patientQueue = List.from( - // l.map((model) => AccessRequest.fromJson(model))); - // //print("Here3"); - // //print(patientQueue); - // return patientQueue; - // } else { - // throw Exception('failed to load patients'); - // } - // } - List filterSearchResults(List accessList) { List templist = []; - for (var item in accessList) { if (filterController.text == "All") { templist.add(item); @@ -83,16 +52,24 @@ class _MihAccessRequestState extends State { } void refreshList() { + MzansiProfileProvider mzansiProfileProvider = + context.read(); + MihAccessControllsProvider accessProvider = + context.read(); if (forceRefresh == true) { + MihAccessControlsServices().getBusinessAccessListOfPatient( + mzansiProfileProvider.user!.app_id, + accessProvider, + ); setState(() { - accessList = MIHApiCalls.getBusinessAccessListOfPatient( - widget.signedInUser.app_id); forceRefresh = false; }); } else if (selectedDropdown != filterController.text) { + MihAccessControlsServices().getBusinessAccessListOfPatient( + mzansiProfileProvider.user!.app_id, + accessProvider, + ); setState(() { - accessList = MIHApiCalls.getBusinessAccessListOfPatient( - widget.signedInUser.app_id); selectedDropdown = filterController.text; }); } @@ -131,166 +108,92 @@ class _MihAccessRequestState extends State { } Widget getBody() { - return MihSingleChildScroll( - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.max, + return Consumer2( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, + MihAccessControllsProvider accessProvider, + Widget? child) { + if (isLoading) { + return const Center( + child: Mihloadingcircle(), + ); + } + return MihSingleChildScroll( + child: Column( children: [ - Flexible( - child: MihDropdownField( - controller: filterController, - hintText: "Access Type", - dropdownOptions: const [ - "All", - "Approved", - "Pending", - "Declined", - "Cancelled", - ], - requiredText: true, - editable: true, - enableSearch: true, - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - ), - IconButton( - iconSize: 35, - onPressed: () { - setState(() { - forceRefresh = true; - }); - KenLogger.warning("Refreshing Access List"); - refreshList(); - }, - icon: const Icon( - Icons.refresh, - ), - ), - ], - ), - const SizedBox(height: 10), - FutureBuilder( - future: accessList, - builder: (context, snapshot) { - //print("patient Queue List ${snapshot.hasData}"); - if (snapshot.connectionState == ConnectionState.waiting) { - return const Mihloadingcircle(); - } else if (snapshot.connectionState == ConnectionState.done) { - List accessRequestList; - accessRequestList = filterSearchResults(snapshot.requireData); - if (accessRequestList.isNotEmpty) { - return BuildBusinessAccessList( - signedInUser: widget.signedInUser, - patientAccessList: accessRequestList, - onSuccessUpate: () { + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + child: MihDropdownField( + controller: filterController, + hintText: "Access Type", + dropdownOptions: const [ + "All", + "Approved", + "Pending", + "Declined", + "Cancelled", + ], + requiredText: true, + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + ), + IconButton( + iconSize: 35, + onPressed: () { setState(() { forceRefresh = true; }); + KenLogger.warning("Refreshing Access List"); refreshList(); }, - ); - } else { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 50), - Icon( - MihIcons.accessControl, - size: 165, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - const SizedBox(height: 10), - Text( - "No access has been granted to your MIH Profile", - textAlign: TextAlign.center, - overflow: TextOverflow.visible, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - // const SizedBox(height: 10), - // Center( - // child: RichText( - // textAlign: TextAlign.center, - // text: TextSpan( - // style: TextStyle( - // fontSize: 20, - // fontWeight: FontWeight.normal, - // color: MzansiInnovationHub.of(context)! - // .theme - // .secondaryColor(), - // ), - // children: [ - // TextSpan(text: "Press "), - // WidgetSpan( - // alignment: PlaceholderAlignment.middle, - // child: Icon( - // Icons.menu, - // size: 20, - // color: MzansiInnovationHub.of(context)! - // .theme - // .secondaryColor(), - // ), - // ), - // TextSpan( - // text: " to add your first loyalty card."), - // ], - // ), - // ), - // ), - ], + icon: const Icon( + Icons.refresh, ), - ); - // return Center( - // child: Text( - // "No Request have been made.", - // style: TextStyle( - // fontSize: 25, - // color: MzansiInnovationHub.of(context)! - // .theme - // .messageTextColor()), - // textAlign: TextAlign.center, - // ), - // ); - } - - // return Expanded( - // child: displayAccessRequestList(accessRequestList), - // ); - } else { - return Center( - child: Text( - "$errorCode: Error pulling Patients Data\n$baseUrl/queue/patients/\n$errorBody", - style: TextStyle( - fontSize: 25, - color: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark")), - textAlign: TextAlign.center, ), - ); - } - }, + ], + ), + const SizedBox(height: 10), + BuildBusinessAccessList( + filterText: filterController.text, + onSuccessUpate: () { + setState(() { + forceRefresh = true; + }); + refreshList(); + }, + ), + ], ), - ], - ), + ); + }, ); } + Future initiasizeAccessList() async { + MzansiProfileProvider mzansiProfileProvider = + context.read(); + MihAccessControllsProvider accessProvider = + context.read(); + setState(() { + isLoading = true; + }); + await MihAccessControlsServices().getBusinessAccessListOfPatient( + mzansiProfileProvider.user!.app_id, + accessProvider, + ); + setState(() { + isLoading = false; + }); + } + @override void dispose() { filterController.dispose(); @@ -302,9 +205,8 @@ class _MihAccessRequestState extends State { selectedDropdown = "All"; filterController.text = "All"; filterController.addListener(refreshList); - setState(() { - accessList = MIHApiCalls.getBusinessAccessListOfPatient( - widget.signedInUser.app_id); + WidgetsBinding.instance.addPostFrameCallback((_) async { + await initiasizeAccessList(); }); super.initState(); } diff --git a/Frontend/lib/mih_packages/calendar/mzansi_calendar.dart b/Frontend/lib/mih_packages/calendar/mzansi_calendar.dart index cb0687e4..45f093da 100644 --- a/Frontend/lib/mih_packages/calendar/mzansi_calendar.dart +++ b/Frontend/lib/mih_packages/calendar/mzansi_calendar.dart @@ -37,7 +37,6 @@ class _MzansiCalendarState extends State { icon: const Icon(Icons.arrow_back), iconSize: 35, onTap: () { - // Navigator.of(context).pop(); context.read().resetSelectedDay(); context.goNamed( 'mihHome', diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart index dac8ef6c..941055be 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart @@ -98,7 +98,6 @@ class _MihPersonalHomeState extends State //=============== Mzansi Wallet =============== temp.add({ "Mzansi Wallet": MihWalletTile( - signedInUser: widget.signedInUser, packageSize: packageSize, ) }); @@ -150,7 +149,6 @@ class _MihPersonalHomeState extends State //=============== MIH Access =============== temp.add({ "MIH Access": MihAccessTile( - signedInUser: widget.signedInUser, packageSize: packageSize, ) }); diff --git a/Frontend/lib/mih_packages/mzansi_wallet/package_tiles/mih_wallet_tile.dart b/Frontend/lib/mih_packages/mzansi_wallet/package_tiles/mih_wallet_tile.dart index ddb89401..baa72c54 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/package_tiles/mih_wallet_tile.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/package_tiles/mih_wallet_tile.dart @@ -2,18 +2,14 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:flutter/material.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; class MihWalletTile extends StatefulWidget { - final AppUser signedInUser; final double packageSize; const MihWalletTile({ super.key, - required this.signedInUser, required this.packageSize, }); @@ -29,7 +25,6 @@ class _MihWalletTileState extends State { onTap: () { context.goNamed( 'mzansiWallet', - extra: WalletArguments(widget.signedInUser, 0), ); // Navigator.of(context).pushNamed( // '/mzansi-wallet', diff --git a/Frontend/lib/mih_services/mih_access_controls_services.dart b/Frontend/lib/mih_services/mih_access_controls_services.dart index 931c4899..65718929 100644 --- a/Frontend/lib/mih_services/mih_access_controls_services.dart +++ b/Frontend/lib/mih_services/mih_access_controls_services.dart @@ -2,11 +2,36 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_access_controlls_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:supertokens_flutter/http.dart' as http; class MihAccessControlsServices { + Future getBusinessAccessListOfPatient( + String app_id, + MihAccessControllsProvider mihAccessColtrollsProvider, + ) async { + final response = await http.get(Uri.parse( + "${AppEnviroment.baseApiUrl}/access-requests/personal/patient/$app_id")); + // var errorCode = response.statusCode.toString(); + // print(response.statusCode); + // print(response.body); + + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List patientAccesses = List.from( + l.map((model) => PatientAccess.fromJson(model))); + if (response.statusCode == 200) { + mihAccessColtrollsProvider.setAccessList(patientAccesses); + } + return response.statusCode; + } else { + throw Exception('failed to pull patient access List for business'); + } + } + /// This function is used to UPDATE access the business has. /// /// Patameters:- diff --git a/Frontend/lib/mih_services/mih_service_calls.dart b/Frontend/lib/mih_services/mih_service_calls.dart index 9375c2ec..ec463b70 100644 --- a/Frontend/lib/mih_services/mih_service_calls.dart +++ b/Frontend/lib/mih_services/mih_service_calls.dart @@ -1,5 +1,4 @@ import 'dart:convert'; - import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_my_business_user_services.dart'; @@ -7,20 +6,8 @@ import 'package:mzansi_innovation_hub/mih_services/mih_notification_services.dar import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; -// import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; -// import '../mih_components/mih_pop_up_messages/mih_success_message.dart'; -// import '../mih_env/mih_env.dart'; -// import '../mih_objects/app_user.dart'; -// import '../mih_objects/arguments.dart'; -// import '../mih_objects/business.dart'; -// import '../mih_objects/business_user.dart'; -// import '../mih_objects/notification.dart'; -// import '../mih_objects/patient_access.dart'; -// import '../mih_objects/patient_queue.dart'; -// import '../mih_objects/patients.dart'; import 'package:supertokens_flutter/supertokens.dart'; import 'package:supertokens_flutter/http.dart' as http; - import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; import '../mih_components/mih_pop_up_messages/mih_success_message.dart'; import '../mih_config/mih_env.dart'; @@ -163,29 +150,6 @@ class MIHApiCalls { } } - /// This function is used to get list of access the business has. - /// - /// Patameters: String business_id. - /// - /// Returns List (List of access that match the above parameters). - static Future> getBusinessAccessListOfPatient( - String app_id) async { - final response = await http.get(Uri.parse( - "${AppEnviroment.baseApiUrl}/access-requests/personal/patient/$app_id")); - // var errorCode = response.statusCode.toString(); - // print(response.statusCode); - // print(response.body); - - if (response.statusCode == 200) { - Iterable l = jsonDecode(response.body); - List patientAccesses = List.from( - l.map((model) => PatientAccess.fromJson(model))); - return patientAccesses; - } else { - throw Exception('failed to pull patient access List for business'); - } - } - /// This function is used to UPDATE access the business has. /// /// Patameters:- From 9bd039ca257954ccc584c95be176a008c5e8365b Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 22 Oct 2025 14:43:01 +0200 Subject: [PATCH 28/45] NEW: Mzansi Directory Provider Setup --- Frontend/lib/main.dart | 4 + .../package_tools/package_tool_one.dart | 3 +- .../mih_business_profile_preview.dart | 147 +-- .../mzansi_directory_provider.dart | 84 ++ Frontend/lib/mih_config/mih_go_router.dart | 23 +- .../builder/build_business_access_list.dart | 128 ++- .../package_tools/mih_business_home.dart | 1 - .../package_tools/mih_personal_home.dart | 1 - .../build_business_search_resultsList.dart | 91 +- .../build_favourite_businesses_list.dart | 92 +- .../build_user_search_results_list.dart | 79 +- .../mzansi_directory/mzansi_directory.dart | 99 +- .../package_tiles/mzansi_directory_tile.dart | 7 - .../mih_favourite_businesses.dart | 263 +++--- .../package_tools/mih_search_mzansi.dart | 894 +++++++++--------- .../components/mih_add_bookmark_alert.dart | 138 +-- .../components/mih_business_info_card.dart | 562 ++++++----- .../components/mih_delete_bookmark_alert.dart | 26 +- .../mih_review_business_window.dart | 550 ++++++----- .../mzansi_business_profile.dart | 2 +- .../mzansi_business_profile_view.dart | 106 +-- .../package_tools/mih_business_details.dart | 2 +- .../mih_business_details_view.dart | 338 +++---- .../package_tools/mih_business_qr_code.dart | 4 +- .../package_tools/mih_business_reviews.dart | 1 + .../personal_profile/mzansi_profile_view.dart | 18 +- .../mih_personal_profile_view.dart | 262 +++-- .../mih_mzansi_directory_services.dart | 10 +- 28 files changed, 2007 insertions(+), 1928 deletions(-) create mode 100644 Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart diff --git a/Frontend/lib/main.dart b/Frontend/lib/main.dart index 9e9925f6..3569ecb1 100644 --- a/Frontend/lib/main.dart +++ b/Frontend/lib/main.dart @@ -8,6 +8,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calculato import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_ai_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; @@ -91,6 +92,9 @@ class _MzansiInnovationHubState extends State { ChangeNotifierProvider( create: (context) => MzansiAiProvider(), ), + ChangeNotifierProvider( + create: (context) => MzansiDirectoryProvider(), + ), ChangeNotifierProvider( create: (context) => MihBannerAdProvider(), ), diff --git a/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart b/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart index 16d0bd2c..e72699bf 100644 --- a/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart +++ b/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart @@ -396,7 +396,6 @@ class _PackageToolOneState extends State { return widget.business != null ? MihBusinessProfilePreview( business: widget.business!, - myLocation: myLocation, ) : Text("NoBusiness Data"); } @@ -424,7 +423,7 @@ class _PackageToolOneState extends State { "rating", "mission_vision", ), - startUpSearch: '', + // startUpSearch: '', width: 300, ).redacted( context: context, diff --git a/Frontend/lib/mih_components/mih_package_components/mih_business_profile_preview.dart b/Frontend/lib/mih_components/mih_package_components/mih_business_profile_preview.dart index 725c1183..53683653 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_business_profile_preview.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_business_profile_preview.dart @@ -4,17 +4,17 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_location_services.dart'; +import 'package:provider/provider.dart'; class MihBusinessProfilePreview extends StatefulWidget { final Business business; - final String? myLocation; const MihBusinessProfilePreview({ super.key, required this.business, - required this.myLocation, }); @override @@ -26,10 +26,10 @@ class _MihBusinessProfilePreviewState extends State { late Future futureImageUrl; PlatformFile? file; - String calculateDistance() { + String calculateDistance(MzansiDirectoryProvider directoryProvider) { try { double distanceInKm = MIHLocationAPI().getDistanceInMeaters( - widget.myLocation!, widget.business.gps_location) / + directoryProvider.userLocation, widget.business.gps_location) / 1000; return "${distanceInKm.toStringAsFixed(2)} km"; } catch (error) { @@ -48,73 +48,82 @@ class _MihBusinessProfilePreviewState extends State { @override Widget build(BuildContext context) { double profilePictureWidth = 60; - return Row( - children: [ - FutureBuilder( - future: futureImageUrl, - builder: (context, asyncSnapshot) { - if (asyncSnapshot.connectionState == ConnectionState.done && - asyncSnapshot.hasData) { - if (asyncSnapshot.requireData != "") { - return MihCircleAvatar( - imageFile: NetworkImage(asyncSnapshot.requireData), - width: profilePictureWidth, - editable: false, - fileNameController: TextEditingController(), - userSelectedfile: file, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onChange: () {}, - ); - } else { - return Icon( - MihIcons.iDontKnow, - size: profilePictureWidth, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - } - } else { - return Icon( - MihIcons.mihRing, - size: profilePictureWidth, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - } - }), - const SizedBox(width: 15), - Column( - crossAxisAlignment: CrossAxisAlignment.start, + return Consumer( + builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, + Widget? child) { + return Row( children: [ - Text( - widget.business.Name, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - Text( - widget.business.type, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 15, - ), - ), - Text( - widget.myLocation != null || widget.myLocation!.isEmpty - ? calculateDistance() - : "0.00 km", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 10, - ), - ), + FutureBuilder( + future: futureImageUrl, + builder: (context, asyncSnapshot) { + if (asyncSnapshot.connectionState == ConnectionState.done && + asyncSnapshot.hasData) { + if (asyncSnapshot.requireData != "") { + return MihCircleAvatar( + imageFile: NetworkImage(asyncSnapshot.requireData), + width: profilePictureWidth, + editable: false, + fileNameController: TextEditingController(), + userSelectedfile: file, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: () {}, + ); + } else { + return Icon( + MihIcons.iDontKnow, + size: profilePictureWidth, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ); + } + } else { + return Icon( + MihIcons.mihRing, + size: profilePictureWidth, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ); + } + }), + const SizedBox(width: 15), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.business.Name, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + Text( + widget.business.type, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 15, + ), + ), + Text( + directoryProvider.userPosition != null + ? calculateDistance(directoryProvider) + : "0.00 km", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 10, + ), + ), + ], + ) ], - ) - ], + ); + }, ); } } diff --git a/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart b/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart new file mode 100644 index 00000000..e18bcc3d --- /dev/null +++ b/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/bookmarked_business.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; + +class MzansiDirectoryProvider extends ChangeNotifier { + int toolIndex; + Position? userPosition; + String userLocation; + bool personalSearch; + List bookmarkedBusinesses = []; + Map businessDetailsMap = {}; + List? searchedBusinesses; + Business? selectedBusiness; + List? searchedUsers; + AppUser? selectedUser; + String searchTerm; + String businessTypeFilter; + + MzansiDirectoryProvider({ + this.toolIndex = 0, + this.personalSearch = true, + this.userLocation = "Unknown Location", + this.searchTerm = "", + this.businessTypeFilter = "", + }); + + void setToolIndex(int index) { + toolIndex = index; + notifyListeners(); + } + + void setUserPosition(Position? position) { + userPosition = position; + userLocation = "${position?.latitude}, ${position?.longitude}"; + notifyListeners(); + } + + void setPersonalSearch(bool personal) { + personalSearch = personal; + notifyListeners(); + } + + void setFavouriteBusinesses({required List businesses}) { + bookmarkedBusinesses = businesses; + notifyListeners(); + } + + void setBusinessDetailsMap({required Map detailsMap}) { + businessDetailsMap = detailsMap; + notifyListeners(); + } + + void setSearchedBusinesses({required List searchedBusinesses}) { + this.searchedBusinesses = searchedBusinesses; + notifyListeners(); + } + + void setSelectedBusiness({required Business business}) { + selectedBusiness = business; + notifyListeners(); + } + + void setSearchedUsers({required List searchedUsers}) { + this.searchedUsers = searchedUsers; + notifyListeners(); + } + + void setSelectedUser({required AppUser user}) { + selectedUser = user; + notifyListeners(); + } + + void setSearchTerm({required String searchTerm}) { + this.searchTerm = searchTerm; + notifyListeners(); + } + + void setBusinessTypeFilter({required String businessTypeFilter}) { + this.businessTypeFilter = businessTypeFilter; + notifyListeners(); + } +} diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index b315cc52..42bb7d73 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_print_prevew.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/Example/package_test.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/about_mih/about_mih.dart'; import 'package:mzansi_innovation_hub/mih_packages/access_review/mih_access.dart'; @@ -169,14 +169,15 @@ class MihGoRouter { path: MihGoRouterPaths.mzansiProfileView, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: mzansiProfileView"); - final AppUser? user = state.extra as AppUser?; - if (user == null) { + MzansiDirectoryProvider directoryProvider = + context.read(); + if (directoryProvider.selectedUser == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); return const SizedBox.shrink(); } - return MzansiProfileView(user: user); + return MzansiProfileView(); }, ), // ========================== Mzansi Profile Business ================================== @@ -203,9 +204,10 @@ class MihGoRouter { KenLogger.success("MihGoRouter: businessProfileView"); String? businessId = state.uri.queryParameters['business_id']; KenLogger.success("businessId: $businessId"); - final BusinessViewArguments? args = - state.extra as BusinessViewArguments?; - if (args == null && businessId == null) { + MzansiDirectoryProvider directoryProvider = + context.read(); + if (directoryProvider.selectedBusiness == null && + businessId == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); @@ -213,7 +215,6 @@ class MihGoRouter { } return MzansiBusinessProfileView( key: UniqueKey(), - arguments: args, businessId: businessId, ); }, @@ -406,15 +407,13 @@ class MihGoRouter { name: "mzansiDirectory", path: MihGoRouterPaths.mzansiDirectory, builder: (BuildContext context, GoRouterState state) { - final MzansiDirectoryArguments? args = - state.extra as MzansiDirectoryArguments?; - if (args == null) { + if (context.watch().business == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); return const SizedBox.shrink(); } - return MzansiDirectory(arguments: args); + return MzansiDirectory(); }, ), // ========================== End ================================== diff --git a/Frontend/lib/mih_packages/access_review/builder/build_business_access_list.dart b/Frontend/lib/mih_packages/access_review/builder/build_business_access_list.dart index 2aca7f2c..782c75a3 100644 --- a/Frontend/lib/mih_packages/access_review/builder/build_business_access_list.dart +++ b/Frontend/lib/mih_packages/access_review/builder/build_business_access_list.dart @@ -2,7 +2,10 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_access_controlls_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_access_controls_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; @@ -10,18 +13,15 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_warning_message.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; +import 'package:provider/provider.dart'; class BuildBusinessAccessList extends StatefulWidget { - final List patientAccessList; - final AppUser signedInUser; + final String filterText; final void Function()? onSuccessUpate; const BuildBusinessAccessList({ super.key, - required this.patientAccessList, - required this.signedInUser, + required this.filterText, required this.onSuccessUpate, }); @@ -60,18 +60,20 @@ class _BuildPatientsListState extends State { ); } - Widget displayQueue(int index) { - String line1 = - "Business Name: ${widget.patientAccessList[index].requested_by}"; + Widget displayQueue( + MzansiProfileProvider mzansiProfileProvider, + MihAccessControllsProvider accessProvider, + int index, + List filteredList) { + String line1 = "Business Name: ${filteredList[index].requested_by}"; String line2 = ""; line2 += - "Request Date: ${widget.patientAccessList[index].requested_on.substring(0, 16).replaceAll("T", " ")}\n"; - line2 += - "Profile Type: ${widget.patientAccessList[index].type.toUpperCase()}\n"; + "Request Date: ${filteredList[index].requested_on.substring(0, 16).replaceAll("T", " ")}\n"; + line2 += "Profile Type: ${filteredList[index].type.toUpperCase()}\n"; //subtitle += "Business Type: ${widget.patientAccessList[index].type}\n"; String line3 = "Status: "; - String access = widget.patientAccessList[index].status.toUpperCase(); + String access = filteredList[index].status.toUpperCase(); TextSpan accessWithColour; if (access == "APPROVED") { @@ -118,7 +120,7 @@ class _BuildPatientsListState extends State { // ), // ), onTap: () { - viewApprovalPopUp(index); + viewApprovalPopUp(mzansiProfileProvider, accessProvider, index); }, // trailing: Icon( // Icons.arrow_forward, @@ -153,23 +155,24 @@ class _BuildPatientsListState extends State { } } - void viewApprovalPopUp(int index) { + void viewApprovalPopUp(MzansiProfileProvider mzansiProfileProvider, + MihAccessControllsProvider accessProvider, int index) { String subtitle = - "Business Name: ${widget.patientAccessList[index].requested_by}\n"; + "Business Name: ${accessProvider.accessList![index].requested_by}\n"; subtitle += - "Requested Date: ${widget.patientAccessList[index].requested_on.substring(0, 16).replaceAll("T", " ")}\n"; + "Requested Date: ${accessProvider.accessList![index].requested_on.substring(0, 16).replaceAll("T", " ")}\n"; subtitle += - "Profile Type: ${widget.patientAccessList[index].type.toUpperCase()}\n"; + "Profile Type: ${accessProvider.accessList![index].type.toUpperCase()}\n"; subtitle += - "Status: ${widget.patientAccessList[index].status.toUpperCase()}"; - if (widget.patientAccessList[index].status == 'pending') { + "Status: ${accessProvider.accessList![index].status.toUpperCase()}"; + if (accessProvider.accessList![index].status == 'pending') { // "\nYou are about to approve an access request to your patient profile.\nPlease be aware that once approved, ${widget.patientAccessList[index].requested_by} will have access to your profile forever and will be able to contribute to it.\nIf you are unsure about an upcoming appointment with ${widget.patientAccessList[index].requested_by}, please contact *Add Number here* for clarification before approving this request."; } else { subtitle += - "\nActioned By: ${widget.patientAccessList[index].approved_by}\n"; + "\nActioned By: ${accessProvider.accessList![index].approved_by}\n"; subtitle += - "Actioned On: ${widget.patientAccessList[index].approved_on.substring(0, 16).replaceAll("T", " ")}"; + "Actioned On: ${accessProvider.accessList![index].approved_on.substring(0, 16).replaceAll("T", " ")}"; // subtitle += // "You have approved this access request to your patient profile.\nPlease be aware that once approved, ${widget.patientAccessList[index].requested_by} will have access to your profile forever and will be able to contribute to it."; } @@ -199,7 +202,7 @@ class _BuildPatientsListState extends State { ), const SizedBox(height: 20.0), Visibility( - visible: widget.patientAccessList[index].status == 'pending', + visible: accessProvider.accessList![index].status == 'pending', child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.start, @@ -271,7 +274,7 @@ class _BuildPatientsListState extends State { ), ), Visibility( - visible: widget.patientAccessList[index].status == 'approved', + visible: accessProvider.accessList![index].status == 'approved', child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.start, @@ -338,7 +341,7 @@ class _BuildPatientsListState extends State { height: 20, ), Visibility( - visible: widget.patientAccessList[index].status == 'pending', + visible: accessProvider.accessList![index].status == 'pending', child: Wrap( runSpacing: 10, spacing: 10, @@ -348,15 +351,20 @@ class _BuildPatientsListState extends State { print("request declined"); int statusCode = await MihAccessControlsServices() .updatePatientAccessAPICall( - widget.patientAccessList[index].business_id, - widget.patientAccessList[index].requested_by, - widget.patientAccessList[index].app_id, + accessProvider.accessList![index].business_id, + accessProvider.accessList![index].requested_by, + accessProvider.accessList![index].app_id, "declined", - "${widget.signedInUser.fname} ${widget.signedInUser.lname}", - widget.signedInUser, + "${mzansiProfileProvider.user!.fname} ${mzansiProfileProvider.user!.lname}", + mzansiProfileProvider.user!, context, ); if (statusCode == 200) { + await MihAccessControlsServices() + .getBusinessAccessListOfPatient( + mzansiProfileProvider.user!.app_id, + accessProvider, + ); context.pop(); successPopUp("Successfully Actioned Request", "You have successfully Declined access request"); @@ -384,15 +392,20 @@ class _BuildPatientsListState extends State { print("request approved"); int statusCode = await MihAccessControlsServices() .updatePatientAccessAPICall( - widget.patientAccessList[index].business_id, - widget.patientAccessList[index].requested_by, - widget.patientAccessList[index].app_id, + accessProvider.accessList![index].business_id, + accessProvider.accessList![index].requested_by, + accessProvider.accessList![index].app_id, "approved", - "${widget.signedInUser.fname} ${widget.signedInUser.lname}", - widget.signedInUser, + "${mzansiProfileProvider.user!.fname} ${mzansiProfileProvider.user!.lname}", + mzansiProfileProvider.user!, context, ); if (statusCode == 200) { + await MihAccessControlsServices() + .getBusinessAccessListOfPatient( + mzansiProfileProvider.user!.app_id, + accessProvider, + ); context.pop(); successPopUp("Successfully Actioned Request", "You have successfully Accepted access request"); @@ -487,6 +500,16 @@ class _BuildPatientsListState extends State { ); } + List filterAccessList(List accessList) { + if (widget.filterText == "All") { + return accessList; + } + return accessList + .where((item) => + item.status.toLowerCase() == widget.filterText.toLowerCase()) + .toList(); + } + @override void dispose() { super.dispose(); @@ -500,21 +523,30 @@ class _BuildPatientsListState extends State { height = size.height; }); checkScreenSize(); - return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (BuildContext context, index) { - return Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + return Consumer2( + builder: (BuildContext context, + MzansiProfileProvider mzansiProfileProvider, + MihAccessControllsProvider accessProvider, + Widget? child) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (BuildContext context, index) { + return Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + itemCount: filterAccessList(accessProvider.accessList!).length, + itemBuilder: (context, index) { + //final patient = widget.patients[index].id_no.contains(widget.searchString); + //print(index); + final filteredList = filterAccessList(accessProvider.accessList!); + return displayQueue( + mzansiProfileProvider, accessProvider, index, filteredList); + }, ); }, - itemCount: widget.patientAccessList.length, - itemBuilder: (context, index) { - //final patient = widget.patients[index].id_no.contains(widget.searchString); - //print(index); - return displayQueue(index); - }, ); } } diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart index 6b19a4c2..76efabbc 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart @@ -105,7 +105,6 @@ class _MihBusinessHomeState extends State temp.add({ "Mzansi Directory": MzansiDirectoryTile( packageSize: packageSize, - personalSelected: false, ) }); //=============== Calculator =============== diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart index 941055be..abc038ea 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart @@ -118,7 +118,6 @@ class _MihPersonalHomeState extends State temp.add({ "Mzansi Directory": MzansiDirectoryTile( packageSize: packageSize, - personalSelected: true, ) }); //=============== Calendar =============== diff --git a/Frontend/lib/mih_packages/mzansi_directory/builders/build_business_search_resultsList.dart b/Frontend/lib/mih_packages/mzansi_directory/builders/build_business_search_resultsList.dart index 9740c534..6d715696 100644 --- a/Frontend/lib/mih_packages/mzansi_directory/builders/build_business_search_resultsList.dart +++ b/Frontend/lib/mih_packages/mzansi_directory/builders/build_business_search_resultsList.dart @@ -1,20 +1,17 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_business_profile_preview.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:provider/provider.dart'; class BuildBusinessSearchResultsList extends StatefulWidget { final List businessList; - final String myLocation; - final String? startUpSearch; const BuildBusinessSearchResultsList({ super.key, required this.businessList, - required this.myLocation, - required this.startUpSearch, }); @override @@ -26,52 +23,48 @@ class _BuildBusinessSearchResultsListState extends State { @override Widget build(BuildContext context) { - return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: widget.businessList.length, - separatorBuilder: (BuildContext context, index) { - return Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - }, - itemBuilder: (context, index) { - return Material( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: InkWell( - onTap: () { - context.goNamed( - 'businessProfileView', - extra: BusinessViewArguments( - widget.businessList[index], - widget.businessList[index].Name, + return Consumer( + builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, + Widget? child) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: widget.businessList.length, + separatorBuilder: (BuildContext context, index) { + return Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + itemBuilder: (context, index) { + return Material( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: InkWell( + onTap: () { + directoryProvider.setSelectedBusiness( + business: widget.businessList[index], + ); + context.pushNamed( + 'businessProfileView', + ); + }, + splashColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark") + .withOpacity(0.2), + borderRadius: BorderRadius.circular(15), + child: Padding( + padding: EdgeInsetsGeometry.symmetric( + // vertical: 5, + horizontal: 25, + ), + child: MihBusinessProfilePreview( + business: widget.businessList[index], + ), ), - ); - // // Navigator.of(context).pushNamed( - // // '/business-profile/view', - // // arguments: BusinessViewArguments( - // // widget.businessList[index], - // // widget.businessList[index].Name, - // // ), - // ); - }, - splashColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark") - .withOpacity(0.2), - borderRadius: BorderRadius.circular(15), - child: Padding( - padding: EdgeInsetsGeometry.symmetric( - // vertical: 5, - horizontal: 25, ), - child: MihBusinessProfilePreview( - business: widget.businessList[index], - myLocation: widget.myLocation, - ), - ), - ), + ); + }, ); }, ); diff --git a/Frontend/lib/mih_packages/mzansi_directory/builders/build_favourite_businesses_list.dart b/Frontend/lib/mih_packages/mzansi_directory/builders/build_favourite_businesses_list.dart index 1c2509fa..8f4e638d 100644 --- a/Frontend/lib/mih_packages/mzansi_directory/builders/build_favourite_businesses_list.dart +++ b/Frontend/lib/mih_packages/mzansi_directory/builders/build_favourite_businesses_list.dart @@ -1,18 +1,17 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_business_profile_preview.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:provider/provider.dart'; class BuildFavouriteBusinessesList extends StatefulWidget { final List favouriteBusinesses; - final String? myLocation; const BuildFavouriteBusinessesList({ super.key, required this.favouriteBusinesses, - required this.myLocation, }); @override @@ -24,54 +23,49 @@ class _BuildFavouriteBusinessesListState extends State { @override Widget build(BuildContext context) { - return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: widget.favouriteBusinesses.length, - separatorBuilder: (BuildContext context, index) { - return Divider( - color: Theme.of(context).colorScheme.secondary, - ); - }, - itemBuilder: (context, index) { - final Business? business = widget.favouriteBusinesses[index]; - - if (business == null) { - return const SizedBox(); // Or a placeholder if a business couldn't be loaded - } - - return Material( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: InkWell( - onTap: () { - context.goNamed( - 'businessProfileView', - extra: BusinessViewArguments( - widget.favouriteBusinesses[index]!, - widget.favouriteBusinesses[index]!.Name, + return Consumer( + builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, + Widget? child) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: widget.favouriteBusinesses.length, + separatorBuilder: (BuildContext context, index) { + return Divider( + color: Theme.of(context).colorScheme.secondary, + ); + }, + itemBuilder: (context, index) { + if (widget.favouriteBusinesses[index] == null) { + return const SizedBox(); // Or a placeholder if a business couldn't be loaded + } + return Material( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: InkWell( + onTap: () { + directoryProvider.setSelectedBusiness( + business: widget.favouriteBusinesses[index]!, + ); + context.goNamed( + 'businessProfileView', + ); + }, + splashColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark") + .withOpacity(0.2), + borderRadius: BorderRadius.circular(15), + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: 25, + ), + child: MihBusinessProfilePreview( + business: widget.favouriteBusinesses[index]!, + ), ), - ); - // Navigator.of(context).pushNamed( - // '/business-profile/view', - // arguments: BusinessViewArguments( - // business, - // business.Name, - // ), - // ); - }, - splashColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark") - .withOpacity(0.2), - borderRadius: BorderRadius.circular(15), - child: Padding( - padding: EdgeInsets.symmetric( - horizontal: 25, ), - child: MihBusinessProfilePreview( - business: business, myLocation: widget.myLocation), - ), - ), + ); + }, ); }, ); diff --git a/Frontend/lib/mih_packages/mzansi_directory/builders/build_user_search_results_list.dart b/Frontend/lib/mih_packages/mzansi_directory/builders/build_user_search_results_list.dart index 8135ce94..bebd0521 100644 --- a/Frontend/lib/mih_packages/mzansi_directory/builders/build_user_search_results_list.dart +++ b/Frontend/lib/mih_packages/mzansi_directory/builders/build_user_search_results_list.dart @@ -3,7 +3,9 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_personal_profile_preview.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:provider/provider.dart'; class BuildUserSearchResultsList extends StatefulWidget { final List userList; @@ -21,45 +23,46 @@ class _BuildUserSearchResultsListState extends State { @override Widget build(BuildContext context) { - return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: widget.userList.length, - separatorBuilder: (BuildContext context, index) { - return Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - }, - itemBuilder: (context, index) { - return Material( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: InkWell( - onTap: () { - context.goNamed( - 'mzansiProfileView', - extra: widget.userList[index], - ); - // Navigator.of(context).pushNamed( - // '/mzansi-profile/view', - // arguments: widget.userList[index], - // ); - }, - splashColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark") - .withOpacity(0.2), - borderRadius: BorderRadius.circular(15), - child: Padding( - padding: EdgeInsetsGeometry.symmetric( - // vertical: 5, - horizontal: 25, + return Consumer( + builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, + Widget? child) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: widget.userList.length, + separatorBuilder: (BuildContext context, index) { + return Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + itemBuilder: (context, index) { + return Material( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: InkWell( + onTap: () { + directoryProvider.setSelectedUser( + user: widget.userList[index]); + context.pushNamed( + 'mzansiProfileView', + ); + }, + splashColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark") + .withOpacity(0.2), + borderRadius: BorderRadius.circular(15), + child: Padding( + padding: EdgeInsetsGeometry.symmetric( + // vertical: 5, + horizontal: 25, + ), + child: + MihPersonalProfilePreview(user: widget.userList[index]), + ), ), - child: MihPersonalProfilePreview( - user: widget.userList[index], - ), - ), - ), + ); + }, ); }, ); diff --git a/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart b/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart index 403c62c8..f9710d97 100644 --- a/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart +++ b/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart @@ -1,19 +1,18 @@ import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:go_router/go_router.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/package_tools/mih_favourite_businesses.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_location_services.dart'; +import 'package:provider/provider.dart'; class MzansiDirectory extends StatefulWidget { - final MzansiDirectoryArguments arguments; const MzansiDirectory({ super.key, - required this.arguments, }); @override @@ -21,75 +20,54 @@ class MzansiDirectory extends StatefulWidget { } class _MzansiDirectoryState extends State { - int _selcetedIndex = 0; late Future futurePosition = MIHLocationAPI().getGPSPosition(context); + Future initialiseGPSLocation() async { + MzansiDirectoryProvider directoryProvider = + context.read(); + MIHLocationAPI().getGPSPosition(context).then((position) { + directoryProvider.setUserPosition(position); + }); + } + @override void initState() { super.initState(); - if (widget.arguments.packageIndex == null) { - _selcetedIndex = 0; - } else { - _selcetedIndex = widget.arguments.packageIndex!; - } + initialiseGPSLocation(); } @override Widget build(BuildContext context) { - print('MzansiDirectory build method called!'); return MihPackage( appActionButton: getAction(), appTools: getTools(), appBody: getToolBody(), appToolTitles: getToolTitle(), - selectedbodyIndex: _selcetedIndex, + selectedbodyIndex: context.watch().toolIndex, onIndexChange: (newValue) { - setState(() { - _selcetedIndex = newValue; - }); + context.read().setToolIndex(newValue); }, ); } List getToolBody() { - List toolBodies = [ - FutureBuilder( - future: futurePosition, - builder: (context, asyncSnapshot) { - String myLocation = ""; - if (asyncSnapshot.connectionState == ConnectionState.waiting) { - myLocation = "Getting Your GPS Location Ready"; - } else { - myLocation = asyncSnapshot.data - .toString() - .replaceAll("Latitude: ", "") - .replaceAll("Longitude: ", ""); - } - return MihSearchMzansi( - personalSearch: widget.arguments.personalSearch, - myLocation: myLocation, - startSearchText: widget.arguments.startSearchText, - ); - }), + List toolBodies = []; + // String myLocation = "Getting Your GPS Location Ready"; + // if (directoryProvider.userPosition != null) { + // myLocation = directoryProvider.userPosition + // .toString() + // .replaceAll("Latitude: ", "") + // .replaceAll("Longitude: ", ""); + // } + toolBodies.addAll([ + MihSearchMzansi( + // personalSearch: directoryProvider.personalSearch, + // startSearchText: "", + ), // MihContacts(), - FutureBuilder( - future: futurePosition, - builder: (context, asyncSnapshot) { - String myLocation = ""; - if (asyncSnapshot.connectionState == ConnectionState.waiting) { - myLocation = "Getting Your GPS Location Ready"; - } else { - myLocation = asyncSnapshot.data - .toString() - .replaceAll("Latitude: ", "") - .replaceAll("Longitude: ", ""); - } - return MihFavouriteBusinesses( - myLocation: myLocation, - ); - }), - ]; + MihFavouriteBusinesses(), + ]); return toolBodies; } @@ -98,9 +76,13 @@ class _MzansiDirectoryState extends State { icon: const Icon(Icons.arrow_back), iconSize: 35, onTap: () { + MzansiDirectoryProvider directoryProvider = + context.read(); context.goNamed( 'mihHome', ); + directoryProvider.setToolIndex(0); + directoryProvider.setPersonalSearch(true); FocusScope.of(context).unfocus(); }, ); @@ -109,23 +91,14 @@ class _MzansiDirectoryState extends State { MihPackageTools getTools() { Map temp = {}; temp[const Icon(Icons.search)] = () { - setState(() { - _selcetedIndex = 0; - }); + context.read().setToolIndex(0); }; - // temp[const Icon(Icons.person)] = () { - // setState(() { - // _selcetedIndex = 1; - // }); - // }; temp[const Icon(Icons.business_center)] = () { - setState(() { - _selcetedIndex = 1; - }); + context.read().setToolIndex(1); }; return MihPackageTools( tools: temp, - selcetedIndex: _selcetedIndex, + selcetedIndex: context.watch().toolIndex, ); } @@ -133,7 +106,7 @@ class _MzansiDirectoryState extends State { List toolTitles = [ "Mzansi Search", "Favourite Businesses", - "Contacts", + // "Contacts", ]; return toolTitles; } diff --git a/Frontend/lib/mih_packages/mzansi_directory/package_tiles/mzansi_directory_tile.dart b/Frontend/lib/mih_packages/mzansi_directory/package_tiles/mzansi_directory_tile.dart index ee72ba50..10dfa6ac 100644 --- a/Frontend/lib/mih_packages/mzansi_directory/package_tiles/mzansi_directory_tile.dart +++ b/Frontend/lib/mih_packages/mzansi_directory/package_tiles/mzansi_directory_tile.dart @@ -1,18 +1,15 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; class MzansiDirectoryTile extends StatefulWidget { final double packageSize; - final bool personalSelected; const MzansiDirectoryTile({ super.key, required this.packageSize, - required this.personalSelected, }); @override @@ -26,10 +23,6 @@ class _MzansiDirectoryTileState extends State { onTap: () { context.goNamed( "mzansiDirectory", - extra: MzansiDirectoryArguments( - personalSearch: widget.personalSelected, - startSearchText: null, - ), ); // Navigator.of(context).pushNamed( // '/mzansi-directory', diff --git a/Frontend/lib/mih_packages/mzansi_directory/package_tools/mih_favourite_businesses.dart b/Frontend/lib/mih_packages/mzansi_directory/package_tools/mih_favourite_businesses.dart index 6c8898ca..eeb53ba0 100644 --- a/Frontend/lib/mih_packages/mzansi_directory/package_tools/mih_favourite_businesses.dart +++ b/Frontend/lib/mih_packages/mzansi_directory/package_tools/mih_favourite_businesses.dart @@ -1,24 +1,22 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/bookmarked_business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/builders/build_favourite_businesses_list.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_directory_services.dart'; -import 'package:supertokens_flutter/supertokens.dart'; +import 'package:provider/provider.dart'; class MihFavouriteBusinesses extends StatefulWidget { - final String? myLocation; const MihFavouriteBusinesses({ super.key, - required this.myLocation, }); @override @@ -29,42 +27,42 @@ class _MihFavouriteBusinessesState extends State { final TextEditingController businessSearchController = TextEditingController(); final FocusNode searchFocusNode = FocusNode(); - late Future> boookmarkedBusinessListFuture; - List listBookmarkedBusinesses = []; final ValueNotifier> searchBookmarkedBusinesses = ValueNotifier([]); - late Future> businessDetailsMapFuture; - Map _businessDetailsMap = {}; Timer? _debounce; - Future> - getAndMapAllBusinessDetailsForBookmarkedBusinesses() async { - String user_id = await SuperTokens.getUserId(); - List bookmarked = await MihMzansiDirectoryServices() - .getAllUserBookmarkedBusiness(user_id); - listBookmarkedBusinesses = bookmarked; + Future getAndMapAllBusinessDetailsForBookmarkedBusinesses( + MzansiProfileProvider mzansiProfileProvider, + MzansiDirectoryProvider directoryProvider, + ) async { + await MihMzansiDirectoryServices().getAllUserBookmarkedBusiness( + mzansiProfileProvider.user!.app_id, + directoryProvider, + ); Map businessMap = {}; List> detailFutures = []; - for (var item in bookmarked) { + for (var item in directoryProvider.bookmarkedBusinesses) { detailFutures.add(MihBusinessDetailsServices() .getBusinessDetailsByBusinessId(item.business_id)); } List details = await Future.wait(detailFutures); - for (int i = 0; i < bookmarked.length; i++) { - businessMap[bookmarked[i].business_id] = details[i]; + for (int i = 0; i < directoryProvider.bookmarkedBusinesses.length; i++) { + businessMap[directoryProvider.bookmarkedBusinesses[i].business_id] = + details[i]; } - _businessDetailsMap = businessMap; - _filterAndSetBusinesses(); - return businessMap; + directoryProvider.setBusinessDetailsMap(detailsMap: businessMap); + _filterAndSetBusinesses(directoryProvider); } - void _filterAndSetBusinesses() { + void _filterAndSetBusinesses(MzansiDirectoryProvider directoryProvider) { List businessesToDisplay = []; String query = businessSearchController.text.toLowerCase(); - for (var bookmarked in listBookmarkedBusinesses) { + for (var bookmarked in directoryProvider.bookmarkedBusinesses) { if (bookmarked.business_name.toLowerCase().contains(query)) { - if (_businessDetailsMap.containsKey(bookmarked.business_id)) { - businessesToDisplay.add(_businessDetailsMap[bookmarked.business_id]); + if (directoryProvider.businessDetailsMap + .containsKey(bookmarked.business_id)) { + businessesToDisplay.add( + directoryProvider.businessDetailsMap[bookmarked.business_id]); } } } @@ -82,14 +80,21 @@ class _MihFavouriteBusinessesState extends State { @override void initState() { super.initState(); - businessDetailsMapFuture = - getAndMapAllBusinessDetailsForBookmarkedBusinesses(); + MzansiDirectoryProvider directoryProvider = + context.read(); + MzansiProfileProvider mzansiProfileProvider = + context.read(); + + getAndMapAllBusinessDetailsForBookmarkedBusinesses( + mzansiProfileProvider, + directoryProvider, + ); businessSearchController.addListener(() { if (_debounce?.isActive ?? false) { _debounce!.cancel(); } _debounce = Timer(const Duration(milliseconds: 200), () { - _filterAndSetBusinesses(); + _filterAndSetBusinesses(directoryProvider); }); }); } @@ -123,141 +128,95 @@ class _MihFavouriteBusinessesState extends State { ), ), const SizedBox(height: 10), - FutureBuilder>( - future: businessDetailsMapFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return Mihloadingcircle( - message: "Getting your favourites", + ValueListenableBuilder>( + valueListenable: searchBookmarkedBusinesses, + builder: (context, filteredBusinesses, child) { + if (filteredBusinesses.isEmpty && + businessSearchController.text.isNotEmpty) { + return Column( + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.iDontKnow, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + const SizedBox(height: 10), + Text( + "Let's try refining your search", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ], ); - } else if (snapshot.connectionState == ConnectionState.done) { - if (snapshot.hasData && snapshot.data!.isNotEmpty) { - // No need to re-filter here, _filterAndSetBusinesses is called in initState - // and by the text controller listener. - return ValueListenableBuilder>( - valueListenable: - searchBookmarkedBusinesses, // Listen to changes in this - builder: (context, businesses, child) { - // Display message if no results after search - if (businesses.isEmpty && - businessSearchController.text.isNotEmpty) { - return Column( - children: [ - const SizedBox(height: 50), - Icon( - MihIcons.iDontKnow, - size: 165, + } else if (filteredBusinesses.isEmpty && + businessSearchController.text.isEmpty) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.businessProfile, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + const SizedBox(height: 10), + Text( + "No favourite businesses added to your mzansi directory", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + const SizedBox(height: 25), + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)! .theme .mode == "Dark"), ), - const SizedBox(height: 10), - Text( - "Let's try refining your search", - textAlign: TextAlign.center, - overflow: TextOverflow.visible, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - ), - ), - ], - ); - } - return BuildFavouriteBusinessesList( - favouriteBusinesses: - businesses, // Pass the filtered list from ValueNotifier - myLocation: widget.myLocation, - ); - }, - ); - } else { - // This block handles the case where there are no bookmarked businesses initially - - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 50), - Icon( - MihIcons.businessProfile, - size: 165, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - const SizedBox(height: 10), - Text( - "No favourite businesses added to your mzansi directory", - textAlign: TextAlign.center, - overflow: TextOverflow.visible, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), + children: [ + TextSpan(text: "Use the mzansi search"), + TextSpan( + text: + " to find your favourite businesses of mzansi"), + ], ), ), - const SizedBox(height: 25), - Center( - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.normal, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - ), - children: [ - TextSpan(text: "Use the mzansi search"), - // WidgetSpan( - // alignment: - // PlaceholderAlignment.middle, - // child: Icon( - // Icons.search, - // size: 20, - // color: - // MzansiInnovationHub.of(context)! - // .theme - // .secondaryColor(), - // ), - // ), - TextSpan( - text: - " to find your favourite businesses of mzansi"), - ], - ), - ), - ), - ], - ), - ); - } - } else if (snapshot.hasError) { - return Center( - child: Text( - "Error loading bookmarked businesses: ${snapshot.error}"), // Show specific error - ); - } else { - // Fallback for unexpected states - return Center( - child: Text("An unknown error occurred."), + ), + ], + ), ); } + return BuildFavouriteBusinessesList( + favouriteBusinesses: filteredBusinesses, + ); }), ], ), diff --git a/Frontend/lib/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart b/Frontend/lib/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart index 73cfc4bb..f3596d26 100644 --- a/Frontend/lib/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart +++ b/Frontend/lib/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; @@ -9,22 +10,18 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/builders/build_business_search_resultsList.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/builders/build_user_search_results_list.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; +import 'package:provider/provider.dart'; class MihSearchMzansi extends StatefulWidget { - final bool personalSearch; - final String? myLocation; - final String? startSearchText; const MihSearchMzansi({ super.key, - required this.personalSearch, - required this.myLocation, - required this.startSearchText, }); @override @@ -35,80 +32,87 @@ class _MihSearchMzansiState extends State { final TextEditingController mzansiSearchController = TextEditingController(); final TextEditingController businessTypeController = TextEditingController(); final FocusNode searchFocusNode = FocusNode(); - late bool userSearch; - Future?> futureUserSearchResults = Future.value(); - Future?> futureBusinessSearchResults = Future.value(); + // late bool userSearch; + // Future?> futureUserSearchResults = Future.value(); List userSearchResults = []; List businessSearchResults = []; late Future> availableBusinessTypes; bool filterOn = false; + bool loadingSearchResults = false; - void swapPressed() { + Future swapPressed(MzansiDirectoryProvider directoryProvider) async { + directoryProvider.setPersonalSearch(!directoryProvider.personalSearch); setState(() { - userSearch = !userSearch; if (filterOn) { filterOn = !filterOn; } }); if (businessTypeController.text.isNotEmpty) { setState(() { - futureBusinessSearchResults = Future.value(); businessTypeController.clear(); }); } - searchPressed(); + await searchPressed(directoryProvider); } - void clearAll() { + void clearAll(MzansiDirectoryProvider directoryProvider) { + directoryProvider.setSearchedBusinesses(searchedBusinesses: []); + directoryProvider.setSearchedUsers(searchedUsers: []); + directoryProvider.setSearchTerm(searchTerm: ""); setState(() { - futureUserSearchResults = Future.value(); - futureBusinessSearchResults = Future.value(); mzansiSearchController.clear(); businessTypeController.clear(); }); } - void searchPressed() { + Future searchPressed(MzansiDirectoryProvider directoryProvider) async { setState(() { - // userSearch = !userSearch; - if (userSearch && mzansiSearchController.text.isNotEmpty) { - futureUserSearchResults = - MihUserServices().searchUsers(mzansiSearchController.text, context); - } else { - if ( - // mzansiSearchController.text.isNotEmpty && - businessTypeController.text.isNotEmpty) { - futureBusinessSearchResults = MihBusinessDetailsServices() - .searchBusinesses(mzansiSearchController.text, - businessTypeController.text, context); - } else if (mzansiSearchController.text.isNotEmpty) { - futureBusinessSearchResults = MihBusinessDetailsServices() - .searchBusinesses(mzansiSearchController.text, - businessTypeController.text, context); - } + loadingSearchResults = true; + }); + directoryProvider.setSearchTerm(searchTerm: mzansiSearchController.text); + directoryProvider.setBusinessTypeFilter( + businessTypeFilter: businessTypeController.text); + if (directoryProvider.personalSearch && + directoryProvider.searchTerm.isNotEmpty) { + final userResults = await MihUserServices() + .searchUsers(directoryProvider.searchTerm, context); + directoryProvider.setSearchedUsers(searchedUsers: userResults); + } else { + List? businessSearchResults = []; + if (directoryProvider.businessTypeFilter.isNotEmpty) { + businessSearchResults = await MihBusinessDetailsServices() + .searchBusinesses(directoryProvider.searchTerm, + directoryProvider.businessTypeFilter, context); + } else if (directoryProvider.searchTerm.isNotEmpty) { + businessSearchResults = await MihBusinessDetailsServices() + .searchBusinesses(directoryProvider.searchTerm, + directoryProvider.businessTypeFilter, context); } + directoryProvider.setSearchedBusinesses( + searchedBusinesses: businessSearchResults); + } + setState(() { + loadingSearchResults = false; }); } @override void dispose() { super.dispose(); + businessTypeController.dispose(); mzansiSearchController.dispose(); } @override void initState() { super.initState(); + MzansiDirectoryProvider directoryProvider = + context.read(); + directoryProvider.setSearchedUsers(searchedUsers: []); setState(() { - userSearch = widget.personalSearch; availableBusinessTypes = MihBusinessDetailsServices().fetchAllBusinessTypes(); - if (widget.startSearchText != null) { - mzansiSearchController.text = widget.startSearchText!; - searchPressed(); - } else { - mzansiSearchController.text = ""; - } + mzansiSearchController.text = ""; }); } @@ -123,444 +127,426 @@ class _MihSearchMzansiState extends State { } Widget getBody(double width) { - return MihSingleChildScroll( - child: Column( - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: width / 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - child: MihSearchBar( - controller: mzansiSearchController, - hintText: "Search Mzansi", - prefixIcon: Icons.search, - prefixAltIcon: userSearch ? Icons.person : Icons.business, - suffixTools: [ - IconButton( - onPressed: () { - swapPressed(); - }, - icon: Icon( - Icons.swap_horiz_rounded, - size: 35, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ], - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - hintColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onPrefixIconTap: () { - searchPressed(); - }, - onClearIconTap: () { - clearAll(); - }, - searchFocusNode: searchFocusNode, - ), - ), - Visibility( - visible: !userSearch, - child: const SizedBox(width: 10), - ), - Visibility( - visible: !userSearch, - child: IconButton( - onPressed: () { - if (filterOn) { - clearAll(); - } - setState(() { - filterOn = !filterOn; - }); - }, - icon: Icon( - !filterOn - ? Icons.filter_list_rounded - : Icons.filter_list_off_rounded, - size: 35, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ), - ], - ), - ), - const SizedBox(height: 10), - FutureBuilder( - future: availableBusinessTypes, - builder: (context, asyncSnapshot) { - List options = []; - if (asyncSnapshot.connectionState == ConnectionState.done) { - options.addAll(asyncSnapshot.data!); - } - return Visibility( - visible: filterOn, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: width / 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded( - child: MihDropdownField( - controller: businessTypeController, - hintText: "Business Type", - dropdownOptions: options, - requiredText: true, - editable: true, - enableSearch: true, - ), - ), - const SizedBox(width: 10), - MihButton( - onPressed: () { - if (businessTypeController.text.isNotEmpty) { - searchPressed(); - } else { - MihAlertServices().errorAlert( - "Business Type Not Selected", - "Please ensure you have selected a Business Type before seareching for Businesses of Mzansi", - context, - ); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - elevation: 10, - child: Text( - "Search", - style: TextStyle( + return Consumer( + builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, + Widget? child) { + return MihSingleChildScroll( + child: Column( + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: MihSearchBar( + controller: mzansiSearchController, + hintText: "Search Mzansi", + prefixIcon: Icons.search, + prefixAltIcon: directoryProvider.personalSearch + ? Icons.person + : Icons.business, + suffixTools: [ + IconButton( + onPressed: () { + swapPressed(directoryProvider); + }, + icon: Icon( + Icons.swap_horiz_rounded, + size: 35, color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, ), ), - ), - ], + ], + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + hintColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onPrefixIconTap: () { + searchPressed(directoryProvider); + }, + onClearIconTap: () { + clearAll(directoryProvider); + }, + searchFocusNode: searchFocusNode, + ), ), - ), - ); - }), - const SizedBox(height: 10), - displaySearchResults(userSearch, widget.myLocation ?? ""), - ], - ), + Visibility( + visible: !directoryProvider.personalSearch, + child: const SizedBox(width: 10), + ), + Visibility( + visible: !directoryProvider.personalSearch, + child: IconButton( + onPressed: () { + if (filterOn) { + clearAll(directoryProvider); + } + setState(() { + filterOn = !filterOn; + }); + }, + icon: Icon( + !filterOn + ? Icons.filter_list_rounded + : Icons.filter_list_off_rounded, + size: 35, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + ], + ), + ), + const SizedBox(height: 10), + FutureBuilder( + future: availableBusinessTypes, + builder: (context, asyncSnapshot) { + List options = []; + if (asyncSnapshot.connectionState == ConnectionState.done) { + options.addAll(asyncSnapshot.data!); + } + return Visibility( + visible: filterOn, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: MihDropdownField( + controller: businessTypeController, + hintText: "Business Type", + dropdownOptions: options, + requiredText: true, + editable: true, + enableSearch: true, + ), + ), + const SizedBox(width: 10), + MihButton( + onPressed: () { + if (businessTypeController.text.isNotEmpty) { + searchPressed(directoryProvider); + } else { + MihAlertServices().errorAlert( + "Business Type Not Selected", + "Please ensure you have selected a Business Type before seareching for Businesses of Mzansi", + context, + ); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + elevation: 10, + child: Text( + "Search", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ), + ); + }), + const SizedBox(height: 10), + displaySearchResults(directoryProvider), + ], + ), + ); + }, ); } - Widget displaySearchResults(bool userSearch, String myLocation) { - if (userSearch) { - return FutureBuilder( - future: futureUserSearchResults, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Mihloadingcircle(); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData && - snapshot.requireData!.isNotEmpty) { - // return Text("Pulled Data successfully"); - snapshot.requireData! - .sort((a, b) => a.username.compareTo(b.username)); - return Column( - children: [ - Text( - "People of Mzansi", - style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 10), - BuildUserSearchResultsList(userList: snapshot.requireData!), - ], - ); - } else if (!snapshot.hasData) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 50), - Icon( - MihIcons.personalProfile, - size: 165, + Widget displayBusinessSearchResults( + MzansiDirectoryProvider directoryProvider) { + KenLogger.success( + "Searched Businesses: ${directoryProvider.searchedBusinesses}"); + if (directoryProvider.searchedBusinesses == null || loadingSearchResults) { + return Center( + child: const Mihloadingcircle(), + ); + } else if (directoryProvider.searchedBusinesses!.isNotEmpty) { + // return Text("Pulled Data successfully"); + directoryProvider.searchedBusinesses! + .sort((a, b) => a.Name.compareTo(b.Name)); + return Column( + children: [ + Text( + "Businesses of Mzansi", + style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 10), + BuildBusinessSearchResultsList( + businessList: directoryProvider.searchedBusinesses!, + ), + ], + ); + } else if (directoryProvider.searchedBusinesses!.isEmpty && + directoryProvider.searchTerm.isNotEmpty) { + // return Text("Pulled Data successfully"); + return Column( + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.iDontKnow, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + const SizedBox(height: 25), + Text( + "Let's try refining your search", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + ], + ); + } else if (directoryProvider.searchedBusinesses!.isEmpty && + directoryProvider.searchTerm.isEmpty) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.businessProfile, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + const SizedBox(height: 10), + Text( + "Search for businesses of Mzansi!", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + const SizedBox(height: 25), + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), - const SizedBox(height: 10), - Text( - "Search for people of Mzansi!", - textAlign: TextAlign.center, - overflow: TextOverflow.visible, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - const SizedBox(height: 25), - Center( - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.normal, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - children: [ - TextSpan(text: "Press "), - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Icon( - Icons.swap_horiz_rounded, - size: 20, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - TextSpan(text: " to search for businesses of Mzansi"), - ], + children: [ + TextSpan(text: "Press "), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + Icons.swap_horiz_rounded, + size: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), ), ), - ), - ], - ), - ); - // return Column( - // mainAxisAlignment: MainAxisAlignment.center, - // crossAxisAlignment: CrossAxisAlignment.center, - // children: [ - // const SizedBox(height: 50), - // Icon( - // MihIcons.personalProfile, - // size: 165, - // color: - // MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // const SizedBox(height: 10), - // Text( - // "People Of Mzansi!", - // textAlign: TextAlign.center, - // overflow: TextOverflow.visible, - // style: TextStyle( - // fontSize: 25, - // fontWeight: FontWeight.bold, - // color: - // MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // ), - // ], - // ); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData && - snapshot.requireData!.isEmpty) { - // return Text("Pulled Data successfully"); - return Column( - children: [ - const SizedBox(height: 50), - Icon( - MihIcons.iDontKnow, - size: 165, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + TextSpan(text: " to search for people of Mzansi"), + ], ), - const SizedBox(height: 10), - Text( - "Let's try refining your search", - textAlign: TextAlign.center, - overflow: TextOverflow.visible, + ), + ), + const SizedBox(height: 10), + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, + fontSize: 20, + fontWeight: FontWeight.normal, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), + children: [ + TextSpan(text: "Press "), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + Icons.filter_list_rounded, + size: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + TextSpan(text: " to filter business types"), + ], ), - ], - ); - } else { - return Center( - child: Text( - "Error pulling Patients Data\n/users/search/${mzansiSearchController.text}", - style: TextStyle( - fontSize: 25, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark")), - textAlign: TextAlign.center, ), - ); - } - }, + ), + ], + ), ); } else { - return FutureBuilder( - future: futureBusinessSearchResults, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Mihloadingcircle(); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData && - snapshot.requireData!.isNotEmpty) { - // return Text("Pulled Data successfully"); - snapshot.requireData!.sort((a, b) => a.Name.compareTo(b.Name)); - return Column( - children: [ - Text( - "Businesses of Mzansi", - style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 10), - BuildBusinessSearchResultsList( - businessList: snapshot.requireData!, - myLocation: myLocation, - startUpSearch: mzansiSearchController.text, - ), - ], - ); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData && - snapshot.requireData!.isEmpty) { - // return Text("Pulled Data successfully"); - return Column( - children: [ - const SizedBox(height: 50), - Icon( - MihIcons.iDontKnow, - size: 165, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - const SizedBox(height: 25), - Text( - "Let's try refining your search", - textAlign: TextAlign.center, - overflow: TextOverflow.visible, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - ], - ); - } else if (!snapshot.hasData) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 50), - Icon( - MihIcons.businessProfile, - size: 165, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - const SizedBox(height: 10), - Text( - "Search for businesses of Mzansi!", - textAlign: TextAlign.center, - overflow: TextOverflow.visible, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - const SizedBox(height: 25), - Center( - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.normal, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - children: [ - TextSpan(text: "Press "), - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Icon( - Icons.swap_horiz_rounded, - size: 20, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - TextSpan(text: " to search for people of Mzansi"), - ], - ), - ), - ), - const SizedBox(height: 10), - Center( - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.normal, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - children: [ - TextSpan(text: "Press "), - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Icon( - Icons.filter_list_rounded, - size: 20, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - TextSpan(text: " to filter business types"), - ], - ), - ), - ), - ], - ), - ); - } else { - return Center( - child: Text( - "Error pulling Patients Data\n/users/search/${mzansiSearchController.text}", - style: TextStyle( - fontSize: 25, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark")), - textAlign: TextAlign.center, - ), - ); - } - }, + return Center( + child: Text( + "Error pulling Patients Data\n/users/search/${directoryProvider.searchTerm}", + style: TextStyle( + fontSize: 25, + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark")), + textAlign: TextAlign.center, + ), ); } } + + Widget displayPersonalSearchResults( + MzansiDirectoryProvider directoryProvider) { + if (directoryProvider.searchedUsers == null || loadingSearchResults) { + return Center( + child: const Mihloadingcircle(), + ); + } else if (directoryProvider.searchedUsers!.isNotEmpty) { + // return Text("Pulled Data successfully"); + directoryProvider.searchedUsers! + .sort((a, b) => a.username.compareTo(b.username)); + return Column( + children: [ + Text( + "People of Mzansi", + style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 10), + BuildUserSearchResultsList( + userList: directoryProvider.searchedUsers!), + ], + ); + } else if (directoryProvider.searchedUsers!.isEmpty && + directoryProvider.searchTerm.isEmpty) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.personalProfile, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + const SizedBox(height: 10), + Text( + "Search for people of Mzansi!", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + const SizedBox(height: 25), + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + children: [ + TextSpan(text: "Press "), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + Icons.swap_horiz_rounded, + size: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + TextSpan(text: " to search for businesses of Mzansi"), + ], + ), + ), + ), + ], + ), + ); + } else if (directoryProvider.searchedUsers!.isEmpty && + directoryProvider.searchTerm.isNotEmpty) { + return Column( + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.iDontKnow, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + const SizedBox(height: 10), + Text( + "Let's try refining your search", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + ], + ); + } else { + return Center( + child: Text( + "Error pulling Patients Data\n/users/search/${directoryProvider.searchTerm}", + style: TextStyle( + fontSize: 25, + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark")), + textAlign: TextAlign.center, + ), + ); + } + } + + Widget displaySearchResults(MzansiDirectoryProvider directoryProvider) { + if (directoryProvider.personalSearch) { + return displayPersonalSearchResults(directoryProvider); + } else { + return displayBusinessSearchResults(directoryProvider); + } + } } diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_add_bookmark_alert.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_add_bookmark_alert.dart index 6e70de6b..e50a5d59 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_add_bookmark_alert.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_add_bookmark_alert.dart @@ -1,21 +1,23 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_directory_services.dart'; -import 'package:supertokens_flutter/supertokens.dart'; +import 'package:provider/provider.dart'; class MihAddBookmarkAlert extends StatefulWidget { final Business business; + final void Function()? onSuccessDismissPressed; const MihAddBookmarkAlert({ super.key, required this.business, + required this.onSuccessDismissPressed, }); @override @@ -23,16 +25,16 @@ class MihAddBookmarkAlert extends StatefulWidget { } class _MihAddBookmarkAlertState extends State { - Future addBookmark(String business_id) async { + Future addBookmark( + MzansiProfileProvider profileProvider, String business_id) async { showDialog( context: context, builder: (context) { return const Mihloadingcircle(); }, ); - String user_id = await SuperTokens.getUserId(); await MihMzansiDirectoryServices() - .addBookmarkedBusiness(user_id, business_id) + .addBookmarkedBusiness(profileProvider.user!.app_id, business_id) .then((statusCode) { context.pop(); if (statusCode == 201) { @@ -77,14 +79,9 @@ class _MihAddBookmarkAlertState extends State { Center( child: MihButton( onPressed: () { - context.goNamed( - "mzansiDirectory", - extra: MzansiDirectoryArguments( - personalSearch: false, - startSearchText: widget.business.Name, - packageIndex: 1, - ), - ); + widget.onSuccessDismissPressed!.call(); + context.pop(); + context.pop(); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -117,69 +114,76 @@ class _MihAddBookmarkAlertState extends State { @override Widget build(BuildContext context) { - return MihPackageAlert( - alertColour: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - alertIcon: Icon( - Icons.warning_rounded, - size: 100, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - alertTitle: "Bookmark Business", - alertBody: Column( - children: [ - Text( - "Are you sure you want to save ${widget.business.Name} to your Mzansi Directory?", - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 15, - ), + return Consumer( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + Widget? child) { + return MihPackageAlert( + alertColour: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + alertIcon: Icon( + Icons.warning_rounded, + size: 100, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), - const SizedBox(height: 25), - Wrap( - spacing: 10, - runSpacing: 10, + alertTitle: "Bookmark Business", + alertBody: Column( children: [ - MihButton( - width: 300, - onPressed: () async { - Navigator.of(context).pop(); - }, - buttonColor: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: Text( - "Cancel", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + Text( + "Are you sure you want to save ${widget.business.Name} to your Mzansi Directory?", + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontSize: 15, ), ), - MihButton( - width: 300, - onPressed: () { - addBookmark(widget.business.business_id); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: Text( - "Bookmark Business", - style: TextStyle( - color: MihColors.getPrimaryColor( + const SizedBox(height: 25), + Wrap( + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + width: 300, + onPressed: () async { + Navigator.of(context).pop(); + }, + buttonColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, + child: Text( + "Cancel", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), ), - ), + MihButton( + width: 300, + onPressed: () { + addBookmark(profileProvider, widget.business.business_id); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: Text( + "Bookmark Business", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], ), ], ), - ], - ), + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_business_info_card.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_business_info_card.dart index 124bb903..7f5a1b39 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_business_info_card.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_business_info_card.dart @@ -7,23 +7,24 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_review import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_add_bookmark_alert.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_delete_bookmark_alert.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_directory_services.dart'; +import 'package:provider/provider.dart'; import 'package:redacted/redacted.dart'; import 'package:supertokens_flutter/supertokens.dart'; import 'package:url_launcher/url_launcher.dart'; class MihBusinessCard extends StatefulWidget { final Business business; - final String? startUpSearch; final double width; const MihBusinessCard({ super.key, required this.business, - required this.startUpSearch, required this.width, }); @@ -409,274 +410,292 @@ class _MihBusinessCardState extends State { @override Widget build(BuildContext context) { // double screenWidth = MediaQuery.of(context).size.width; - return Material( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark") - .withValues(alpha: 0.6), - borderRadius: BorderRadius.circular(25), - elevation: 10, - shadowColor: Colors.black, - child: Container( - decoration: BoxDecoration( + return Consumer( + builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, + Widget? child) { + return Material( color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - borderRadius: BorderRadius.circular(10), - ), - child: Column( - children: [ - const SizedBox(height: 10), - _buildContactInfo( - "Call", - "Give us a quick call.", - Icons.phone, - MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark") + .withValues(alpha: 0.6), + borderRadius: BorderRadius.circular(25), + elevation: 10, + shadowColor: Colors.black, + child: Container( + decoration: BoxDecoration( + color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - false, - () { - // print("Calling ${widget.cellNumber}"); - _makePhoneCall(widget.business.contact_no); - }, + borderRadius: BorderRadius.circular(10), ), - Divider( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - _buildContactInfo( - "Email", - "Send us an email.", - Icons.email, - MihColors.getPinkColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - false, - () { - // print("Emailing ${widget.email}"); - _launchEmail( - widget.business.bus_email, - "Inquiery about ${widget.business.Name}", - "Dear ${widget.business.Name},\n\nI would like to inquire about your services.\n\nBest regards,\n", - ); - }, - ), - Visibility( - visible: isValidGps(widget.business.gps_location), - child: Column( - children: [ - Divider( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: Column( + children: [ + const SizedBox(height: 10), + _buildContactInfo( + "Call", + "Give us a quick call.", + Icons.phone, + MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + false, + () { + // print("Calling ${widget.cellNumber}"); + _makePhoneCall(widget.business.contact_no); + }, + ), + Divider( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + _buildContactInfo( + "Email", + "Send us an email.", + Icons.email, + MihColors.getPinkColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + false, + () { + // print("Emailing ${widget.email}"); + _launchEmail( + widget.business.bus_email, + "Inquiery about ${widget.business.Name}", + "Dear ${widget.business.Name},\n\nI would like to inquire about your services.\n\nBest regards,\n", + ); + }, + ), + Visibility( + visible: isValidGps(widget.business.gps_location), + child: Column( + children: [ + Divider( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + _buildContactInfo( + "Location", + "Come visit us.", + Icons.location_on, + MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + false, + () { + final latitude = double.parse( + widget.business.gps_location.split(',')[0]); + final longitude = double.parse( + widget.business.gps_location.split(',')[1]); + _launchGoogleMapsWithUrl( + latitude: latitude, + longitude: longitude, + ); + }, + ), + ], ), - _buildContactInfo( - "Location", - "Come visit us.", - Icons.location_on, - MihColors.getOrangeColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - false, - () { - final latitude = double.parse( - widget.business.gps_location.split(',')[0]); - final longitude = double.parse( - widget.business.gps_location.split(',')[1]); - _launchGoogleMapsWithUrl( - latitude: latitude, - longitude: longitude, + ), + Visibility( + visible: widget.business.website.isNotEmpty && + widget.business.website != "", + child: Column( + children: [ + Divider( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + _buildContactInfo( + "Website", + "Find out more about us.", + Icons.vpn_lock, + MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + false, + () { + _launchWebsite(widget.business.website); + }, + ), + ], + ), + ), + FutureBuilder( + future: _businessReviewFuture, + builder: (context, asyncSnapshot) { + if (asyncSnapshot.connectionState == + ConnectionState.waiting) { + // return const SizedBox.shrink(); + return Column( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 10.0), + child: Divider( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + Container( + child: _buildContactInfo( + "Loading Rating", + "Loading your rating.", + Icons.star_rate_rounded, + MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + true, + null, + ), + ).redacted(context: context, redact: true), + ], ); - }, - ), - ], - ), + } else { + BusinessReview? businessReview = asyncSnapshot.data; + String ratingDisplayTitle = ""; + if (businessReview == null) { + ratingDisplayTitle = "Rate Us"; + } else { + ratingDisplayTitle = "Update Rating"; + } + return Column( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 10.0), + child: Divider( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + _buildContactInfo( + ratingDisplayTitle, + "Let us know how we are doing.", + Icons.star_rate_rounded, + MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + false, + () { + businessReviewRatingWindow(directoryProvider, + businessReview, true, widget.width); + }, + ), + ], + ); + } + }, + ), + FutureBuilder( + future: _bookmarkedBusinessFuture, + builder: (context, asyncSnapshot) { + if (asyncSnapshot.connectionState == + ConnectionState.waiting) { + // return const SizedBox.shrink(); + return Column( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 10.0), + child: Divider( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + Container( + child: _buildContactInfo( + "Loading Bookmark", + "Loading your bookmark.", + Icons.bookmark_add_rounded, + MihColors.getBluishPurpleColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + true, + null, + ), + ), + ], + ); + } else { + BookmarkedBusiness? bookmarkBusiness = asyncSnapshot.data; + String bookmarkDisplayTitle = ""; + if (bookmarkBusiness == null) { + bookmarkDisplayTitle = "Bookmark Us"; + } else { + bookmarkDisplayTitle = "Remove Bookmark"; + } + return Column( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 10.0), + child: Divider( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + _buildContactInfo( + bookmarkDisplayTitle, + "Save us for later.", + bookmarkBusiness == null + ? Icons.bookmark_add_rounded + : Icons.bookmark_remove_rounded, + MihColors.getBluishPurpleColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + false, + () { + // _launchWebsite(widget.website); + if (bookmarkBusiness == null) { + showAddBookmarkAlert(); + } else { + showDeleteBookmarkAlert(bookmarkBusiness); + } + }, + ), + ], + ); + } + }, + ), + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 10.0), + // child: Divider( + // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // ), + // ), + // _buildContactInfo( + // "Bookmark", + // "Save us for later.", + // Icons.bookmark_add_rounded, + // MihColors.getBluishPurpleColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // () { + // // _launchWebsite(widget.website); + // print("Saving ${widget.business.Name} to Directory"); + // showBookmarkAlert(); + // }, + // ), + const SizedBox(height: 10), + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 10.0), + // child: Divider( + // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // ), + // ), + ], ), - Visibility( - visible: widget.business.website.isNotEmpty && - widget.business.website != "", - child: Column( - children: [ - Divider( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - _buildContactInfo( - "Website", - "Find out more about us.", - Icons.vpn_lock, - MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - false, - () { - _launchWebsite(widget.business.website); - }, - ), - ], - ), - ), - FutureBuilder( - future: _businessReviewFuture, - builder: (context, asyncSnapshot) { - if (asyncSnapshot.connectionState == ConnectionState.waiting) { - // return const SizedBox.shrink(); - return Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Divider( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - Container( - child: _buildContactInfo( - "Loading Rating", - "Loading your rating.", - Icons.star_rate_rounded, - MihColors.getYellowColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - true, - null, - ), - ).redacted(context: context, redact: true), - ], - ); - } else { - BusinessReview? businessReview = asyncSnapshot.data; - String ratingDisplayTitle = ""; - if (businessReview == null) { - ratingDisplayTitle = "Rate Us"; - } else { - ratingDisplayTitle = "Update Rating"; - } - return Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Divider( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - _buildContactInfo( - ratingDisplayTitle, - "Let us know how we are doing.", - Icons.star_rate_rounded, - MihColors.getYellowColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - false, - () { - businessReviewRatingWindow( - businessReview, true, widget.width); - }, - ), - ], - ); - } - }, - ), - FutureBuilder( - future: _bookmarkedBusinessFuture, - builder: (context, asyncSnapshot) { - if (asyncSnapshot.connectionState == ConnectionState.waiting) { - // return const SizedBox.shrink(); - return Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Divider( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - Container( - child: _buildContactInfo( - "Loading Bookmark", - "Loading your bookmark.", - Icons.bookmark_add_rounded, - MihColors.getBluishPurpleColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - true, - null, - ), - ), - ], - ); - } else { - BookmarkedBusiness? bookmarkBusiness = asyncSnapshot.data; - String bookmarkDisplayTitle = ""; - if (bookmarkBusiness == null) { - bookmarkDisplayTitle = "Bookmark Us"; - } else { - bookmarkDisplayTitle = "Remove Bookmark"; - } - return Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Divider( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - _buildContactInfo( - bookmarkDisplayTitle, - "Save us for later.", - bookmarkBusiness == null - ? Icons.bookmark_add_rounded - : Icons.bookmark_remove_rounded, - MihColors.getBluishPurpleColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - false, - () { - // _launchWebsite(widget.website); - if (bookmarkBusiness == null) { - showAddBookmarkAlert(); - } else { - showDeleteBookmarkAlert(bookmarkBusiness); - } - }, - ), - ], - ); - } - }, - ), - // Padding( - // padding: const EdgeInsets.symmetric(horizontal: 10.0), - // child: Divider( - // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // ), - // _buildContactInfo( - // "Bookmark", - // "Save us for later.", - // Icons.bookmark_add_rounded, - // MihColors.getBluishPurpleColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // () { - // // _launchWebsite(widget.website); - // print("Saving ${widget.business.Name} to Directory"); - // showBookmarkAlert(); - // }, - // ), - const SizedBox(height: 10), - // Padding( - // padding: const EdgeInsets.symmetric(horizontal: 10.0), - // child: Divider( - // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // ), - ], - ), - ), + ), + ); + }, ); } Future businessReviewRatingWindow( - BusinessReview? myReview, bool previouslyRated, double width) async { + MzansiDirectoryProvider directoryProvider, + BusinessReview? myReview, + bool previouslyRated, + double width) async { if (_isUserSignedIn) { showDialog( context: context, @@ -685,6 +704,17 @@ class _MihBusinessCardState extends State { businessReview: myReview, screenWidth: width, readOnly: false, + onSuccessDismissPressed: () async { + List? businessSearchResults = []; + businessSearchResults = await MihBusinessDetailsServices() + .searchBusinesses(directoryProvider.searchTerm, + directoryProvider.businessTypeFilter, context); + directoryProvider.setSearchedBusinesses( + searchedBusinesses: businessSearchResults); + setState(() { + _businessReviewFuture = getUserReview(); + }); + }, ), ); } else { @@ -698,6 +728,11 @@ class _MihBusinessCardState extends State { context: context, builder: (context) => MihAddBookmarkAlert( business: widget.business, + onSuccessDismissPressed: () { + setState(() { + _bookmarkedBusinessFuture = getUserBookmark(); + }); + }, ), ); } else { @@ -712,7 +747,12 @@ class _MihBusinessCardState extends State { builder: (context) => MihDeleteBookmarkAlert( business: widget.business, bookmarkBusiness: bookmarkBusiness, - startUpSearch: widget.startUpSearch, + onSuccessDismissPressed: () { + setState(() { + _bookmarkedBusinessFuture = getUserBookmark(); + }); + }, + // startUpSearch: widget.startUpSearch, )); } else { showSignInRequiredAlert(); diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_delete_bookmark_alert.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_delete_bookmark_alert.dart index 4d5dbae8..c5496820 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_delete_bookmark_alert.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_delete_bookmark_alert.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/bookmarked_business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; @@ -14,12 +13,14 @@ import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_directory_services class MihDeleteBookmarkAlert extends StatefulWidget { final Business business; final BookmarkedBusiness? bookmarkBusiness; - final String? startUpSearch; + final void Function()? onSuccessDismissPressed; + // final String? startUpSearch; const MihDeleteBookmarkAlert({ super.key, required this.business, required this.bookmarkBusiness, - required this.startUpSearch, + required this.onSuccessDismissPressed, + // required this.startUpSearch, }); @override @@ -80,14 +81,17 @@ class _MihDeleteBookmarkAlertState extends State { Center( child: MihButton( onPressed: () { - context.goNamed( - "mzansiDirectory", - extra: MzansiDirectoryArguments( - personalSearch: false, - startSearchText: widget.business.Name, - packageIndex: 1, - ), - ); + // context.goNamed( + // "mzansiDirectory", + // extra: MzansiDirectoryArguments( + // personalSearch: false, + // startSearchText: widget.business.Name, + // packageIndex: 1, + // ), + // ); + widget.onSuccessDismissPressed!.call(); + context.pop(); + context.pop(); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart index 48de194b..c26477a5 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_review.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; @@ -13,23 +12,28 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_directory_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; -import 'package:supertokens_flutter/supertokens.dart'; +import 'package:provider/provider.dart'; class MihReviewBusinessWindow extends StatefulWidget { final Business business; final BusinessReview? businessReview; final double screenWidth; final bool readOnly; + final void Function()? onSuccessDismissPressed; const MihReviewBusinessWindow({ super.key, required this.business, required this.businessReview, required this.screenWidth, required this.readOnly, + required this.onSuccessDismissPressed, }); @override @@ -47,9 +51,8 @@ class _MihReviewBusinessWindowState extends State { TextEditingController(); late final VoidCallback _reviewDescriptionListener; final ValueNotifier _counter = ValueNotifier(0); - String userId = ""; - void showDeleteReviewAlert() { + void showDeleteReviewAlert(MzansiDirectoryProvider directoryProvider) { showDialog( context: context, builder: (context) => MihPackageAlert( @@ -93,10 +96,11 @@ class _MihReviewBusinessWindowState extends State { widget.businessReview!.rating_score, widget.business.rating, ) - .then((statusCode) { + .then((statusCode) async { context.pop(); //Remove loading dialog context.pop(); //Remove delete dialog if (statusCode == 200) { + await refreshBusiness(directoryProvider); context.pop(); //Remove window successPopUp( "Successfully Deleted Review!", @@ -160,7 +164,19 @@ class _MihReviewBusinessWindowState extends State { } } - void submitForm() async { + Future refreshBusiness( + MzansiDirectoryProvider directoryProvider) async { + Business? refresedBusiness = await MihBusinessDetailsServices() + .getBusinessDetailsByBusinessId(widget.business.business_id); + if (refresedBusiness != null) { + directoryProvider.setSelectedBusiness(business: refresedBusiness); + } + } + + void submitForm( + MzansiProfileProvider profileProvider, + MzansiDirectoryProvider directoryProvider, + ) async { showDialog( context: context, builder: (context) { @@ -178,9 +194,10 @@ class _MihReviewBusinessWindowState extends State { widget.businessReview!.rating_score, widget.business.rating, ) - .then((statusCode) { + .then((statusCode) async { context.pop(); //Remove loading dialog if (statusCode == 200) { + await refreshBusiness(directoryProvider); context.pop(); successPopUp( "Successfully Updated Review!", @@ -197,16 +214,17 @@ class _MihReviewBusinessWindowState extends State { } else { await MihMzansiDirectoryServices() .addBusinessReview( - userId, + profileProvider.user!.app_id, widget.business.business_id, _reviewTitleController.text, _reviewDescriptionController.text, _reviewScoreController.text, widget.business.rating.isEmpty ? "0.0" : widget.business.rating, ) - .then((statusCode) { + .then((statusCode) async { context.pop(); //Remove loading dialog if (statusCode == 201) { + await refreshBusiness(directoryProvider); context.pop(); successPopUp( "Successfully Added Review!", @@ -250,13 +268,15 @@ class _MihReviewBusinessWindowState extends State { Center( child: MihButton( onPressed: () { - context.goNamed( - "mzansiDirectory", - extra: MzansiDirectoryArguments( - personalSearch: false, - startSearchText: widget.business.Name, - ), - ); + // context.goNamed( + // "mzansiDirectory", + // extra: MzansiDirectoryArguments( + // personalSearch: false, + // startSearchText: widget.business.Name, + // ), + // ); + widget.onSuccessDismissPressed!.call(); + context.pop(); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -323,265 +343,277 @@ class _MihReviewBusinessWindowState extends State { } else { _reviewScoreController.text = "1.0"; // Default score } - SuperTokens.getUserId().then((value) { - setState(() { - userId = value; - }); - }); } @override Widget build(BuildContext context) { // return const Placeholder(); - return MihPackageWindow( - fullscreen: false, - windowTitle: getWindowTitle(), - onWindowTapClose: () { - Navigator.of(context).pop(); - }, - menuOptions: widget.businessReview != null && !widget.readOnly - ? [ - SpeedDialChild( - child: Icon( - Icons.delete, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - label: "Delete Review", - labelBackgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - labelStyle: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontWeight: FontWeight.bold, - ), - backgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onTap: () { - showDeleteReviewAlert(); - }, - ), - ] - : null, - windowBody: MihSingleChildScroll( - child: Padding( - padding: - MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + MzansiDirectoryProvider directoryProvider, Widget? child) { + return MihPackageWindow( + fullscreen: false, + windowTitle: getWindowTitle(), + onWindowTapClose: () { + Navigator.of(context).pop(); + }, + menuOptions: widget.businessReview != null && !widget.readOnly + ? [ + SpeedDialChild( + child: Icon( + Icons.delete, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + label: "Delete Review", + labelBackgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onTap: () { + showDeleteReviewAlert(directoryProvider); + }, + ), + ] + : null, + windowBody: MihSingleChildScroll( + child: Padding( + padding: MzansiInnovationHub.of(context)!.theme.screenType == + "desktop" ? EdgeInsets.symmetric(horizontal: widget.screenWidth * 0.05) : EdgeInsets.symmetric(horizontal: widget.screenWidth * 0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - MihForm( - formKey: _formKey, - formFields: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Business Rating", - textAlign: TextAlign.left, - style: TextStyle( - color: MihColors.getSecondaryColor( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Business Rating", + textAlign: TextAlign.left, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 4), + widget.readOnly + ? RatingBar.readOnly( + size: 50, + alignment: Alignment.centerLeft, + filledIcon: Icons.star, + emptyIcon: Icons.star_border, + halfFilledIcon: Icons.star_half, + filledColor: MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + // filledColor: MzansiInnovationHub.of(context)! + // .theme + // .secondaryColor(), + emptyColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + halfFilledColor: MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + // MzansiInnovationHub.of(context)! + // .theme + // .secondaryColor(), + isHalfAllowed: true, + initialRating: widget.businessReview != null + ? double.parse(_reviewScoreController.text) + : 1, + maxRating: 5, + ) + : RatingBar( + size: 50, + alignment: Alignment.centerLeft, + filledIcon: Icons.star, + emptyIcon: Icons.star_border, + halfFilledIcon: Icons.star_half, + filledColor: MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + emptyColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + halfFilledColor: MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + isHalfAllowed: true, + initialRating: widget.businessReview != null + ? double.parse(_reviewScoreController.text) + : 1, + maxRating: 5, + onRatingChanged: (double) { + setState(() { + _reviewScoreController.text = + double.toStringAsFixed(1); + }); + print(_reviewScoreController.text); + }, + ), + Visibility( + visible: widget.readOnly, + child: const SizedBox(height: 10), + ), + Visibility( + visible: widget.readOnly, + child: MihTextFormField( + // width: 200, + fillColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 18, - fontWeight: FontWeight.bold, + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: _reviewReviewerController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Reviewer", + validator: (value) { + return null; + }, + ), + ), + const SizedBox(height: 10), + MihTextFormField( + // width: 200, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: _reviewTitleController, + multiLineInput: false, + requiredText: true, + readOnly: widget.readOnly, + hintText: "Review Title", + validator: (value) { + return MihValidationServices() + .isEmpty(_reviewTitleController.text); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + height: 250, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: _reviewDescriptionController, + multiLineInput: true, + requiredText: widget.readOnly, + readOnly: widget.readOnly, + hintText: "Review Description", + validator: (value) { + if (_reviewDescriptionController.text.isEmpty) { + return null; + } else { + return MihValidationServices().validateLength( + _reviewDescriptionController.text, 256); + } + }, + ), + Visibility( + visible: !widget.readOnly, + child: SizedBox( + height: 15, + child: ValueListenableBuilder( + valueListenable: _counter, + builder: (BuildContext context, int value, + Widget? child) { + return Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "$value", + style: TextStyle( + color: getMissionVisionLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 5), + Text( + "/256", + style: TextStyle( + color: getMissionVisionLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + ], + ); + }, + ), + ), + ), + const SizedBox(height: 25), + Visibility( + visible: !widget.readOnly, + child: Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm( + profileProvider, + directoryProvider, + ); + } else { + MihAlertServices() + .formNotFilledCompletely(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + widget.businessReview != null + ? "Update Review" + : "Add Review", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), ), ), ], ), - const SizedBox(height: 4), - widget.readOnly - ? RatingBar.readOnly( - size: 50, - alignment: Alignment.centerLeft, - filledIcon: Icons.star, - emptyIcon: Icons.star_border, - halfFilledIcon: Icons.star_half, - filledColor: MihColors.getYellowColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - // filledColor: MzansiInnovationHub.of(context)! - // .theme - // .secondaryColor(), - emptyColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - halfFilledColor: MihColors.getYellowColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - // MzansiInnovationHub.of(context)! - // .theme - // .secondaryColor(), - isHalfAllowed: true, - initialRating: widget.businessReview != null - ? double.parse(_reviewScoreController.text) - : 1, - maxRating: 5, - ) - : RatingBar( - size: 50, - alignment: Alignment.centerLeft, - filledIcon: Icons.star, - emptyIcon: Icons.star_border, - halfFilledIcon: Icons.star_half, - filledColor: MihColors.getYellowColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - emptyColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - halfFilledColor: MihColors.getYellowColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - isHalfAllowed: true, - initialRating: widget.businessReview != null - ? double.parse(_reviewScoreController.text) - : 1, - maxRating: 5, - onRatingChanged: (double) { - setState(() { - _reviewScoreController.text = - double.toStringAsFixed(1); - }); - print(_reviewScoreController.text); - }, - ), - Visibility( - visible: widget.readOnly, - child: const SizedBox(height: 10), - ), - Visibility( - visible: widget.readOnly, - child: MihTextFormField( - // width: 200, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: _reviewReviewerController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Reviewer", - validator: (value) { - return null; - }, - ), - ), - const SizedBox(height: 10), - MihTextFormField( - // width: 200, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: _reviewTitleController, - multiLineInput: false, - requiredText: true, - readOnly: widget.readOnly, - hintText: "Review Title", - validator: (value) { - return MihValidationServices() - .isEmpty(_reviewTitleController.text); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - height: 250, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: _reviewDescriptionController, - multiLineInput: true, - requiredText: widget.readOnly, - readOnly: widget.readOnly, - hintText: "Review Description", - validator: (value) { - if (_reviewDescriptionController.text.isEmpty) { - return null; - } else { - return MihValidationServices().validateLength( - _reviewDescriptionController.text, 256); - } - }, - ), - Visibility( - visible: !widget.readOnly, - child: SizedBox( - height: 15, - child: ValueListenableBuilder( - valueListenable: _counter, - builder: - (BuildContext context, int value, Widget? child) { - return Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - "$value", - style: TextStyle( - color: getMissionVisionLimitColor(256), - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(width: 5), - Text( - "/256", - style: TextStyle( - color: getMissionVisionLimitColor(256), - fontWeight: FontWeight.bold, - ), - ), - ], - ); - }, - ), - ), - ), - const SizedBox(height: 25), - Visibility( - visible: !widget.readOnly, - child: Center( - child: MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - submitForm(); - } else { - MihAlertServices().formNotFilledCompletely(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - widget.businessReview != null - ? "Update Review" - : "Add Review", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), ], ), - ], + ), ), - ), - ), + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart index 3e3736ab..97f91792 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart @@ -86,7 +86,7 @@ class _MzansiBusinessProfileState extends State { business: context.watch().business!), MihBusinessQrCode( business: context.watch().business!, - startUpSearch: "", + // startUpSearch: "", ), ]; return toolBodies; diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile_view.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile_view.dart index 2e625382..21231d4a 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile_view.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile_view.dart @@ -1,23 +1,22 @@ import 'package:go_router/go_router.dart'; import 'package:ken_logger/ken_logger.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_reviews.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; +import 'package:provider/provider.dart'; class MzansiBusinessProfileView extends StatefulWidget { - final BusinessViewArguments? arguments; final String? businessId; const MzansiBusinessProfileView({ super.key, - required this.arguments, required this.businessId, }); @@ -28,16 +27,10 @@ class MzansiBusinessProfileView extends StatefulWidget { class _MzansiBusinessProfileViewState extends State { int _selcetedIndex = 0; - Business? business; - String startUpSearch = ""; - Future _fetchBusinessDetails() async { - if (widget.arguments != null) { - setState(() { - business = widget.arguments!.business; - startUpSearch = widget.arguments!.startUpSearch ?? ""; - }); - } else if (widget.businessId != null) { + Future _fetchBusinessDetails( + MzansiDirectoryProvider directoryProvider) async { + if (widget.businessId != null) { final biz = await MihBusinessDetailsServices() .getBusinessDetailsByBusinessId(widget.businessId!); if (biz == null) { @@ -47,10 +40,7 @@ class _MzansiBusinessProfileViewState extends State { ); } else { KenLogger.success("Business found: ${biz.Name}"); - setState(() { - business = biz; - startUpSearch = ""; - }); + directoryProvider.setSelectedBusiness(business: biz); } } } @@ -58,32 +48,39 @@ class _MzansiBusinessProfileViewState extends State { @override void initState() { super.initState(); - _fetchBusinessDetails(); + MzansiDirectoryProvider directoryProvider = + context.read(); + _fetchBusinessDetails(directoryProvider); } @override Widget build(BuildContext context) { - if (business == null) { - KenLogger.warning("Business is null, showing loading indicator"); - return Scaffold( - body: const Center( - child: Mihloadingcircle(), - ), - ); - } else { - return MihPackage( - appActionButton: getAction(), - appTools: getTools(), - appBody: getToolBody(), - appToolTitles: getToolTitle(), - selectedbodyIndex: _selcetedIndex, - onIndexChange: (newValue) { - setState(() { - _selcetedIndex = newValue; - }); - }, - ); - } + return Consumer( + builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, + Widget? child) { + if (directoryProvider.selectedBusiness == null) { + KenLogger.warning("Business is null, showing loading indicator"); + return Scaffold( + body: const Center( + child: Mihloadingcircle(), + ), + ); + } else { + return MihPackage( + appActionButton: getAction(), + appTools: getTools(), + appBody: getToolBody(directoryProvider), + appToolTitles: getToolTitle(), + selectedbodyIndex: _selcetedIndex, + onIndexChange: (newValue) { + setState(() { + _selcetedIndex = newValue; + }); + }, + ); + } + }, + ); } MihPackageAction getAction() { @@ -91,13 +88,18 @@ class _MzansiBusinessProfileViewState extends State { icon: const Icon(Icons.arrow_back), iconSize: 35, onTap: () { - context.goNamed( - "mzansiDirectory", - extra: MzansiDirectoryArguments( - personalSearch: false, - startSearchText: business!.Name, - ), - ); + MzansiProfileProvider profileProvider = + context.read(); + if (profileProvider.user == null) { + context.goNamed( + 'mihHome', + ); + } else { + context.pop(); + } + // context.goNamed( + // "mzansiDirectory", + // ); FocusScope.of(context).unfocus(); }, ); @@ -126,16 +128,12 @@ class _MzansiBusinessProfileViewState extends State { ); } - List getToolBody() { + List getToolBody(MzansiDirectoryProvider directoryProvider) { List toolBodies = [ - MihBusinessDetailsView( - business: business!, - startUpSearch: startUpSearch, - ), - MihBusinessReviews(business: business!), + MihBusinessDetailsView(), + MihBusinessReviews(business: directoryProvider.selectedBusiness!), MihBusinessQrCode( - business: business!, - startUpSearch: startUpSearch, + business: directoryProvider.selectedBusiness!, ) ]; return toolBodies; diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart index b682df21..c65a144c 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart @@ -135,7 +135,7 @@ class _MihBusinessDetailsState extends State { width: 700, child: MihBusinessCard( business: mzansiProfileProvider.business!, - startUpSearch: null, + // startUpSearch: null, width: width, ), ), diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart index d2f064b1..1a379b81 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart @@ -2,22 +2,19 @@ import 'package:custom_rating_bar/custom_rating_bar.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_business_info_card.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; +import 'package:provider/provider.dart'; class MihBusinessDetailsView extends StatefulWidget { - final Business business; - final String? startUpSearch; const MihBusinessDetailsView({ super.key, - required this.business, - required this.startUpSearch, }); @override @@ -36,8 +33,10 @@ class _MihBusinessDetailsViewState extends State { @override void initState() { super.initState(); - futureImageUrl = - MihFileApi.getMinioFileUrl(widget.business.logo_path, context); + MzansiDirectoryProvider directoryProvider = + context.read(); + futureImageUrl = MihFileApi.getMinioFileUrl( + directoryProvider.selectedBusiness!.logo_path, context); } @override @@ -52,173 +51,182 @@ class _MihBusinessDetailsViewState extends State { Widget getBody(double width, BuildContext context) { double profilePictureWidth = 150; - return Stack( - children: [ - MihSingleChildScroll( - child: Padding( - padding: - MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + return Consumer( + builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, + Widget? child) { + return Stack( + children: [ + MihSingleChildScroll( + child: Padding( + padding: MzansiInnovationHub.of(context)!.theme.screenType == + "desktop" ? EdgeInsets.symmetric(horizontal: width * 0.2) : EdgeInsets.symmetric(horizontal: width * 0.075), - child: Column( - children: [ - FutureBuilder( - future: futureImageUrl, - builder: (context, asyncSnapshot) { - if (asyncSnapshot.connectionState == - ConnectionState.done && - asyncSnapshot.hasData) { - if (asyncSnapshot.requireData != "") { - return MihCircleAvatar( - imageFile: NetworkImage(asyncSnapshot.requireData), - width: profilePictureWidth, - editable: false, - fileNameController: TextEditingController(), - userSelectedfile: file, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: () {}, - ); - } else { - return Icon( - MihIcons.iDontKnow, - size: profilePictureWidth, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ); - } - } else { - return Icon( - MihIcons.mihRing, - size: profilePictureWidth, + child: Column( + children: [ + FutureBuilder( + future: futureImageUrl, + builder: (context, asyncSnapshot) { + if (asyncSnapshot.connectionState == + ConnectionState.done && + asyncSnapshot.hasData) { + if (asyncSnapshot.requireData != "") { + return MihCircleAvatar( + imageFile: + NetworkImage(asyncSnapshot.requireData), + width: profilePictureWidth, + editable: false, + fileNameController: TextEditingController(), + userSelectedfile: file, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + onChange: () {}, + ); + } else { + return Icon( + MihIcons.iDontKnow, + size: profilePictureWidth, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ); + } + } else { + return Icon( + MihIcons.mihRing, + size: profilePictureWidth, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ); + } + }), + // Center( + // child: MihCircleAvatar( + // imageFile: widget.logoImage, + // width: 150, + // editable: false, + // fileNameController: fileNameController, + // userSelectedfile: imageFile, + // frameColor: + // MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // backgroundColor: + // MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // onChange: (selectedfile) { + // setState(() { + // imageFile = selectedfile; + // }); + // }, + // ), + // ), + FittedBox( + child: Text( + directoryProvider.selectedBusiness!.Name, + style: TextStyle( + fontSize: 35, + fontWeight: FontWeight.bold, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - } - }), - // Center( - // child: MihCircleAvatar( - // imageFile: widget.logoImage, - // width: 150, - // editable: false, - // fileNameController: fileNameController, - // userSelectedfile: imageFile, - // frameColor: - // MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // backgroundColor: - // MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // onChange: (selectedfile) { - // setState(() { - // imageFile = selectedfile; - // }); - // }, - // ), - // ), - FittedBox( - child: Text( - widget.business.Name, - style: TextStyle( - fontSize: 35, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ), - FittedBox( - child: Text( - widget.business.type, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w600, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ), - const SizedBox(height: 5), - // FittedBox( - // child: Text( - // "Mission & Vision", - // style: TextStyle( - // fontSize: 15, - // fontWeight: FontWeight.bold, - // color: MzansiInnovationHub.of(context)! - // .theme - // .secondaryColor(), - // ), - // ), - // ), - Center( - child: SizedBox( - width: 700, - child: Text( - widget.business.mission_vision.isNotEmpty - ? widget.business.mission_vision - : "No Mission & Vision added yet", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), + ), ), ), - ), + FittedBox( + child: Text( + directoryProvider.selectedBusiness!.type, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + const SizedBox(height: 5), + // FittedBox( + // child: Text( + // "Mission & Vision", + // style: TextStyle( + // fontSize: 15, + // fontWeight: FontWeight.bold, + // color: MzansiInnovationHub.of(context)! + // .theme + // .secondaryColor(), + // ), + // ), + // ), + Center( + child: SizedBox( + width: 700, + child: Text( + directoryProvider + .selectedBusiness!.mission_vision.isNotEmpty + ? directoryProvider + .selectedBusiness!.mission_vision + : "No Mission & Vision added yet", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + ), + const SizedBox(height: 10), + RatingBar.readOnly( + size: 50, + alignment: Alignment.center, + filledIcon: Icons.star, + emptyIcon: Icons.star_border, + halfFilledIcon: Icons.star_half, + filledColor: MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + // MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + emptyColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + halfFilledColor: MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + // MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + isHalfAllowed: true, + initialRating: + directoryProvider.selectedBusiness!.rating.isNotEmpty + ? double.parse( + directoryProvider.selectedBusiness!.rating) + : 0, + maxRating: 5, + ), + const SizedBox(height: 20), + SizedBox( + width: 700, + child: MihBusinessCard( + business: directoryProvider.selectedBusiness!, + width: width, + ), + ), + ], ), - const SizedBox(height: 10), - RatingBar.readOnly( - size: 50, - alignment: Alignment.center, - filledIcon: Icons.star, - emptyIcon: Icons.star_border, - halfFilledIcon: Icons.star_half, - filledColor: MihColors.getYellowColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - emptyColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - halfFilledColor: MihColors.getYellowColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - isHalfAllowed: true, - initialRating: widget.business.rating.isNotEmpty - ? double.parse(widget.business.rating) - : 0, - maxRating: 5, - ), - const SizedBox(height: 20), - SizedBox( - width: 700, - child: MihBusinessCard( - business: widget.business, - startUpSearch: widget.startUpSearch, - // businessid: widget.business.business_id, - // businessName: widget.business.Name, - // cellNumber: widget.business.contact_no, - // email: widget.business.bus_email, - // gpsLocation: widget.business.gps_location, - // rating: widget.business.rating.isNotEmpty - // ? double.parse(widget.business.rating) - // : 0, - // website: widget.business.website, - width: width, - ), - ), - ], + ), ), - ), - ), - ], + ], + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart index 577efd23..268c768f 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart @@ -25,11 +25,11 @@ import 'package:supertokens_flutter/supertokens.dart'; class MihBusinessQrCode extends StatefulWidget { final Business business; - final String? startUpSearch; + // final String? startUpSearch; const MihBusinessQrCode({ super.key, required this.business, - required this.startUpSearch, + // required this.startUpSearch, }); @override diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_reviews.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_reviews.dart index 33330023..42f9f06a 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_reviews.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_reviews.dart @@ -41,6 +41,7 @@ class _MihBusinessReviewsState extends State { businessReview: businessReview, screenWidth: width, readOnly: true, + onSuccessDismissPressed: () {}, ); }, ); diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile_view.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile_view.dart index edea06c9..1eabbf3f 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile_view.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile_view.dart @@ -1,6 +1,4 @@ import 'package:go_router/go_router.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; @@ -8,10 +6,8 @@ import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profi import 'package:flutter/material.dart'; class MzansiProfileView extends StatefulWidget { - final AppUser user; const MzansiProfileView({ super.key, - required this.user, }); @override @@ -42,13 +38,7 @@ class _MzansiProfileViewState extends State { icon: const Icon(Icons.arrow_back), iconSize: 35, onTap: () { - context.goNamed( - "mzansiDirectory", - extra: MzansiDirectoryArguments( - personalSearch: true, - startSearchText: widget.user.username, - ), - ); + context.pop(); FocusScope.of(context).unfocus(); }, ); @@ -69,9 +59,9 @@ class _MzansiProfileViewState extends State { List getToolBody() { List toolBodies = []; - toolBodies.add(MihPersonalProfileView( - user: widget.user, - )); + toolBodies.add( + MihPersonalProfileView(), + ); return toolBodies; } diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart index 7ec7447d..58a005c1 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart @@ -1,6 +1,6 @@ import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; @@ -8,12 +8,11 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class MihPersonalProfileView extends StatefulWidget { - final AppUser user; const MihPersonalProfileView({ super.key, - required this.user, }); @override @@ -32,8 +31,10 @@ class _MihPersonalProfileViewState extends State { @override void initState() { super.initState(); - futureImageUrl = - MihFileApi.getMinioFileUrl(widget.user.pro_pic_path, context); + MzansiDirectoryProvider directoryProvider = + context.read(); + futureImageUrl = MihFileApi.getMinioFileUrl( + directoryProvider.selectedUser!.pro_pic_path, context); } @override @@ -48,152 +49,123 @@ class _MihPersonalProfileViewState extends State { Widget getBody(double width) { double profilePictureWidth = 150; - return MihSingleChildScroll( - child: Padding( - padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.2) - : EdgeInsets.symmetric(horizontal: width * 0.075), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - FutureBuilder( - future: futureImageUrl, - builder: (context, asyncSnapshot) { - if (asyncSnapshot.connectionState == ConnectionState.done && - asyncSnapshot.hasData) { - if (asyncSnapshot.requireData != "") { - return MihCircleAvatar( - imageFile: NetworkImage(asyncSnapshot.requireData), - width: profilePictureWidth, - editable: false, - fileNameController: TextEditingController(), - userSelectedfile: file, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: () {}, - ); - } else { - return Icon( - MihIcons.iDontKnow, - size: profilePictureWidth, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ); - } - } else { - return Icon( - MihIcons.mihRing, - size: profilePictureWidth, + return Consumer( + builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, + Widget? child) { + return MihSingleChildScroll( + child: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + FutureBuilder( + future: futureImageUrl, + builder: (context, asyncSnapshot) { + if (asyncSnapshot.connectionState == + ConnectionState.done && + asyncSnapshot.hasData) { + if (asyncSnapshot.requireData != "") { + return MihCircleAvatar( + imageFile: NetworkImage(asyncSnapshot.requireData), + width: profilePictureWidth, + editable: false, + fileNameController: TextEditingController(), + userSelectedfile: file, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: () {}, + ); + } else { + return Icon( + MihIcons.iDontKnow, + size: profilePictureWidth, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ); + } + } else { + return Icon( + MihIcons.mihRing, + size: profilePictureWidth, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ); + } + }), + FittedBox( + child: Text( + directoryProvider.selectedUser!.username.isNotEmpty + ? directoryProvider.selectedUser!.username + : "Username", + style: TextStyle( + fontSize: 35, + fontWeight: FontWeight.bold, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - } - // return Center( - // child: MihCircleAvatar( - // imageFile: propicPreview, - // width: 150, - // editable: false, - // fileNameController: proPicController, - // userSelectedfile: proPic, - // frameColor: MzansiInnovationHub.of(context)! - // .theme - // .secondaryColor(), - // backgroundColor: - // MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // onChange: (selectedImage) { - // setState(() { - // proPic = selectedImage; - // }); - // }, - // ), - // ); - }), - FittedBox( - child: Text( - widget.user.username.isNotEmpty - ? widget.user.username - : "Username", - style: TextStyle( - fontSize: 35, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - ), - FittedBox( - child: Text( - widget.user.fname.isNotEmpty - ? "${widget.user.fname} ${widget.user.lname}" - : "Name Surname", - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - ), - FittedBox( - child: Text( - widget.user.type.toUpperCase(), - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - ), - const SizedBox(height: 10.0), - Center( - child: SizedBox( - width: 700, - child: Text( - widget.user.purpose.isNotEmpty - ? widget.user.purpose - : "No Personal Mission added yet", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), ), ), - ), + FittedBox( + child: Text( + directoryProvider.selectedUser!.fname.isNotEmpty + ? "${directoryProvider.selectedUser!.fname} ${directoryProvider.selectedUser!.lname}" + : "Name Surname", + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + FittedBox( + child: Text( + directoryProvider.selectedUser!.type.toUpperCase(), + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + const SizedBox(height: 10.0), + Center( + child: SizedBox( + width: 700, + child: Text( + directoryProvider.selectedUser!.purpose.isNotEmpty + ? directoryProvider.selectedUser!.purpose + : "No Personal Mission added yet", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + ), + const SizedBox(height: 30.0), + ], ), - const SizedBox(height: 30.0), - // Center( - // child: MihButton( - // onPressed: () { - // // Connect with the user - // }, - // buttonColor: - // MihColors.getGreenColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // width: 300, - // child: Text( - // widget.user.username.isEmpty - // ? "Set Up Profile" - // : "Edit Profile", - // style: TextStyle( - // color: - // MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // fontSize: 20, - // fontWeight: FontWeight.bold, - // ), - // ), - // ), - // ), - ], - ), - ), + ), + ); + }, ); } } diff --git a/Frontend/lib/mih_services/mih_mzansi_directory_services.dart b/Frontend/lib/mih_services/mih_mzansi_directory_services.dart index 18c6af8c..322615de 100644 --- a/Frontend/lib/mih_services/mih_mzansi_directory_services.dart +++ b/Frontend/lib/mih_services/mih_mzansi_directory_services.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/bookmarked_business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_review.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:supertokens_flutter/http.dart' as http; @@ -156,14 +157,17 @@ class MihMzansiDirectoryServices { Future> getAllUserBookmarkedBusiness( String app_id, + MzansiDirectoryProvider directoryProvider, ) async { final response = await http.get(Uri.parse( "${AppEnviroment.baseApiUrl}/mzansi-directory/bookmarked-business/user/all/$app_id/")); if (response.statusCode == 200) { Iterable l = jsonDecode(response.body); - List businessReviews = List.from( - l.map((model) => BookmarkedBusiness.fromJson(model))); - return businessReviews; + List favouriteBusinesses = + List.from( + l.map((model) => BookmarkedBusiness.fromJson(model))); + directoryProvider.setFavouriteBusinesses(businesses: favouriteBusinesses); + return favouriteBusinesses; } else if (response.statusCode == 404) { return []; } else { From ac22e50ecab3506fe8870596bd1fdcf0cbb22bfc Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 23 Oct 2025 11:01:39 +0200 Subject: [PATCH 29/45] Change patient profile folder to patient manager --- Frontend/lib/mih_config/mih_go_router.dart | 10 +++++----- .../mih_home/package_tools/mih_business_home.dart | 2 +- .../mih_home/package_tools/mih_personal_home.dart | 2 +- .../list_builders/build_mih_patient_search_list.dart | 0 .../list_builders/build_my_patient_list_list.dart | 0 .../list_builders/build_waiting_room_list.dart | 0 .../pat_manager/package_tiles/pat_manager_tile.dart | 0 .../pat_manager/package_tools/mih_patient_search.dart | 2 +- .../pat_manager/package_tools/my_patient_list.dart | 2 +- .../pat_manager/package_tools/waiting_room.dart | 0 .../pat_manager/pat_manager.dart | 6 +++--- .../pat_profile/add_or_view_patient.dart | 4 ++-- .../pat_profile/components/claim_statement_window.dart | 2 +- .../pat_profile/components/full_screen_file.dart | 0 .../pat_profile/components/icd10_search_window.dart | 2 +- .../pat_profile/components/medicine_search.dart | 2 +- .../pat_profile/components/prescip_input.dart | 2 +- .../build_claim_statement_files_list.dart | 2 +- .../pat_profile/list_builders/build_file_view.dart | 0 .../pat_profile/list_builders/build_files_list.dart | 2 +- .../list_builders/build_icd10_code_list.dart | 0 .../pat_profile/list_builders/build_med_list.dart | 0 .../pat_profile/list_builders/build_notes_list.dart | 0 .../package_tiles/patient_profile_tile.dart | 0 .../package_tools/patient_claim_or_statement.dart | 4 ++-- .../package_tools/patient_consultation.dart | 2 +- .../pat_profile/package_tools/patient_documents.dart | 4 ++-- .../pat_profile/package_tools/patient_info.dart | 0 .../pat_profile/patient_add.dart | 0 .../pat_profile/patient_edit.dart | 0 .../pat_profile/patient_profile.dart | 8 ++++---- 31 files changed, 29 insertions(+), 29 deletions(-) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_manager/list_builders/build_mih_patient_search_list.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_manager/list_builders/build_my_patient_list_list.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_manager/list_builders/build_waiting_room_list.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_manager/package_tiles/pat_manager_tile.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_manager/package_tools/mih_patient_search.dart (98%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_manager/package_tools/my_patient_list.dart (98%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_manager/package_tools/waiting_room.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_manager/pat_manager.dart (90%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/add_or_view_patient.dart (92%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/components/claim_statement_window.dart (99%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/components/full_screen_file.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/components/icd10_search_window.dart (95%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/components/medicine_search.dart (96%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/components/prescip_input.dart (99%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/list_builders/build_claim_statement_files_list.dart (99%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/list_builders/build_file_view.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/list_builders/build_files_list.dart (99%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/list_builders/build_icd10_code_list.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/list_builders/build_med_list.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/list_builders/build_notes_list.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/package_tiles/patient_profile_tile.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/package_tools/patient_claim_or_statement.dart (95%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/package_tools/patient_consultation.dart (99%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/package_tools/patient_documents.dart (99%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/package_tools/patient_info.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/patient_add.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/patient_edit.dart (100%) rename Frontend/lib/mih_packages/{patient_profile => patient_manager}/pat_profile/patient_profile.dart (88%) diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index 42bb7d73..430304b8 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -25,11 +25,11 @@ import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profi import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_barcode_scanner.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/mih_wallet.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_manager/pat_manager.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/add_or_view_patient.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/full_screen_file.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/patient_edit.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/patient_profile.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/pat_manager.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/add_or_view_patient.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/components/full_screen_file.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/patient_edit.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/patient_profile.dart'; import 'package:provider/provider.dart'; import 'package:supertokens_flutter/supertokens.dart'; diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart index 76efabbc..a24e60a3 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart @@ -16,7 +16,7 @@ import 'package:mzansi_innovation_hub/mih_packages/mzansi_ai/package_tiles/mzans import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/package_tiles/mzansi_directory_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tiles/mzansi_business_profile_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tiles/mzansi_setup_business_profile_tile.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_manager/package_tiles/pat_manager_tile.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/package_tiles/pat_manager_tile.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart index abc038ea..6daf28fb 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_personal_home.dart @@ -21,7 +21,7 @@ import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/package_tile import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/package_tiles/mzansi_profile_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/package_tiles/mzansi_setup_profile_tile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/package_tiles/mih_wallet_tile.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/package_tiles/patient_profile_tile.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tiles/patient_profile_tile.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_mih_patient_search_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_mih_patient_search_list.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_mih_patient_search_list.dart rename to Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_mih_patient_search_list.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_my_patient_list_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_my_patient_list_list.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_my_patient_list_list.dart rename to Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_my_patient_list_list.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_waiting_room_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_waiting_room_list.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_manager/list_builders/build_waiting_room_list.dart rename to Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_waiting_room_list.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tiles/pat_manager_tile.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tiles/pat_manager_tile.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_manager/package_tiles/pat_manager_tile.dart rename to Frontend/lib/mih_packages/patient_manager/pat_manager/package_tiles/pat_manager_tile.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/mih_patient_search.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/mih_patient_search.dart similarity index 98% rename from Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/mih_patient_search.dart rename to Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/mih_patient_search.dart index 92ff42a7..10d39928 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/mih_patient_search.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/mih_patient_search.dart @@ -12,7 +12,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_manager/list_builders/build_mih_patient_search_list.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/list_builders/build_mih_patient_search_list.dart'; import 'package:flutter/material.dart'; class MihPatientSearch extends StatefulWidget { diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/my_patient_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/my_patient_list.dart similarity index 98% rename from Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/my_patient_list.dart rename to Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/my_patient_list.dart index 470a5150..d87f56a8 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/my_patient_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/my_patient_list.dart @@ -11,7 +11,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_manager/list_builders/build_my_patient_list_list.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/list_builders/build_my_patient_list_list.dart'; import 'package:flutter/material.dart'; class MyPatientList extends StatefulWidget { diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/waiting_room.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/waiting_room.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_manager/package_tools/waiting_room.dart rename to Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/waiting_room.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_manager/pat_manager.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/pat_manager.dart similarity index 90% rename from Frontend/lib/mih_packages/patient_profile/pat_manager/pat_manager.dart rename to Frontend/lib/mih_packages/patient_manager/pat_manager/pat_manager.dart index ed5d077f..dca4e520 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_manager/pat_manager.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/pat_manager.dart @@ -3,9 +3,9 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_manager/package_tools/mih_patient_search.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_manager/package_tools/my_patient_list.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_manager/package_tools/waiting_room.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/package_tools/mih_patient_search.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/package_tools/my_patient_list.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/package_tools/waiting_room.dart'; import 'package:flutter/material.dart'; class PatManager extends StatefulWidget { diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/add_or_view_patient.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/add_or_view_patient.dart similarity index 92% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/add_or_view_patient.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/add_or_view_patient.dart index c7a6455a..841ca9f3 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/add_or_view_patient.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/add_or_view_patient.dart @@ -3,8 +3,8 @@ import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loa import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/patient_add.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/patient_profile.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/patient_add.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/patient_profile.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/claim_statement_window.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/claim_statement_window.dart similarity index 99% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/components/claim_statement_window.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/components/claim_statement_window.dart index 39da94a6..d6f499df 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/claim_statement_window.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/claim_statement_window.dart @@ -18,7 +18,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/icd10_code.dart.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/icd10_search_window.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/components/icd10_search_window.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/full_screen_file.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/full_screen_file.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/components/full_screen_file.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/components/full_screen_file.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/icd10_search_window.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/icd10_search_window.dart similarity index 95% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/components/icd10_search_window.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/components/icd10_search_window.dart index eaffd071..c6699842 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/icd10_search_window.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/icd10_search_window.dart @@ -4,7 +4,7 @@ import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart' import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/icd10_code.dart.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/list_builders/build_icd10_code_list.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/list_builders/build_icd10_code_list.dart'; import 'package:flutter/material.dart'; class ICD10SearchWindow extends StatefulWidget { diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/medicine_search.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/medicine_search.dart similarity index 96% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/components/medicine_search.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/components/medicine_search.dart index 56a8886e..f3420c85 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/medicine_search.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/medicine_search.dart @@ -4,7 +4,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_err import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/medicine.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/list_builders/build_med_list.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/list_builders/build_med_list.dart'; import 'package:flutter/material.dart'; import 'package:supertokens_flutter/http.dart' as http; diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/prescip_input.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/prescip_input.dart similarity index 99% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/components/prescip_input.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/components/prescip_input.dart index 6c6e90b2..543d26a7 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/components/prescip_input.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/prescip_input.dart @@ -6,7 +6,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_numeric_stepper.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/medicine_search.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/components/medicine_search.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_claim_statement_files_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart similarity index 99% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_claim_statement_files_list.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart index 469018c5..2b0b2dce 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_claim_statement_files_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart @@ -20,7 +20,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/claim_statement_file.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/list_builders/build_file_view.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/list_builders/build_file_view.dart'; import 'package:flutter/material.dart'; import 'package:supertokens_flutter/http.dart' as http; import 'package:http/http.dart' as http2; diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_file_view.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_file_view.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_file_view.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_file_view.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_files_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart similarity index 99% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_files_list.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart index 3a302712..e825d002 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_files_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart @@ -20,7 +20,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/files.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/list_builders/build_file_view.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/list_builders/build_file_view.dart'; import 'package:flutter/material.dart'; import 'package:supertokens_flutter/http.dart' as http; import 'package:http/http.dart' as http2; diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_icd10_code_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_icd10_code_list.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_icd10_code_list.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_icd10_code_list.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_med_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_med_list.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_med_list.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_med_list.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_notes_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_notes_list.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/list_builders/build_notes_list.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_notes_list.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tiles/patient_profile_tile.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tiles/patient_profile_tile.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/package_tiles/patient_profile_tile.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/package_tiles/patient_profile_tile.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_claim_or_statement.dart similarity index 95% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_claim_or_statement.dart index c26c0480..19690da9 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_claim_or_statement.dart @@ -11,8 +11,8 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/claim_statement_file.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/claim_statement_window.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/list_builders/build_claim_statement_files_list.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/components/claim_statement_window.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart'; import 'package:flutter/material.dart'; class PatientClaimOrStatement extends StatefulWidget { diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_consultation.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_consultation.dart similarity index 99% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_consultation.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_consultation.dart index a6489ac9..f7cca32d 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_consultation.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_consultation.dart @@ -20,7 +20,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/notes.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/list_builders/build_notes_list.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/list_builders/build_notes_list.dart'; import 'package:flutter/material.dart'; import 'package:supertokens_flutter/http.dart' as http; diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_documents.dart similarity index 99% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_documents.dart index 44a2e485..c537baa6 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_documents.dart @@ -23,8 +23,8 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/files.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/prescip_input.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/list_builders/build_files_list.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/components/prescip_input.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:supertokens_flutter/http.dart' as http; diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_info.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/package_tools/patient_info.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_add.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_add.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/patient_add.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/patient_add.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_edit.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_edit.dart similarity index 100% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/patient_edit.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/patient_edit.dart diff --git a/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_profile.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart similarity index 88% rename from Frontend/lib/mih_packages/patient_profile/pat_profile/patient_profile.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart index 623d4787..fccb9c0b 100644 --- a/Frontend/lib/mih_packages/patient_profile/pat_profile/patient_profile.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart @@ -3,10 +3,10 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/package_tools/patient_claim_or_statement.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/package_tools/patient_consultation.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/package_tools/patient_documents.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/package_tools/patient_info.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_claim_or_statement.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_consultation.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_documents.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart'; import 'package:flutter/material.dart'; class PatientProfile extends StatefulWidget { From 7de2cb7b36c7ace64076537ef50794aa2dd8c875 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 24 Oct 2025 12:57:49 +0200 Subject: [PATCH 30/45] QOL: Update Alert title size --- .../mih_package_components/mih_package_alert.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/mih_package_alert.dart b/Frontend/lib/mih_components/mih_package_components/mih_package_alert.dart index ce87d21f..a087be0c 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_package_alert.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_package_alert.dart @@ -35,7 +35,7 @@ class _MihPackageAlertState extends State { setState(() { popUpWidth = (size!.width / 4) * 2; popUpheight = null; - popUpTitleSize = 25.0; + popUpTitleSize = 30.0; popUpSubtitleSize = 20.0; popUpBodySize = 15; popUpPaddingSize = 25.0; @@ -45,7 +45,7 @@ class _MihPackageAlertState extends State { setState(() { popUpWidth = size!.width - (size!.width * 0.1); popUpheight = null; - popUpTitleSize = 20.0; + popUpTitleSize = 25.0; popUpSubtitleSize = 18.0; popUpBodySize = 15; popUpPaddingSize = 15.0; From a9ea3594b91f57d9d0b506b80092502cdd2fbee5 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 24 Oct 2025 12:58:29 +0200 Subject: [PATCH 31/45] QOL: Add reset function to providers --- .../mih_providers/about_mih_provider.dart | 5 +++ .../mih_access_controlls_provider.dart | 6 +++ .../mih_authentication_provider.dart | 5 +++ .../mih_providers/mih_banner_ad_provider.dart | 7 ++++ .../mih_calculator_provider.dart | 6 +++ .../mih_providers/mih_calendar_provider.dart | 7 ++++ .../mih_mine_sweeper_provider.dart | 16 +++++++ .../mih_providers/mzansi_ai_provider.dart | 6 +++ .../mzansi_directory_provider.dart | 16 +++++++ .../mzansi_profile_provider.dart | 1 + .../mih_providers/mzansi_wallet_provider.dart | 6 +++ .../patient_manager_provider.dart | 42 +++++++++++++++++++ 12 files changed, 123 insertions(+) create mode 100644 Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart diff --git a/Frontend/lib/mih_components/mih_providers/about_mih_provider.dart b/Frontend/lib/mih_components/mih_providers/about_mih_provider.dart index 5ef994ba..18b2e985 100644 --- a/Frontend/lib/mih_components/mih_providers/about_mih_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/about_mih_provider.dart @@ -7,6 +7,11 @@ class AboutMihProvider extends ChangeNotifier { this.toolIndex = 0, }); + void reset() { + toolIndex = 0; + notifyListeners(); + } + void setToolIndex(int index) { toolIndex = index; notifyListeners(); diff --git a/Frontend/lib/mih_components/mih_providers/mih_access_controlls_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_access_controlls_provider.dart index 4fb1c2b6..dd7f11a0 100644 --- a/Frontend/lib/mih_components/mih_providers/mih_access_controlls_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mih_access_controlls_provider.dart @@ -9,6 +9,12 @@ class MihAccessControllsProvider extends ChangeNotifier { this.toolIndex = 0, }); + void reset() { + toolIndex = 0; + accessList = null; + notifyListeners(); + } + void setToolIndex(int index) { toolIndex = index; } diff --git a/Frontend/lib/mih_components/mih_providers/mih_authentication_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_authentication_provider.dart index 94d33ba3..d53213bc 100644 --- a/Frontend/lib/mih_components/mih_providers/mih_authentication_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mih_authentication_provider.dart @@ -7,6 +7,11 @@ class MihAuthenticationProvider extends ChangeNotifier { this.toolIndex = 0, }); + void reset() { + toolIndex = 0; + notifyListeners(); + } + void setToolIndex(int index) { toolIndex = index; notifyListeners(); diff --git a/Frontend/lib/mih_components/mih_providers/mih_banner_ad_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_banner_ad_provider.dart index 610c5697..560fc91a 100644 --- a/Frontend/lib/mih_components/mih_providers/mih_banner_ad_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mih_banner_ad_provider.dart @@ -14,6 +14,13 @@ class MihBannerAdProvider extends ChangeNotifier { this.errorMessage = '', }); + void reset() { + bannerAd = null; + isBannerAdLoaded = false; + errorMessage = ""; + notifyListeners(); + } + @override void dispose() { bannerAd?.dispose(); diff --git a/Frontend/lib/mih_components/mih_providers/mih_calculator_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_calculator_provider.dart index e2c66757..29052ff7 100644 --- a/Frontend/lib/mih_components/mih_providers/mih_calculator_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mih_calculator_provider.dart @@ -9,6 +9,12 @@ class MihCalculatorProvider extends ChangeNotifier { this.toolIndex = 0, }); + void reset() { + availableCurrencies = []; + toolIndex = 0; + notifyListeners(); + } + void setToolIndex(int index) { toolIndex = index; notifyListeners(); diff --git a/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart index 57cb2e92..40265f45 100644 --- a/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mih_calendar_provider.dart @@ -11,6 +11,13 @@ class MihCalendarProvider extends ChangeNotifier { this.toolIndex = 0, }); + void reset() { + toolIndex = 0; + personalAppointments = null; + businessAppointments = null; + notifyListeners(); + } + void setToolIndex(int index) { toolIndex = index; notifyListeners(); diff --git a/Frontend/lib/mih_components/mih_providers/mih_mine_sweeper_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_mine_sweeper_provider.dart index 1d881fd9..f6d3ea90 100644 --- a/Frontend/lib/mih_components/mih_providers/mih_mine_sweeper_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mih_mine_sweeper_provider.dart @@ -1,18 +1,34 @@ import 'package:flutter/widgets.dart'; class MihMineSweeperProvider extends ChangeNotifier { + String difficulty; int toolIndex; int rowCount; int columnCount; int totalMines; MihMineSweeperProvider({ + this.difficulty = "Normal", this.toolIndex = 0, this.rowCount = 10, this.columnCount = 10, this.totalMines = 15, }); + void reset() { + difficulty = "Normal"; + toolIndex = 0; + rowCount = 10; + columnCount = 10; + totalMines = 15; + notifyListeners(); + } + + void setDifficulty(String difficulty) { + this.difficulty = difficulty; + notifyListeners(); + } + void setToolIndex(int index) { toolIndex = index; notifyListeners(); diff --git a/Frontend/lib/mih_components/mih_providers/mzansi_ai_provider.dart b/Frontend/lib/mih_components/mih_providers/mzansi_ai_provider.dart index fc6b31fb..1ba96af5 100644 --- a/Frontend/lib/mih_components/mih_providers/mzansi_ai_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mzansi_ai_provider.dart @@ -8,6 +8,12 @@ class MzansiAiProvider extends ChangeNotifier { this.toolIndex = 0, }); + void reset() { + toolIndex = 0; + startUpQuestion = null; + notifyListeners(); + } + void setToolIndex(int index) { toolIndex = index; notifyListeners(); diff --git a/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart b/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart index e18bcc3d..da94c4d8 100644 --- a/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart @@ -26,6 +26,22 @@ class MzansiDirectoryProvider extends ChangeNotifier { this.businessTypeFilter = "", }); + void reset() { + toolIndex = 0; + userPosition = null; + userLocation = "Unknown Location"; + personalSearch = true; + bookmarkedBusinesses = []; + businessDetailsMap = {}; + searchedBusinesses = null; + selectedBusiness = null; + searchedUsers = null; + selectedUser = null; + searchTerm = ""; + businessTypeFilter = ""; + notifyListeners(); + } + void setToolIndex(int index) { toolIndex = index; notifyListeners(); diff --git a/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart b/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart index cf6e6d8d..0f4b9414 100644 --- a/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart @@ -41,6 +41,7 @@ class MzansiProfileProvider extends ChangeNotifier { businessUserSignatureUrl = null; businessUserSignature = null; userConsent = null; + notifyListeners(); } void setPersonalHome(bool isPersonalHome) { diff --git a/Frontend/lib/mih_components/mih_providers/mzansi_wallet_provider.dart b/Frontend/lib/mih_components/mih_providers/mzansi_wallet_provider.dart index 9358eaa1..f09a3135 100644 --- a/Frontend/lib/mih_components/mih_providers/mzansi_wallet_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mzansi_wallet_provider.dart @@ -12,6 +12,12 @@ class MzansiWalletProvider extends ChangeNotifier { this.toolIndex = 0, }); + void reset() { + toolIndex = 0; + loyaltyCards = []; + favouriteCards = []; + } + void setToolIndex(int index) { toolIndex = index; notifyListeners(); diff --git a/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart b/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart new file mode 100644 index 00000000..cbddf3e1 --- /dev/null +++ b/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; + +class PatientManagerProvider extends ChangeNotifier { + int patientProfileIndex; + int patientManagerIndex; + bool personalMode; + Patient? selectedPatient; + + PatientManagerProvider({ + this.patientProfileIndex = 0, + this.patientManagerIndex = 0, + this.personalMode = true, + }); + + void reset() { + patientProfileIndex = 0; + patientManagerIndex = 0; + personalMode = true; + selectedPatient = null; + } + + void setPatientProfileIndex(int index) { + patientProfileIndex = index; + notifyListeners(); + } + + void setPatientManagerIndex(int index) { + patientManagerIndex = index; + notifyListeners(); + } + + void setPersonalMode(bool personalMode) { + this.personalMode = personalMode; + notifyListeners(); + } + + void setSelectedPatient({required Patient? selectedPatient}) { + this.selectedPatient = selectedPatient; + notifyListeners(); + } +} From 656e1cd3d77c168d6927474191816136c9ba2ade Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 24 Oct 2025 12:59:11 +0200 Subject: [PATCH 32/45] QOL: reset providers on signout and signin --- .../package_tools/mih_register.dart | 2 + .../package_tools/mih_sign_in.dart | 2 + .../mih_home/components/mih_app_drawer.dart | 46 ++++++++++++++----- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_register.dart b/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_register.dart index f97a0334..f16c6ef0 100644 --- a/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_register.dart +++ b/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_register.dart @@ -12,6 +12,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_authentication_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; @@ -75,6 +76,7 @@ class _MihRegisterState extends State { } Future signUserUp() async { + context.read().reset(); if (!validEmail()) { emailError(); } else if (passwordController.text != confirmPasswordController.text) { diff --git a/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart b/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart index d21ee78c..68751125 100644 --- a/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart +++ b/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart @@ -10,6 +10,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_authentication_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; @@ -39,6 +40,7 @@ class _MihSignInState extends State { //sign user in Future signUserIn() async { + context.read().reset(); try { successfulSignIn = await MihAuthenticationServices().signUserIn( emailController.text, diff --git a/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart b/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart index c74fe1c8..8dff220e 100644 --- a/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart +++ b/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart @@ -4,7 +4,17 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart' import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/about_mih_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_access_controlls_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_authentication_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calculator_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_ai_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:provider/provider.dart'; import '../../../main.dart'; @@ -22,6 +32,21 @@ class MIHAppDrawer extends StatefulWidget { class _MIHAppDrawerState extends State { final proPicController = TextEditingController(); late Widget profilePictureLoaded; + + void resetProviders() { + context.read().reset(); + context.read().reset(); + context.read().reset(); + context.read().reset(); + context.read().reset(); + context.read().reset(); + context.read().reset(); + context.read().reset(); + context.read().reset(); + context.read().reset(); + context.read().reset(); + } + Future signOut() async { await SuperTokens.signOut(completionHandler: (error) { // handle error if any @@ -107,7 +132,7 @@ class _MIHAppDrawerState extends State { Visibility( visible: !mzansiProfileProvider.personalHome, child: Text( - mzansiProfileProvider.business!.Name, + mzansiProfileProvider.business?.Name ?? "", style: TextStyle( fontWeight: FontWeight.bold, color: MihColors.getPrimaryColor( @@ -135,7 +160,7 @@ class _MIHAppDrawerState extends State { Visibility( visible: !mzansiProfileProvider.personalHome, child: Text( - mzansiProfileProvider.business!.type, + mzansiProfileProvider.business?.type ?? "", style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, @@ -321,16 +346,13 @@ class _MIHAppDrawerState extends State { }); if (await SuperTokens.doesSessionExist() == false) { - mzansiProfileProvider.reset(); - context.goNamed( - 'mihHome', - extra: true, - ); - // Navigator.of(context).pop(); - // Navigator.of(context).popAndPushNamed( - // '/', - // arguments: AuthArguments(true, false), - // ); + resetProviders(); + await Future.delayed(Duration.zero); + if (context.mounted) { + context.goNamed( + 'mihHome', + ); + } } }, ), From 1fe817919f244018890c99ae89bd55c85c9710e5 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 24 Oct 2025 13:00:19 +0200 Subject: [PATCH 33/45] QOL: Fix New User Setup flow --- .../lib/mih_packages/mih_home/mih_home.dart | 20 +-- .../package_tools/mih_business_home.dart | 81 +++++++----- .../mzansi_setup_business_profile_tile.dart | 9 +- .../mih_edit_personal_profile_window.dart | 121 +++++++++++++++++- 4 files changed, 179 insertions(+), 52 deletions(-) diff --git a/Frontend/lib/mih_packages/mih_home/mih_home.dart b/Frontend/lib/mih_packages/mih_home/mih_home.dart index b294cc37..877057e6 100644 --- a/Frontend/lib/mih_packages/mih_home/mih_home.dart +++ b/Frontend/lib/mih_packages/mih_home/mih_home.dart @@ -82,14 +82,14 @@ class _MihHomeState extends State { String signatureUrl; Business? responseBusiness = await MihBusinessDetailsServices().getBusinessDetailsByUser(context); - if (responseBusiness == null && user!.type == "business") { - if (mounted) { - context.goNamed( - 'businessProfileSetup', - extra: user, - ); - } - } + // if (responseBusiness == null && user!.type == "business") { + // if (mounted) { + // context.goNamed( + // 'businessProfileSetup', + // extra: user, + // ); + // } + // } if (responseBusiness != null && user!.type == "business") { // Get Business @@ -548,7 +548,9 @@ class _MihHomeState extends State { ); if (user.type != "personal") { toolBodies.add( - MihBusinessHome(), + MihBusinessHome( + isLoading: _isLoadingInitialData, + ), ); } return toolBodies; diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart index a24e60a3..b8c7746e 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart @@ -1,11 +1,11 @@ import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_ai_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; @@ -21,8 +21,10 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class MihBusinessHome extends StatefulWidget { + final bool isLoading; const MihBusinessHome({ super.key, + required this.isLoading, }); @override @@ -61,7 +63,6 @@ class _MihBusinessHomeState extends State List> temp = []; temp.add({ "Setup Business": MzansiSetupBusinessProfileTile( - signedInUser: context.read().user!, packageSize: packageSize, ) }); @@ -71,12 +72,22 @@ class _MihBusinessHomeState extends State List> setBusinessPackages() { MzansiProfileProvider mzansiProfileProvider = context.read(); - if (mzansiProfileProvider.user == null || - mzansiProfileProvider.business == null || - mzansiProfileProvider.businessUser == null) { - return []; // Return empty list if data isn't ready - } + // if (mzansiProfileProvider.user == null || + // mzansiProfileProvider.business == null || + // mzansiProfileProvider.businessUser == null) { + // return []; // Return empty list if data isn't ready + // } List> temp = []; + KenLogger.success("here"); + if (mzansiProfileProvider.business == null && !widget.isLoading) { + KenLogger.success("here"); + temp.add({ + "Setup Business": MzansiSetupBusinessProfileTile( + packageSize: packageSize, + ) + }); + return temp; + } //=============== Biz Profile =============== temp.add({ "Business Profile": MzansiBusinessProfileTile( @@ -174,10 +185,8 @@ class _MihBusinessHomeState extends State super.initState(); searchController.addListener(searchPackage); - WidgetsBinding.instance.addPostFrameCallback((_) { - businessPackagesMap = setBusinessPackages(); - searchPackage(); - }); + businessPackagesMap = setBusinessPackages(); + searchPackage(); } @override @@ -197,33 +206,39 @@ class _MihBusinessHomeState extends State MzansiProfileProvider mzansiProfileProvider, MzansiAiProvider mzansiAiProvider, Widget? child) { - if (mzansiProfileProvider.business == null) { - return Center( - child: Mihloadingcircle(), - ); - } + // if (mzansiProfileProvider.user == null || + // mzansiProfileProvider.business == null || + // mzansiProfileProvider.businessUser == null) { + // return Center( + // child: Mihloadingcircle(), + // ); + // } return MihSingleChildScroll( child: Column( children: [ Padding( padding: EdgeInsets.symmetric(horizontal: width / 20), - child: MihSearchBar( - controller: searchController, - hintText: "Ask Mzansi", - prefixIcon: Icons.search, - prefixAltIcon: MihIcons.mzansiAi, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - hintColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onPrefixIconTap: () { - mzansiAiProvider.setStartUpQuestion(searchController.text); - context.goNamed( - "mzansiAi", - ); - searchController.clear(); - }, - searchFocusNode: _searchFocusNode, + child: Visibility( + visible: mzansiProfileProvider.business != null, + child: MihSearchBar( + controller: searchController, + hintText: "Ask Mzansi", + prefixIcon: Icons.search, + prefixAltIcon: MihIcons.mzansiAi, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + hintColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onPrefixIconTap: () { + mzansiAiProvider + .setStartUpQuestion(searchController.text); + context.goNamed( + "mzansiAi", + ); + searchController.clear(); + }, + searchFocusNode: _searchFocusNode, + ), ), ), const SizedBox(height: 20), diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tiles/mzansi_setup_business_profile_tile.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tiles/mzansi_setup_business_profile_tile.dart index 268cea2a..4ae9ec40 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tiles/mzansi_setup_business_profile_tile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tiles/mzansi_setup_business_profile_tile.dart @@ -2,16 +2,15 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:provider/provider.dart'; class MzansiSetupBusinessProfileTile extends StatefulWidget { - final AppUser signedInUser; final double packageSize; const MzansiSetupBusinessProfileTile({ super.key, - required this.signedInUser, required this.packageSize, }); @@ -24,11 +23,13 @@ class _MzansiSetupBusinessProfileTileState extends State { @override Widget build(BuildContext context) { + MzansiProfileProvider profileProvider = + context.read(); return MihPackageTile( onTap: () { context.goNamed( 'businessProfileSetup', - extra: widget.signedInUser, + extra: profileProvider.user, ); // Navigator.of(context).pushNamed( // '/business-profile/set-up', diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart index c4b47711..bd80f937 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart @@ -6,6 +6,7 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; @@ -96,13 +97,14 @@ class _MihEditPersonalProfileWindowState setProfileVariables(mzansiProfileProvider); newSelectedProPic = null; }); - bool stayOnPersonalSide = true; // if (originalProfileTypeIsBusiness == false && businessUser == true) { // stayOnPersonalSide = false; // } String message = "Your information has been updated successfully!"; - context.pop(); - successPopUp(message, stayOnPersonalSide); + successPopUp( + mzansiProfileProvider, + message, + ); } else { internetConnectionPopUp(); } @@ -158,7 +160,10 @@ class _MihEditPersonalProfileWindowState } } - void successPopUp(String message, bool stayOnPersonalSide) { + void successPopUp( + MzansiProfileProvider profileProvider, + String message, + ) { showDialog( context: context, builder: (context) { @@ -185,7 +190,14 @@ class _MihEditPersonalProfileWindowState Center( child: MihButton( onPressed: () { - context.pop(); + if (profileProvider.user!.type.toLowerCase() == + "business" && + profileProvider.business == null) { + setupBusinessPopUp(profileProvider); + } else { + context.pop(); + context.pop(); + } }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -216,6 +228,101 @@ class _MihEditPersonalProfileWindowState ); } + void setupBusinessPopUp( + MzansiProfileProvider profileProvider, + ) { + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + MihIcons.businessSetup, + size: 150, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + alertTitle: "Setup Business Profile?", + alertBody: Column( + children: [ + Text( + "It looks like this is the first time activating your business account. Would you like to set up your business now or would you like to do it later?", + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25), + Center( + child: Wrap( + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + onPressed: () { + context.pop(); + context.goNamed( + 'businessProfileSetup', + extra: profileProvider.user, + ); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + elevation: 10, + width: 300, + child: Text( + "Setup Business", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + MihButton( + onPressed: () { + context.pop(); + context.pop(); + context.pop(); + }, + buttonColor: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + elevation: 10, + width: 300, + child: Text( + "Setup Later", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ) + ], + ), + alertColour: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + // return MIHSuccessMessage( + // successType: "Success", + // successMessage: message, + // ); + }, + ); + } + void internetConnectionPopUp() { showDialog( context: context, @@ -447,7 +554,9 @@ class _MihEditPersonalProfileWindowState "Dark"), width: 300, child: Text( - "Update", + mzansiProfileProvider.user!.username.isEmpty + ? "Setup Profile" + : "Update", style: TextStyle( color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == From fd2f3a2138abd67c25d7e2825681fab40fa0b3f0 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 24 Oct 2025 13:11:42 +0200 Subject: [PATCH 34/45] BUG: Fix MIH Logo press on app drawer --- .../mih_home/components/mih_app_drawer.dart | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart b/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart index 8dff220e..6a0e9f27 100644 --- a/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart +++ b/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/about_mih_provider.dart'; @@ -62,9 +61,16 @@ class _MIHAppDrawerState extends State { 'mzansiProfileManage', ); } else { - context.goNamed( - "businessProfileManage", - ); + if (mzansiProfileProvider.business == null) { + context.goNamed( + 'businessProfileSetup', + extra: mzansiProfileProvider.user, + ); + } else { + context.goNamed( + "businessProfileManage", + ); + } } }, child: MihCircleAvatar( @@ -132,7 +138,8 @@ class _MIHAppDrawerState extends State { Visibility( visible: !mzansiProfileProvider.personalHome, child: Text( - mzansiProfileProvider.business?.Name ?? "", + mzansiProfileProvider.business?.Name ?? + "Setup Business", style: TextStyle( fontWeight: FontWeight.bold, color: MihColors.getPrimaryColor( @@ -368,26 +375,22 @@ class _MIHAppDrawerState extends State { height: 30, child: InkWell( onTap: () { - setState(() { - if (MzansiInnovationHub.of(context)?.theme.mode == - "Dark") { - //darkm = !darkm; - MzansiInnovationHub.of(context)! - .changeTheme(ThemeMode.light); - //print("Dark Mode: $darkm"); - } else { - //darkm = !darkm; - MzansiInnovationHub.of(context)! - .changeTheme(ThemeMode.dark); - //print("Dark Mode: $darkm"); - } - Navigator.of(context).pop(); - Navigator.of(context).popAndPushNamed( - '/', - arguments: AuthArguments(true, false), - ); - // Navigator.of(context).popAndPushNamed('/',); - }); + // setState(() { + // if (MzansiInnovationHub.of(context)?.theme.mode == + // "Dark") { + // //darkm = !darkm; + // MzansiInnovationHub.of(context)! + // .changeTheme(ThemeMode.light); + // //print("Dark Mode: $darkm"); + // } else { + // //darkm = !darkm; + // MzansiInnovationHub.of(context)! + // .changeTheme(ThemeMode.dark); + // //print("Dark Mode: $darkm"); + // } + // // Navigator.of(context).popAndPushNamed('/',); + // }); + context.goNamed("aboutMih"); }, child: Icon( MihIcons.mihLogo, From f548db7d82015d0a36799b4b6828cc15c2353ef8 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 27 Oct 2025 18:46:20 +0200 Subject: [PATCH 35/45] NEW: Patient Manager Provider Setup pt1 --- Frontend/lib/main.dart | 4 + .../patient_manager_provider.dart | 21 + Frontend/lib/mih_config/mih_go_router.dart | 50 +- .../pat_profile/add_or_view_patient.dart | 79 -- .../mih_edit_patient_details_window.dart} | 350 +++---- .../list_builders/build_files_list.dart | 415 ++++---- .../list_builders/build_notes_list.dart | 382 ++++---- .../package_tiles/patient_profile_tile.dart | 1 - .../package_tools/patient_consultation.dart | 197 ++-- .../package_tools/patient_documents.dart | 301 +++--- .../package_tools/patient_info.dart | 254 ++--- .../package_tools/patient_setup_form.dart | 543 +++++++++++ .../pat_profile/patient_edit.dart | 903 ------------------ .../pat_profile/patient_profile.dart | 135 ++- .../pat_profile/patient_set_up.dart | 72 ++ Frontend/lib/mih_packages/test/test.dart | 68 -- .../mih_services/mih_patient_services.dart | 194 +++- .../lib/mih_services/mih_service_calls.dart | 17 +- 18 files changed, 1784 insertions(+), 2202 deletions(-) delete mode 100644 Frontend/lib/mih_packages/patient_manager/pat_profile/add_or_view_patient.dart rename Frontend/lib/mih_packages/patient_manager/pat_profile/{patient_add.dart => components/mih_edit_patient_details_window.dart} (76%) create mode 100644 Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_setup_form.dart delete mode 100644 Frontend/lib/mih_packages/patient_manager/pat_profile/patient_edit.dart create mode 100644 Frontend/lib/mih_packages/patient_manager/pat_profile/patient_set_up.dart delete mode 100644 Frontend/lib/mih_packages/test/test.dart diff --git a/Frontend/lib/main.dart b/Frontend/lib/main.dart index 3569ecb1..783a11a3 100644 --- a/Frontend/lib/main.dart +++ b/Frontend/lib/main.dart @@ -11,6 +11,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_ai_pro import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_wallet_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:provider/provider.dart'; import 'package:upgrader/upgrader.dart'; @@ -113,6 +114,9 @@ class _MzansiInnovationHubState extends State { ChangeNotifierProvider( create: (context) => MihMineSweeperProvider(), ), + ChangeNotifierProvider( + create: (context) => PatientManagerProvider(), + ), ], child: MaterialApp.router( title: getTitle(), diff --git a/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart b/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart index cbddf3e1..a0d10806 100644 --- a/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart @@ -1,15 +1,21 @@ import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/files.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/notes.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; class PatientManagerProvider extends ChangeNotifier { int patientProfileIndex; int patientManagerIndex; + int fileViewerIndex; bool personalMode; Patient? selectedPatient; + List? consultationNotes; + List? patientDocuments; PatientManagerProvider({ this.patientProfileIndex = 0, this.patientManagerIndex = 0, + this.fileViewerIndex = 0, this.personalMode = true, }); @@ -30,6 +36,11 @@ class PatientManagerProvider extends ChangeNotifier { notifyListeners(); } + void setFileViewerIndex(int index) { + patientProfileIndex = index; + notifyListeners(); + } + void setPersonalMode(bool personalMode) { this.personalMode = personalMode; notifyListeners(); @@ -39,4 +50,14 @@ class PatientManagerProvider extends ChangeNotifier { this.selectedPatient = selectedPatient; notifyListeners(); } + + void setConsultationNotes({required List? consultationNotes}) { + this.consultationNotes = consultationNotes ?? []; + notifyListeners(); + } + + void setPatientDocuments({required List? patientDocuments}) { + this.patientDocuments = patientDocuments ?? []; + notifyListeners(); + } } diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index 430304b8..9dae1781 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -26,10 +26,9 @@ import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_barcode_scanner.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/mih_wallet.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/pat_manager.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/add_or_view_patient.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/components/full_screen_file.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/patient_edit.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/patient_profile.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/patient_set_up.dart'; import 'package:provider/provider.dart'; import 'package:supertokens_flutter/supertokens.dart'; @@ -53,7 +52,6 @@ class MihGoRouterPaths { static const String businessProfileView = '/business-profile/view'; static const String patientProfile = '/patient-profile'; static const String patientProfileSetup = '/patient-profile/set-up'; - static const String patientProfileEdit = '/patient-profile/edit'; static const String mzansiWallet = '/mzansi-wallet'; static const String mzansiDirectory = '/mzansi-directory'; static const String mihAccess = '/mih-access'; @@ -66,7 +64,7 @@ class MihGoRouterPaths { static const String barcodeScanner = '/scanner'; static const String calculator = '/calculator'; static const String mzansiAi = '/mzansi-ai'; - static const String mihMineSweeper = '/mih-mine-sweeper'; + static const String mihMineSweeper = '/mih-minesweeper'; static const String packageDevTest = '/package-dev'; } @@ -274,7 +272,7 @@ class MihGoRouter { path: MihGoRouterPaths.mzansiWallet, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: mzansiWallet"); - if (context.watch().business == null) { + if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); @@ -322,7 +320,7 @@ class MihGoRouter { name: "mihAccess", path: MihGoRouterPaths.mihAccess, builder: (BuildContext context, GoRouterState state) { - if (context.watch().business == null) { + if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); @@ -338,36 +336,27 @@ class MihGoRouter { name: "patientProfile", path: MihGoRouterPaths.patientProfile, builder: (BuildContext context, GoRouterState state) { - final PatientViewArguments? args = - state.extra as PatientViewArguments?; - if (args == null) { + final String? argPatientAppId = state.extra as String?; + if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); return const SizedBox.shrink(); } - return AddOrViewPatient( - key: UniqueKey(), - arguments: args, - ); + return PatientProfile(patientAppId: argPatientAppId); }, ), GoRoute( - name: "patientProfileEdit", - path: MihGoRouterPaths.patientProfileEdit, + name: "patientProfileSetup", + path: MihGoRouterPaths.patientProfileSetup, builder: (BuildContext context, GoRouterState state) { - final PatientEditArguments? args = - state.extra as PatientEditArguments?; - if (args == null) { + if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); return const SizedBox.shrink(); } - return EditPatient( - signedInUser: args.signedInUser, - selectedPatient: args.selectedPatient, - ); + return PatientSetUp(); }, ), GoRoute( @@ -391,15 +380,14 @@ class MihGoRouter { name: "patientManagerPatient", path: MihGoRouterPaths.patientManagerPatient, builder: (BuildContext context, GoRouterState state) { - final PatientViewArguments? args = - state.extra as PatientViewArguments?; - if (args == null) { + final String? argPatientAppId = state.extra as String?; + if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); return const SizedBox.shrink(); } - return PatientProfile(arguments: args); + return PatientProfile(patientAppId: argPatientAppId); }, ), // ========================== Mzansi Directory ================================== @@ -407,7 +395,7 @@ class MihGoRouter { name: "mzansiDirectory", path: MihGoRouterPaths.mzansiDirectory, builder: (BuildContext context, GoRouterState state) { - if (context.watch().business == null) { + if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); @@ -436,10 +424,16 @@ class MihGoRouter { ), // ========================== MIH Calculator ================================== GoRoute( - name: "mihMineSweeper", + name: "mihMinesweeper", path: MihGoRouterPaths.mihMineSweeper, builder: (BuildContext context, GoRouterState state) { KenLogger.success("MihGoRouter: mihMineSweeper"); + if (context.watch().user == null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + context.go(MihGoRouterPaths.mihHome); + }); + return const SizedBox.shrink(); + } return MihMineSweeper(); }, ), diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/add_or_view_patient.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/add_or_view_patient.dart deleted file mode 100644 index 841ca9f3..00000000 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/add_or_view_patient.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; -import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/patient_add.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/patient_profile.dart'; -import 'package:flutter/material.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; - -class AddOrViewPatient extends StatefulWidget { - //final AppUser signedInUser; - final PatientViewArguments arguments; - const AddOrViewPatient({ - super.key, - required this.arguments, - }); - - @override - State createState() => _AddOrViewPatientState(); -} - -class _AddOrViewPatientState extends State { - late double width; - late double height; - late Widget loading; - late Future patient; - - Future fetchPatientData() async { - return await MihPatientServices() - .getPatientDetails(widget.arguments.signedInUser.app_id); - } - - @override - void initState() { - super.initState(); - patient = fetchPatientData(); - } - - @override - Widget build(BuildContext context) { - print("AddOrViewPatient"); - var size = MediaQuery.of(context).size; - setState(() { - width = size.width; - height = size.height; - }); - return FutureBuilder( - future: patient, - builder: (ctx, snapshot) { - if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - // Extracting data from snapshot object - //final data = snapshot.data as String; - return PatientProfile( - arguments: PatientViewArguments( - widget.arguments.signedInUser, - snapshot.requireData, - null, - null, - widget.arguments.type, - )); - } else if (snapshot.connectionState == ConnectionState.waiting) { - loading = Container( - width: width, - height: height, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: const Mihloadingcircle(), - ); - - return loading; - } else { - return AddPatient(signedInUser: widget.arguments.signedInUser); - } - }, - ); - } -} diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_add.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/mih_edit_patient_details_window.dart similarity index 76% rename from Frontend/lib/mih_packages/patient_manager/pat_profile/patient_add.dart rename to Frontend/lib/mih_packages/patient_manager/pat_profile/components/mih_edit_patient_details_window.dart index 3863c927..87defc63 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_add.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/mih_edit_patient_details_window.dart @@ -1,39 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_action.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_body.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_header.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_layout_builder.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; -class AddPatient extends StatefulWidget { - final AppUser signedInUser; - - const AddPatient({ - super.key, - required this.signedInUser, - }); +class MihEditPatientDetailsWindow extends StatefulWidget { + const MihEditPatientDetailsWindow({super.key}); @override - State createState() => _AddPatientState(); + State createState() => + _MihEditPatientDetailsWindowState(); } -class _AddPatientState extends State { - final idController = TextEditingController(); +class _MihEditPatientDetailsWindowState + extends State { + var idController = TextEditingController(); final fnameController = TextEditingController(); final lnameController = TextEditingController(); final cellController = TextEditingController(); @@ -45,51 +37,16 @@ class _AddPatientState extends State { final medAidController = TextEditingController(); final medMainMemController = TextEditingController(); final medAidCodeController = TextEditingController(); - - late bool medAidPosition; - late bool medMainMemberPosition; - final baseAPI = AppEnviroment.baseApiUrl; - late int futureDocOfficeId; - //late bool medRequired; - final ValueNotifier medRequired = ValueNotifier(false); final FocusNode _focusNode = FocusNode(); final _formKey = GlobalKey(); + late bool medAidPosition; + late bool medMainMemberPosition; + final ValueNotifier medRequired = ValueNotifier(false); - bool isFieldsFilled() { - if (medRequired.value) { - if (idController.text.isEmpty || - fnameController.text.isEmpty || - lnameController.text.isEmpty || - cellController.text.isEmpty || - emailController.text.isEmpty || - medNoController.text.isEmpty || - medNameController.text.isEmpty || - medSchemeController.text.isEmpty || - addressController.text.isEmpty || - medAidController.text.isEmpty || - medMainMemController.text.isEmpty || - medAidCodeController.text.isEmpty) { - return false; - } else { - return true; - } - } else { - if (idController.text.isEmpty || - fnameController.text.isEmpty || - lnameController.text.isEmpty || - cellController.text.isEmpty || - emailController.text.isEmpty || - addressController.text.isEmpty || - medAidController.text.isEmpty) { - return false; - } else { - return true; - } - } - } - - Future addPatientService() async { - int statusCode = await MihPatientServices().addPatientService( + Future updatePatientApiCall( + PatientManagerProvider patientManagerProvider) async { + var statusCode = await MihPatientServices().updatePatientService( + patientManagerProvider.selectedPatient!.app_id, idController.text, fnameController.text, lnameController.text, @@ -102,14 +59,19 @@ class _AddPatientState extends State { medNameController.text, medSchemeController.text, addressController.text, - widget.signedInUser, + patientManagerProvider, ); - if (statusCode == 201) { - String message = - "${fnameController.text} ${lnameController.text} patient profile has been successfully added!\n"; - successPopUp("Successfully created Patient Profile", message); + if (statusCode == 200) { + successPopUp( + "Successfully Updated Profile!", + "${fnameController.text} ${lnameController.text}'s information has been updated successfully! Their medical records and details are now current.", + ); } else { - internetConnectionPopUp(); + MihAlertServices().errorAlert( + "Error Updating Profile", + "There was an error updating your profile. Please try again later.", + context, + ); } } @@ -140,17 +102,18 @@ class _AddPatientState extends State { Center( child: MihButton( onPressed: () { + // context.goNamed( + // "patientProfile", + // extra: PatientViewArguments( + // widget.signedInUser, + // widget.selectedPatient, + // null, + // null, + // "personal", + // ), + // ); + context.pop(); context.pop(); - context.goNamed( - 'patientProfile', - extra: PatientViewArguments( - widget.signedInUser, - null, - null, - null, - "personal", - ), - ); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -173,45 +136,21 @@ class _AddPatientState extends State { alertColour: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ); + // return MIHSuccessMessage( + // successType: "Success", + // successMessage: message, + // ); }, ); } - void internetConnectionPopUp() { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Internet Connection"); - }, - ); - } - - void messagePopUp(error) { - showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: Text(error), - ); - }, - ); - } - - void isRequired() { - //print("listerner triggered"); - if (medAidController.text == "Yes") { - medRequired.value = true; - } else { - medRequired.value = false; - } - } - - Widget displayForm(double width) { + Widget displayForm( + PatientManagerProvider patientManagerProvider, double width) { return SingleChildScrollView( child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.2) - : EdgeInsets.symmetric(horizontal: width * 0.075), + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), child: Column( children: [ MihForm( @@ -485,7 +424,7 @@ class _AddPatientState extends State { child: MihButton( onPressed: () { if (_formKey.currentState!.validate()) { - submitForm(); + updatePatientApiCall(patientManagerProvider); } else { MihAlertServices().formNotFilledCompletely(context); } @@ -494,7 +433,7 @@ class _AddPatientState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), width: 300, child: Text( - "Add", + "Update", style: TextStyle( color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == @@ -514,60 +453,12 @@ class _AddPatientState extends State { ); } - void submitForm() { - addPatientService(); - } - - MIHAction getActionButton() { - return MIHAction( - icon: const Icon(Icons.arrow_back), - iconSize: 35, - onTap: () { - context.goNamed( - 'mihHome', - extra: true, - ); - FocusScope.of(context).unfocus(); - }, - ); - } - - MIHHeader getHeader() { - return const MIHHeader( - headerAlignment: MainAxisAlignment.center, - headerItems: [ - Text( - "Set Up Patient Profile", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 25, - ), - ), - ], - ); - } - - MIHBody getBody(double width) { - return MIHBody( - borderOn: false, - bodyItems: [ - KeyboardListener( - focusNode: _focusNode, - autofocus: true, - onKeyEvent: (event) async { - if (event is KeyDownEvent && - event.logicalKey == LogicalKeyboardKey.enter) { - if (_formKey.currentState!.validate()) { - submitForm(); - } else { - MihAlertServices().formNotFilledCompletely(context); - } - } - }, - child: displayForm(width), - ), - ], - ); + void isRequired() { + if (medAidController.text == "Yes") { + medRequired.value = true; + } else if (medAidController.text == "No") { + medRequired.value = false; + } else {} } @override @@ -583,9 +474,9 @@ class _AddPatientState extends State { addressController.dispose(); medAidController.dispose(); medAidCodeController.removeListener(isRequired); - medRequired.dispose(); medMainMemController.dispose(); medAidCodeController.dispose(); + medRequired.dispose(); _focusNode.dispose(); super.dispose(); } @@ -593,67 +484,76 @@ class _AddPatientState extends State { @override void initState() { medAidController.addListener(isRequired); + PatientManagerProvider patientManagerProvider = + context.read(); setState(() { - fnameController.text = widget.signedInUser.fname; - lnameController.text = widget.signedInUser.lname; - emailController.text = widget.signedInUser.email; - medAidPosition = false; - medMainMemberPosition = false; - medAidController.text = "No"; - medMainMemController.text = "No"; + idController.text = patientManagerProvider.selectedPatient!.id_no; + fnameController.text = patientManagerProvider.selectedPatient!.first_name; + lnameController.text = patientManagerProvider.selectedPatient!.last_name; + cellController.text = patientManagerProvider.selectedPatient!.cell_no; + emailController.text = patientManagerProvider.selectedPatient!.email; + medNameController.text = + patientManagerProvider.selectedPatient!.medical_aid_name; + medNoController.text = + patientManagerProvider.selectedPatient!.medical_aid_no; + medSchemeController.text = + patientManagerProvider.selectedPatient!.medical_aid_scheme; + addressController.text = patientManagerProvider.selectedPatient!.address; + medAidController.text = + patientManagerProvider.selectedPatient!.medical_aid; + medMainMemController.text = + patientManagerProvider.selectedPatient!.medical_aid_main_member; + medAidCodeController.text = + patientManagerProvider.selectedPatient!.medical_aid_code; }); + if (medAidController.text == "Yes") { + medAidPosition = true; + } else { + medAidPosition = false; + medAidController.text = "No"; + } + if (medMainMemController.text == "Yes") { + medMainMemberPosition = true; + } else { + medMainMemberPosition = false; + medMainMemController.text = "No"; + } super.initState(); } @override Widget build(BuildContext context) { - double screenWidth = MediaQuery.of(context).size.width; - return MIHLayoutBuilder( - actionButton: getActionButton(), - header: getHeader(), - secondaryActionButton: null, - body: getBody(screenWidth), - actionDrawer: null, - secondaryActionDrawer: null, - bottomNavBar: null, - pullDownToRefresh: false, - onPullDown: () async {}, + var size = MediaQuery.of(context).size; + return MihPackageWindow( + fullscreen: false, + windowTitle: "Edit Patient Details", + onWindowTapClose: () { + context.pop(); + }, + windowBody: getBody(size.width), + ); + } + + Widget getBody(double width) { + return Consumer( + builder: (BuildContext context, + PatientManagerProvider patientManagerProvider, Widget? child) { + return KeyboardListener( + focusNode: _focusNode, + autofocus: true, + onKeyEvent: (event) async { + if (event is KeyDownEvent && + event.logicalKey == LogicalKeyboardKey.enter) { + if (_formKey.currentState!.validate()) { + updatePatientApiCall(patientManagerProvider); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + } + }, + child: displayForm(patientManagerProvider, width), + ); + }, ); - // return Scaffold( - // // appBar: const MIHAppBar( - // // barTitle: "Add Patient", - // // propicFile: null, - // // ), - // //drawer: MIHAppDrawer(signedInUser: widget.signedInUser), - // body: SafeArea( - // child: Stack( - // children: [ - // KeyboardListener( - // focusNode: _focusNode, - // autofocus: true, - // onKeyEvent: (event) async { - // if (event is KeyDownEvent && - // event.logicalKey == LogicalKeyboardKey.enter) { - // submitForm(); - // } - // }, - // child: displayForm(), - // ), - // Positioned( - // top: 10, - // left: 5, - // width: 50, - // height: 50, - // child: IconButton( - // onPressed: () { - // Navigator.of(context).pop(); - // }, - // icon: const Icon(Icons.arrow_back), - // ), - // ) - // ], - // ), - // ), - // ); } } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart index e825d002..a7b38555 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart @@ -1,48 +1,30 @@ import 'dart:async'; -import 'dart:convert'; import 'package:fl_downloader/fl_downloader.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_delete_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/files.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/list_builders/build_file_view.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:supertokens_flutter/http.dart' as http; import 'package:http/http.dart' as http2; import "package:universal_html/html.dart" as html; class BuildFilesList extends StatefulWidget { - final AppUser signedInUser; - final List files; - final Patient selectedPatient; - final Business? business; - final BusinessUser? businessUser; - final String type; - final String env; const BuildFilesList({ super.key, - required this.files, - required this.signedInUser, - required this.selectedPatient, - required this.business, - required this.businessUser, - required this.type, - required this.env, }); @override @@ -68,71 +50,72 @@ class _BuildFilesListState extends State { return teporaryFileUrl; } - Future deleteFileApiCall(String filePath, int fileID) async { - var response = await MihFileApi.deleteFile( - widget.selectedPatient.app_id, - widget.env, - "patient_files", - filePath.split("/").last, - context, - ); - if (response == 200) { - // delete file from database - await deletePatientFileLocationToDB(fileID); - } else { - String message = - "The File has not been deleted successfully. Please try again."; - successPopUp(message); - } - } + // Future deleteFileApiCall(PatientManagerProvider patientManagerProvider, + // String filePath, int fileID) async { + // var response = await MihFileApi.deleteFile( + // patientManagerProvider.selectedPatient!.app_id, + // widget.env, + // "patient_files", + // filePath.split("/").last, + // context, + // ); + // if (response == 200) { + // // delete file from database + // await deletePatientFileLocationToDB(fileID); + // } else { + // String message = + // "The File has not been deleted successfully. Please try again."; + // successPopUp(message); + // } + // } - Future deletePatientFileLocationToDB(int fileID) async { - showDialog( - context: context, - builder: (context) { - return const Mihloadingcircle(); - }, - ); - var response2 = await http.delete( - Uri.parse("$baseAPI/patient_files/delete/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "idpatient_files": fileID, - "env": widget.env, - }), - ); - if (response2.statusCode == 200) { - context.pop(); //Remove Loading Dialog - context.pop(); //Remove Delete Dialog - context.pop(); //Remove File View Dialog - context.pop(); //Remove File List Dialog - //print(widget.business); - if (widget.business == null) { - context.pushNamed('patientManagerPatient', - extra: PatientViewArguments( - widget.signedInUser, - widget.selectedPatient, - widget.businessUser, - widget.business, - "personal")); - } else { - context.pushNamed('patientManagerPatient', - extra: PatientViewArguments( - widget.signedInUser, - widget.selectedPatient, - widget.businessUser, - widget.business, - "business")); - } - String message = - "The File has been deleted successfully. This means it will no longer be visible on your and cannot be used for future appointments."; - successPopUp(message); - } else { - internetConnectionPopUp(); - } - } + // Future deletePatientFileLocationToDB(int fileID) async { + // showDialog( + // context: context, + // builder: (context) { + // return const Mihloadingcircle(); + // }, + // ); + // var response2 = await http.delete( + // Uri.parse("$baseAPI/patient_files/delete/"), + // headers: { + // "Content-Type": "application/json; charset=UTF-8" + // }, + // body: jsonEncode({ + // "idpatient_files": fileID, + // "env": widget.env, + // }), + // ); + // if (response2.statusCode == 200) { + // context.pop(); //Remove Loading Dialog + // context.pop(); //Remove Delete Dialog + // context.pop(); //Remove File View Dialog + // context.pop(); //Remove File List Dialog + // //print(widget.business); + // if (widget.business == null) { + // context.pushNamed('patientManagerPatient', + // extra: PatientViewArguments( + // widget.signedInUser, + // widget.selectedPatient, + // widget.businessUser, + // widget.business, + // "personal")); + // } else { + // context.pushNamed('patientManagerPatient', + // extra: PatientViewArguments( + // widget.signedInUser, + // widget.selectedPatient, + // widget.businessUser, + // widget.business, + // "business")); + // } + // String message = + // "The File has been deleted successfully. This means it will no longer be visible on your and cannot be used for future appointments."; + // successPopUp(message); + // } else { + // internetConnectionPopUp(); + // } + // } void internetConnectionPopUp() { showDialog( @@ -155,18 +138,18 @@ class _BuildFilesListState extends State { ); } - void deleteFilePopUp(String filePath, int fileID) { - showDialog( - context: context, - barrierDismissible: false, - builder: (context) => MIHDeleteMessage( - deleteType: "File", - onTap: () async { - await deleteFileApiCall(filePath, fileID); - }, - ), - ); - } + // void deleteFilePopUp(String filePath, int fileID) { + // showDialog( + // context: context, + // barrierDismissible: false, + // builder: (context) => MIHDeleteMessage( + // deleteType: "File", + // onTap: () async { + // await deleteFileApiCall(filePath, fileID); + // }, + // ), + // ); + // } String getFileName(String path) { //print(pdfLink.split(".")[1]); @@ -202,9 +185,10 @@ class _BuildFilesListState extends State { } } - void viewFilePopUp(String fileName, String filePath, int fileID, String url) { + void viewFilePopUp(PatientManagerProvider patientManagerProvider, + String fileName, String filePath, int fileID, String url) { bool hasAccessToDelete = false; - if (widget.type == "business") { + if (!patientManagerProvider.personalMode) { hasAccessToDelete = true; } @@ -307,7 +291,7 @@ class _BuildFilesListState extends State { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - deleteFilePopUp(filePath, fileID); + // deleteFilePopUp(filePath, fileID); }, ), ); @@ -368,133 +352,138 @@ class _BuildFilesListState extends State { @override Widget build(BuildContext context) { - if (widget.files.isNotEmpty) { - return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (BuildContext context, int index) { - return Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - }, - itemCount: widget.files.length, - itemBuilder: (context, index) { - return ListTile( - title: Text( - widget.files[index].file_name, - style: TextStyle( + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Widget? child) { + if (patientManagerProvider.patientDocuments!.isNotEmpty) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (BuildContext context, int index) { + return Divider( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - subtitle: Text( - widget.files[index].insert_date, - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - // trailing: Icon( - // Icons.arrow_forward, - // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - onTap: () async { - await getFileUrlApiCall(widget.files[index].file_path) - .then((urlHere) { - //print(url); - setState(() { - fileUrl = urlHere; - }); - }); - - viewFilePopUp( - widget.files[index].file_name, - widget.files[index].file_path, - widget.files[index].idpatient_files, - fileUrl); + ); }, - ); - }, - ); - } else { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Column( - // mainAxisAlignment: MainAxisAlignment.center, - // crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 50), - Stack( - alignment: AlignmentDirectional.center, - children: [ - Icon( - MihIcons.mihRing, - size: 165, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - Icon( - Icons.file_present, - size: 110, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ], - ), - const SizedBox(height: 10), - Text( - "No Documents have been added to this profile.", - textAlign: TextAlign.center, - overflow: TextOverflow.visible, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - const SizedBox(height: 25), - Center( - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( + itemCount: patientManagerProvider.patientDocuments!.length, + itemBuilder: (context, index) { + return ListTile( + title: Text( + patientManagerProvider.patientDocuments![index].file_name, style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.normal, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), + ), + subtitle: Text( + patientManagerProvider.patientDocuments![index].insert_date, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + // trailing: Icon( + // Icons.arrow_forward, + // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // ), + onTap: () async { + await getFileUrlApiCall(patientManagerProvider + .patientDocuments![index].file_path) + .then((urlHere) { + //print(url); + setState(() { + fileUrl = urlHere; + }); + }); + + viewFilePopUp( + patientManagerProvider, + patientManagerProvider.patientDocuments![index].file_name, + patientManagerProvider.patientDocuments![index].file_path, + patientManagerProvider + .patientDocuments![index].idpatient_files, + fileUrl); + }, + ); + }, + ); + } else { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + // mainAxisAlignment: MainAxisAlignment.center, + // crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 50), + Stack( + alignment: AlignmentDirectional.center, children: [ - TextSpan(text: "Press "), - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Icon( - Icons.menu, - size: 20, + Icon( + MihIcons.mihRing, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + Icon( + Icons.file_present, + size: 110, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ], + ), + const SizedBox(height: 10), + Text( + "No Documents have been added to this profile.", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + const SizedBox(height: 25), + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), + children: [ + TextSpan(text: "Press "), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + Icons.menu, + size: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + TextSpan(text: " to add "), + !patientManagerProvider.personalMode + ? TextSpan( + text: " or generate a the first document") + : TextSpan(text: " the first document"), + ], ), - TextSpan(text: " to add "), - widget.business != null - ? TextSpan(text: " or generate a the first document") - : TextSpan(text: " the first document"), - ], + ), ), - ), + ], ), - ], - ), - ); - // return const Center( - // child: Text( - // "No Documents Available", - // style: TextStyle(fontSize: 25, color: Colors.grey), - // textAlign: TextAlign.center, - // ), - // ); - } + ); + } + }, + ); } } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_notes_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_notes_list.dart index e3bb088a..832d0d9f 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_notes_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_notes_list.dart @@ -1,38 +1,25 @@ -import 'dart:convert'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; +import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_delete_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/notes.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; import 'package:flutter/material.dart'; -import 'package:supertokens_flutter/http.dart' as http; +import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; +import 'package:provider/provider.dart'; class BuildNotesList extends StatefulWidget { - final AppUser signedInUser; - final List notes; - final Patient selectedPatient; - final Business? business; - final BusinessUser? businessUser; - final String type; const BuildNotesList({ super.key, - required this.notes, - required this.signedInUser, - required this.selectedPatient, - required this.business, - required this.businessUser, - required this.type, }); @override @@ -48,45 +35,80 @@ class _BuildNotesListState extends State { int indexOn = 0; final baseAPI = AppEnviroment.baseApiUrl; - Future deleteNoteApiCall(int NoteId) async { - var response = await http.delete( - Uri.parse("$baseAPI/notes/delete/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({"idpatient_notes": NoteId}), - ); + Future deleteNoteApiCall( + PatientManagerProvider patientManagerProvider, int NoteId) async { + int statusCode = await MihPatientServices() + .deletePatientConsultaionNote(NoteId, patientManagerProvider); //print("Here4"); //print(response.statusCode); - if (response.statusCode == 200) { - Navigator.of(context).pop(); - Navigator.of(context).pop(); - if (widget.business == null) { - Navigator.of(context).pushNamed('/patient-manager/patient', - arguments: PatientViewArguments( - widget.signedInUser, - widget.selectedPatient, - widget.businessUser, - widget.business, - "personal")); - } else { - Navigator.of(context).pushNamed('/patient-manager/patient', - arguments: PatientViewArguments( - widget.signedInUser, - widget.selectedPatient, - widget.businessUser, - widget.business, - "business")); - } - setState(() {}); + if (statusCode == 200) { String message = "The note has been deleted successfully. This means it will no longer be visible on your and cannot be used for future appointments."; - successPopUp(message); + successPopUp("Successfuly Deleted", message); } else { internetConnectionPopUp(); } } + void successPopUp(String title, String message) { + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + Icons.check_circle_outline_rounded, + size: 150, + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + alertTitle: title, + alertBody: Column( + children: [ + Text( + message, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + context.pop(); + context.pop(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + elevation: 10, + width: 300, + child: Text( + "Dismiss", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ) + ], + ), + alertColour: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + // return MIHSuccessMessage( + // successType: "Success", + // successMessage: message, + // ); + }, + ); + } + void internetConnectionPopUp() { showDialog( context: context, @@ -96,32 +118,22 @@ class _BuildNotesListState extends State { ); } - void successPopUp(String message) { - showDialog( - context: context, - builder: (context) { - return MIHSuccessMessage( - successType: "Success", - successMessage: message, - ); - }, - ); - } - - void deletePatientPopUp(int NoteId) { + void deletePatientPopUp( + PatientManagerProvider patientManagerProvider, int NoteId) { showDialog( context: context, barrierDismissible: false, builder: (context) => MIHDeleteMessage( deleteType: "Note", onTap: () { - deleteNoteApiCall(NoteId); + deleteNoteApiCall(patientManagerProvider, NoteId); }, ), ); } - void viewNotePopUp(Note selectednote) { + void viewNotePopUp(MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Note selectednote) { setState(() { noteTitleController.text = selectednote.note_name; noteTextController.text = selectednote.note_text; @@ -130,8 +142,8 @@ class _BuildNotesListState extends State { dateController.text = selectednote.insert_date; }); bool hasAccessToDelete = false; - if (widget.type == "business" && - selectednote.doc_office == widget.business!.Name) { + if (!patientManagerProvider.personalMode && + selectednote.doc_office == profileProvider.business!.Name) { hasAccessToDelete = true; } showDialog( @@ -159,7 +171,8 @@ class _BuildNotesListState extends State { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - deletePatientPopUp(selectednote.idpatient_notes); + deletePatientPopUp( + patientManagerProvider, selectednote.idpatient_notes); }, ), ] @@ -248,136 +261,141 @@ class _BuildNotesListState extends State { @override Widget build(BuildContext context) { - if (widget.notes.isNotEmpty) { - return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (BuildContext context, int index) { - return Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - }, - itemCount: widget.notes.length, - itemBuilder: (context, index) { - String notePreview = widget.notes[index].note_text; - if (notePreview.length > 30) { - notePreview = "${notePreview.substring(0, 30)} ..."; - } - return ListTile( - title: Text( - "${widget.notes[index].note_name}\n${widget.notes[index].doc_office} - ${widget.notes[index].doctor}", - style: TextStyle( + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Widget? child) { + if (patientManagerProvider.consultationNotes!.isNotEmpty) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (BuildContext context, int index) { + return Divider( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - subtitle: Text( - "${widget.notes[index].insert_date}:\n$notePreview", - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), //Text(widget.notes[index].note_text), - trailing: Icon( - Icons.arrow_forward, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - onTap: () { - viewNotePopUp(widget.notes[index]); + ); }, - ); - }, - ); - } else { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - const SizedBox(height: 50), - Stack( - alignment: AlignmentDirectional.center, - children: [ - Icon( - MihIcons.mihRing, - size: 165, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - Icon( - Icons.article_outlined, - size: 110, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ], - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - child: Text( - "No Notes have been added to this profile.", - textAlign: TextAlign.center, - overflow: TextOverflow.visible, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), + itemCount: patientManagerProvider.consultationNotes!.length, + itemBuilder: (context, index) { + String notePreview = + patientManagerProvider.consultationNotes![index].note_text; + if (notePreview.length > 30) { + notePreview = "${notePreview.substring(0, 30)} ..."; + } + return ListTile( + title: Text( + "${patientManagerProvider.consultationNotes![index].note_name}\n${patientManagerProvider.consultationNotes![index].doc_office} - ${patientManagerProvider.consultationNotes![index].doctor}", + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), ), - ], - ), - const SizedBox(height: 25), - Visibility( - visible: widget.business != null, - child: Center( - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.normal, + subtitle: Text( + "${patientManagerProvider.consultationNotes![index].insert_date}:\n$notePreview", + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), //Text(widget.notes[index].note_text), + trailing: Icon( + Icons.arrow_forward, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + onTap: () { + viewNotePopUp( + profileProvider, + patientManagerProvider, + patientManagerProvider.consultationNotes![index], + ); + }, + ); + }, + ); + } else { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + const SizedBox(height: 50), + Stack( + alignment: AlignmentDirectional.center, + children: [ + Icon( + MihIcons.mihRing, + size: 165, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), - children: [ - TextSpan(text: "Press "), - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Icon( - Icons.menu, - size: 20, + Icon( + Icons.article_outlined, + size: 110, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ], + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + "No Notes have been added to this profile.", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), ), - TextSpan(text: " to add the first note"), - ], + ), + ], + ), + const SizedBox(height: 25), + Visibility( + visible: !patientManagerProvider.personalMode, + child: Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + children: [ + TextSpan(text: "Press "), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + Icons.menu, + size: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + TextSpan(text: " to add the first note"), + ], + ), + ), ), ), - ), + ], ), - ], - ), - ); - // return const Center( - // child: Text( - // "No Notes Available", - // style: TextStyle(fontSize: 25, color: Colors.grey), - // textAlign: TextAlign.center, - // ), - // ); - } + ); + } + }, + ); } } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tiles/patient_profile_tile.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tiles/patient_profile_tile.dart index e6a82763..e85c1c02 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tiles/patient_profile_tile.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tiles/patient_profile_tile.dart @@ -28,7 +28,6 @@ class _PatientProfileTileState extends State { onTap: () { context.goNamed( 'patientProfile', - extra: widget.arguments, ); // Navigator.of(context).pushNamed( // '/patient-profile', diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_consultation.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_consultation.dart index f7cca32d..fdd28fbe 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_consultation.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_consultation.dart @@ -1,6 +1,7 @@ -import 'dart:convert'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; @@ -12,33 +13,15 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/notes.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/list_builders/build_notes_list.dart'; import 'package:flutter/material.dart'; -import 'package:supertokens_flutter/http.dart' as http; +import 'package:provider/provider.dart'; class PatientConsultation extends StatefulWidget { - final String patientAppId; - final Patient selectedPatient; - final AppUser signedInUser; - final Business? business; - final BusinessUser? businessUser; - final String type; const PatientConsultation({ super.key, - required this.patientAppId, - required this.selectedPatient, - required this.signedInUser, - required this.business, - required this.businessUser, - required this.type, }); @override @@ -46,7 +29,6 @@ class PatientConsultation extends StatefulWidget { } class _PatientConsultationState extends State { - late Future> futueNotes; final titleController = TextEditingController(); final noteTextController = TextEditingController(); final officeController = TextEditingController(); @@ -56,33 +38,18 @@ class _PatientConsultationState extends State { String endpoint = "${AppEnviroment.baseApiUrl}/notes/patients/"; final _formKey = GlobalKey(); - Future> fetchNotes(String endpoint) async { - final response = await http.get(Uri.parse( - "${AppEnviroment.baseApiUrl}/notes/patients/${widget.selectedPatient.app_id}")); - if (response.statusCode == 200) { - Iterable l = jsonDecode(response.body); - List notes = - List.from(l.map((model) => Note.fromJson(model))); - //print("Here notes"); - return notes; - } else { - internetConnectionPopUp(); - throw Exception('failed to load patients'); - } - } - - void addNotePopUp(double width) { + void addNotePopUp(MzansiProfileProvider profileProvider, double width) { DateTime now = new DateTime.now(); DateTime date = new DateTime(now.year, now.month, now.day); var title = ""; - print("Business User: ${widget.businessUser}"); - if (widget.businessUser?.title == "Doctor") { + print("Business User: ${profileProvider.businessUser}"); + if (profileProvider.businessUser?.title == "Doctor") { title = "Dr."; } setState(() { - officeController.text = widget.business!.Name; + officeController.text = profileProvider.business!.Name; doctorController.text = - "$title ${widget.signedInUser.fname} ${widget.signedInUser.lname}"; + "$title ${profileProvider.user!.fname} ${profileProvider.user!.lname}"; dateController.text = date.toString().substring(0, 10); }); showDialog( @@ -205,7 +172,7 @@ class _PatientConsultationState extends State { child: MihButton( onPressed: () { if (_formKey.currentState!.validate()) { - addPatientNoteAPICall(); + // addPatientNoteAPICall(); Navigator.pop(context); } else { MihAlertServices().formNotFilledCompletely(context); @@ -236,38 +203,6 @@ class _PatientConsultationState extends State { ); } - Future addPatientNoteAPICall() async { - // String title = ""; - // if (widget.businessUser!.title == "Doctor") { - // title = "Dr."; - // } - var response = await http.post( - Uri.parse("${AppEnviroment.baseApiUrl}/notes/insert/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "note_name": titleController.text, - "note_text": noteTextController.text, - "doc_office": officeController.text, - "doctor": doctorController.text, - "app_id": widget.selectedPatient.app_id, - }), - ); - if (response.statusCode == 201) { - setState(() { - futueNotes = fetchNotes(endpoint + widget.patientAppId.toString()); - }); - // Navigator.of(context) - // .pushNamed('/patient-manager', arguments: widget.userEmail); - String message = - "Your note has been successfully added to the patients medical record. You can now view it alongside their other important information."; - successPopUp(message); - } else { - internetConnectionPopUp(); - } - } - bool isFieldsFilled() { if (titleController.text.isEmpty || noteTextController.text.isEmpty || @@ -321,7 +256,6 @@ class _PatientConsultationState extends State { @override void initState() { - futueNotes = fetchNotes(endpoint + widget.patientAppId); noteTextController.addListener(() { setState(() { _counter.value = noteTextController.text.characters.length; @@ -340,71 +274,56 @@ class _PatientConsultationState extends State { } Widget getBody(double width) { - return Stack( - children: [ - MihSingleChildScroll( - child: FutureBuilder( - future: futueNotes, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center( - child: Mihloadingcircle(), - ); - } else if (snapshot.hasData) { - final notesList = snapshot.data!; - return Column(children: [ - BuildNotesList( - notes: notesList, - signedInUser: widget.signedInUser, - selectedPatient: widget.selectedPatient, - business: widget.business, - businessUser: widget.businessUser, - type: widget.type, - ), - ]); - } else { - return const Center( - child: Text("Error Loading Notes"), - ); - } - }, - ), - ), - Visibility( - visible: widget.type != "personal", - child: Positioned( - right: 10, - bottom: 10, - child: MihFloatingMenu( - icon: Icons.add, - animatedIcon: AnimatedIcons.menu_close, - children: [ - SpeedDialChild( - child: Icon( - Icons.add, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - label: "Add Note", - labelBackgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - labelStyle: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontWeight: FontWeight.bold, - ), - backgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onTap: () { - // addConsultationNotePopUp(); - addNotePopUp(width); - }, - ) - ], + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Widget? child) { + return Stack( + children: [ + MihSingleChildScroll( + child: Column(children: [ + BuildNotesList(), + ])), + Visibility( + visible: !patientManagerProvider.personalMode, + child: Positioned( + right: 10, + bottom: 10, + child: MihFloatingMenu( + icon: Icons.add, + animatedIcon: AnimatedIcons.menu_close, + children: [ + SpeedDialChild( + child: Icon( + Icons.add, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + label: "Add Note", + labelBackgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onTap: () { + // addConsultationNotePopUp(); + addNotePopUp(profileProvider, width); + }, + ) + ], + ), + ), ), - ), - ), - ], + ], + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_documents.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_documents.dart index c537baa6..7f278050 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_documents.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_documents.dart @@ -1,10 +1,13 @@ -import 'dart:convert'; - import 'package:flutter_speed_dial/flutter_speed_dial.dart'; +import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; @@ -16,34 +19,16 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/files.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/components/prescip_input.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/list_builders/build_files_list.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; -import 'package:supertokens_flutter/http.dart' as http; +import 'package:provider/provider.dart'; class PatientDocuments extends StatefulWidget { - final int patientIndex; - final Patient selectedPatient; - final AppUser signedInUser; - final Business? business; - final BusinessUser? businessUser; - final String type; const PatientDocuments({ super.key, - required this.patientIndex, - required this.selectedPatient, - required this.signedInUser, - required this.business, - required this.businessUser, - required this.type, }); @override @@ -51,7 +36,6 @@ class PatientDocuments extends StatefulWidget { } class _PatientDocumentsState extends State { - late Future> futueFiles; final selectedFileController = TextEditingController(); final startDateController = TextEditingController(); final endDateTextController = TextEditingController(); @@ -68,9 +52,10 @@ class _PatientDocumentsState extends State { final _formKey2 = GlobalKey(); late String env; - Future submitDocUploadForm() async { + Future submitDocUploadForm( + PatientManagerProvider patientManagerProvider) async { if (isFileFieldsFilled()) { - await uploadSelectedFile(selected); + await uploadSelectedFile(patientManagerProvider, selected); } else { showDialog( context: context, @@ -81,75 +66,49 @@ class _PatientDocumentsState extends State { } } - Future> fetchFiles() async { - final response = await http.get(Uri.parse( - "${AppEnviroment.baseApiUrl}/patient_files/get/${widget.selectedPatient.app_id}")); - //print(response.statusCode); - //print(response.body); - if (response.statusCode == 200) { - Iterable l = jsonDecode(response.body); - List files = - List.from(l.map((model) => PFile.fromJson(model))); - return files; - } else { - internetConnectionPopUp(); - throw Exception('failed to load patients'); - } - } - - Future addPatientFileLocationToDB(PlatformFile? file) async { + Future addPatientFileLocationToDB( + PatientManagerProvider patientManagerProvider, PlatformFile? file) async { showDialog( context: context, builder: (context) { return const Mihloadingcircle(); }, ); - var fname = file!.name.replaceAll(RegExp(r' '), '-'); - var filePath = "${widget.selectedPatient.app_id}/patient_files/$fname"; - var response2 = await http.post( - Uri.parse("${AppEnviroment.baseApiUrl}/patient_files/insert/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "file_path": filePath, - "file_name": fname, - "app_id": widget.selectedPatient.app_id - }), - ); - //print("here5"); - //print(response2.statusCode); - if (response2.statusCode == 201) { + int statusCode = + await MihPatientServices().addPatientFile(file, patientManagerProvider); + if (statusCode == 201) { setState(() { selectedFileController.clear(); - futueFiles = fetchFiles(); }); + var fname = file!.name.replaceAll(RegExp(r' '), '-'); // end loading circle Navigator.of(context).pop(); String message = - "The file ${file.name.replaceAll(RegExp(r' '), '-')} has been successfully generated and added to ${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}'s record. You can now access and download it for their use."; - successPopUp(message); + "The file $fname has been successfully generated and added to ${patientManagerProvider.selectedPatient!.first_name} ${patientManagerProvider.selectedPatient!.last_name}'s record. You can now access and download it for their use."; + successPopUp("Successfully Uplouded File", message); } else { internetConnectionPopUp(); } } - Future uploadSelectedFile(PlatformFile? file) async { + Future uploadSelectedFile( + PatientManagerProvider patientManagerProvider, PlatformFile? file) async { var response = await MihFileApi.uploadFile( - widget.selectedPatient.app_id, + patientManagerProvider.selectedPatient!.app_id, env, "patient_files", file, context, ); if (response == 200) { - await addPatientFileLocationToDB(file); + await addPatientFileLocationToDB(patientManagerProvider, file); } else { internetConnectionPopUp(); } } - Future generateMedCert() async { + Future generateMedCert(MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider) async { //start loading circle showDialog( context: context, @@ -157,73 +116,30 @@ class _PatientDocumentsState extends State { return const Mihloadingcircle(); }, ); - DateTime now = DateTime.now(); - // DateTime date = new DateTime(now.year, now.month, now.day); - String fileName = - "Med-Cert-${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}-${now.toString().substring(0, 19)}.pdf" - .replaceAll(RegExp(r' '), '-'); - var response1 = await http.post( - Uri.parse("${AppEnviroment.baseApiUrl}/minio/generate/med-cert/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "app_id": widget.selectedPatient.app_id, - "env": env, - "patient_full_name": - "${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}", - "fileName": fileName, - "id_no": widget.selectedPatient.id_no, - "docfname": - "DR. ${widget.signedInUser.fname} ${widget.signedInUser.lname}", - "startDate": startDateController.text, - "busName": widget.business!.Name, - "busAddr": "*TO BE ADDED IN THE FUTURE*", - "busNo": widget.business!.contact_no, - "busEmail": widget.business!.bus_email, - "endDate": endDateTextController.text, - "returnDate": retDateTextController.text, - "logo_path": widget.business!.logo_path, - "sig_path": widget.businessUser!.sig_path, - }), + int statusCodeCetificateGeneration = + await MihPatientServices().generateMedicalCertificate( + startDateController.text, + endDateTextController.text, + retDateTextController.text, + profileProvider, + patientManagerProvider, ); - print(response1.statusCode); - if (response1.statusCode == 200) { - var response2 = await http.post( - Uri.parse("${AppEnviroment.baseApiUrl}/patient_files/insert/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "file_path": - "${widget.selectedPatient.app_id}/patient_files/$fileName", - "file_name": fileName, - "app_id": widget.selectedPatient.app_id - }), - ); - //print(response2.statusCode); - if (response2.statusCode == 201) { - setState(() { - startDateController.clear(); - endDateTextController.clear(); - retDateTextController.clear(); - futueFiles = fetchFiles(); - }); - // end loading circle - Navigator.of(context).pop(); - Navigator.of(context).pop(); - String message = - "The medical certificate $fileName has been successfully generated and added to ${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}'s record. You can now access and download it for their use."; - successPopUp(message); - } else { - internetConnectionPopUp(); - } + DateTime now = DateTime.now(); + String fileName = + "Med-Cert-${patientManagerProvider.selectedPatient!.first_name} ${patientManagerProvider.selectedPatient!.last_name}-${now.toString().substring(0, 19)}.pdf" + .replaceAll(RegExp(r' '), '-'); + if (statusCodeCetificateGeneration == 200) { + context.pop(); //Loading removal + String message = + "The medical certificate $fileName has been successfully generated and added to ${patientManagerProvider.selectedPatient!.first_name} ${patientManagerProvider.selectedPatient!.last_name}'s record. You can now access and download it for their use."; + successPopUp("Successfully Generated Certificate", message); } else { internetConnectionPopUp(); } } - void uploudFilePopUp(double width) { + void uploudFilePopUp( + PatientManagerProvider patientManagerProvider, double width) { showDialog( context: context, barrierDismissible: false, @@ -304,7 +220,7 @@ class _PatientDocumentsState extends State { child: MihButton( onPressed: () { if (_formKey.currentState!.validate()) { - submitDocUploadForm(); + submitDocUploadForm(patientManagerProvider); // uploadSelectedFile(selected); Navigator.pop(context); } else { @@ -336,7 +252,10 @@ class _PatientDocumentsState extends State { ); } - void medCertPopUp() { + void medCertPopUp( + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, + ) { showDialog( context: context, barrierDismissible: false, @@ -387,7 +306,8 @@ class _PatientDocumentsState extends State { child: MihButton( onPressed: () async { if (_formKey2.currentState!.validate()) { - await generateMedCert(); + await generateMedCert( + profileProvider, patientManagerProvider); //Navigator.pop(context); } else { MihAlertServices().formNotFilledCompletely(context); @@ -416,7 +336,10 @@ class _PatientDocumentsState extends State { ); } - void prescritionPopUp() { + void prescritionPopUp( + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, + ) { showDialog( context: context, barrierDismissible: false, @@ -442,10 +365,10 @@ class _PatientDocumentsState extends State { noDaysController: noDaysController, noRepeatsController: noRepeatsController, outputController: outputController, - selectedPatient: widget.selectedPatient, - signedInUser: widget.signedInUser, - business: widget.business, - businessUser: widget.businessUser, + selectedPatient: patientManagerProvider.selectedPatient!, + signedInUser: profileProvider.user!, + business: profileProvider.business, + businessUser: profileProvider.businessUser, env: env, ), ], @@ -472,8 +395,9 @@ class _PatientDocumentsState extends State { } } - Widget getMenu(double width) { - if (widget.type == "personal") { + Widget getMenu(MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, double width) { + if (patientManagerProvider.personalMode) { return Positioned( right: 10, bottom: 10, @@ -498,7 +422,7 @@ class _PatientDocumentsState extends State { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - uploudFilePopUp(width); + uploudFilePopUp(patientManagerProvider, width); }, ) ], @@ -529,7 +453,7 @@ class _PatientDocumentsState extends State { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - uploudFilePopUp(width); + uploudFilePopUp(patientManagerProvider, width); }, ), SpeedDialChild( @@ -549,7 +473,7 @@ class _PatientDocumentsState extends State { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - medCertPopUp(); + medCertPopUp(profileProvider, patientManagerProvider); }, ), SpeedDialChild( @@ -569,7 +493,7 @@ class _PatientDocumentsState extends State { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - prescritionPopUp(); + prescritionPopUp(profileProvider, patientManagerProvider); }, ), ], @@ -578,13 +502,56 @@ class _PatientDocumentsState extends State { } } - void successPopUp(String message) { + void successPopUp(String title, String message) { showDialog( context: context, builder: (context) { - return MIHSuccessMessage( - successType: "Success", - successMessage: message, + return MihPackageAlert( + alertIcon: Icon( + Icons.check_circle_outline_rounded, + size: 150, + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + alertTitle: title, + alertBody: Column( + children: [ + Text( + message, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + context.pop(); + context.pop(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + elevation: 10, + width: 300, + child: Text( + "Dismiss", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ) + ], + ), + alertColour: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ); }, ); @@ -617,7 +584,6 @@ class _PatientDocumentsState extends State { @override void initState() { - futueFiles = fetchFiles(); if (AppEnviroment.getEnv() == "Prod") { env = "Prod"; } else { @@ -636,39 +602,20 @@ class _PatientDocumentsState extends State { } Widget getBody(double width) { - return Stack( - children: [ - MihSingleChildScroll( - child: FutureBuilder( - future: futueFiles, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center( - child: Mihloadingcircle(), - ); - } else if (snapshot.hasData) { - final filesList = snapshot.data!; - return Column(children: [ - BuildFilesList( - files: filesList, - signedInUser: widget.signedInUser, - selectedPatient: widget.selectedPatient, - business: widget.business, - businessUser: widget.businessUser, - type: widget.type, - env: env, - ), - ]); - } else { - return const Center( - child: Text("Error Loading Notes"), - ); - } - }, - ), - ), - getMenu(width), - ], + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Widget? child) { + return Stack( + children: [ + MihSingleChildScroll( + child: Column(children: [ + BuildFilesList(), + ]), + ), + getMenu(profileProvider, patientManagerProvider, width), + ], + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart index 2f59f61e..a5a04253 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart @@ -1,5 +1,4 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; -import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; @@ -7,21 +6,16 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/components/mih_edit_patient_details_window.dart'; +import 'package:provider/provider.dart'; class PatientInfo extends StatefulWidget { - final AppUser signedInUser; - final Patient selectedPatient; - final String type; const PatientInfo({ super.key, - required this.signedInUser, - required this.selectedPatient, - required this.type, }); @override @@ -297,6 +291,40 @@ class _PatientInfoState extends State { ); } + void initialiseControllers(PatientManagerProvider patientManagerProvider) { + idController.text = patientManagerProvider.selectedPatient!.id_no; + fnameController.text = patientManagerProvider.selectedPatient!.first_name; + lnameController.text = patientManagerProvider.selectedPatient!.last_name; + cellController.text = patientManagerProvider.selectedPatient!.cell_no; + emailController.text = patientManagerProvider.selectedPatient!.email; + medNameController.text = + patientManagerProvider.selectedPatient!.medical_aid_name; + medNoController.text = + patientManagerProvider.selectedPatient!.medical_aid_no; + medSchemeController.text = + patientManagerProvider.selectedPatient!.medical_aid_scheme; + addressController.text = patientManagerProvider.selectedPatient!.address; + medAidController.text = patientManagerProvider.selectedPatient!.medical_aid; + medMainMemController.text = + patientManagerProvider.selectedPatient!.medical_aid_main_member; + medAidCodeController.text = + patientManagerProvider.selectedPatient!.medical_aid_code; + medAid = patientManagerProvider.selectedPatient!.medical_aid; + if (medAid == "Yes") { + medAidPosition = true; + } else { + medAidPosition = false; + } + } + + void showEditPatientWindow() { + showDialog( + context: context, + builder: (context) { + return MihEditPatientDetailsWindow(); + }); + } + @override void dispose() { idController.dispose(); @@ -316,37 +344,6 @@ class _PatientInfoState extends State { @override void initState() { - setState(() { - idController.value = TextEditingValue(text: widget.selectedPatient.id_no); - fnameController.value = - TextEditingValue(text: widget.selectedPatient.first_name); - lnameController.value = - TextEditingValue(text: widget.selectedPatient.last_name); - cellController.value = - TextEditingValue(text: widget.selectedPatient.cell_no); - emailController.value = - TextEditingValue(text: widget.selectedPatient.email); - medNameController.value = - TextEditingValue(text: widget.selectedPatient.medical_aid_name); - medNoController.value = - TextEditingValue(text: widget.selectedPatient.medical_aid_no); - medSchemeController.value = - TextEditingValue(text: widget.selectedPatient.medical_aid_scheme); - addressController.value = - TextEditingValue(text: widget.selectedPatient.address); - medAidController.value = - TextEditingValue(text: widget.selectedPatient.medical_aid); - medMainMemController.value = TextEditingValue( - text: widget.selectedPatient.medical_aid_main_member); - medAidCodeController.value = - TextEditingValue(text: widget.selectedPatient.medical_aid_code); - medAid = widget.selectedPatient.medical_aid; - }); - if (medAid == "Yes") { - medAidPosition = true; - } else { - medAidPosition = false; - } super.initState(); } @@ -361,21 +358,47 @@ class _PatientInfoState extends State { } Widget getBody(double width) { - return Stack( - children: [ - MihSingleChildScroll( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - MihForm( - formKey: _formKey, - formFields: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - //crossAxisAlignment: , - children: [ - Text( - "Personal", + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Widget? child) { + initialiseControllers(patientManagerProvider); + return Stack( + children: [ + MihSingleChildScroll( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + //crossAxisAlignment: , + children: [ + Text( + "Personal", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + ]), + Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark")), + const SizedBox(height: 10), + getPatientDetailsField(), + const SizedBox(height: 10), + Center( + child: Text( + "Medical Aid", textAlign: TextAlign.center, style: TextStyle( fontSize: 25, @@ -385,78 +408,65 @@ class _PatientInfoState extends State { "Dark"), ), ), - ]), - Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark")), - const SizedBox(height: 10), - getPatientDetailsField(), - const SizedBox(height: 10), - Center( - child: Text( - "Medical Aid", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( + ), + Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark")), + const SizedBox(height: 10), + getMedAidDetailsFields(), + ], + ), + ], + ), + ), + Visibility( + visible: patientManagerProvider.personalMode, + child: Positioned( + right: 10, + bottom: 10, + child: MihFloatingMenu( + icon: Icons.add, + animatedIcon: AnimatedIcons.menu_close, + children: [ + SpeedDialChild( + child: Icon( + Icons.edit, + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), - ), - ), - Divider( - color: MihColors.getSecondaryColor( + label: "Edit Profile", + labelBackgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == - "Dark")), - const SizedBox(height: 10), - getMedAidDetailsFields(), - ], - ), - ], - ), - ), - Visibility( - visible: widget.type == "personal", - child: Positioned( - right: 10, - bottom: 10, - child: MihFloatingMenu( - icon: Icons.add, - animatedIcon: AnimatedIcons.menu_close, - children: [ - SpeedDialChild( - child: Icon( - Icons.edit, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - label: "Edit Profile", - labelBackgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - labelStyle: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontWeight: FontWeight.bold, - ), - backgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onTap: () { - context.goNamed( - 'patientProfileEdit', - extra: PatientEditArguments( - widget.signedInUser, - widget.selectedPatient, + "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, ), - ); - }, - ) - ], + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onTap: () { + // context.goNamed( + // 'patientProfileEdit', + // extra: PatientEditArguments( + // profileProvider.user!, + // patientManagerProvider.selectedPatient!, + // ), + // ); + showEditPatientWindow(); + }, + ) + ], + ), + ), ), - ), - ), - ], + ], + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_setup_form.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_setup_form.dart new file mode 100644 index 00000000..c982820a --- /dev/null +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_setup_form.dart @@ -0,0 +1,543 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; + +class PatientSetupForm extends StatefulWidget { + const PatientSetupForm({super.key}); + + @override + State createState() => _PatientSetupFormState(); +} + +class _PatientSetupFormState extends State { + final idController = TextEditingController(); + final fnameController = TextEditingController(); + final lnameController = TextEditingController(); + final cellController = TextEditingController(); + final emailController = TextEditingController(); + final medNoController = TextEditingController(); + final medNameController = TextEditingController(); + final medSchemeController = TextEditingController(); + final addressController = TextEditingController(); + final medAidController = TextEditingController(); + final medMainMemController = TextEditingController(); + final medAidCodeController = TextEditingController(); + final _formKey = GlobalKey(); + final FocusNode _focusNode = FocusNode(); + late bool medAidPosition; + late bool medMainMemberPosition; + final ValueNotifier medRequired = ValueNotifier(false); + + Future addPatientService( + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, + ) async { + int statusCode = await MihPatientServices().addPatientService( + idController.text, + fnameController.text, + lnameController.text, + emailController.text, + cellController.text, + medAidController.text, + medMainMemController.text, + medNoController.text, + medAidCodeController.text, + medNameController.text, + medSchemeController.text, + addressController.text, + profileProvider, + patientManagerProvider, + ); + if (statusCode == 201) { + String message = + "${fnameController.text} ${lnameController.text} patient profile has been successfully added!\n"; + successPopUp("Successfully created Patient Profile", message); + } else { + internetConnectionPopUp(); + } + } + + void successPopUp(String title, String message) { + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + Icons.check_circle_outline_rounded, + size: 150, + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + alertTitle: title, + alertBody: Column( + children: [ + Text( + message, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + context.pop(); + context.goNamed( + 'patientProfile', + ); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + elevation: 10, + width: 300, + child: Text( + "Dismiss", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ) + ], + ), + alertColour: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + ); + } + + void internetConnectionPopUp() { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Internet Connection"); + }, + ); + } + + void isRequired() { + //print("listerner triggered"); + if (medAidController.text == "Yes") { + medRequired.value = true; + } else { + medRequired.value = false; + } + } + + Widget displayForm(double width) { + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Widget? child) { + return SingleChildScrollView( + child: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Personal", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 25.0, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ], + ), + Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark")), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: idController, + multiLineInput: false, + requiredText: true, + hintText: "ID No.", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: fnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: lnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Surname", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: cellController, + multiLineInput: false, + requiredText: true, + hintText: "Cell No.", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: emailController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Email", + validator: (value) { + return MihValidationServices().validateEmail(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + height: 100, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: addressController, + multiLineInput: true, + requiredText: true, + hintText: "Address", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 15.0), + Center( + child: Text( + "Medical Aid Details", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 25.0, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark")), + const SizedBox(height: 10.0), + MihToggle( + hintText: "Medical Aid", + initialPostion: medAidPosition, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + secondaryFillColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: (value) { + if (value) { + setState(() { + medAidController.text = "Yes"; + medAidPosition = value; + }); + } else { + setState(() { + medAidController.text = "No"; + medAidPosition = value; + }); + } + }, + ), + ValueListenableBuilder( + valueListenable: medRequired, + builder: + (BuildContext context, bool value, Widget? child) { + return Visibility( + visible: value, + child: Column( + children: [ + const SizedBox(height: 10.0), + MihToggle( + hintText: "Main Member", + initialPostion: medMainMemberPosition, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + secondaryFillColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + onChange: (value) { + if (value) { + setState(() { + medMainMemController.text = "Yes"; + medMainMemberPosition = value; + }); + } else { + setState(() { + medMainMemController.text = "No"; + medMainMemberPosition = value; + }); + } + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + controller: medNoController, + multiLineInput: false, + requiredText: true, + hintText: "No.", + validator: (validationValue) { + if (value) { + return MihValidationServices() + .isEmpty(validationValue); + } + return null; + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + controller: medAidCodeController, + multiLineInput: false, + requiredText: true, + hintText: "Code", + validator: (validationValue) { + if (value) { + return MihValidationServices() + .isEmpty(validationValue); + } + return null; + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + controller: medNameController, + multiLineInput: false, + requiredText: true, + hintText: "Name", + validator: (validationValue) { + if (value) { + return MihValidationServices() + .isEmpty(validationValue); + } + return null; + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + controller: medSchemeController, + multiLineInput: false, + requiredText: true, + hintText: "Plan", + validator: (validationValue) { + if (value) { + return MihValidationServices() + .isEmpty(validationValue); + } + return null; + }, + ), + const SizedBox(height: 10.0), + ], + ), + ); + }, + ), + const SizedBox(height: 20.0), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + addPatientService( + profileProvider, patientManagerProvider); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Add", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(height: 30.0), + ], + ), + ], + ), + ), + ); + }, + ); + } + + @override + void dispose() { + idController.dispose(); + fnameController.dispose(); + lnameController.dispose(); + cellController.dispose(); + emailController.dispose(); + medNoController.dispose(); + medNameController.dispose(); + medSchemeController.dispose(); + addressController.dispose(); + medAidController.dispose(); + medAidCodeController.removeListener(isRequired); + medRequired.dispose(); + medMainMemController.dispose(); + medAidCodeController.dispose(); + _focusNode.dispose(); + super.dispose(); + } + + @override + void initState() { + medAidController.addListener(isRequired); + MzansiProfileProvider profileProvider = + context.read(); + setState(() { + fnameController.text = profileProvider.user!.fname; + lnameController.text = profileProvider.user!.lname; + emailController.text = profileProvider.user!.email; + medAidPosition = false; + medMainMemberPosition = false; + medAidController.text = "No"; + medMainMemController.text = "No"; + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; + return displayForm(screenWidth); + } +} diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_edit.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_edit.dart deleted file mode 100644 index 1de1d5e4..00000000 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_edit.dart +++ /dev/null @@ -1,903 +0,0 @@ -import 'dart:convert'; - -import 'package:go_router/go_router.dart'; -import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; -import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_action.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_body.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_header.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_layout_builder.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_toggle.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:supertokens_flutter/supertokens.dart'; -import 'package:supertokens_flutter/http.dart' as http; - -class EditPatient extends StatefulWidget { - final Patient selectedPatient; - final AppUser signedInUser; - const EditPatient({ - super.key, - required this.selectedPatient, - required this.signedInUser, - }); - - @override - State createState() => _EditPatientState(); -} - -class _EditPatientState extends State { - var idController = TextEditingController(); - final fnameController = TextEditingController(); - final lnameController = TextEditingController(); - final cellController = TextEditingController(); - final emailController = TextEditingController(); - final medNoController = TextEditingController(); - final medNameController = TextEditingController(); - final medSchemeController = TextEditingController(); - final addressController = TextEditingController(); - final medAidController = TextEditingController(); - final medMainMemController = TextEditingController(); - final medAidCodeController = TextEditingController(); - final baseAPI = AppEnviroment.baseApiUrl; - final docOfficeIdApiUrl = "${AppEnviroment.baseApiUrl}/users/profile/"; - final apiUrlEdit = "${AppEnviroment.baseApiUrl}/patients/update/"; - final apiUrlDelete = "${AppEnviroment.baseApiUrl}/patients/delete/"; - final _formKey = GlobalKey(); - - late bool medAidPosition; - late bool medMainMemberPosition; - late int futureDocOfficeId; - late String userEmail; - // bool medRequired = false; - final ValueNotifier medRequired = ValueNotifier(false); - - late double width; - late double height; - - final FocusNode _focusNode = FocusNode(); - - // Future getOfficeIdByUser(String endpoint) async { - // final response = await http.get(Uri.parse(endpoint)); - // if (response.statusCode == 200) { - // String body = response.body; - // var decodedData = jsonDecode(body); - // AppUser u = AppUser.fromJson(decodedData as Map); - // setState(() { - // //futureDocOfficeId = u.docOffice_id; - // //print(futureDocOfficeId); - // }); - // } else { - // internetConnectionPopUp(); - // throw Exception('failed to load patients'); - // } - // } - - Future updatePatientApiCall() async { - var statusCode = await MihPatientServices().updatePatientService( - widget.selectedPatient.app_id, - idController.text, - fnameController.text, - lnameController.text, - emailController.text, - cellController.text, - medAidController.text, - medMainMemController.text, - medNoController.text, - medAidCodeController.text, - medNameController.text, - medSchemeController.text, - addressController.text, - ); - if (statusCode == 200) { - successPopUp( - "Successfully Updated Profile!", - "${fnameController.text} ${lnameController.text}'s information has been updated successfully! Their medical records and details are now current.", - ); - } else { - MihAlertServices().errorAlert( - "Error Updating Profile", - "There was an error updating your profile. Please try again later.", - context, - ); - } - // var response = await http.put( - // Uri.parse(apiUrlEdit), - // headers: { - // "Content-Type": "application/json; charset=UTF-8" - // }, - // body: jsonEncode({ - // "id_no": idController.text, - // "first_name": fnameController.text, - // "last_name": lnameController.text, - // "email": emailController.text, - // "cell_no": cellController.text, - // "medical_aid": medAidController.text, - // "medical_aid_main_member": medMainMemController.text, - // "medical_aid_no": medNoController.text, - // "medical_aid_code": medAidCodeController.text, - // "medical_aid_name": medNameController.text, - // "medical_aid_scheme": medSchemeController.text, - // "address": addressController.text, - // "app_id": widget.selectedPatient.app_id, - // }), - // ); - // print(response.statusCode); - // if (response.statusCode == 200) { - // Navigator.of(context).pop(); - // Navigator.of(context).pop(); - // Navigator.of(context).pushNamed('/patient-profile', - // arguments: PatientViewArguments( - // widget.signedInUser, null, null, null, "personal")); - // //Navigator.of(context).pushNamed('/'); - // String message = - // "${fnameController.text} ${lnameController.text}'s information has been updated successfully! Their medical records and details are now current."; - // successPopUp(message); - // } else { - // internetConnectionPopUp(); - // } - } - - void successPopUp(String title, String message) { - showDialog( - context: context, - builder: (context) { - return MihPackageAlert( - alertIcon: Icon( - Icons.check_circle_outline_rounded, - size: 150, - color: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - alertTitle: title, - alertBody: Column( - children: [ - Text( - message, - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 25), - Center( - child: MihButton( - onPressed: () { - context.goNamed( - "patientProfile", - extra: PatientViewArguments( - widget.signedInUser, - widget.selectedPatient, - null, - null, - "personal", - ), - ); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - elevation: 10, - width: 300, - child: Text( - "Dismiss", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ) - ], - ), - alertColour: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - // return MIHSuccessMessage( - // successType: "Success", - // successMessage: message, - // ); - }, - ); - } - - Future deletePatientApiCall() async { - //print("Here1"); - //userEmail = getLoginUserEmail() as String; - //print(userEmail); - //print("Here2"); - //await getOfficeIdByUser(docOfficeIdApiUrl + userEmail); - //print("Office ID: ${futureDocOfficeId.toString()}"); - //print("OPatient ID No: ${idController.text}"); - //print("Here3"); - var response = await http.delete( - Uri.parse(apiUrlDelete), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode( - {"app_id": widget.selectedPatient.app_id}), - ); - //print("Here4"); - //print(response.statusCode); - if (response.statusCode == 200) { - Navigator.of(context).pop(); - Navigator.of(context).pop(); - Navigator.of(context).popAndPushNamed('/patient-profile', - arguments: PatientViewArguments( - widget.signedInUser, null, null, null, "personal")); - String message = - "${fnameController.text} ${lnameController.text}'s record has been deleted successfully. This means it will no longer be visible in patient manager and cannot be used for future appointments."; - successPopUp("Error", message); - } else { - internetConnectionPopUp(); - } - } - - Future getLoginUserEmail() async { - var uid = await SuperTokens.getUserId(); - var response = await http.get(Uri.parse("$baseAPI/user/$uid")); - if (response.statusCode == 200) { - var user = jsonDecode(response.body); - userEmail = user["email"]; - } - } - - void messagePopUp(error) { - showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: Text(error), - ); - }, - ); - } - - void internetConnectionPopUp() { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Internet Connection"); - }, - ); - } - - void deletePatientPopUp() { - showDialog( - context: context, - barrierDismissible: false, - builder: (context) => Dialog( - child: Stack( - children: [ - Container( - padding: const EdgeInsets.all(10.0), - width: 700.0, - height: (height / 3) * 2, - decoration: BoxDecoration( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - borderRadius: BorderRadius.circular(25.0), - border: Border.all( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 5.0), - ), - child: SingleChildScrollView( - child: Column( - //mainAxisSize: MainAxisSize.max, - children: [ - Icon( - Icons.warning_amber_rounded, - size: 100, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - const SizedBox(height: 15), - Text( - "Are you sure you want to delete this?", - textAlign: TextAlign.center, - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 25.0, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 10), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 25.0), - child: Text( - "This action is permanent! Deleting ${fnameController.text} ${lnameController.text} will remove him\\her from your account. You won't be able to recover it once it's gone.", - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 15.0, - fontWeight: FontWeight.bold, - ), - ), - ), - const SizedBox(height: 15), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 25.0), - child: Text( - "Here's what you'll be deleting:", - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20.0, - fontWeight: FontWeight.bold, - ), - ), - ), - const SizedBox(height: 10), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 25.0), - child: SizedBox( - width: 450, - child: Text( - "1) Patient Profile Information.\n2) Patient Notes\n3) Patient Files.", - textAlign: TextAlign.left, - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 15.0, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - MihButton( - onPressed: deletePatientApiCall, - buttonColor: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Delete", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - ), - ), - Positioned( - top: 5, - right: 5, - width: 50, - height: 50, - child: IconButton( - onPressed: () { - Navigator.pop(context); - }, - icon: Icon( - Icons.close, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - size: 35, - ), - ), - ), - ], - ), - ), - ); - } - - bool isFieldsFilled() { - if (medRequired.value) { - if (idController.text.isEmpty || - fnameController.text.isEmpty || - lnameController.text.isEmpty || - cellController.text.isEmpty || - emailController.text.isEmpty || - medNoController.text.isEmpty || - medNameController.text.isEmpty || - medSchemeController.text.isEmpty || - addressController.text.isEmpty || - medAidController.text.isEmpty || - medMainMemController.text.isEmpty || - medAidCodeController.text.isEmpty) { - return false; - } else { - return true; - } - } else { - if (idController.text.isEmpty || - fnameController.text.isEmpty || - lnameController.text.isEmpty || - cellController.text.isEmpty || - emailController.text.isEmpty || - addressController.text.isEmpty || - medAidController.text.isEmpty) { - return false; - } else { - return true; - } - } - } - - void isRequired() { - print("listerner triggered"); - if (medAidController.text == "Yes") { - medRequired.value = true; - } else if (medAidController.text == "No") { - medRequired.value = false; - } else { - //print("here"); - } - } - - Widget displayForm(double width) { - return SingleChildScrollView( - child: Padding( - padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.2) - : EdgeInsets.symmetric(horizontal: width * 0.075), - child: Column( - children: [ - MihForm( - formKey: _formKey, - formFields: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Personal", - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 25.0, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ], - ), - Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark")), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: idController, - multiLineInput: false, - requiredText: true, - hintText: "ID No.", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: fnameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "First Name", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: lnameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Surname", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: cellController, - multiLineInput: false, - requiredText: true, - hintText: "Cell No.", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: emailController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Email", - validator: (value) { - return MihValidationServices().validateEmail(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - height: 100, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: addressController, - multiLineInput: true, - requiredText: true, - hintText: "Address", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 15.0), - Center( - child: Text( - "Medical Aid Details", - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 25.0, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ), - Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark")), - const SizedBox(height: 10.0), - MihToggle( - hintText: "Medical Aid", - initialPostion: medAidPosition, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - secondaryFillColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onChange: (value) { - if (value) { - setState(() { - medAidController.text = "Yes"; - medAidPosition = value; - }); - } else { - setState(() { - medAidController.text = "No"; - medAidPosition = value; - }); - } - }, - ), - ValueListenableBuilder( - valueListenable: medRequired, - builder: (BuildContext context, bool value, Widget? child) { - return Visibility( - visible: value, - child: Column( - children: [ - const SizedBox(height: 10.0), - MihToggle( - hintText: "Main Member", - initialPostion: medMainMemberPosition, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - secondaryFillColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: (value) { - if (value) { - setState(() { - medMainMemController.text = "Yes"; - medMainMemberPosition = value; - }); - } else { - setState(() { - medMainMemController.text = "No"; - medMainMemberPosition = value; - }); - } - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: medNoController, - multiLineInput: false, - requiredText: true, - hintText: "No.", - validator: (validationValue) { - if (value) { - return MihValidationServices() - .isEmpty(validationValue); - } - return null; - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: medAidCodeController, - multiLineInput: false, - requiredText: true, - hintText: "Code", - validator: (validationValue) { - if (value) { - return MihValidationServices() - .isEmpty(validationValue); - } - return null; - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: medNameController, - multiLineInput: false, - requiredText: true, - hintText: "Name", - validator: (validationValue) { - if (value) { - return MihValidationServices() - .isEmpty(validationValue); - } - return null; - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: medSchemeController, - multiLineInput: false, - requiredText: true, - hintText: "Plan", - validator: (validationValue) { - if (value) { - return MihValidationServices() - .isEmpty(validationValue); - } - return null; - }, - ), - const SizedBox(height: 10.0), - ], - ), - ); - }, - ), - const SizedBox(height: 20.0), - Center( - child: MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - submitForm(); - } else { - MihAlertServices().formNotFilledCompletely(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - const SizedBox(height: 20.0), - ], - ), - ], - ), - ), - ); - } - - void submitForm() { - updatePatientApiCall(); - } - - MIHAction getActionButton() { - return MIHAction( - icon: const Icon(Icons.arrow_back), - iconSize: 35, - onTap: () { - context.goNamed( - 'patientProfile', - extra: PatientViewArguments( - widget.signedInUser, - null, - null, - null, - "personal", - ), - ); - // Navigator.of(context).pop(); - }, - ); - } - - MIHHeader getHeader() { - return const MIHHeader( - headerAlignment: MainAxisAlignment.center, - headerItems: [ - Text( - "Edit Patient Details", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 25, - ), - ), - ], - ); - } - - MIHBody getBody(double width) { - return MIHBody( - borderOn: false, - bodyItems: [ - KeyboardListener( - focusNode: _focusNode, - autofocus: true, - onKeyEvent: (event) async { - if (event is KeyDownEvent && - event.logicalKey == LogicalKeyboardKey.enter) { - if (_formKey.currentState!.validate()) { - submitForm(); - } else { - MihAlertServices().formNotFilledCompletely(context); - } - } - }, - child: displayForm(width), - ), - ], - ); - } - - @override - void dispose() { - idController.dispose(); - fnameController.dispose(); - lnameController.dispose(); - cellController.dispose(); - emailController.dispose(); - medNoController.dispose(); - medNameController.dispose(); - medSchemeController.dispose(); - addressController.dispose(); - medAidController.dispose(); - medAidCodeController.removeListener(isRequired); - medMainMemController.dispose(); - medAidCodeController.dispose(); - medRequired.dispose(); - _focusNode.dispose(); - super.dispose(); - } - - @override - void initState() { - getLoginUserEmail(); - medAidController.addListener(isRequired); - setState(() { - idController.text = widget.selectedPatient.id_no; - fnameController.text = widget.selectedPatient.first_name; - lnameController.text = widget.selectedPatient.last_name; - cellController.text = widget.selectedPatient.cell_no; - emailController.text = widget.selectedPatient.email; - medNameController.text = widget.selectedPatient.medical_aid_name; - medNoController.text = widget.selectedPatient.medical_aid_no; - medSchemeController.text = widget.selectedPatient.medical_aid_scheme; - addressController.text = widget.selectedPatient.address; - medAidController.text = widget.selectedPatient.medical_aid; - medMainMemController.text = - widget.selectedPatient.medical_aid_main_member; - medAidCodeController.text = widget.selectedPatient.medical_aid_code; - }); - - if (medAidController.text == "Yes") { - medAidPosition = true; - } else { - medAidPosition = false; - medAidController.text = "No"; - } - if (medMainMemController.text == "Yes") { - medMainMemberPosition = true; - } else { - medMainMemberPosition = false; - medMainMemController.text = "No"; - } - super.initState(); - } - - @override - Widget build(BuildContext context) { - var size = MediaQuery.of(context).size; - setState(() { - width = size.width; - height = size.height; - }); - return MIHLayoutBuilder( - actionButton: getActionButton(), - header: getHeader(), - secondaryActionButton: null, - body: getBody(width), - actionDrawer: null, - secondaryActionDrawer: null, - bottomNavBar: null, - pullDownToRefresh: false, - onPullDown: () async {}, - ); - } -} diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart index fccb9c0b..420def9f 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart @@ -2,18 +2,21 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_claim_or_statement.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_consultation.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_documents.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; +import 'package:provider/provider.dart'; class PatientProfile extends StatefulWidget { - final PatientViewArguments arguments; + final String? patientAppId; const PatientProfile({ super.key, - required this.arguments, + required this.patientAppId, }); @override @@ -21,7 +24,42 @@ class PatientProfile extends StatefulWidget { } class _PatientProfileState extends State { - int _selcetedIndex = 0; + bool isLoading = true; + + Future initialisePatientData() async { + setState(() { + isLoading = true; + }); + MzansiProfileProvider profileProvider = + context.read(); + PatientManagerProvider patientManagerProvider = + context.read(); + String? app_id = widget.patientAppId ?? profileProvider.user!.app_id; + + if (patientManagerProvider.selectedPatient == null) { + await MihPatientServices() + .getPatientDetails(app_id, patientManagerProvider); + } + + if (patientManagerProvider.selectedPatient == null) { + // go to set up patient package + context.goNamed("patientProfileSetup"); + } else { + await MihPatientServices() + .getPatientConsultationNotes(patientManagerProvider); + await MihPatientServices().getPatientDocuments(patientManagerProvider); + } + setState(() { + isLoading = false; + }); + } + + @override + void initState() { + super.initState(); + initialisePatientData(); + } + @override Widget build(BuildContext context) { return MihPackage( @@ -29,21 +67,24 @@ class _PatientProfileState extends State { appTools: getTools(), appBody: getToolBody(), appToolTitles: getToolTitle(), - selectedbodyIndex: _selcetedIndex, + selectedbodyIndex: + context.watch().patientProfileIndex, onIndexChange: (newValue) { - setState(() { - _selcetedIndex = newValue; - }); + context.read().setPatientProfileIndex(newValue); }, ); } MihPackageAction getAction() { + PatientManagerProvider patientManagerProvider = + context.read(); return MihPackageAction( icon: const Icon(Icons.arrow_back), iconSize: 35, onTap: () { - if (widget.arguments.type == "business") { + patientManagerProvider.setPatientProfileIndex(0); + patientManagerProvider.setPatientManagerIndex(0); + if (!patientManagerProvider.personalMode) { context.pop(); } else { context.goNamed( @@ -56,64 +97,54 @@ class _PatientProfileState extends State { } MihPackageTools getTools() { + PatientManagerProvider patientManagerProvider = + context.read(); Map temp = {}; temp[const Icon(Icons.perm_identity)] = () { - setState(() { - _selcetedIndex = 0; - }); + patientManagerProvider.setPatientProfileIndex(0); }; temp[const Icon(Icons.article_outlined)] = () { - setState(() { - _selcetedIndex = 1; - }); + patientManagerProvider.setPatientProfileIndex(1); }; temp[const Icon(Icons.file_present)] = () { - setState(() { - _selcetedIndex = 2; - }); + patientManagerProvider.setPatientProfileIndex(2); }; temp[const Icon(Icons.file_open_outlined)] = () { - setState(() { - _selcetedIndex = 3; - }); + patientManagerProvider.setPatientProfileIndex(3); }; return MihPackageTools( tools: temp, - selcetedIndex: _selcetedIndex, + selcetedIndex: patientManagerProvider.patientProfileIndex, ); } List getToolBody() { + if (isLoading) { + return [ + Center( + child: Mihloadingcircle(), + ), + ]; + } + PatientManagerProvider patientManagerProvider = + context.read(); + if (patientManagerProvider.selectedPatient == null) { + return [ + const SizedBox(), + ]; + } List toolBodies = [ - PatientInfo( - signedInUser: widget.arguments.signedInUser, - selectedPatient: widget.arguments.selectedPatient!, - type: widget.arguments.type, - ), - PatientConsultation( - patientAppId: widget.arguments.selectedPatient!.app_id, - selectedPatient: widget.arguments.selectedPatient!, - signedInUser: widget.arguments.signedInUser, - business: widget.arguments.business, - businessUser: widget.arguments.businessUser, - type: widget.arguments.type, - ), - PatientDocuments( - patientIndex: widget.arguments.selectedPatient!.idpatients, - selectedPatient: widget.arguments.selectedPatient!, - signedInUser: widget.arguments.signedInUser, - business: widget.arguments.business, - businessUser: widget.arguments.businessUser, - type: widget.arguments.type, - ), - PatientClaimOrStatement( - patientIndex: widget.arguments.selectedPatient!.idpatients, - selectedPatient: widget.arguments.selectedPatient!, - signedInUser: widget.arguments.signedInUser, - business: widget.arguments.business, - businessUser: widget.arguments.businessUser, - type: widget.arguments.type, - ), + PatientInfo(), + PatientConsultation(), + PatientDocuments(), + // PatientClaimOrStatement( + // patientIndex: widget.arguments.selectedPatient!.idpatients, + // selectedPatient: widget.arguments.selectedPatient!, + // signedInUser: widget.arguments.signedInUser, + // business: widget.arguments.business, + // businessUser: widget.arguments.businessUser, + // type: widget.arguments.type, + // ), ]; return toolBodies; } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_set_up.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_set_up.dart new file mode 100644 index 00000000..5f4f319d --- /dev/null +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_set_up.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_setup_form.dart'; +import 'package:provider/provider.dart'; + +class PatientSetUp extends StatefulWidget { + const PatientSetUp({super.key}); + + @override + State createState() => _PatientSetUpState(); +} + +class _PatientSetUpState extends State { + @override + Widget build(BuildContext context) { + return MihPackage( + appActionButton: getAction(), + appTools: getTools(), + appBody: getToolBody(), + appToolTitles: getToolTitle(), + selectedbodyIndex: + context.watch().patientProfileIndex, + onIndexChange: (newValue) { + context.read().setPatientProfileIndex(newValue); + }, + ); + } + + MihPackageAction getAction() { + return MihPackageAction( + icon: const Icon(Icons.arrow_back), + iconSize: 35, + onTap: () { + context.goNamed( + 'mihHome', + ); + FocusScope.of(context).unfocus(); + }, + ); + } + + MihPackageTools getTools() { + PatientManagerProvider patientManagerProvider = + context.read(); + Map temp = {}; + temp[const Icon(Icons.medical_services)] = () { + patientManagerProvider.setPatientProfileIndex(0); + }; + return MihPackageTools( + tools: temp, + selcetedIndex: patientManagerProvider.patientProfileIndex, + ); + } + + List getToolBody() { + List toolBodies = [ + PatientSetupForm(), + ]; + return toolBodies; + } + + List getToolTitle() { + List toolTitles = [ + "Set Up Patient Profile", + ]; + return toolTitles; + } +} diff --git a/Frontend/lib/mih_packages/test/test.dart b/Frontend/lib/mih_packages/test/test.dart deleted file mode 100644 index af787b72..00000000 --- a/Frontend/lib/mih_packages/test/test.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../mih_components/mih_layout/mih_action.dart'; -import '../../mih_components/mih_layout/mih_body.dart'; -import '../../mih_components/mih_layout/mih_header.dart'; -import '../../mih_components/mih_layout/mih_layout_builder.dart'; - -class MIHTest extends StatefulWidget { - const MIHTest({super.key}); - - @override - State createState() => _MIHTestState(); -} - -class _MIHTestState extends State { - // late YoutubePlayerController videoController; - // String videoLink = "https://www.youtube.com/watch?v=P2bM9eosJ_A"; - // @override - // void initState() { - // videoController = YoutubePlayerController( - // initialVideoId: "P2bM9eosJ_A", - // ); - // super.initState(); - // } - - @override - Widget build(BuildContext context) { - return MIHLayoutBuilder( - actionButton: MIHAction( - icon: const Icon(Icons.arrow_back), - iconSize: 35, - onTap: () { - Navigator.of(context).pushNamedAndRemoveUntil( - '/', - arguments: true, - (route) => false, - ); - }, - ), - header: const MIHHeader( - headerAlignment: MainAxisAlignment.center, - headerItems: [ - Text( - "Test", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 25, - ), - ), - ], - ), - secondaryActionButton: null, - body: const MIHBody( - borderOn: false, - bodyItems: [ - // YoutubePlayer( - // controller: videoController, - // ), - ], - ), - actionDrawer: null, - secondaryActionDrawer: null, - bottomNavBar: null, - pullDownToRefresh: false, - onPullDown: () async {}, - ); - } -} diff --git a/Frontend/lib/mih_services/mih_patient_services.dart b/Frontend/lib/mih_services/mih_patient_services.dart index 57420896..10e1bea3 100644 --- a/Frontend/lib/mih_services/mih_patient_services.dart +++ b/Frontend/lib/mih_services/mih_patient_services.dart @@ -1,7 +1,12 @@ import 'dart:convert'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:ken_logger/ken_logger.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/files.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/notes.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:supertokens_flutter/http.dart' as http; @@ -10,6 +15,7 @@ class MihPatientServices { Future getPatientDetails( String appId, + PatientManagerProvider patientManagerProvider, ) async { var response = await http.get( Uri.parse("${AppEnviroment.baseApiUrl}/patients/$appId"), @@ -19,8 +25,11 @@ class MihPatientServices { ); if (response.statusCode == 200) { String body = response.body; + KenLogger.success(response.body); var jsonBody = jsonDecode(body); - return Patient.fromJson(jsonBody); + Patient patient = Patient.fromJson(jsonBody); + patientManagerProvider.setSelectedPatient(selectedPatient: patient); + return patient; } else { return null; } @@ -39,7 +48,8 @@ class MihPatientServices { String medName, String medScheme, String address, - AppUser signedInUser, + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, ) async { var response = await http.post( Uri.parse("$baseAPI/patients/insert/"), @@ -59,9 +69,31 @@ class MihPatientServices { "medical_aid_name": medName, "medical_aid_scheme": medScheme, "address": address, - "app_id": signedInUser.app_id, + "app_id": profileProvider.user!.app_id, }), ); + if (response.statusCode == 201) { + await getPatientDetails( + profileProvider.user!.app_id, patientManagerProvider); + // patientManagerProvider.setSelectedPatient( + // selectedPatient: Patient( + // idpatients: 0, + // id_no: id_no, + // first_name: fname, + // last_name: lname, + // email: email, + // cell_no: cell, + // medical_aid: medAid, + // medical_aid_name: medName, + // medical_aid_no: medNo, + // medical_aid_main_member: medMainMem, + // medical_aid_code: medAidCode, + // medical_aid_scheme: medScheme, + // address: address, + // app_id: profileProvider.user!.app_id, + // ), + // ); + } return response.statusCode; } @@ -79,6 +111,7 @@ class MihPatientServices { String medName, String medScheme, String address, + PatientManagerProvider patientManagerProvider, ) async { var response = await http.put( Uri.parse("$baseAPI/patients/update/"), @@ -101,6 +134,159 @@ class MihPatientServices { "app_id": app_id, }), ); + if (response.statusCode == 200) { + await getPatientDetails(app_id, patientManagerProvider); + } + return response.statusCode; + } + + Future getPatientConsultationNotes( + PatientManagerProvider patientManagerProvider) async { + final response = await http.get(Uri.parse( + "${AppEnviroment.baseApiUrl}/notes/patients/${patientManagerProvider.selectedPatient!.app_id}")); + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List notes = + List.from(l.map((model) => Note.fromJson(model))); + patientManagerProvider.setConsultationNotes(consultationNotes: notes); + } + return response.statusCode; + } + + Future addPatientNoteAPICall( + String title, + String noteText, + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, + ) async { + var response = await http.post( + Uri.parse("${AppEnviroment.baseApiUrl}/notes/insert/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "note_name": title, + "note_text": noteText, + "doc_office": profileProvider.business!.Name, + "doctor": + "${profileProvider.user!.fname} ${profileProvider.user!.lname}", + "app_id": patientManagerProvider.selectedPatient!.app_id, + }), + ); + if (response.statusCode == 201) { + await getPatientConsultationNotes(patientManagerProvider); + } + return response.statusCode; + } + + Future deletePatientConsultaionNote( + int NoteId, + PatientManagerProvider patientManagerProvider, + ) async { + var response = await http.delete( + Uri.parse("$baseAPI/notes/delete/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({"idpatient_notes": NoteId}), + ); + if (response.statusCode == 201) { + await getPatientConsultationNotes(patientManagerProvider); + } + return response.statusCode; + } + + Future getPatientDocuments( + PatientManagerProvider patientManagerProvider) async { + final response = await http.get(Uri.parse( + "${AppEnviroment.baseApiUrl}/patient_files/get/${patientManagerProvider.selectedPatient!.app_id}")); + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List patientDocuments = + List.from(l.map((model) => PFile.fromJson(model))); + patientManagerProvider.setPatientDocuments( + patientDocuments: patientDocuments); + } + return response.statusCode; + } + + Future addPatientFile( + PlatformFile? file, + PatientManagerProvider patientManagerProvider, + ) async { + var fname = file!.name.replaceAll(RegExp(r' '), '-'); + var filePath = + "${patientManagerProvider.selectedPatient!.app_id}/patient_files/$fname"; + var response = await http.post( + Uri.parse("${AppEnviroment.baseApiUrl}/patient_files/insert/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "file_path": filePath, + "file_name": fname, + "app_id": patientManagerProvider.selectedPatient!.app_id + }), + ); + if (response.statusCode == 201) { + await getPatientDocuments(patientManagerProvider); + } + return response.statusCode; + } + + Future generateMedicalCertificate( + String startDate, + String endDate, + String returnDate, + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, + ) async { + DateTime now = DateTime.now(); + String fileName = + "Med-Cert-${patientManagerProvider.selectedPatient!.first_name} ${patientManagerProvider.selectedPatient!.last_name}-${now.toString().substring(0, 19)}.pdf" + .replaceAll(RegExp(r' '), '-'); + var response = await http.post( + Uri.parse("${AppEnviroment.baseApiUrl}/minio/generate/med-cert/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "app_id": patientManagerProvider.selectedPatient!.app_id, + "env": AppEnviroment.getEnv(), + "patient_full_name": + "${patientManagerProvider.selectedPatient!.first_name} ${patientManagerProvider.selectedPatient!.last_name}", + "fileName": fileName, + "id_no": patientManagerProvider.selectedPatient!.id_no, + "docfname": + "DR. ${profileProvider.user!.fname} ${profileProvider.user!.lname}", + "startDate": startDate, + "busName": profileProvider.business!.Name, + "busAddr": "*TO BE ADDED IN THE FUTURE*", + "busNo": profileProvider.business!.contact_no, + "busEmail": profileProvider.business!.bus_email, + "endDate": endDate, + "returnDate": returnDate, + "logo_path": profileProvider.business!.logo_path, + "sig_path": profileProvider.businessUser!.sig_path, + }), + ); + if (response.statusCode == 200) { + var responseAddFiletoDB = await http.post( + Uri.parse("${AppEnviroment.baseApiUrl}/patient_files/insert/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "file_path": + "${patientManagerProvider.selectedPatient!.app_id}/patient_files/$fileName", + "file_name": fileName, + "app_id": patientManagerProvider.selectedPatient!.app_id + }), + ); + if (responseAddFiletoDB.statusCode == 201) { + await getPatientDocuments(patientManagerProvider); + } + } return response.statusCode; } } diff --git a/Frontend/lib/mih_services/mih_service_calls.dart b/Frontend/lib/mih_services/mih_service_calls.dart index ec463b70..2fc9014e 100644 --- a/Frontend/lib/mih_services/mih_service_calls.dart +++ b/Frontend/lib/mih_services/mih_service_calls.dart @@ -4,7 +4,6 @@ import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_my_business_user_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_notification_services.dart'; import 'package:flutter/material.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; import 'package:supertokens_flutter/supertokens.dart'; import 'package:supertokens_flutter/http.dart' as http; @@ -88,14 +87,14 @@ class MIHApiCalls { ); //get patient profile - Patient? patient = await MihPatientServices().getPatientDetails( - uid, - ); - if (patient != null) { - patientData = patient; - } else { - patientData = null; - } + // Patient? patient = await MihPatientServices().getPatientDetails( + // uid, + // ); + // if (patient != null) { + // patientData = patient; + // } else { + // patientData = null; + // } return HomeArguments( userData, bUserData, busData, patientData, notifi, userPic); From 23c3cf4173c2789228fb8e91548c499828e4d439 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 29 Oct 2025 13:06:55 +0200 Subject: [PATCH 36/45] NEW: MIH MineSweeper Package pt2 --- .../mih_objects/minesweeper_player_score.dart | 42 ++ .../mih_dropdwn_field.dart | 3 + .../mih_mine_sweeper_provider.dart | 34 +- Frontend/lib/mih_config/mih_go_router.dart | 2 +- .../build_minesweeper_leaderboard_list.dart | 88 ++++ .../builders/build_my_scoreboard_list.dart | 70 +++ .../components/leaderboard_user_ranking.dart | 85 ++++ .../mih_mine_sweeper_start_game_window.dart | 174 +++++++ .../mine_sweeper/mih_mine_sweeper.dart | 34 +- .../package_tiles/mih_mine_sweeper_tile.dart | 4 +- .../mih_mine_sweeper_leader_board.dart | 202 ++++++++ .../package_tools/mine_sweeper_game.dart | 446 ++++++++++++------ .../mine_sweeper_quick_start_guide.dart | 279 +++++++++++ .../package_tools/my_score_board.dart | 212 +++++++++ .../mih_minesweeper_services.dart | 80 ++++ backend/.DS_Store | Bin 8196 -> 10244 bytes backend/main.py | 2 + backend/mih_database/mihDbObjects.py | 23 +- backend/routers/mine_sweeper_leaderboard.py | 171 +++++++ 19 files changed, 1805 insertions(+), 146 deletions(-) create mode 100644 Frontend/lib/mih_components/mih_objects/minesweeper_player_score.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/builders/build_my_scoreboard_list.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/components/leaderboard_user_ranking.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/components/mih_mine_sweeper_start_game_window.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart create mode 100644 Frontend/lib/mih_services/mih_minesweeper_services.dart create mode 100644 backend/routers/mine_sweeper_leaderboard.py diff --git a/Frontend/lib/mih_components/mih_objects/minesweeper_player_score.dart b/Frontend/lib/mih_components/mih_objects/minesweeper_player_score.dart new file mode 100644 index 00000000..9a1dad89 --- /dev/null +++ b/Frontend/lib/mih_components/mih_objects/minesweeper_player_score.dart @@ -0,0 +1,42 @@ +class MinesweeperPlayerScore { + String app_id; + String username; + String proPicUrl; + String difficulty; + String game_time; + double game_score; + DateTime played_date; + + MinesweeperPlayerScore({ + required this.app_id, + required this.username, + required this.proPicUrl, + required this.difficulty, + required this.game_time, + required this.game_score, + required this.played_date, + }); + + factory MinesweeperPlayerScore.fromJson(Map json) { + return MinesweeperPlayerScore( + app_id: json['app_id'], + username: json['username'], + proPicUrl: json['proPicUrl'], + difficulty: json['difficulty'], + game_time: json['game_time'], + game_score: json['game_score'], + played_date: DateTime.parse(json['played_date']), + ); + } + + Map toJson() { + return { + 'app_id': app_id, + 'username': username, + 'proPicUrl': proPicUrl, + 'difficulty': difficulty, + 'game_time': game_score, + 'played_date': played_date.toIso8601String(), + }; + } +} diff --git a/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart b/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart index 9bd6d44f..8bb9a88d 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart @@ -10,6 +10,7 @@ class MihDropdownField extends StatefulWidget { final bool editable; final bool enableSearch; final FormFieldValidator? validator; + final Function(String?)? onSelected; const MihDropdownField({ super.key, @@ -20,6 +21,7 @@ class MihDropdownField extends StatefulWidget { required this.editable, required this.enableSearch, this.validator, + this.onSelected, }); @override @@ -153,6 +155,7 @@ class _MihDropdownFieldState extends State { ), onSelected: (String? selectedValue) { field.didChange(selectedValue); + widget.onSelected?.call(selectedValue); }, menuStyle: MenuStyle( backgroundColor: WidgetStatePropertyAll( diff --git a/Frontend/lib/mih_components/mih_providers/mih_mine_sweeper_provider.dart b/Frontend/lib/mih_components/mih_providers/mih_mine_sweeper_provider.dart index f6d3ea90..50b58831 100644 --- a/Frontend/lib/mih_components/mih_providers/mih_mine_sweeper_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mih_mine_sweeper_provider.dart @@ -1,4 +1,5 @@ import 'package:flutter/widgets.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/minesweeper_player_score.dart'; class MihMineSweeperProvider extends ChangeNotifier { String difficulty; @@ -6,9 +7,12 @@ class MihMineSweeperProvider extends ChangeNotifier { int rowCount; int columnCount; int totalMines; + List? leaderboard; + List? myScoreboard; + List?> leaderboardUserPictures = []; MihMineSweeperProvider({ - this.difficulty = "Normal", + this.difficulty = "Easy", this.toolIndex = 0, this.rowCount = 10, this.columnCount = 10, @@ -16,7 +20,7 @@ class MihMineSweeperProvider extends ChangeNotifier { }); void reset() { - difficulty = "Normal"; + difficulty = "Easy"; toolIndex = 0; rowCount = 10; columnCount = 10; @@ -48,4 +52,30 @@ class MihMineSweeperProvider extends ChangeNotifier { this.totalMines = totalMines; notifyListeners(); } + + void setLeaderboard({required List? leaderboard}) { + if (leaderboard == null) { + this.leaderboard = []; + } else { + this.leaderboard = leaderboard; + } + notifyListeners(); + } + + void setMyScoreboard({ + required List? myScoreboard, + }) { + if (myScoreboard == null) { + this.myScoreboard = []; + } else { + this.myScoreboard = myScoreboard; + } + notifyListeners(); + } + + void setLeaderboardUserPictures( + {required List?> leaderboardUserPictures}) { + this.leaderboardUserPictures = leaderboardUserPictures; + notifyListeners(); + } } diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index 9dae1781..e0963b7c 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -422,7 +422,7 @@ class MihGoRouter { return MIHPrintPreview(arguments: args!); }, ), - // ========================== MIH Calculator ================================== + // ========================== MIH Minesweeper ================================== GoRoute( name: "mihMinesweeper", path: MihGoRouterPaths.mihMineSweeper, diff --git a/Frontend/lib/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart b/Frontend/lib/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart new file mode 100644 index 00000000..cc622ed0 --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:provider/provider.dart'; + +class BuildMinesweeperLeaderboardList extends StatefulWidget { + const BuildMinesweeperLeaderboardList({super.key}); + + @override + State createState() => + _BuildMinesweeperLeaderboardListState(); +} + +class _BuildMinesweeperLeaderboardListState + extends State { + @override + Widget build(BuildContext context) { + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + MihMineSweeperProvider mineSweeperProvider, Widget? child) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (BuildContext context, index) { + return Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + itemCount: mineSweeperProvider.leaderboard!.length, + itemBuilder: (context, index) { + return ListTile( + leading: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "#${index + 1}", + style: TextStyle( + fontSize: 25, + ), + ), + const SizedBox(width: 10), + MihCircleAvatar( + key: UniqueKey(), + imageFile: + mineSweeperProvider.leaderboardUserPictures.isNotEmpty + ? mineSweeperProvider.leaderboardUserPictures[index] + : null, + width: 60, + editable: false, + fileNameController: null, + userSelectedfile: null, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onChange: () {}, + ), + ], + ), + title: Text( + "${mineSweeperProvider.leaderboard![index].username}${profileProvider.user!.username == mineSweeperProvider.leaderboard![index].username ? " (You)" : ""}", + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + subtitle: Text( + "Score: ${mineSweeperProvider.leaderboard![index].game_score}\nTime: ${mineSweeperProvider.leaderboard![index].game_time}", + style: TextStyle( + fontSize: 18, + // fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + ); + }, + ); + }, + ); + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/builders/build_my_scoreboard_list.dart b/Frontend/lib/mih_packages/mine_sweeper/builders/build_my_scoreboard_list.dart new file mode 100644 index 00000000..9b877c06 --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/builders/build_my_scoreboard_list.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:provider/provider.dart'; + +class BuildMyScoreBoardList extends StatefulWidget { + const BuildMyScoreBoardList({super.key}); + + @override + State createState() => + _BuildMinesweeperLeaderboardListState(); +} + +class _BuildMinesweeperLeaderboardListState + extends State { + @override + Widget build(BuildContext context) { + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + MihMineSweeperProvider mineSweeperProvider, Widget? child) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (BuildContext context, index) { + return Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + itemCount: mineSweeperProvider.myScoreboard!.length, + itemBuilder: (context, index) { + return ListTile( + leading: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "#${index + 1}", + style: TextStyle( + fontSize: 25, + ), + ), + ], + ), + title: Text( + "Score: ${mineSweeperProvider.myScoreboard![index].game_score}", + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + subtitle: Text( + "Time: ${mineSweeperProvider.myScoreboard![index].game_time}", + style: TextStyle( + fontSize: 18, + // fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + ); + }, + ); + }, + ); + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/components/leaderboard_user_ranking.dart b/Frontend/lib/mih_packages/mine_sweeper/components/leaderboard_user_ranking.dart new file mode 100644 index 00000000..e2c4feb2 --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/components/leaderboard_user_ranking.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:ken_logger/ken_logger.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:redacted/redacted.dart'; + +class LeaderboardUserRanking extends StatelessWidget { + final int index; + final String proPicUrl; + final String username; + final dynamic gameScore; + final String gameTime; + final bool isCurrentUser; + final Future?> Function(String) getUserPicture; + + const LeaderboardUserRanking({ + super.key, + required this.index, + required this.proPicUrl, + required this.username, + required this.gameScore, + required this.gameTime, + required this.isCurrentUser, + required this.getUserPicture, + }); + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: getUserPicture(proPicUrl), + builder: (context, asyncSnapshot) { + bool isLoading = + asyncSnapshot.connectionState == ConnectionState.waiting; + + KenLogger.success("URL: ${asyncSnapshot.data.toString()}"); + return ListTile( + leading: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "#${index + 1}", + style: const TextStyle( + fontSize: 25, + ), + ), + const SizedBox(width: 10), + MihCircleAvatar( + key: ValueKey(asyncSnapshot.data + .toString()), // Use ValueKey for stable identity + imageFile: asyncSnapshot.data, + width: 60, + editable: false, + fileNameController: null, + userSelectedfile: null, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onChange: () {}, + ), + ], + ), + title: Text( + "$username${isCurrentUser ? " (You)" : ""}", + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ).redacted(context: context, redact: isLoading), + subtitle: Text( + "Score: $gameScore\nTime: $gameTime", + style: TextStyle( + fontSize: 18, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ).redacted(context: context, redact: isLoading), + ); + }, + ); + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/components/mih_mine_sweeper_start_game_window.dart b/Frontend/lib/mih_packages/mine_sweeper/components/mih_mine_sweeper_start_game_window.dart new file mode 100644 index 00000000..3ec5092e --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/components/mih_mine_sweeper_start_game_window.dart @@ -0,0 +1,174 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:provider/provider.dart'; + +class MihMineSweeperStartGameWindow extends StatefulWidget { + final void Function()? onPressed; + const MihMineSweeperStartGameWindow({ + super.key, + required this.onPressed, + }); + + @override + State createState() => + _MihMineSweeperStartGameWindowState(); +} + +class _MihMineSweeperStartGameWindowState + extends State { + TextEditingController modeController = TextEditingController(); + final _formKey = GlobalKey(); + + void applyGameSettings(MihMineSweeperProvider mihMineSweeperProvider) { + mihMineSweeperProvider.setDifficulty(modeController.text); + switch (mihMineSweeperProvider.difficulty) { + case ("Very Easy"): + mihMineSweeperProvider.setRowCount(6); + mihMineSweeperProvider.setCoulmnCount(6); + mihMineSweeperProvider.setTotalMines(5); + // mihMineSweeperProvider.setRowCount(5); + // mihMineSweeperProvider.setCoulmnCount(5); + // mihMineSweeperProvider.setTotalMines(3); + break; + case ("Easy"): + mihMineSweeperProvider.setRowCount(8); + mihMineSweeperProvider.setCoulmnCount(8); + mihMineSweeperProvider.setTotalMines(10); + // mihMineSweeperProvider.setRowCount(10); + // mihMineSweeperProvider.setCoulmnCount(10); + // mihMineSweeperProvider.setTotalMines(15); + break; + case ("Intermediate"): + mihMineSweeperProvider.setRowCount(10); + mihMineSweeperProvider.setCoulmnCount(10); + mihMineSweeperProvider.setTotalMines(18); + // mihMineSweeperProvider.setRowCount(15); + // mihMineSweeperProvider.setCoulmnCount(10); + // mihMineSweeperProvider.setTotalMines(23); + break; + case ("Hard"): + mihMineSweeperProvider.setRowCount(12); + mihMineSweeperProvider.setCoulmnCount(10); + mihMineSweeperProvider.setTotalMines(30); + // mihMineSweeperProvider.setRowCount(20); + // mihMineSweeperProvider.setCoulmnCount(10); + // mihMineSweeperProvider.setTotalMines(30); + break; + default: + break; + } + } + + String getModeConfig() { + switch (modeController.text) { + case ("Very Easy"): + return "Columns: 6\nRows: 6\nBombs: 5"; + case ("Easy"): + return "Columns: 8\nRows: 8\nBombs: 10"; + case ("Intermediate"): + return "Columns: 10\nRows: 10\nBombs: 18"; + case ("Hard"): + return "Columns: 10\nRows: 12\nBombs: 30"; + default: + return "Error"; + } + } + + void _onModeChanged() { + setState(() {}); + } + + @override + void dispose() { + modeController.removeListener(_onModeChanged); + modeController.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + modeController.text = context.read().difficulty; + modeController.addListener(_onModeChanged); + } + + @override + Widget build(BuildContext context) { + return MihPackageWindow( + fullscreen: false, + windowTitle: "New Game Settings", + onWindowTapClose: () { + context.pop(); + }, + windowBody: Consumer( + builder: (BuildContext context, + MihMineSweeperProvider mihMineSweeperProvider, Widget? child) { + return Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihDropdownField( + controller: modeController, + hintText: "Difficulty", + dropdownOptions: [ + "Very Easy", + "Easy", + "Intermediate", + "Hard" + ], + requiredText: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 10), + Text( + getModeConfig(), + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + applyGameSettings(mihMineSweeperProvider); + context.pop(); + widget.onPressed?.call(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Start Game", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ], + ); + }, + ), + ); + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart b/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart index b0659619..ef545c7a 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart @@ -4,8 +4,12 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart'; import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/package_tools/my_score_board.dart'; import 'package:provider/provider.dart'; class MihMineSweeper extends StatefulWidget { @@ -16,6 +20,14 @@ class MihMineSweeper extends StatefulWidget { } class _MihMineSweeperState extends State { + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + context.read().loadBannerAd(); + }); + } + @override Widget build(BuildContext context) { return MihPackage( @@ -35,9 +47,12 @@ class _MihMineSweeperState extends State { icon: const Icon(Icons.arrow_back), iconSize: 35, onTap: () { + MihMineSweeperProvider mineSweeperProvider = + context.read(); + mineSweeperProvider.setToolIndex(0); + mineSweeperProvider.setDifficulty("Easy"); context.goNamed( 'mihHome', - extra: true, ); FocusScope.of(context).unfocus(); }, @@ -49,6 +64,15 @@ class _MihMineSweeperState extends State { temp[const Icon(FontAwesomeIcons.bomb)] = () { context.read().setToolIndex(0); }; + temp[const Icon(Icons.leaderboard_rounded)] = () { + context.read().setToolIndex(1); + }; + temp[const Icon(Icons.perm_identity_rounded)] = () { + context.read().setToolIndex(2); + }; + temp[const Icon(Icons.rule_rounded)] = () { + context.read().setToolIndex(3); + }; return MihPackageTools( tools: temp, selcetedIndex: context.watch().toolIndex, @@ -57,7 +81,10 @@ class _MihMineSweeperState extends State { List getToolTitle() { List toolTitles = [ - "MineSweeper", + "Minesweeper", + "Leader Board", + "My Scores", + "Guide", ]; return toolTitles; } @@ -65,6 +92,9 @@ class _MihMineSweeperState extends State { List getToolBody() { List toolBodies = [ const MineSweeperGame(), + const MihMineSweeperLeaderBoard(), + const MyScoreBoard(), + const MineSweeperQuickStartGuide(), ]; return toolBodies; } diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart index 81cab8fc..9654cfcb 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart @@ -24,10 +24,10 @@ class _MihMineSweeperTileState extends State { return MihPackageTile( onTap: () { context.goNamed( - "mihMineSweeper", + "mihMinesweeper", ); }, - appName: "MineSweeper", + appName: "Minesweeper", appIcon: Icon( MihIcons.mineSweeper, color: MihColors.getSecondaryColor( diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart new file mode 100644 index 00000000..5e3769c1 --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart @@ -0,0 +1,202 @@ +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:ken_logger/ken_logger.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_minesweeper_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; + +class MihMineSweeperLeaderBoard extends StatefulWidget { + const MihMineSweeperLeaderBoard({super.key}); + + @override + State createState() => + _MihMineSweeperLeaderBoardState(); +} + +class _MihMineSweeperLeaderBoardState extends State { + TextEditingController filterController = TextEditingController(); + + Future initialiseLeaderboard() async { + MihMineSweeperProvider mineSweeperProvider = + context.read(); + filterController.text = mineSweeperProvider.difficulty; + if (mineSweeperProvider.leaderboard == null || + mineSweeperProvider.leaderboard!.isEmpty) { + KenLogger.success("getting data"); + await MihMinesweeperServices().getTop20Leaderboard(mineSweeperProvider); + List?> userPictures = []; + String userPicUrl = ""; + for (final ranking in mineSweeperProvider.leaderboard!) { + userPicUrl = + await MihFileApi.getMinioFileUrl(ranking.proPicUrl, context); + userPictures.add(NetworkImage(userPicUrl)); + } + mineSweeperProvider.setLeaderboardUserPictures( + leaderboardUserPictures: userPictures); + } + } + + void refreshLeaderBoard( + MihMineSweeperProvider mineSweeperProvider, String difficulty) { + mineSweeperProvider.setDifficulty(difficulty); + mineSweeperProvider.setLeaderboard(leaderboard: null); + mineSweeperProvider.setMyScoreboard(myScoreboard: null); + initialiseLeaderboard(); + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + await initialiseLeaderboard(); + }); + } + + @override + Widget build(BuildContext context) { + final double width = MediaQuery.sizeOf(context).width; + return Consumer( + builder: (BuildContext context, + MihMineSweeperProvider mineSweeperProvider, Widget? child) { + return RefreshIndicator( + onRefresh: () async { + refreshLeaderBoard(mineSweeperProvider, filterController.text); + }, + child: MihPackageToolBody( + borderOn: false, + bodyItem: getBody(width), + ), + ); + }, + ); + } + + Widget getBody(double width) { + return Consumer( + builder: (BuildContext context, + MihMineSweeperProvider mineSweeperProvider, Widget? child) { + if (mineSweeperProvider.leaderboard == null) { + return Center( + child: Mihloadingcircle(), + ); + } else { + return SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: Column( + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + child: MihDropdownField( + controller: filterController, + hintText: "Leaderboards", + dropdownOptions: const [ + "Very Easy", + "Easy", + "Intermediate", + "Hard", + ], + requiredText: true, + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + onSelected: (selection) { + refreshLeaderBoard(mineSweeperProvider, selection!); + }, + ), + ), + ], + ), + ), + const SizedBox(height: 10), + mineSweeperProvider.leaderboard!.isEmpty + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.mineSweeper, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + const SizedBox(height: 10), + Text( + "Be the first on the leaderboard.", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + const SizedBox(height: 25), + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + children: [ + TextSpan(text: "Press "), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + FontAwesomeIcons.bomb, + size: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + TextSpan(text: " and start a new game"), + ], + ), + ), + ), + ], + ), + ) + : BuildMinesweeperLeaderboardList(), + ], + ), + ); + } + }, + ); + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart index 01b16f05..6933b0b1 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart @@ -1,22 +1,26 @@ +import 'dart:async'; import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_banner_ad.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_banner_ad_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/components/board_square.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/components/mih_mine_sweeper_start_game_window.dart'; import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/components/mine_tile.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_minesweeper_services.dart'; import 'package:provider/provider.dart'; class MineSweeperGame extends StatefulWidget { @@ -27,92 +31,115 @@ class MineSweeperGame extends StatefulWidget { } class _MineSweeperGameState extends State { - TextEditingController modeController = TextEditingController(); - final _formKey = GlobalKey(); List> board = []; bool isGameOver = false; bool isGameWon = false; int squaresLeft = -1; - bool _isFirstLoad = true; + Timer? _timer; + int _milliseconds = 0; + bool _isRunning = false; + static const int millisecondsPerUpdate = 10; - String getModeConfig() { - switch (modeController.text) { - case ("Easy"): - return "Columns: 10\nRows: 10\nBomds: 15"; - case ("Normal"): - return "Columns: 10\nRows: 15\nBomds: 23"; - case ("Hard"): - return "Columns: 10\nRows: 20\nBomds: 30"; - default: - return "Error"; + double timeStringToTotalSeconds(String timeString) { + try { + List parts = timeString.split(':'); + if (parts.length < 4) { + return 0.0; + } + double hours = double.parse(parts[0]); + double minutes = double.parse(parts[1]); + double seconds = double.parse(parts[2]); + double milliseconds = double.parse(parts[3]); + double totalSeconds = + (hours * 3600) + (minutes * 60) + seconds + (milliseconds / 1000); + return totalSeconds; + } catch (e) { + print("Error parsing time string: $e"); + return 0.0; } } - void showStartGameWindow(MihMineSweeperProvider mihMineSweeperProvider) { + double calculateGameScore(MihMineSweeperProvider mihMineSweeperProvider) { + int scoreConst = 10000; + double dificusltyMultiplier; + switch (mihMineSweeperProvider.difficulty) { + case ("Very Easy"): + dificusltyMultiplier = 0.5; + break; + case ("Easy"): + dificusltyMultiplier = 1.0; + break; + case ("Intermediate"): + dificusltyMultiplier = 2.5; + break; + case ("Hard"): + dificusltyMultiplier = 5.0; + break; + default: + dificusltyMultiplier = 0.0; + break; + } + double rawScore = (scoreConst * dificusltyMultiplier) / + timeStringToTotalSeconds(_formatTime()); + + String scoreString = rawScore.toStringAsFixed(5); + return double.parse(scoreString); + } + + void startTimer() { + if (_isRunning) return; + _isRunning = true; + _timer = Timer.periodic(const Duration(milliseconds: millisecondsPerUpdate), + (timer) { + setState(() { + _milliseconds += millisecondsPerUpdate; // Increment by the interval + }); + }); + } + + void stopTimer() { + _timer?.cancel(); + setState(() { + _isRunning = false; + }); + } + + void resetTimer() { + stopTimer(); // Stop the timer first + setState(() { + _milliseconds = 0; // Reset the time to zero + }); + } + + String _formatTime() { + Duration duration = Duration(milliseconds: _milliseconds); + final int hours = duration.inHours.remainder(60); + final int minutes = duration.inMinutes.remainder(60); + final int seconds = duration.inSeconds.remainder(60); + final int centiseconds = (duration.inMilliseconds.remainder(1000)) ~/ 10; + String hoursStr = hours.toString().padLeft(2, '0'); + String minutesStr = minutes.toString().padLeft(2, '0'); + String secondsStr = seconds.toString().padLeft(2, '0'); + String centiStr = centiseconds.toString().padLeft(2, '0'); + return '$hoursStr:$minutesStr:$secondsStr:$centiStr'; + } + + void showStartGameWindow(MihMineSweeperProvider mihMineSweeperProvider, + MihBannerAdProvider addProvider) { // easy - 10 * 10 & 15 bombs - // Normal - 10 * 15 & 23 bombs + // Intermediate - 10 * 15 & 23 bombs // Hard - 10 * 20 & 30 bombs + addProvider.loadBannerAd(); showDialog( context: context, builder: (context) { - return MihPackageWindow( - fullscreen: false, - windowTitle: "New Game Settings", - onWindowTapClose: () { - context.pop(); + return MihMineSweeperStartGameWindow( + onPressed: () { + resetTimer(); + mihMineSweeperProvider + .setDifficulty(mihMineSweeperProvider.difficulty); + setState(() => initializeBoard(mihMineSweeperProvider)); }, - windowBody: Column( - children: [ - MihForm( - formKey: _formKey, - formFields: [ - MihDropdownField( - controller: modeController, - hintText: "Difficulty", - dropdownOptions: ["Easy", "Normal", "Hard"], - requiredText: true, - editable: true, - enableSearch: false, - ), - const SizedBox(height: 10), - Text( - getModeConfig(), - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 25), - Center( - child: MihButton( - onPressed: () { - setState( - () => initializeBoard(mihMineSweeperProvider)); - Navigator.of(context).pop(); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Start Game", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), - ], - ), ); }); } @@ -137,6 +164,7 @@ class _MineSweeperGameState extends State { isGameOver = false; isGameWon = false; // You'd typically add a call to setState here, but it's in initState. + startTimer(); } void placeBombs(MihMineSweeperProvider mihMineSweeperProvider) { @@ -213,12 +241,18 @@ class _MineSweeperGameState extends State { } } - void handleTap(MihMineSweeperProvider mihMineSweeperProvider, int r, int c) { + Future handleTap( + MzansiProfileProvider profileProvider, + MihMineSweeperProvider mihMineSweeperProvider, + MihBannerAdProvider adProvider, + int r, + int c) async { if (isGameOver || board[r][c].isOpened || board[r][c].isFlagged) { return; } // 1. Check for bomb (LOSS) if (board[r][c].hasBomb) { + stopTimer(); setState(() { board[r][c].isOpened = true; isGameOver = true; @@ -227,19 +261,34 @@ class _MineSweeperGameState extends State { context: context, builder: (context) { return MihPackageAlert( - alertIcon: Icon( - FontAwesomeIcons.bomb, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - size: 100, + alertIcon: Padding( + padding: const EdgeInsets.all(8.0), + child: Icon( + FontAwesomeIcons.bomb, + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + size: 100, + ), ), alertTitle: "Better Luck Next Time", alertBody: Column( children: [ Text( "Your lost this game of MIH MineSweeper!!!", + textAlign: TextAlign.center, style: TextStyle( - fontSize: 15, + fontSize: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + const SizedBox(height: 10), + Text( + "Please feel free to start a New Game or check out the Leader Board to find out who's the best in Mzansi.", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 18, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -254,9 +303,9 @@ class _MineSweeperGameState extends State { children: [ MihButton( onPressed: () { - setState( - () => initializeBoard(mihMineSweeperProvider)); - Navigator.of(context).pop(); + context.pop(); + showStartGameWindow( + mihMineSweeperProvider, adProvider); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == @@ -273,6 +322,26 @@ class _MineSweeperGameState extends State { ), ), ), + MihButton( + onPressed: () { + context.pop(); + mihMineSweeperProvider.setToolIndex(1); + }, + buttonColor: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Leader Board", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), ], ), ], @@ -295,7 +364,7 @@ class _MineSweeperGameState extends State { squaresLeft--; } // 3. Check for win - _checkWinCondition(mihMineSweeperProvider); + _checkWinCondition(profileProvider, mihMineSweeperProvider, adProvider); // Update the UI setState(() {}); } @@ -311,9 +380,14 @@ class _MineSweeperGameState extends State { } // --- GAME ACTION LOGIC --- - void _checkWinCondition(MihMineSweeperProvider mihMineSweeperProvider) { + Future _checkWinCondition( + MzansiProfileProvider profileProvider, + MihMineSweeperProvider mihMineSweeperProvider, + MihBannerAdProvider adProvider, + ) async { // Game is won if all non-mine squares are opened. if (squaresLeft <= mihMineSweeperProvider.totalMines) { + stopTimer(); isGameWon = true; isGameOver = true; // win alert @@ -327,13 +401,41 @@ class _MineSweeperGameState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), size: 100, ), - alertTitle: "Congradulations", + alertTitle: "Congratulations", alertBody: Column( children: [ Text( "Your won this game of MIH MineSweeper!!!", + textAlign: TextAlign.center, style: TextStyle( - fontSize: 15, + fontSize: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + const SizedBox(height: 10), + // Text( + // "You took ${_formatTime()} to complete the game on ${mihMineSweeperProvider.difficulty} mode.", + // style: TextStyle( + // fontSize: 15, + // color: MihColors.getSecondaryColor( + // MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // ), + // ), + // const SizedBox(height: 10), + Text( + "Time Taken: ${_formatTime().replaceAll("00:", "")}", + style: TextStyle( + fontSize: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + const SizedBox(height: 10), + Text( + "Score: ${calculateGameScore(mihMineSweeperProvider)}", + style: TextStyle( + fontSize: 20, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), @@ -347,8 +449,8 @@ class _MineSweeperGameState extends State { children: [ MihButton( onPressed: () { - setState(() => initializeBoard(mihMineSweeperProvider)); - Navigator.of(context).pop(); + context.pop(); + showStartGameWindow(mihMineSweeperProvider, adProvider); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == @@ -365,6 +467,26 @@ class _MineSweeperGameState extends State { ), ), ), + MihButton( + onPressed: () { + context.pop(); + mihMineSweeperProvider.setToolIndex(1); + }, + buttonColor: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Leader Board", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), ], ), ], @@ -374,17 +496,35 @@ class _MineSweeperGameState extends State { ); }, ); + showDialog( + context: context, + builder: (context) { + return Mihloadingcircle( + message: "Uploading your score", + ); + }); + await MihMinesweeperServices().addPlayerScore( + profileProvider, + mihMineSweeperProvider, + _formatTime().replaceAll("00:", ""), + calculateGameScore(mihMineSweeperProvider), + ); + context.pop(); } } - Color? getDifficultyColor() { - String mode = modeController.text; + Color? getDifficultyColor(MihMineSweeperProvider mihMineSweeperProvider) { + String mode = mihMineSweeperProvider.difficulty; switch (mode) { - case "Easy": + case "Very Easy": return MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark", ); - case "Normal": + case "Easy": + return MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark", + ); + case "Intermediate": return MihColors.getOrangeColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark", ); @@ -398,42 +538,33 @@ class _MineSweeperGameState extends State { } @override - void initState() { - super.initState(); - modeController.text = "Easy"; - // showStartGameWindow(context.read()); - // initializeBoard(); + void dispose() { + _timer?.cancel(); + super.dispose(); } @override - void didChangeDependencies() { - super.didChangeDependencies(); - // This method is safe for calling showDialog or reading provider values. - if (_isFirstLoad) { - // 1. Get the provider safely. - WidgetsBinding.instance.addPostFrameCallback((_) { - final mihMineSweeperProvider = context.read(); - // board = List.generate( - // mihMineSweeperProvider.rowCount, - // (i) => List.generate( - // mihMineSweeperProvider.columnCount, - // (j) => BoardSquare(), - // ), - // ); - // 2. Show the dialog to get initial game settings. - // The user selection in the dialog will call initializeBoard(). - showStartGameWindow(mihMineSweeperProvider); - }); - // 3. Set flag to prevent showing the dialog on subsequent dependency changes - _isFirstLoad = false; - } + void initState() { + // UBongani was here during the MIH Live + super.initState(); } @override Widget build(BuildContext context) { - return Consumer( + return MihPackageToolBody( + borderOn: false, + bodyItem: getBody(), + ); + } + + Widget getBody() { + return Consumer3( builder: (BuildContext context, - MihMineSweeperProvider mihMineSweeperProvider, Widget? child) { + MzansiProfileProvider profileProvider, + MihMineSweeperProvider mihMineSweeperProvider, + MihBannerAdProvider adProvider, + Widget? child) { return Stack( alignment: Alignment.topCenter, children: [ @@ -456,7 +587,7 @@ class _MineSweeperGameState extends State { ), const SizedBox(height: 10), Text( - "Welcom to MIH MineSweeper, the first game of MIH.", + "Welcom to Minesweeper, the first game of MIH.", textAlign: TextAlign.center, overflow: TextOverflow.visible, style: TextStyle( @@ -495,7 +626,9 @@ class _MineSweeperGameState extends State { "Dark"), ), ), - TextSpan(text: " to start a new game."), + TextSpan( + text: + " to start a new game or learn how to play the minesweeper."), ], ), ), @@ -514,7 +647,8 @@ class _MineSweeperGameState extends State { children: [ Expanded( child: Padding( - padding: const EdgeInsets.all(10.0), + padding: const EdgeInsets.symmetric( + horizontal: 10.0), child: Text( 'Mines: ${mihMineSweeperProvider.totalMines}', textAlign: TextAlign.left, @@ -526,20 +660,29 @@ class _MineSweeperGameState extends State { ), Expanded( child: Padding( - padding: const EdgeInsets.all(10.0), + padding: const EdgeInsets.symmetric( + horizontal: 10.0), child: Text( - modeController.text, + _formatTime().replaceAll("00:", ""), textAlign: TextAlign.right, - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: getDifficultyColor(), - ), + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold), ), ), ), ], ), + Text( + mihMineSweeperProvider.difficulty, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: getDifficultyColor(mihMineSweeperProvider), + ), + ), + // const SizedBox( // height: 30, // ), @@ -571,13 +714,16 @@ class _MineSweeperGameState extends State { return MineTile( square: board[r][c], - onTap: () => - handleTap(mihMineSweeperProvider, r, c), + onTap: () => handleTap(profileProvider, + mihMineSweeperProvider, adProvider, r, c), onLongPress: () => handleLongPress(r, c), ); }, ), ), + SizedBox(height: 30), + MihBannerAd(), + // const SizedBox(height: 100), ], ), ), @@ -587,6 +733,30 @@ class _MineSweeperGameState extends State { child: MihFloatingMenu( animatedIcon: AnimatedIcons.menu_close, children: [ + SpeedDialChild( + child: Icon( + Icons.add, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + label: "Learn how to play", + labelBackgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onTap: () { + mihMineSweeperProvider.setToolIndex(2); + }, + ), SpeedDialChild( child: Icon( Icons.add, @@ -610,9 +780,9 @@ class _MineSweeperGameState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - showStartGameWindow(mihMineSweeperProvider); + showStartGameWindow(mihMineSweeperProvider, adProvider); }, - ) + ), ]), ) ], diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart new file mode 100644 index 00000000..4079f2f0 --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart @@ -0,0 +1,279 @@ +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; + +class MineSweeperQuickStartGuide extends StatefulWidget { + const MineSweeperQuickStartGuide({super.key}); + + @override + State createState() => + _MineSweeperQuickStartGuideState(); +} + +class _MineSweeperQuickStartGuideState + extends State { + Widget _buildSectionTitle(String title) { + return Text( + title, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + ), + ); + } + + Widget _buildSubSectionTitle(String title) { + return Text( + title, + style: const TextStyle( + fontSize: 17, + fontWeight: FontWeight.w600, + ), + ); + } + + Widget _buildRulePoint({ + required String title, + required List points, + required Color color, + }) { + return Padding( + padding: const EdgeInsets.only(left: 8.0, top: 4.0, bottom: 4.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: color, + ), + ), + ...points + .map((point) => Padding( + padding: const EdgeInsets.only(left: 10.0), + child: Text( + '• $point', + style: const TextStyle(fontSize: 16), + ), + )) + .toList(), + ], + ), + ); + } + + Widget _buildNumberClue(String clue, String explanation) { + return Padding( + padding: const EdgeInsets.only(left: 8.0, bottom: 4.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('• ', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), + Expanded( + child: RichText( + text: TextSpan( + style: TextStyle( + fontSize: 16, + color: MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark")), + children: [ + TextSpan( + text: 'If you see a $clue: ', + style: const TextStyle(fontWeight: FontWeight.bold)), + TextSpan(text: explanation), + ], + ), + ), + ), + ], + ), + ); + } + + Widget _buildStrategyPoint(String title, String explanation, + {bool isAction = false}) { + return Padding( + padding: const EdgeInsets.only(left: 8.0, bottom: 4.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RichText( + text: TextSpan( + style: TextStyle( + fontSize: 16, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark")), + children: [ + TextSpan( + text: title, + style: TextStyle( + fontWeight: isAction ? FontWeight.bold : FontWeight.normal, + color: isAction + ? MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark") + : MihColors.getPurpleColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Dark"), + ), + ), + TextSpan(text: isAction ? ' $explanation' : ': $explanation'), + ], + ), + ), + ], + ), + ); + } + + Widget _buildTipPoint(String title, String explanation) { + return Padding( + padding: const EdgeInsets.only(left: 8.0, bottom: 4.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('• ', + style: TextStyle( + fontSize: 18, + color: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark"), + fontWeight: FontWeight.bold)), + Expanded( + child: RichText( + text: TextSpan( + style: TextStyle( + fontSize: 16, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark")), + children: [ + TextSpan( + text: title, + style: const TextStyle(fontWeight: FontWeight.bold)), + TextSpan(text: explanation), + ], + ), + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + final Size size = MediaQuery.sizeOf(context); + final double width = size.width; + return MihPackageToolBody( + borderOn: false, + bodyItem: getBody(width), + ); + } + + Widget getBody(double width) { + return MihSingleChildScroll( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: Column( + children: [ + const Text( + 'Simple Rules and Strategy', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 30, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + const Text( + 'Minesweeper is a puzzle game where you use numbers to figure out where the hidden bombs (mines) are located.', + style: TextStyle(fontSize: 16), + ), + const Divider(height: 30), + + // --- 1. Two Main Actions --- + _buildSectionTitle('1. Two Main Actions (Your Controls)'), + const SizedBox(height: 8), + _buildRulePoint( + title: 'Quick Tap (or Click): This is the Dig action.', + points: [ + 'Goal: To uncover a square and see a number clue.', + 'Risk: If you click a mine, the game ends!', + ], + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark"), + ), + _buildRulePoint( + title: + 'Tap and Hold (or Long Press): This is the Flag action (🚩).', + points: [ + 'Goal: To safely mark a square that you are **certain** is a mine.', + 'Benefit: You cannot accidentally click a square that is flagged.', + ], + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark"), + ), + const Divider(height: 30), + + // --- 2. The Golden Rule: Reading the Numbers --- + _buildSectionTitle('2. The Golden Rule: Reading the Numbers'), + const SizedBox(height: 8), + const Text( + 'The number tells you exactly how many mines are touching that square (including sides and corners).', + style: TextStyle(fontSize: 18, fontStyle: FontStyle.italic), + ), + const SizedBox(height: 8), + _buildNumberClue('Blank Space (a \'0\')', + 'Zero (0) mines are touching it. All surrounding squares are safe, and the game will open them for you automatically.'), + _buildNumberClue('\'1\'', + 'Only **one** mine is touching this square. You must find and flag that single mine.'), + _buildNumberClue('\'3\'', + 'Three mines are touching this square. You must find and flag all three.'), + const Divider(height: 30), + + // --- 3. The Winning Strategy --- + _buildSectionTitle('3. The Winning Strategy (The Deduction Loop)'), + const SizedBox(height: 8), + const Text( + 'The game is won by uncovering every single safe square and correctly flagging all the mines. Use this two-step loop to clear the board:', + style: TextStyle(fontSize: 18), + ), + const SizedBox(height: 8), + + _buildSubSectionTitle('A. Find the Mines (Where to Flag 🚩)'), + _buildStrategyPoint( + 'Look for a number that only has one choice for a mine.', + 'Example: If a \'1\' is touching only one hidden square, that hidden square **must** be the mine.'), + _buildStrategyPoint('Action:', + 'Tap and Hold to place a **Flag** on the square you are sure is a mine.', + isAction: true), + + const SizedBox(height: 12), + + _buildSubSectionTitle('B. Find the Safe Squares (Where to Dig)'), + _buildStrategyPoint( + 'Look for a number that has been \'satisfied\' by your flags.', + 'Example: You see a \'2\'. You have already placed two 🚩 flags touching it. The \'2\' is satisfied.'), + _buildStrategyPoint('Action:', + 'Quick Tap any of the remaining hidden squares touching that \'satisfied\' number. They **must be safe** because the mine requirement has already been met.', + isAction: true), + + const Divider(height: 30), + + // --- Key Beginner Tip --- + _buildSectionTitle('✨ Key Beginner Tips'), + _buildTipPoint('Start on the Edges and Corners:', + 'Numbers on the edge or corner of the board are easier to solve because they have fewer surrounding squares to check.'), + _buildTipPoint('Don\'t Guess:', + 'If you are down to two squares and either one could be the mine, look somewhere else on the board for a guaranteed, safe move.'), + ], + ), + ), + ); + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart new file mode 100644 index 00000000..eca9dd2f --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart @@ -0,0 +1,212 @@ +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:ken_logger/ken_logger.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/builders/build_my_scoreboard_list.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_minesweeper_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; + +class MyScoreBoard extends StatefulWidget { + const MyScoreBoard({super.key}); + + @override + State createState() => _MihMineSweeperLeaderBoardState(); +} + +class _MihMineSweeperLeaderBoardState extends State { + TextEditingController filterController = TextEditingController(); + + Future initialiseLeaderboard() async { + MzansiProfileProvider profileProvider = + context.read(); + MihMineSweeperProvider mineSweeperProvider = + context.read(); + filterController.text = mineSweeperProvider.difficulty; + if (mineSweeperProvider.myScoreboard == null || + mineSweeperProvider.myScoreboard!.isEmpty) { + KenLogger.success("getting data"); + await MihMinesweeperServices() + .getMyScoreboard(profileProvider, mineSweeperProvider); + KenLogger.success("${mineSweeperProvider.myScoreboard}"); + } + } + + void refreshLeaderBoard( + MihMineSweeperProvider mineSweeperProvider, String difficulty) { + mineSweeperProvider.setDifficulty(difficulty); + mineSweeperProvider.setLeaderboard(leaderboard: null); + mineSweeperProvider.setMyScoreboard(myScoreboard: null); + initialiseLeaderboard(); + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + await initialiseLeaderboard(); + }); + } + + @override + Widget build(BuildContext context) { + final double width = MediaQuery.sizeOf(context).width; + return Consumer( + builder: (BuildContext context, + MihMineSweeperProvider mineSweeperProvider, Widget? child) { + return RefreshIndicator( + onRefresh: () async { + refreshLeaderBoard(mineSweeperProvider, filterController.text); + }, + child: MihPackageToolBody( + borderOn: false, + bodyItem: getBody(width), + ), + ); + }, + ); + } + + Widget getBody(double width) { + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + MihMineSweeperProvider mineSweeperProvider, Widget? child) { + if (mineSweeperProvider.myScoreboard == null) { + return Center( + child: Mihloadingcircle(), + ); + } else { + return SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: Column( + children: [ + Center( + child: MihCircleAvatar( + imageFile: profileProvider.userProfilePicture, + width: 150, + editable: false, + fileNameController: null, + userSelectedfile: null, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onChange: (selectedImage) {}, + key: ValueKey(profileProvider.userProfilePicUrl), + ), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + child: MihDropdownField( + controller: filterController, + hintText: "Scoreboards", + dropdownOptions: const [ + "Very Easy", + "Easy", + "Intermediate", + "Hard", + ], + requiredText: true, + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + onSelected: (selection) { + refreshLeaderBoard(mineSweeperProvider, selection!); + }, + ), + ), + ], + ), + ), + const SizedBox(height: 10), + mineSweeperProvider.myScoreboard!.isEmpty + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.mineSweeper, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + const SizedBox(height: 10), + Text( + "You have played and ${mineSweeperProvider.difficulty} yet.", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + const SizedBox(height: 25), + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + children: [ + TextSpan(text: "Press "), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + FontAwesomeIcons.bomb, + size: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + TextSpan(text: " and start a new game"), + ], + ), + ), + ), + ], + ), + ) + : BuildMyScoreBoardList(), + ], + ), + ); + } + }, + ); + } +} diff --git a/Frontend/lib/mih_services/mih_minesweeper_services.dart b/Frontend/lib/mih_services/mih_minesweeper_services.dart new file mode 100644 index 00000000..6d5eb524 --- /dev/null +++ b/Frontend/lib/mih_services/mih_minesweeper_services.dart @@ -0,0 +1,80 @@ +import 'dart:convert'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/minesweeper_player_score.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:supertokens_flutter/http.dart' as http; + +class MihMinesweeperServices { + Future getTop20Leaderboard( + MihMineSweeperProvider mineSweeperProvider, + ) async { + String difficulty = mineSweeperProvider.difficulty; + var response = await http.get( + Uri.parse( + "${AppEnviroment.baseApiUrl}/minesweeper/leaderboard/top20/$difficulty"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + ); + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List leaderboard = + List.from( + l.map((model) => MinesweeperPlayerScore.fromJson(model))); + mineSweeperProvider.setLeaderboard(leaderboard: leaderboard); + } else { + mineSweeperProvider.setLeaderboard(leaderboard: null); + } + return response.statusCode; + } + + Future getMyScoreboard( + MzansiProfileProvider profileProvider, + MihMineSweeperProvider mineSweeperProvider, + ) async { + String difficulty = mineSweeperProvider.difficulty; + var response = await http.get( + Uri.parse( + "${AppEnviroment.baseApiUrl}/minesweeper/leaderboard/top_score/$difficulty/${profileProvider.user!.app_id}"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + ); + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List leaderboard = + List.from( + l.map((model) => MinesweeperPlayerScore.fromJson(model))); + mineSweeperProvider.setMyScoreboard(myScoreboard: leaderboard); + } else { + mineSweeperProvider.setMyScoreboard(myScoreboard: null); + } + return response.statusCode; + } + + Future addPlayerScore( + MzansiProfileProvider profileProvider, + MihMineSweeperProvider mineSweeperProvider, + String game_time, + double game_score, + ) async { + DateTime now = DateTime.now(); + String formattedDateTime = now.toString(); + var response = await http.post( + Uri.parse( + "${AppEnviroment.baseApiUrl}/minesweeper/leaderboard/player_score/insert/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "app_id": profileProvider.user!.app_id, + "difficulty": mineSweeperProvider.difficulty, + "game_time": game_time, + "game_score": game_score, + "played_date": formattedDateTime, + }), + ); + return response.statusCode; + } +} diff --git a/backend/.DS_Store b/backend/.DS_Store index 74465b9f37d4f3079203ee8e7c04443801d8f858..051f6a8cbd7f20dbeb4bf2d4e55cc55989e7065d 100644 GIT binary patch literal 10244 zcmeHMYitzP6~5mX?3rbNv11JEX1xo>ffxhEHW;vh^@~R^;IMx4Sa!WrJY~IOc6RL~ zE{WSpQCkxAnJDTbQhp>2eek1dBB~~B(<)Karaux9RFXE8+Nf%)HmcgF`O_ag_ug6X zuI;F8QqhVTY39ti_nbR>&V1*7bMG?7(2+}SWh~4XQ|aW=(CISI!Tb3+=TO`h-U;$& zEXm?5OJ{;k@9;9bg}cOnbf^9>Hzyf!<&2clok6-Y zxKD<=LVSe&oz}yV*veDT%v)CAm6|CPKW+tYbiA2gykj>@9M9Olq z4GmYJlq_0YTBeq%OVpFmF?%YSjc0RCM?7_(o-is;OGcST#M}($Z2NZf{+1Nn$P210(*VGj? zTUw9B&ZfrG_Ge^BaHj>fv?#<2?-yUnne3GDmH6}V{URTq=35dN9P*6}S)+D3YTakX zjO7jmc#zcIj5$ex4UXEW+<4lF8Ret#)Mzdh&zkM26gPH;vgSQmemCOSnQW&pj2TAG zF^`#KXHA-2WKFIWe59ijS<6m417^k{SrciHVQ8216~VQ4Y;4%JYj4-V!*^d|bka(n8KDfOv(`r}GozJbMC(h($IUB7)yh??{eeKS zb$*ngT*5k+v$FRZHL5C~5elr)jAzsnN&1n8?Ia&DDS85-K&`4C=k1*tldiJaw;@oc z8F97Gp^)Ven|xa|!_oTA(rcEkjlO2pNNWA5c*0D{rWW5$)i|ULPRht-W1DY}T8?^c zXw)7br+6IM+#cvujTh8Y{MkKmCwp|lOy_^qzQ6(1cv&5B#^M?C=oBGM`s@qzsH%8# z)Xtr{lUCNwh?E=&1p>o-u=ZrqOj6{ls#Y3-XrNy;ULzmFN>5sZZF(UR;%ZH#PQDkB zR;{uKYn;PYv$d?5wXt3{Ow}~S9%7HMN7<9?5_^_C$6jKuve($_>?(Vcz0Ll}-ev#5 zVw6FJh6>z<6{tcD>ahu%u?wB(!anRr5Bf2HAq?Xb&R`55#aW!geVE31+>ZzGS$qy( z#Fy|jJcY00BEEs|;m7z1Uc^gy6>s28{1WfrJq3!QlqkBgR9UVVN{zBk*`zcoO)?54 zUqQzUqf)v^UvP$?3UX%%<=lJ~6x_GpckrfG&^4XcOnJp^l`E=iHf(C#-Ws_MD+$Cr z_GV*Rz_hVll3GetAk{nT zfcoQ!7D zDLZ|JY&fvXSccgwN1M|o-8na%*qV3LhqpCt{eZ+)6xA#`Yswen8?)$4U+Nzi92gqb z=OvwgkKVZTXvR*ZdTqzzQ{?bZaf%>{F~aL#pTCgi#8}n-@LZbXJ^pI{x+0nr4(t7Q-k>?rQm=2m zL36@&tKKw==0wwWeMbS!iN;oacM;8r=7_&zKAIDK-TwW>H0QP-nwREy=!dKQ{sNj4 z9>@HB3({P^&1-rEpw{;V{@yX!?@mdT?F)>UKvrXaw%-|FFBtDHV5VJi(Q^VuL zY)^wG1w4Zv;D>mD7*2BAukaTBfWP8zcvmSUW?QZJl>l*Dt+HO(ptLG&O1E-Ei7F># zR15Ol$+^?SEOvW({(=e}IC$W$L;pVobuG_@RV%~1u6FG1_>kF+s|{O2y32-K-BwR3XG5;++@zuP`fl*b8=Es8un~_qu&_!&=lN8(Wr0{*k4Rmr_cQZ@eN8GjXMnq{ c1Gcv=&;BNw=&##3gN^yhL&7wx&Ev8@8nnO4r?;0VYgm%FgT- zY>M@l2Gqnq8sGnjiO+;bh>sus@PR)xA%uX@#AxJ~e=t!KF~)P}?h@M4ADU=D=O*`_ zIrp4%XU>`L+`DI%F@~1B(ZpCSV@#&bsix9!i^k==PisT2oXHD4L>JVnCRaJi^t9#*1`9P+`s>%o&PzMzKOc zaCfqc1nLZNLBlbOKp27P5#Z@lK~=lU^31=ves?n@IhPr+EzfUkyacJNeAes=xk6Uu zeaVCFXwpynd9Nj%+snCb*R?aH>vU$1Wsat_>V)g~Y0EKlfq`Y1q%zoRIfgsh;^rO0 z3v81@AS<$x(rU-XHZ*UHMb@ot8jnTBHmzxlMVi;HA0Job1<{7hyHkhkVaGi#96@n2 zU~{K9c4E3$wpU1GZ0=RrV9BemN?s{*RCTW2Kd^Uj-%v`^@}9Zdw9~#-Fk92U>7}&! z9yz%!>pERIvp~-EW?ef!?2x1~o3^ugQZ~2RcG7xOXlHY-ZFjkzN(?C7PI}n9SXH}d@!d;weX4e8 zmA-t&I-Ixsqgqs!#XaivsG^;b2Muzv!!`JdMj+Aa^%b(bm(M41CXHfRU8TnqEiHF@ z)^Ops@L^?zSvg7Fb(p2aqXfiy+`krwF_jUSx&(s#M6rqz?Y-(_K5&>(fBHXzNjFK z1%Zyn8wFoonl4g)(&?;`wXp4Mh>ftL>;!v`y~a+nGwdw;n0>)6v9H-xc8&eSerCV0 z>nO(@RAUL2VFgy=UaY}dtiyUFuoE5Fg#lz?U_TDPMjizm!BHH;6L=EGaRSfcMZAPp z@G4H?9lVQEIE@eS2|mSne2y#l4&UPkT*Wo~hU@rUnkUsr_0m!)D#fJLQiIeeC8SoV zL)s&yBtse&UPz_POHKApI!64I{e&`)z6bKmlTO__^Xl5SZQrr83&t!$|*U8Y|BH$ zGQM93KG8}m@l=!lDafB^7uaR?E&Gum{|Cw-qXrQyM~oo81#yCTE7}O=UD%Bzy0H%_ zq>&-e+i);~!^mL_<9G}cc$^^r6rRR2cpfhh>|Z9}pTz5U18?FjoW(i3hxhS8kN{ue zGQPppDS+NJ8PNE3I-m>5oMXGr0g{x`V6xF2!j*~VtmXB8+sxnp?+|ao#|$G7M&R#6 z0OhU8))umyX*ZKd7NPzKb>6t%grI>54P1rK2jw`?8-Ezmb)+bZ7wLqcB%$`Ne+Vf4 VDE}+Jyu" ) + class UserConsent(Base): __tablename__ = 'user_consent' __table_args__ = {'schema': 'app_data'} @@ -97,4 +98,24 @@ class UserConsent(Base): f"app_id='{self.app_id}', " f"privacy_policy_accepted='{self.privacy_policy_accepted}', " f"terms_of_services_accepted='{self.terms_of_services_accepted}')>" + ) + +class MineSweeperLeaderboard(Base): + __tablename__ = 'player_score' + __table_args__ = {'schema': 'minesweeper_leaderboard'} + idplayer_score = Column(Integer, primary_key=True) + app_id = Column(String(128), nullable=False,server_default=text("''")) + difficulty = Column(String(45), nullable=False,server_default=text("''")) + game_time = Column(String(45), nullable=False,server_default=text("''")) + game_score = Column(DECIMAL(45), nullable=False) + played_date = Column(DateTime, nullable=True) + + def __repr__(self): + return ( + f"" ) \ No newline at end of file diff --git a/backend/routers/mine_sweeper_leaderboard.py b/backend/routers/mine_sweeper_leaderboard.py new file mode 100644 index 00000000..1a665abe --- /dev/null +++ b/backend/routers/mine_sweeper_leaderboard.py @@ -0,0 +1,171 @@ +from fastapi import APIRouter, HTTPException, status +from pydantic import BaseModel +from supertokens_python.recipe.session.framework.fastapi import verify_session +from supertokens_python.recipe.session import SessionContainer +from fastapi import Depends +import mih_database +import mih_database.mihDbConnections +from mih_database.mihDbObjects import MineSweeperLeaderboard, User +from sqlalchemy import and_, func, literal_column +from sqlalchemy.orm import Session, aliased +from sqlalchemy.exc import IntegrityError, SQLAlchemyError +from datetime import datetime +from sqlalchemy.sql.expression import select + +router = APIRouter() + +class playerScoreInsertRequest(BaseModel): + app_id: str + difficulty: str + game_time: str + game_score: float + played_date: datetime + +# get top 20 scores +@router.get("/minesweeper/leaderboard/top20/{difficulty}", tags=["Minesweeper"]) +async def get_user_consent(difficulty: str, session: SessionContainer = Depends(verify_session())):#session: SessionContainer = Depends(verify_session()) + dbEngine = mih_database.mihDbConnections.dbAllConnect() + dbSession = Session(dbEngine) + try: + max_score_subquery = ( + dbSession.query( + MineSweeperLeaderboard.app_id, + func.max(MineSweeperLeaderboard.game_score).label('max_score') + ) + .filter(MineSweeperLeaderboard.difficulty == difficulty) + .group_by(MineSweeperLeaderboard.app_id) + .subquery('max_scores') + ) + queryResults = ( + dbSession.query(MineSweeperLeaderboard, User) + .join(User, User.app_id == MineSweeperLeaderboard.app_id) + .join( + max_score_subquery, + and_( + MineSweeperLeaderboard.app_id == max_score_subquery.c.app_id, + MineSweeperLeaderboard.game_score == max_score_subquery.c.max_score + ) + ) + .filter(MineSweeperLeaderboard.difficulty == difficulty) + .order_by(MineSweeperLeaderboard.game_score.desc()) + .limit(20) + .all() + ) + leaderboardData = [] + if queryResults: + for playerScore, user in queryResults: + leaderboardData.append({ + "app_id": playerScore.app_id, + "username": user.username, + "proPicUrl":user.pro_pic_path, + "difficulty":playerScore.difficulty, + "game_time":playerScore.game_time, + "game_score":playerScore.game_score, + "played_date":playerScore.played_date, + }) + return leaderboardData + else: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="No Score available for user." + ) + except HTTPException as http_exc: + raise http_exc + except Exception as e: + print(f"An error occurred during the ORM query: {e}") + if dbSession.is_active: + dbSession.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Failed to retrieve records due to an internal server error." + ) + finally: + dbSession.close() + +@router.get("/minesweeper/leaderboard/top_score/{difficulty}/{app_id}", tags=["Minesweeper"]) +async def get_user_consent(app_id: str, + difficulty: str, + session: SessionContainer = Depends(verify_session())):#session: SessionContainer = Depends(verify_session()) + dbEngine = mih_database.mihDbConnections.dbAllConnect() + dbSession = Session(dbEngine) + try: + queryResults =(dbSession.query(MineSweeperLeaderboard, User) + .join(User, User.app_id == MineSweeperLeaderboard.app_id) + .filter( + and_( + MineSweeperLeaderboard.app_id == app_id, + MineSweeperLeaderboard.difficulty == difficulty + ) + ) + .order_by(MineSweeperLeaderboard.game_score.desc()) + .all()) + if not queryResults: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="No scores found for this user and difficulty level." + ) + leaderboard_data = [] + for player_score, user in queryResults: + score_data = { + "app_id": player_score.app_id, + "username": user.username, + "proPicUrl": user.pro_pic_path, + "difficulty": player_score.difficulty, + "game_time": player_score.game_time, + "game_score": player_score.game_score, + "played_date": player_score.played_date, + } + leaderboard_data.append(score_data) + return leaderboard_data + except HTTPException as http_exc: + raise http_exc + except Exception as e: + print(f"An error occurred during the ORM query: {e}") + if dbSession.is_active: + dbSession.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Failed to retrieve records due to an internal server error." + ) + finally: + dbSession.close() + +@router.post("/minesweeper/leaderboard/player_score/insert/", + tags=["Minesweeper"], + status_code=status.HTTP_201_CREATED) +async def insert_user_consent(itemRequest: playerScoreInsertRequest, + session: SessionContainer = Depends(verify_session())):#session: SessionContainer = Depends(verify_session()) + dbEngine = mih_database.mihDbConnections.dbAllConnect() + dbSession = Session(dbEngine) + try: + newPlayerScore = MineSweeperLeaderboard( + app_id = itemRequest.app_id, + difficulty = itemRequest.difficulty, + game_time = itemRequest.game_time, + game_score = itemRequest.game_score, + played_date = itemRequest.played_date, + ) + dbSession.add(newPlayerScore) + dbSession.commit() + dbSession.refresh(newPlayerScore) + return {"message": "Successfully Created Player Score Record"} + except IntegrityError as e: + dbSession.rollback() + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, # 409 Conflict is often suitable for constraint errors + detail=f"Data integrity error: The provided data violates a database constraint. Details: {e.orig}" + ) from e + except SQLAlchemyError as e: + dbSession.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"A database error occurred during insertion. Details: {e.orig}" + ) from e + except Exception as e: + dbSession.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"An unexpected error occurred: {e}" + ) from e + finally: + dbSession.close() From 79ed959b42b0502f07660178797d9efb7bab9d87 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 29 Oct 2025 13:17:05 +0200 Subject: [PATCH 37/45] BUG: Dropdown search text disabled --- .../mih_package_components/mih_dropdwn_field.dart | 6 ++++-- .../package_tools/mih_mine_sweeper_leader_board.dart | 2 +- .../mine_sweeper/package_tools/my_score_board.dart | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart b/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart index 8bb9a88d..9c0d6154 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart @@ -119,8 +119,10 @@ class _MihDropdownFieldState extends State { enableSearch: widget.enableSearch, enableFilter: widget.enableSearch, enabled: widget.editable, - textInputAction: TextInputAction.search, - requestFocusOnTap: true, + textInputAction: widget.enableSearch + ? TextInputAction.search + : TextInputAction.none, + requestFocusOnTap: widget.enableSearch, menuHeight: 400, expandedInsets: EdgeInsets.zero, textStyle: TextStyle( diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart index 5e3769c1..c851e5e7 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart @@ -112,7 +112,7 @@ class _MihMineSweeperLeaderBoardState extends State { ], requiredText: true, editable: true, - enableSearch: true, + enableSearch: false, validator: (value) { return MihValidationServices().isEmpty(value); }, diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart index eca9dd2f..df4b9d57 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart @@ -122,7 +122,7 @@ class _MihMineSweeperLeaderBoardState extends State { ], requiredText: true, editable: true, - enableSearch: true, + enableSearch: false, validator: (value) { return MihValidationServices().isEmpty(value); }, From 99d0fa4aa869056277a6ac71f4ebb006318e391c Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 29 Oct 2025 13:59:09 +0200 Subject: [PATCH 38/45] NEW: Patient Manager Provider Setup pt2 --- .../patient_manager_provider.dart | 8 + .../components/claim_statement_window.dart | 706 +++++++++--------- .../build_claim_statement_files_list.dart | 323 ++++---- .../patient_claim_or_statement.dart | 159 ++-- .../pat_profile/patient_profile.dart | 13 +- ...h_claim_statement_generation_services.dart | 23 +- 6 files changed, 603 insertions(+), 629 deletions(-) diff --git a/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart b/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart index a0d10806..308fbe3c 100644 --- a/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/claim_statement_file.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/files.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/notes.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; @@ -11,6 +12,7 @@ class PatientManagerProvider extends ChangeNotifier { Patient? selectedPatient; List? consultationNotes; List? patientDocuments; + List? patientClaimsDocuments; PatientManagerProvider({ this.patientProfileIndex = 0, @@ -60,4 +62,10 @@ class PatientManagerProvider extends ChangeNotifier { this.patientDocuments = patientDocuments ?? []; notifyListeners(); } + + void setClaimsDocuments( + {required List? patientClaimsDocuments}) { + this.patientClaimsDocuments = patientClaimsDocuments ?? []; + notifyListeners(); + } } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/components/claim_statement_window.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/claim_statement_window.dart index d6f499df..aec587b9 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/components/claim_statement_window.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/components/claim_statement_window.dart @@ -1,5 +1,8 @@ import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_claim_statement_generation_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_icd10_code_services.dart'; @@ -12,29 +15,16 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/icd10_code.dart.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/components/icd10_search_window.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; class ClaimStatementWindow extends StatefulWidget { - final Patient selectedPatient; - final AppUser signedInUser; - final Business? business; - final BusinessUser? businessUser; - final String env; const ClaimStatementWindow({ super.key, - required this.selectedPatient, - required this.signedInUser, - required this.business, - required this.businessUser, - required this.env, }); @override @@ -83,326 +73,356 @@ class _ClaimStatementWindowState extends State { } Widget getWindowBody(double width) { - return Padding( - padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.05) - : const EdgeInsets.symmetric(horizontal: 0), - child: Column( - children: [ - MihForm( - formKey: _formKey, - formFields: [ - MihRadioOptions( - controller: _docTypeController, - hintText: "Document Type", - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - secondaryFillColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - requiredText: true, - radioOptions: const ["Claim", "Statement"], - ), - const SizedBox(height: 10), - Center( - child: Text( - "Service Details", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - ), - Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark")), - const SizedBox(height: 10), - MihDateField( - controller: _serviceDateController, - labelText: "Date of Service", - required: true, - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - MihRadioOptions( - controller: _serviceDescController, - hintText: "Serviced Description", - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - secondaryFillColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - requiredText: true, - radioOptions: const [ - "Consultation", - "Procedure", - "Other", - ], - ), - const SizedBox(height: 10), - ValueListenableBuilder( - valueListenable: serviceDesc, - builder: (BuildContext context, String value, Widget? child) { - Widget returnWidget; - switch (value) { - case 'Consultation': - returnWidget = Column( - key: const ValueKey('consultation_fields'), // Added key - children: [ - MihRadioOptions( - key: const ValueKey('consultation_type_dropdown'), - controller: _serviceDescOptionsController, - hintText: "Consultation Type", - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - secondaryFillColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - requiredText: true, - radioOptions: const [ - "General Consultation", - "Follow-Up Consultation", - "Specialist Consultation", - "Emergency Consultation", - ], - ), - const SizedBox(height: 10), - ], - ); - break; - case 'Procedure': - returnWidget = Column( - key: const ValueKey('procedure_fields'), // Added key - children: [ - MihTextFormField( - key: const ValueKey( - 'procedure_name_field'), // Added key - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: _prcedureNameController, - multiLineInput: false, - requiredText: true, - hintText: "Procedure Name", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - key: const ValueKey( - 'procedure_additional_info_field'), // Added key - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: _proceedureAdditionalInfoController, - multiLineInput: false, - requiredText: true, - hintText: "Additional Procedure Information", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 15), - ], - ); - break; - case 'Other': - returnWidget = Column( - key: const ValueKey('other_fields'), // Added key - children: [ - MihTextFormField( - key: const ValueKey( - 'other_service_description_field'), // Added key - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: _serviceDescOptionsController, - multiLineInput: false, - requiredText: true, - hintText: "Service Description Details", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - ], - ); - break; - default: - returnWidget = const SizedBox( - key: const ValueKey('empty_fields')); // Added key - } - return returnWidget; - }, - ), - Column( - children: [ - Align( - alignment: Alignment.centerLeft, - child: Text("ICD-10 Code & Description", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - )), - ), - const SizedBox(height: 4), - MihSearchBar( - controller: _icd10CodeController, - hintText: "ICD-10 Search", - prefixIcon: Icons.search, + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Widget? child) { + return Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.05) + : const EdgeInsets.symmetric(horizontal: 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihRadioOptions( + controller: _docTypeController, + hintText: "Document Type", fillColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - hintColor: MihColors.getPrimaryColor( + secondaryFillColor: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onPrefixIconTap: () { - MIHIcd10CodeApis.getIcd10Codes( - _icd10CodeController.text, context) - .then((result) { - icd10SearchWindow(result); - }); - }, - onClearIconTap: () { - _icd10CodeController.clear(); - }, - searchFocusNode: _searchFocusNode, + requiredText: true, + radioOptions: const ["Claim", "Statement"], ), - ], - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: _amountController, - multiLineInput: false, - requiredText: true, - numberMode: true, - hintText: "Service Cost", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - Center( - child: Text( - "Additional Infomation", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - ), - Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark")), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: _preauthNoController, - multiLineInput: false, - requiredText: false, - hintText: "Pre-authorisation No.", - ), - const SizedBox(height: 20), - Center( - child: MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - if (isInputValid()) { - MIHClaimStatementGenerationApi().generateClaimStatement( - ClaimStatementGenerationArguments( - _docTypeController.text, - widget.selectedPatient.app_id, - _fullNameController.text, - _idController.text, - _medAidController.text, - _medAidNoController.text, - _medAidCodeController.text, - _medAidNameController.text, - _medAidSchemeController.text, - widget.business!.Name, - "*To-Be Added*", - widget.business!.contact_no, - widget.business!.bus_email, - _providerNameController.text, - _practiceNoController.text, - _vatNoController.text, - _serviceDateController.text, - _serviceDescController.text, - _serviceDescOptionsController.text, - _prcedureNameController.text, - _proceedureAdditionalInfoController.text, - _icd10CodeController.text, - _amountController.text, - _preauthNoController.text, - widget.business!.logo_path, - widget.businessUser!.sig_path, - ), - PatientViewArguments( - widget.signedInUser, - widget.selectedPatient, - widget.businessUser, - widget.business, - "business", - ), - widget.env, - context); - } else { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage( - errorType: "Input Error"); - }, - ); - } - } else { - MihAlertServices().formNotFilledCompletely(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 300, - child: Text( - "Generate", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, + const SizedBox(height: 10), + Center( + child: Text( + "Service Details", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), ), ), - ), + Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark")), + const SizedBox(height: 10), + MihDateField( + controller: _serviceDateController, + labelText: "Date of Service", + required: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihRadioOptions( + controller: _serviceDescController, + hintText: "Serviced Description", + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + secondaryFillColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + requiredText: true, + radioOptions: const [ + "Consultation", + "Procedure", + "Other", + ], + ), + const SizedBox(height: 10), + ValueListenableBuilder( + valueListenable: serviceDesc, + builder: + (BuildContext context, String value, Widget? child) { + Widget returnWidget; + switch (value) { + case 'Consultation': + returnWidget = Column( + key: const ValueKey( + 'consultation_fields'), // Added key + children: [ + MihRadioOptions( + key: const ValueKey( + 'consultation_type_dropdown'), + controller: _serviceDescOptionsController, + hintText: "Consultation Type", + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + secondaryFillColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + requiredText: true, + radioOptions: const [ + "General Consultation", + "Follow-Up Consultation", + "Specialist Consultation", + "Emergency Consultation", + ], + ), + const SizedBox(height: 10), + ], + ); + break; + case 'Procedure': + returnWidget = Column( + key: + const ValueKey('procedure_fields'), // Added key + children: [ + MihTextFormField( + key: const ValueKey( + 'procedure_name_field'), // Added key + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + controller: _prcedureNameController, + multiLineInput: false, + requiredText: true, + hintText: "Procedure Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + key: const ValueKey( + 'procedure_additional_info_field'), // Added key + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + controller: _proceedureAdditionalInfoController, + multiLineInput: false, + requiredText: true, + hintText: "Additional Procedure Information", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 15), + ], + ); + break; + case 'Other': + returnWidget = Column( + key: const ValueKey('other_fields'), // Added key + children: [ + MihTextFormField( + key: const ValueKey( + 'other_service_description_field'), // Added key + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + controller: _serviceDescOptionsController, + multiLineInput: false, + requiredText: true, + hintText: "Service Description Details", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + ], + ); + break; + default: + returnWidget = const SizedBox( + key: const ValueKey('empty_fields')); // Added key + } + return returnWidget; + }, + ), + Column( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text("ICD-10 Code & Description", + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + )), + ), + const SizedBox(height: 4), + MihSearchBar( + controller: _icd10CodeController, + hintText: "ICD-10 Search", + prefixIcon: Icons.search, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + hintColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onPrefixIconTap: () { + MIHIcd10CodeApis.getIcd10Codes( + _icd10CodeController.text, context) + .then((result) { + icd10SearchWindow(result); + }); + }, + onClearIconTap: () { + _icd10CodeController.clear(); + }, + searchFocusNode: _searchFocusNode, + ), + ], + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + controller: _amountController, + multiLineInput: false, + requiredText: true, + numberMode: true, + hintText: "Service Cost", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + Center( + child: Text( + "Additional Infomation", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + ), + Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark")), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + controller: _preauthNoController, + multiLineInput: false, + requiredText: false, + hintText: "Pre-authorisation No.", + ), + const SizedBox(height: 20), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + if (isInputValid()) { + MIHClaimStatementGenerationApi() + .generateClaimStatement( + profileProvider, + patientManagerProvider, + ClaimStatementGenerationArguments( + _docTypeController.text, + patientManagerProvider + .selectedPatient!.app_id, + _fullNameController.text, + _idController.text, + _medAidController.text, + _medAidNoController.text, + _medAidCodeController.text, + _medAidNameController.text, + _medAidSchemeController.text, + profileProvider.business!.Name, + "*To-Be Added*", + profileProvider.business!.contact_no, + profileProvider.business!.bus_email, + _providerNameController.text, + _practiceNoController.text, + _vatNoController.text, + _serviceDateController.text, + _serviceDescController.text, + _serviceDescOptionsController.text, + _prcedureNameController.text, + _proceedureAdditionalInfoController.text, + _icd10CodeController.text, + _amountController.text, + _preauthNoController.text, + profileProvider.business!.logo_path, + profileProvider.businessUser!.sig_path, + ), + AppEnviroment.getEnv(), + context); + } else { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage( + errorType: "Input Error"); + }, + ); + } + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Generate", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], ), ], ), - ], - ), + ); + }, ); } @@ -457,11 +477,11 @@ class _ClaimStatementWindowState extends State { return true; } - String getUserTitle() { - if (widget.businessUser!.title == "Doctor") { + String getUserTitle(MzansiProfileProvider profileProvider) { + if (profileProvider.businessUser!.title == "Doctor") { return "Dr."; } else { - return widget.businessUser!.title; + return profileProvider.businessUser!.title; } } @@ -500,24 +520,32 @@ class _ClaimStatementWindowState extends State { @override void initState() { super.initState(); - + PatientManagerProvider patientManagerProvider = + context.read(); + MzansiProfileProvider profileProvider = + context.read(); _serviceDescController.text = "Consultation"; _serviceDescController.addListener(serviceDescriptionSelected); serviceDesc.value = "Consultation"; _medAidController.addListener(hasMedAid); _fullNameController.text = - "${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}"; - _idController.text = widget.selectedPatient.id_no; - _medAidController.text = widget.selectedPatient.medical_aid; - _medAidNameController.text = widget.selectedPatient.medical_aid_name; - _medAidCodeController.text = widget.selectedPatient.medical_aid_code; - _medAidNoController.text = widget.selectedPatient.medical_aid_no; - _medAidSchemeController.text = widget.selectedPatient.medical_aid_scheme; + "${patientManagerProvider.selectedPatient!.first_name} ${patientManagerProvider.selectedPatient!.last_name}"; + _idController.text = patientManagerProvider.selectedPatient!.id_no; + _medAidController.text = + patientManagerProvider.selectedPatient!.medical_aid; + _medAidNameController.text = + patientManagerProvider.selectedPatient!.medical_aid_name; + _medAidCodeController.text = + patientManagerProvider.selectedPatient!.medical_aid_code; + _medAidNoController.text = + patientManagerProvider.selectedPatient!.medical_aid_no; + _medAidSchemeController.text = + patientManagerProvider.selectedPatient!.medical_aid_scheme; _serviceDateController.text = getTodayDate(); _providerNameController.text = - "${getUserTitle()} ${widget.signedInUser.fname} ${widget.signedInUser.lname}"; - _practiceNoController.text = widget.business!.practice_no; - _vatNoController.text = widget.business!.vat_no; + "${getUserTitle(profileProvider)} ${profileProvider.user!.fname} ${profileProvider.user!.lname}"; + _practiceNoController.text = profileProvider.business!.practice_no; + _vatNoController.text = profileProvider.business!.vat_no; hasMedAid(); } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart index 2b0b2dce..30bec822 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart @@ -5,44 +5,26 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_claim_statement_generation_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_delete_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/claim_statement_file.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/list_builders/build_file_view.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:supertokens_flutter/http.dart' as http; import 'package:http/http.dart' as http2; import "package:universal_html/html.dart" as html; class BuildClaimStatementFileList extends StatefulWidget { - final AppUser signedInUser; - final List files; - final Patient selectedPatient; - final Business? business; - final BusinessUser? businessUser; - final String type; - final String env; const BuildClaimStatementFileList({ super.key, - required this.files, - required this.signedInUser, - required this.selectedPatient, - required this.business, - required this.businessUser, - required this.type, - required this.env, }); @override @@ -91,32 +73,32 @@ class _BuildClaimStatementFileListState ); } - void deleteFilePopUp(String filePath, int fileID) { - showDialog( - context: context, - barrierDismissible: false, - builder: (context) => MIHDeleteMessage( - deleteType: "File", - onTap: () async { - //API Call here - await MIHClaimStatementGenerationApi - .deleteClaimStatementFilesByFileID( - PatientViewArguments( - widget.signedInUser, - widget.selectedPatient, - widget.businessUser, - widget.business, - "business", - ), - widget.env, - filePath, - fileID, - context, - ); - }, - ), - ); - } + // void deleteFilePopUp(String filePath, int fileID) { + // showDialog( + // context: context, + // barrierDismissible: false, + // builder: (context) => MIHDeleteMessage( + // deleteType: "File", + // onTap: () async { + // //API Call here + // await MIHClaimStatementGenerationApi + // .deleteClaimStatementFilesByFileID( + // PatientViewArguments( + // widget.signedInUser, + // widget.selectedPatient, + // widget.businessUser, + // widget.business, + // "business", + // ), + // widget.env, + // filePath, + // fileID, + // context, + // ); + // }, + // ), + // ); + // } String getFileName(String path) { //print(pdfLink.split(".")[1]); @@ -159,9 +141,10 @@ class _BuildClaimStatementFileListState } } - void viewFilePopUp(String fileName, String filePath, int fileID, String url) { + void viewFilePopUp(PatientManagerProvider patientManagerProvider, + String fileName, String filePath, int fileID, String url) { bool hasAccessToDelete = false; - if (widget.type == "business") { + if (!patientManagerProvider.personalMode) { hasAccessToDelete = true; } @@ -263,7 +246,7 @@ class _BuildClaimStatementFileListState backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { - deleteFilePopUp(filePath, fileID); + // deleteFilePopUp(filePath, fileID); }, ), ); @@ -332,135 +315,149 @@ class _BuildClaimStatementFileListState @override Widget build(BuildContext context) { - if (widget.files.isNotEmpty) { - return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (BuildContext context, int index) { - return Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ); - }, - itemCount: widget.files.length, - itemBuilder: (context, index) { - return ListTile( - title: Text( - widget.files[index].file_name, - style: TextStyle( + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Widget? child) { + if (patientManagerProvider.patientClaimsDocuments!.isNotEmpty) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (BuildContext context, int index) { + return Divider( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - subtitle: Text( - widget.files[index].insert_date, - style: TextStyle( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - // trailing: Icon( - // Icons.arrow_forward, - // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - onTap: () async { - await getFileUrlApiCall(widget.files[index].file_path) - .then((urlHere) { - //print(url); - setState(() { - fileUrl = urlHere; - }); - }); - - viewFilePopUp( - widget.files[index].file_name, - widget.files[index].file_path, - widget.files[index].idclaim_statement_file, - fileUrl); + ); }, - ); - }, - ); - } else { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - const SizedBox(height: 50), - Stack( - alignment: AlignmentDirectional.center, - children: [ - Icon( - MihIcons.mihRing, - size: 165, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - Icon( - Icons.file_open_outlined, - size: 110, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ], - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - child: Text( - "No Claims or Statements have been added to this profile.", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), + itemCount: patientManagerProvider.patientClaimsDocuments!.length, + itemBuilder: (context, index) { + return ListTile( + title: Text( + patientManagerProvider + .patientClaimsDocuments![index].file_name, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), ), - ], - ), - const SizedBox(height: 25), - Visibility( - visible: widget.business != null, - child: Center( - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.normal, + subtitle: Text( + patientManagerProvider + .patientClaimsDocuments![index].insert_date, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + // trailing: Icon( + // Icons.arrow_forward, + // color: MihColors.getSecondaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // ), + onTap: () async { + await getFileUrlApiCall(patientManagerProvider + .patientClaimsDocuments![index].file_path) + .then((urlHere) { + //print(url); + setState(() { + fileUrl = urlHere; + }); + }); + + viewFilePopUp( + patientManagerProvider, + patientManagerProvider + .patientClaimsDocuments![index].file_name, + patientManagerProvider + .patientClaimsDocuments![index].file_path, + patientManagerProvider.patientClaimsDocuments![index] + .idclaim_statement_file, + fileUrl); + }, + ); + }, + ); + } else { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + const SizedBox(height: 50), + Stack( + alignment: AlignmentDirectional.center, + children: [ + Icon( + MihIcons.mihRing, + size: 165, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), - children: [ - TextSpan(text: "Press "), - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Icon( - Icons.menu, - size: 20, + Icon( + Icons.file_open_outlined, + size: 110, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ], + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + "No Claims or Statements have been added to this profile.", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), ), - TextSpan(text: " to generate the first document"), - ], + ), + ], + ), + const SizedBox(height: 25), + Visibility( + visible: !patientManagerProvider.personalMode, + child: Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + children: [ + TextSpan(text: "Press "), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + Icons.menu, + size: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + TextSpan(text: " to generate the first document"), + ], + ), + ), ), ), - ), + ], ), - ], - ), - ); - } + ); + } + }, + ); } } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_claim_or_statement.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_claim_or_statement.dart index 19690da9..3932042b 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_claim_or_statement.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_claim_or_statement.dart @@ -1,35 +1,18 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_claim_statement_generation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; -import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/claim_statement_file.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/components/claim_statement_window.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/list_builders/build_claim_statement_files_list.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class PatientClaimOrStatement extends StatefulWidget { - final int patientIndex; - final Patient selectedPatient; - final AppUser signedInUser; - final Business? business; - final BusinessUser? businessUser; - final String type; const PatientClaimOrStatement({ super.key, - required this.patientIndex, - required this.selectedPatient, - required this.signedInUser, - required this.business, - required this.businessUser, - required this.type, }); @override @@ -38,39 +21,16 @@ class PatientClaimOrStatement extends StatefulWidget { } class _PatientClaimOrStatementState extends State { - late Future> futueFiles; - late String env; - void claimOrStatementWindow() { showDialog( context: context, barrierDismissible: false, - builder: (context) => ClaimStatementWindow( - selectedPatient: widget.selectedPatient, - signedInUser: widget.signedInUser, - business: widget.business, - businessUser: widget.businessUser, - env: env, - ), + builder: (context) => ClaimStatementWindow(), ); } @override void initState() { - if (widget.business == null) { - futueFiles = - MIHClaimStatementGenerationApi.getClaimStatementFilesByPatient( - widget.signedInUser.app_id); - } else { - futueFiles = - MIHClaimStatementGenerationApi.getClaimStatementFilesByBusiness( - widget.business!.business_id); - } - if (AppEnviroment.getEnv() == "Prod") { - env = "Prod"; - } else { - env = "Dev"; - } super.initState(); } @@ -83,72 +43,57 @@ class _PatientClaimOrStatementState extends State { } Widget getBody() { - return Stack( - children: [ - FutureBuilder( - future: futueFiles, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center( - child: Mihloadingcircle(), - ); - } else if (snapshot.hasData) { - final filesList = snapshot.data!; - return Column( - children: [ - //const Placeholder(), - BuildClaimStatementFileList( - files: filesList, - signedInUser: widget.signedInUser, - selectedPatient: widget.selectedPatient, - business: widget.business, - businessUser: widget.businessUser, - type: widget.type, - env: env, - ), - ], - ); - } else { - return const Center( - child: Text("Error Loading Notes"), - ); - } - }, - ), - Visibility( - visible: widget.type != "personal", - child: Positioned( - right: 10, - bottom: 10, - child: MihFloatingMenu( - icon: Icons.file_copy, - animatedIcon: AnimatedIcons.menu_close, + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Widget? child) { + return Stack( + children: [ + Column( children: [ - SpeedDialChild( - child: Icon( - Icons.add, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - label: "Generate Claim/ Statement", - labelBackgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - labelStyle: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontWeight: FontWeight.bold, - ), - backgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onTap: () { - claimOrStatementWindow(); - }, - ) + //const Placeholder(), + BuildClaimStatementFileList(), ], ), - ), - ), - ], + Visibility( + visible: patientManagerProvider.personalMode, + child: Positioned( + right: 10, + bottom: 10, + child: MihFloatingMenu( + icon: Icons.file_copy, + animatedIcon: AnimatedIcons.menu_close, + children: [ + SpeedDialChild( + child: Icon( + Icons.add, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + label: "Generate Claim/ Statement", + labelBackgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onTap: () { + claimOrStatementWindow(); + }, + ) + ], + ), + ), + ), + ], + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart index 420def9f..9b91e465 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart @@ -5,10 +5,12 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_claim_or_statement.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_consultation.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_documents.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_claim_statement_generation_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; import 'package:provider/provider.dart'; @@ -48,6 +50,8 @@ class _PatientProfileState extends State { await MihPatientServices() .getPatientConsultationNotes(patientManagerProvider); await MihPatientServices().getPatientDocuments(patientManagerProvider); + await MIHClaimStatementGenerationApi.getClaimStatementFilesByPatient( + patientManagerProvider); } setState(() { isLoading = false; @@ -137,14 +141,7 @@ class _PatientProfileState extends State { PatientInfo(), PatientConsultation(), PatientDocuments(), - // PatientClaimOrStatement( - // patientIndex: widget.arguments.selectedPatient!.idpatients, - // selectedPatient: widget.arguments.selectedPatient!, - // signedInUser: widget.arguments.signedInUser, - // business: widget.arguments.business, - // businessUser: widget.arguments.businessUser, - // type: widget.arguments.type, - // ), + PatientClaimOrStatement(), ]; return toolBodies; } diff --git a/Frontend/lib/mih_services/mih_claim_statement_generation_services.dart b/Frontend/lib/mih_services/mih_claim_statement_generation_services.dart index b26edd99..9f615b9f 100644 --- a/Frontend/lib/mih_services/mih_claim_statement_generation_services.dart +++ b/Frontend/lib/mih_services/mih_claim_statement_generation_services.dart @@ -5,6 +5,8 @@ import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loa import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/claim_statement_file.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:supertokens_flutter/http.dart' as http; import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; @@ -20,8 +22,9 @@ class MIHClaimStatementGenerationApi { /// /// Returns TBC. Future generateClaimStatement( + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, ClaimStatementGenerationArguments data, - PatientViewArguments args, String env, BuildContext context, ) async { @@ -84,19 +87,13 @@ class MIHClaimStatementGenerationApi { }, body: jsonEncode({ "app_id": data.patient_app_id, - "business_id": args.business!.business_id, + "business_id": profileProvider.business!.business_id, "file_path": "${data.patient_app_id}/claims-statements/$fileName", "file_name": fileName }), ); if (response2.statusCode == 201) { - context.pop(); // end loading circle - context.pop(); - - context.pushNamed( - 'patientManagerPatient', - extra: args, - ); + getClaimStatementFilesByPatient(patientManagerProvider); String message = "The ${data.document_type}: $fileName has been successfully generated and added to ${data.patient_full_name}'s record. You can now access and download it for their use."; successPopUp(message, context); @@ -114,11 +111,11 @@ class MIHClaimStatementGenerationApi { /// /// Returns List. static Future> getClaimStatementFilesByPatient( - String app_id, + PatientManagerProvider patientManagerProvider, ) async { //print("Patien manager page: $endpoint"); final response = await http.get(Uri.parse( - "${AppEnviroment.baseApiUrl}/files/claim-statement/patient/$app_id")); + "${AppEnviroment.baseApiUrl}/files/claim-statement/patient/${patientManagerProvider.selectedPatient!.app_id}")); // print("Here"); // print("Body: ${response.body}"); // print("Code: ${response.statusCode}"); @@ -132,7 +129,9 @@ class MIHClaimStatementGenerationApi { List docList = List.from( l.map((model) => ClaimStatementFile.fromJson(model))); //print("Here3"); - //print(patientQueue); + print(docList); + patientManagerProvider.setClaimsDocuments( + patientClaimsDocuments: docList); return docList; } else { throw Exception( From 39a42048c2c5942dc804af95bf145dcbb2865f6e Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 29 Oct 2025 15:43:05 +0200 Subject: [PATCH 39/45] NEW: Patient Manager Provider Setup pt3 --- .../patient_manager_provider.dart | 7 + Frontend/lib/mih_config/mih_go_router.dart | 18 +- .../build_my_patient_list_list.dart | 182 +++++++++--------- .../package_tiles/pat_manager_tile.dart | 1 - .../package_tools/my_patient_list.dart | 98 +++------- .../package_tools/waiting_room.dart | 81 ++++---- .../pat_manager/pat_manager.dart | 108 ++++++----- .../package_tiles/patient_profile_tile.dart | 5 + .../pat_profile/patient_profile.dart | 11 +- ...h_claim_statement_generation_services.dart | 1 - .../mih_mzansi_calendar_services.dart | 5 +- .../mih_services/mih_patient_services.dart | 18 ++ .../lib/mih_services/mih_service_calls.dart | 23 --- 13 files changed, 263 insertions(+), 295 deletions(-) diff --git a/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart b/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart index 308fbe3c..160faaf8 100644 --- a/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/claim_statement_file.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/files.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/notes.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; class PatientManagerProvider extends ChangeNotifier { @@ -9,6 +10,7 @@ class PatientManagerProvider extends ChangeNotifier { int patientManagerIndex; int fileViewerIndex; bool personalMode; + List? myPaitentList; Patient? selectedPatient; List? consultationNotes; List? patientDocuments; @@ -53,6 +55,11 @@ class PatientManagerProvider extends ChangeNotifier { notifyListeners(); } + void setMyPatientList({required List? myPaitentList}) { + this.myPaitentList = myPaitentList ?? []; + notifyListeners(); + } + void setConsultationNotes({required List? consultationNotes}) { this.consultationNotes = consultationNotes ?? []; notifyListeners(); diff --git a/Frontend/lib/mih_config/mih_go_router.dart b/Frontend/lib/mih_config/mih_go_router.dart index e0963b7c..71de50cc 100644 --- a/Frontend/lib/mih_config/mih_go_router.dart +++ b/Frontend/lib/mih_config/mih_go_router.dart @@ -320,6 +320,7 @@ class MihGoRouter { name: "mihAccess", path: MihGoRouterPaths.mihAccess, builder: (BuildContext context, GoRouterState state) { + KenLogger.success("MihGoRouter: mihAccess"); if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); @@ -336,20 +337,21 @@ class MihGoRouter { name: "patientProfile", path: MihGoRouterPaths.patientProfile, builder: (BuildContext context, GoRouterState state) { - final String? argPatientAppId = state.extra as String?; + KenLogger.success("MihGoRouter: patientProfile"); if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); return const SizedBox.shrink(); } - return PatientProfile(patientAppId: argPatientAppId); + return PatientProfile(); }, ), GoRoute( name: "patientProfileSetup", path: MihGoRouterPaths.patientProfileSetup, builder: (BuildContext context, GoRouterState state) { + KenLogger.success("MihGoRouter: patientProfileSetup"); if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); @@ -363,8 +365,8 @@ class MihGoRouter { name: "patientManager", path: MihGoRouterPaths.patientManager, builder: (BuildContext context, GoRouterState state) { - final PatManagerArguments? args = state.extra as PatManagerArguments?; - if (args == null) { + KenLogger.success("MihGoRouter: patientManager"); + if (context.watch().business == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); @@ -372,7 +374,6 @@ class MihGoRouter { } return PatManager( key: UniqueKey(), - arguments: args, ); }, ), @@ -380,14 +381,14 @@ class MihGoRouter { name: "patientManagerPatient", path: MihGoRouterPaths.patientManagerPatient, builder: (BuildContext context, GoRouterState state) { - final String? argPatientAppId = state.extra as String?; + KenLogger.success("MihGoRouter: patientManagerPatient"); if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); return const SizedBox.shrink(); } - return PatientProfile(patientAppId: argPatientAppId); + return PatientProfile(); }, ), // ========================== Mzansi Directory ================================== @@ -395,6 +396,7 @@ class MihGoRouter { name: "mzansiDirectory", path: MihGoRouterPaths.mzansiDirectory, builder: (BuildContext context, GoRouterState state) { + KenLogger.success("MihGoRouter: mzansiDirectory"); if (context.watch().user == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); @@ -409,6 +411,7 @@ class MihGoRouter { name: "fileViewer", path: MihGoRouterPaths.fileViewer, builder: (BuildContext context, GoRouterState state) { + KenLogger.success("MihGoRouter: fileViewer"); final FileViewArguments? args = state.extra as FileViewArguments?; return FullScreenFileViewer(arguments: args!); }, @@ -417,6 +420,7 @@ class MihGoRouter { name: "printPreview", path: MihGoRouterPaths.printPreview, builder: (BuildContext context, GoRouterState state) { + KenLogger.success("MihGoRouter: printPreview"); final PrintPreviewArguments? args = state.extra as PrintPreviewArguments?; return MIHPrintPreview(arguments: args!); diff --git a/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_my_patient_list_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_my_patient_list_list.dart index d7e6059a..c588abf5 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_my_patient_list_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_my_patient_list_list.dart @@ -1,9 +1,11 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_service_calls.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_calendar_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; @@ -15,26 +17,12 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_warning_message.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class BuildMyPatientListList extends StatefulWidget { - final List patientAccesses; - final AppUser signedInUser; - final Business? business; - final BusinessUser? businessUser; - const BuildMyPatientListList({ super.key, - required this.patientAccesses, - required this.signedInUser, - required this.business, - required this.businessUser, }); @override @@ -51,24 +39,21 @@ class _BuildPatientsListState extends State { final baseAPI = AppEnviroment.baseApiUrl; - Future submitApointment(int index) async { + Future submitApointment(MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, int index) async { //To-Do: Add the appointment to the database // print("To-Do: Add the appointment to the database"); String description = "Date: ${dateController.text}\nTime: ${timeController.text}\n"; - description += "Medical Practice: ${widget.business!.Name}\n"; - description += "Contact Number: ${widget.business!.contact_no}"; + description += "Medical Practice: ${profileProvider.business!.Name}\n"; + description += "Contact Number: ${profileProvider.business!.contact_no}"; int statusCode; statusCode = await MihMzansiCalendarApis.addPatientAppointment( - widget.signedInUser, + profileProvider.user!, false, - widget.patientAccesses[index].app_id, - BusinessArguments( - widget.signedInUser, - widget.businessUser, - widget.business, - ), - "${widget.patientAccesses[index].fname} ${widget.patientAccesses[index].lname} - Doctors Visit", + patientManagerProvider.myPaitentList![index].app_id, + profileProvider.business!.business_id, + "${patientManagerProvider.myPaitentList![index].fname} ${patientManagerProvider.myPaitentList![index].lname} - Doctors Visit", description, dateController.text, timeController.text, @@ -164,11 +149,16 @@ class _BuildPatientsListState extends State { } } - void appointmentPopUp(int index, double width) { - var firstLetterFName = widget.patientAccesses[index].fname; - var firstLetterLName = widget.patientAccesses[index].lname; + void appointmentPopUp( + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, + int index, + double width, + ) { + var firstLetterFName = patientManagerProvider.myPaitentList![index].fname; + var firstLetterLName = patientManagerProvider.myPaitentList![index].lname; setState(() { - idController.text = widget.patientAccesses[index].id_no; + idController.text = patientManagerProvider.myPaitentList![index].id_no; fnameController.text = firstLetterFName; lnameController.text = firstLetterLName; }); @@ -260,7 +250,8 @@ class _BuildPatientsListState extends State { if (_formKey.currentState!.validate()) { bool filled = isAppointmentFieldsFilled(); if (filled) { - submitApointment(index); + submitApointment( + profileProvider, patientManagerProvider, index); } else { showDialog( context: context, @@ -299,8 +290,9 @@ class _BuildPatientsListState extends State { ); } - void noAccessWarning(int index) { - if (widget.patientAccesses[index].status == "pending") { + void noAccessWarning( + PatientManagerProvider patientManagerProvider, int index) { + if (patientManagerProvider.myPaitentList![index].status == "pending") { showDialog( context: context, builder: (context) { @@ -317,10 +309,11 @@ class _BuildPatientsListState extends State { } } - bool hasAccessToProfile(int index) { + bool hasAccessToProfile( + PatientManagerProvider patientManagerProvider, int index) { var hasAccess = false; - if (widget.patientAccesses[index].status == "approved") { + if (patientManagerProvider.myPaitentList![index].status == "approved") { hasAccess = true; } else { hasAccess = false; @@ -329,11 +322,15 @@ class _BuildPatientsListState extends State { } void patientProfileChoicePopUp( - int index, Patient? patientProfile, double width) async { - var firstLetterFName = widget.patientAccesses[index].fname; - var firstLetterLName = widget.patientAccesses[index].lname; + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, + int index, + double width, + ) async { + var firstLetterFName = patientManagerProvider.myPaitentList![index].fname; + var firstLetterLName = patientManagerProvider.myPaitentList![index].lname; setState(() { - idController.text = widget.patientAccesses[index].id_no; + idController.text = patientManagerProvider.myPaitentList![index].id_no; fnameController.text = firstLetterFName; lnameController.text = firstLetterLName; }); @@ -405,7 +402,8 @@ class _BuildPatientsListState extends State { children: [ MihButton( onPressed: () { - appointmentPopUp(index, width); + appointmentPopUp(profileProvider, + patientManagerProvider, index, width); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == @@ -423,25 +421,14 @@ class _BuildPatientsListState extends State { ), ), MihButton( - onPressed: () { + onPressed: () async { + await MihPatientServices().getPatientDetails( + patientManagerProvider.myPaitentList![index].app_id, + patientManagerProvider); context.pop(); - context.pushNamed('patientManagerPatient', - extra: PatientViewArguments( - widget.signedInUser, - patientProfile, - widget.businessUser, - widget.business, - "business", - )); - // Navigator.of(context) - // .pushNamed('/patient-manager/patient', - // arguments: PatientViewArguments( - // widget.signedInUser, - // patientProfile, - // widget.businessUser, - // widget.business, - // "business", - // )); + context.pushNamed( + 'patientManagerPatient', + ); }, buttonColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == @@ -468,33 +455,43 @@ class _BuildPatientsListState extends State { ); } - Widget displayMyPatientTile(int index, double width) { + Widget displayMyPatientTile( + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, + int index, + double width, + ) { var firstName = ""; var lastName = ""; - String access = widget.patientAccesses[index].status.toUpperCase(); + String access = + patientManagerProvider.myPaitentList![index].status.toUpperCase(); TextSpan accessWithColour; var hasAccess = false; - hasAccess = hasAccessToProfile(index); + hasAccess = hasAccessToProfile(patientManagerProvider, index); //print(hasAccess); if (access == "APPROVED") { - firstName = widget.patientAccesses[index].fname; - lastName = widget.patientAccesses[index].lname; + firstName = patientManagerProvider.myPaitentList![index].fname; + lastName = patientManagerProvider.myPaitentList![index].lname; accessWithColour = TextSpan( text: "$access\n", style: TextStyle( color: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"))); } else if (access == "PENDING") { - firstName = "${widget.patientAccesses[index].fname[0]}********"; - lastName = "${widget.patientAccesses[index].lname[0]}********"; + firstName = + "${patientManagerProvider.myPaitentList![index].fname[0]}********"; + lastName = + "${patientManagerProvider.myPaitentList![index].lname[0]}********"; accessWithColour = TextSpan( text: "$access\n", style: TextStyle( color: MihColors.getGreyColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"))); } else { - firstName = "${widget.patientAccesses[index].fname[0]}********"; - lastName = "${widget.patientAccesses[index].lname[0]}********"; + firstName = + "${patientManagerProvider.myPaitentList![index].fname[0]}********"; + lastName = + "${patientManagerProvider.myPaitentList![index].lname[0]}********"; accessWithColour = TextSpan( text: "$access\n", style: TextStyle( @@ -512,7 +509,8 @@ class _BuildPatientsListState extends State { ), subtitle: RichText( text: TextSpan( - text: "ID No.: ${widget.patientAccesses[index].id_no}\n", + text: + "ID No.: ${patientManagerProvider.myPaitentList![index].id_no}\n", style: DefaultTextStyle.of(context).style, children: [ const TextSpan(text: "Access: "), @@ -520,18 +518,16 @@ class _BuildPatientsListState extends State { ]), ), onTap: () async { - Patient? p; if (hasAccess) { - await MIHApiCalls.fetchPatientByAppId( - widget.patientAccesses[index].app_id) - .then((result) { - setState(() { - p = result; - }); - }); - patientProfileChoicePopUp(index, p, width); + await MihPatientServices() + .getPatientDetails( + patientManagerProvider.myPaitentList![index].app_id, + patientManagerProvider) + .then((result) {}); + patientProfileChoicePopUp( + profileProvider, patientManagerProvider, index, width); } else { - noAccessWarning(index); + noAccessWarning(patientManagerProvider, index); } }, trailing: Icon( @@ -555,19 +551,25 @@ class _BuildPatientsListState extends State { @override Widget build(BuildContext context) { double screenWidth = MediaQuery.of(context).size.width; - return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (BuildContext context, index) { - return Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Widget? child) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (BuildContext context, index) { + return Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + itemCount: patientManagerProvider.myPaitentList!.length, + itemBuilder: (context, index) { + return displayMyPatientTile( + profileProvider, patientManagerProvider, index, screenWidth); + }, ); }, - itemCount: widget.patientAccesses.length, - itemBuilder: (context, index) { - return displayMyPatientTile(index, screenWidth); - }, ); } } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tiles/pat_manager_tile.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tiles/pat_manager_tile.dart index 0d95b243..438f411d 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tiles/pat_manager_tile.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tiles/pat_manager_tile.dart @@ -27,7 +27,6 @@ class _PatManagerTileState extends State { onTap: () { context.goNamed( 'patientManager', - extra: widget.arguments, ); // Navigator.of(context).pushNamed( // '/patient-manager', diff --git a/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/my_patient_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/my_patient_list.dart index d87f56a8..f2b426ee 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/my_patient_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/my_patient_list.dart @@ -1,31 +1,21 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_service_calls.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/list_builders/build_my_patient_list_list.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class MyPatientList extends StatefulWidget { - final AppUser signedInUser; - final Business? business; - final BusinessUser? businessUser; - final bool personalSelected; - const MyPatientList({ super.key, - required this.signedInUser, - this.business, - this.businessUser, - this.personalSelected = false, }); @override @@ -33,7 +23,6 @@ class MyPatientList extends StatefulWidget { } class _MyPatientListState extends State { - late Future> _myPatientList; TextEditingController _myPatientSearchController = TextEditingController(); final FocusNode _searchFocusNode = FocusNode(); bool hasSearchedBefore = false; @@ -42,7 +31,8 @@ class _MyPatientListState extends State { final FocusNode _focusNode = FocusNode(); - Widget myPatientListTool(double width) { + Widget myPatientListTool(MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, double width) { return MihSingleChildScroll( child: Column(mainAxisSize: MainAxisSize.max, children: [ Padding( @@ -56,10 +46,11 @@ class _MyPatientListState extends State { hintColor: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onPrefixIconTap: () { - setState(() { + setState(() async { _myPatientIdSearchString = _myPatientSearchController.text; - _myPatientList = MIHApiCalls.getPatientAccessListOfBusiness( - widget.business!.business_id); + await MihPatientServices().getPatientAccessListOfBusiness( + patientManagerProvider, + profileProvider.business!.business_id); }); }, onClearIconTap: () { @@ -67,57 +58,21 @@ class _MyPatientListState extends State { _myPatientSearchController.clear(); _myPatientIdSearchString = ""; }); - getMyPatientList(); + getMyPatientList(profileProvider, patientManagerProvider); }, searchFocusNode: _searchFocusNode, ), ), //spacer const SizedBox(height: 10), - FutureBuilder( - future: _myPatientList, - builder: (context, snapshot) { - //print("patient Liust ${snapshot.data}"); - if (snapshot.connectionState == ConnectionState.waiting) { - return const Mihloadingcircle(); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - List patientsAccessList; - if (_myPatientIdSearchString == "") { - patientsAccessList = snapshot.data!; - } else { - patientsAccessList = filterAccessResults( - snapshot.data!, _myPatientIdSearchString); - //print(patientsList); - } - return displayMyPatientList(patientsAccessList); - } else { - return Center( - child: Text( - "Error pulling Patient Access Data\n$baseUrl/access-requests/business/patient/${widget.business!.business_id}", - style: TextStyle( - fontSize: 25, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark")), - textAlign: TextAlign.center, - ), - ); - } - }, - ), + displayMyPatientList(patientManagerProvider), ]), ); } - Widget displayMyPatientList(List patientsAccessList) { - if (patientsAccessList.isNotEmpty) { - return BuildMyPatientListList( - patientAccesses: patientsAccessList, - signedInUser: widget.signedInUser, - business: widget.business, - businessUser: widget.businessUser, - ); + Widget displayMyPatientList(PatientManagerProvider patientManagerProvider) { + if (patientManagerProvider.myPaitentList!.isNotEmpty) { + return BuildMyPatientListList(); } if (hasSearchedBefore && _myPatientIdSearchString.isNotEmpty) { return Column( @@ -228,10 +183,11 @@ class _MyPatientListState extends State { return templist; } - void getMyPatientList() { + Future getMyPatientList(MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider) async { + await MihPatientServices().getPatientAccessListOfBusiness( + patientManagerProvider, profileProvider.business!.business_id); setState(() { - _myPatientList = MIHApiCalls.getPatientAccessListOfBusiness( - widget.business!.business_id); hasSearchedBefore = true; }); } @@ -239,8 +195,6 @@ class _MyPatientListState extends State { @override void initState() { super.initState(); - _myPatientList = MIHApiCalls.getPatientAccessListOfBusiness( - widget.business!.business_id); } @override @@ -256,10 +210,16 @@ class _MyPatientListState extends State { Widget build(BuildContext context) { final Size size = MediaQuery.sizeOf(context); final double width = size.width; - return MihPackageToolBody( - borderOn: false, - innerHorizontalPadding: 10, - bodyItem: myPatientListTool(width), + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Widget? child) { + return MihPackageToolBody( + borderOn: false, + innerHorizontalPadding: 10, + bodyItem: + myPatientListTool(profileProvider, patientManagerProvider, width), + ); + }, ); } } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/waiting_room.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/waiting_room.dart index 89e737ef..3c407aac 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/waiting_room.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/waiting_room.dart @@ -5,6 +5,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_calendar_services.dart'; @@ -22,27 +23,14 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/appointment.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_packages/calendar/builder/build_appointment_list.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class WaitingRoom extends StatefulWidget { - final AppUser signedInUser; - final Business? business; - final BusinessUser? businessUser; - final bool personalSelected; - final Function(int) onIndexChange; const WaitingRoom({ super.key, - required this.signedInUser, - required this.business, - required this.businessUser, - required this.personalSelected, - required this.onIndexChange, }); @override @@ -71,8 +59,12 @@ class _WaitingRoomState extends State { // Business Appointment Tool Widget getBusinessAppointmentsTool(double width) { - return Consumer( - builder: (BuildContext context, MihCalendarProvider mihCalendarProvider, + return Consumer3( + builder: (BuildContext context, + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, + MihCalendarProvider mihCalendarProvider, Widget? child) { if (isLoading) { return const Center( @@ -132,7 +124,8 @@ class _WaitingRoomState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onTap: () { // addAppointmentWindow(); - appointmentTypeSelection(mihCalendarProvider, width); + appointmentTypeSelection(profileProvider, + patientManagerProvider, mihCalendarProvider, width); }, ) ], @@ -237,7 +230,10 @@ class _WaitingRoomState extends State { } void appointmentTypeSelection( - MihCalendarProvider mihCalendarProvider, double width) { + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, + MihCalendarProvider mihCalendarProvider, + double width) { String question = "What type of appointment would you like to add?"; question += "\n\nExisting Patient: Add an appointment for an patient your practice has access to."; @@ -268,7 +264,7 @@ class _WaitingRoomState extends State { const SizedBox(height: 15), MihButton( onPressed: () { - widget.onIndexChange(1); + patientManagerProvider.setPatientManagerIndex(1); context.pop(); }, buttonColor: MihColors.getGreenColor( @@ -287,7 +283,7 @@ class _WaitingRoomState extends State { const SizedBox(height: 10), MihButton( onPressed: () { - widget.onIndexChange(2); + patientManagerProvider.setPatientManagerIndex(2); context.pop(); }, buttonColor: MihColors.getGreenColor( @@ -307,7 +303,8 @@ class _WaitingRoomState extends State { MihButton( onPressed: () { Navigator.pop(context); - addAppointmentWindow(mihCalendarProvider, width); + addAppointmentWindow( + profileProvider, mihCalendarProvider, width); }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -329,7 +326,7 @@ class _WaitingRoomState extends State { ); } - void addAppointmentWindow( + void addAppointmentWindow(MzansiProfileProvider profileProvider, MihCalendarProvider mihCalendarProvider, double width) { showDialog( context: context, @@ -411,7 +408,8 @@ class _WaitingRoomState extends State { child: MihButton( onPressed: () { if (_formKey.currentState!.validate()) { - addAppointmentCall(mihCalendarProvider); + addAppointmentCall( + profileProvider, mihCalendarProvider); } else { MihAlertServices().formNotFilledCompletely(context); } @@ -442,34 +440,23 @@ class _WaitingRoomState extends State { ); } - Future addAppointmentCall( + Future addAppointmentCall(MzansiProfileProvider profileProvider, MihCalendarProvider mihCalendarProvider) async { if (isAppointmentInputValid()) { int statusCode; - if (widget.personalSelected == false) { - statusCode = await MihMzansiCalendarApis.addBusinessAppointment( - widget.signedInUser, - widget.business!, - widget.businessUser!, - true, - _appointmentTitleController.text, - _appointmentDescriptionIDController.text, - _appointmentDateController.text, - _appointmentTimeController.text, - mihCalendarProvider, - context, - ); - } else { - statusCode = await MihMzansiCalendarApis.addPersonalAppointment( - widget.signedInUser, - _appointmentTitleController.text, - _appointmentDescriptionIDController.text, - _appointmentDateController.text, - _appointmentTimeController.text, - mihCalendarProvider, - context, - ); - } + statusCode = await MihMzansiCalendarApis.addBusinessAppointment( + profileProvider.user!, + profileProvider.business!, + profileProvider.businessUser!, + true, + _appointmentTitleController.text, + _appointmentDescriptionIDController.text, + _appointmentDateController.text, + _appointmentTimeController.text, + mihCalendarProvider, + context, + ); + if (statusCode == 201) { context.pop(); successPopUp("Successfully Added Appointment", diff --git a/Frontend/lib/mih_packages/patient_manager/pat_manager/pat_manager.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/pat_manager.dart index dca4e520..2c0fe380 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_manager/pat_manager.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/pat_manager.dart @@ -2,17 +2,19 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/package_tools/mih_patient_search.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/package_tools/my_patient_list.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/package_tools/waiting_room.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_calendar_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; +import 'package:provider/provider.dart'; class PatManager extends StatefulWidget { - final PatManagerArguments arguments; const PatManager({ super.key, - required this.arguments, }); @override @@ -20,11 +22,39 @@ class PatManager extends StatefulWidget { } class _PatManagerState extends State { - int _selcetedIndex = 0; + bool isLoading = true; - void updateIndex(int index) { + Future initialisePatientData() async { setState(() { - _selcetedIndex = index; + isLoading = true; + }); + MzansiProfileProvider profileProvider = + context.read(); + PatientManagerProvider patientManagerProvider = + context.read(); + MihCalendarProvider mihCalendarProvider = + context.read(); + patientManagerProvider.setPersonalMode(false); + if (profileProvider.business != null) { + await MihMzansiCalendarApis.getBusinessAppointments( + profileProvider.business!.business_id, + false, + mihCalendarProvider.selectedDay, + mihCalendarProvider, + ); + MihPatientServices().getPatientAccessListOfBusiness( + patientManagerProvider, profileProvider.business!.business_id); + } + setState(() { + isLoading = false; + }); + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + initialisePatientData(); }); } @@ -35,24 +65,30 @@ class _PatManagerState extends State { appTools: getTools(), appBody: getToolBody(), appToolTitles: getToolTitle(), - selectedbodyIndex: _selcetedIndex, + selectedbodyIndex: + context.watch().patientManagerIndex, onIndexChange: (newValue) { - setState(() { - _selcetedIndex = newValue; - }); + context.read().setPatientManagerIndex(newValue); }, ); } MihPackageAction getActionButton() { + PatientManagerProvider patientManagerProvider = + context.read(); return MihPackageAction( icon: const Icon(Icons.arrow_back), iconSize: 35, onTap: () { - // Navigator.of(context).pop(); - context.goNamed( - 'mihHome', - ); + patientManagerProvider.setPatientProfileIndex(0); + patientManagerProvider.setPatientManagerIndex(0); + if (!patientManagerProvider.personalMode) { + context.pop(); + } else { + context.goNamed( + 'mihHome', + ); + } FocusScope.of(context).unfocus(); }, ); @@ -61,55 +97,33 @@ class _PatManagerState extends State { MihPackageTools getTools() { Map temp = {}; temp[const Icon(Icons.calendar_month)] = () { - setState(() { - _selcetedIndex = 0; - }); + context.read().setPatientManagerIndex(0); }; - temp[const Icon(Icons.check_box_outlined)] = () { - setState(() { - _selcetedIndex = 1; - }); + context.read().setPatientManagerIndex(1); }; temp[const Icon(Icons.search)] = () { - setState(() { - _selcetedIndex = 2; - }); + context.read().setPatientManagerIndex(2); }; return MihPackageTools( tools: temp, - selcetedIndex: _selcetedIndex, + selcetedIndex: + context.watch().patientManagerIndex, ); } List getToolBody() { List toolBodies = [ - //appointment here - // Appointments( + WaitingRoom(), + MyPatientList(), + Placeholder(), + // MihPatientSearch( // signedInUser: widget.arguments.signedInUser, // business: widget.arguments.business, // personalSelected: widget.arguments.personalSelected, + // businessUser: widget.arguments.businessUser, // ), - WaitingRoom( - signedInUser: widget.arguments.signedInUser, - business: widget.arguments.business, - businessUser: widget.arguments.businessUser, - personalSelected: widget.arguments.personalSelected, - onIndexChange: updateIndex, - ), - MyPatientList( - signedInUser: widget.arguments.signedInUser, - business: widget.arguments.business, - businessUser: widget.arguments.businessUser, - personalSelected: widget.arguments.personalSelected, - ), - MihPatientSearch( - signedInUser: widget.arguments.signedInUser, - business: widget.arguments.business, - personalSelected: widget.arguments.personalSelected, - businessUser: widget.arguments.businessUser, - ), ]; return toolBodies; } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tiles/patient_profile_tile.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tiles/patient_profile_tile.dart index e85c1c02..1fe19f93 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tiles/patient_profile_tile.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/package_tiles/patient_profile_tile.dart @@ -4,7 +4,9 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:provider/provider.dart'; class PatientProfileTile extends StatefulWidget { final PatientViewArguments arguments; @@ -26,6 +28,9 @@ class _PatientProfileTileState extends State { return MihPackageTile( authenticateUser: true, onTap: () { + PatientManagerProvider patientManagerProvider = + context.read(); + patientManagerProvider.setPersonalMode(true); context.goNamed( 'patientProfile', ); diff --git a/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart index 9b91e465..806ff6d7 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_profile/patient_profile.dart @@ -15,10 +15,8 @@ import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; import 'package:provider/provider.dart'; class PatientProfile extends StatefulWidget { - final String? patientAppId; const PatientProfile({ super.key, - required this.patientAppId, }); @override @@ -36,13 +34,11 @@ class _PatientProfileState extends State { context.read(); PatientManagerProvider patientManagerProvider = context.read(); - String? app_id = widget.patientAppId ?? profileProvider.user!.app_id; - + String? app_id = profileProvider.user!.app_id; if (patientManagerProvider.selectedPatient == null) { await MihPatientServices() .getPatientDetails(app_id, patientManagerProvider); } - if (patientManagerProvider.selectedPatient == null) { // go to set up patient package context.goNamed("patientProfileSetup"); @@ -61,7 +57,9 @@ class _PatientProfileState extends State { @override void initState() { super.initState(); - initialisePatientData(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + initialisePatientData(); + }); } @override @@ -87,7 +85,6 @@ class _PatientProfileState extends State { iconSize: 35, onTap: () { patientManagerProvider.setPatientProfileIndex(0); - patientManagerProvider.setPatientManagerIndex(0); if (!patientManagerProvider.personalMode) { context.pop(); } else { diff --git a/Frontend/lib/mih_services/mih_claim_statement_generation_services.dart b/Frontend/lib/mih_services/mih_claim_statement_generation_services.dart index 9f615b9f..7cb073bd 100644 --- a/Frontend/lib/mih_services/mih_claim_statement_generation_services.dart +++ b/Frontend/lib/mih_services/mih_claim_statement_generation_services.dart @@ -129,7 +129,6 @@ class MIHClaimStatementGenerationApi { List docList = List.from( l.map((model) => ClaimStatementFile.fromJson(model))); //print("Here3"); - print(docList); patientManagerProvider.setClaimsDocuments( patientClaimsDocuments: docList); return docList; diff --git a/Frontend/lib/mih_services/mih_mzansi_calendar_services.dart b/Frontend/lib/mih_services/mih_mzansi_calendar_services.dart index 3acbeeea..6c18fb47 100644 --- a/Frontend/lib/mih_services/mih_mzansi_calendar_services.dart +++ b/Frontend/lib/mih_services/mih_mzansi_calendar_services.dart @@ -4,7 +4,6 @@ import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/appointment.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:flutter/material.dart'; @@ -291,7 +290,7 @@ class MihMzansiCalendarApis { AppUser signedInUser, bool personalSelected, String patientAppId, - BusinessArguments businessArgs, + String businessId, String title, String description, String date, @@ -306,7 +305,7 @@ class MihMzansiCalendarApis { }, body: jsonEncode({ "app_id": patientAppId, - "business_id": businessArgs.business?.business_id, + "business_id": businessId, "title": title, "description": description, "date": date, diff --git a/Frontend/lib/mih_services/mih_patient_services.dart b/Frontend/lib/mih_services/mih_patient_services.dart index 10e1bea3..8556a80f 100644 --- a/Frontend/lib/mih_services/mih_patient_services.dart +++ b/Frontend/lib/mih_services/mih_patient_services.dart @@ -4,6 +4,7 @@ import 'package:file_picker/file_picker.dart'; import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/files.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/notes.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; @@ -289,4 +290,21 @@ class MihPatientServices { } return response.statusCode; } + + Future> getPatientAccessListOfBusiness( + PatientManagerProvider patientManagerProvider, + String business_id, + ) async { + final response = await http.get(Uri.parse( + "${AppEnviroment.baseApiUrl}/access-requests/business/patient/$business_id")); + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List patientAccesses = List.from( + l.map((model) => PatientAccess.fromJson(model))); + patientManagerProvider.setMyPatientList(myPaitentList: patientAccesses); + return patientAccesses; + } else { + throw Exception('failed to pull patient access List for business'); + } + } } diff --git a/Frontend/lib/mih_services/mih_service_calls.dart b/Frontend/lib/mih_services/mih_service_calls.dart index 2fc9014e..4cda4a90 100644 --- a/Frontend/lib/mih_services/mih_service_calls.dart +++ b/Frontend/lib/mih_services/mih_service_calls.dart @@ -126,29 +126,6 @@ class MIHApiCalls { } } - /// This function is used to get list of access the business has. - /// - /// Patameters: String business_id. - /// - /// Returns List (List of access that match the above parameters). - static Future> getPatientAccessListOfBusiness( - String business_id) async { - final response = await http.get(Uri.parse( - "${AppEnviroment.baseApiUrl}/access-requests/business/patient/$business_id")); - // var errorCode = response.statusCode.toString(); - // print(response.statusCode); - // print(response.body); - - if (response.statusCode == 200) { - Iterable l = jsonDecode(response.body); - List patientAccesses = List.from( - l.map((model) => PatientAccess.fromJson(model))); - return patientAccesses; - } else { - throw Exception('failed to pull patient access List for business'); - } - } - /// This function is used to UPDATE access the business has. /// /// Patameters:- From d6f1629485a051b2ce2f1d8d9cca28aca730a313 Mon Sep 17 00:00:00 2001 From: yaso Date: Thu, 30 Oct 2025 11:58:46 +0200 Subject: [PATCH 40/45] NEW: MIH MineSweeper Package Pt 3 --- Frontend/lib/mih_config/mih_colors.dart | 27 ++ .../build_minesweeper_leaderboard_list.dart | 73 ++++-- .../builders/build_my_scoreboard_list.dart | 68 +++-- .../mih_mine_sweeper_leader_board.dart | 22 +- .../package_tools/mine_sweeper_game.dart | 10 +- .../mine_sweeper_quick_start_guide.dart | 233 ++++++++++++------ .../package_tools/my_score_board.dart | 11 +- 7 files changed, 293 insertions(+), 151 deletions(-) diff --git a/Frontend/lib/mih_config/mih_colors.dart b/Frontend/lib/mih_config/mih_colors.dart index 398736af..724868e4 100644 --- a/Frontend/lib/mih_config/mih_colors.dart +++ b/Frontend/lib/mih_config/mih_colors.dart @@ -93,4 +93,31 @@ class MihColors { return const Color(0xFF9857D4); } } + + static Color getGoldColor(bool darkMode) { + if (darkMode == true) { + return const Color(0xFFD4AF37); + } else { + // Add a different shade of pink for light mode + return const Color(0xffFFD700); + } + } + + static Color getSilverColor(bool darkMode) { + if (darkMode == true) { + return const Color(0xffC0C0C0); + } else { + // Add a different shade of pink for light mode + return const Color(0xFFA6A6A6); + } + } + + static Color getBronze(bool darkMode) { + if (darkMode == true) { + return const Color(0xffB1560F); + } else { + // Add a different shade of pink for light mode + return const Color(0xFFCD7F32); + } + } } diff --git a/Frontend/lib/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart b/Frontend/lib/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart index cc622ed0..07b36218 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart @@ -16,8 +16,26 @@ class BuildMinesweeperLeaderboardList extends StatefulWidget { class _BuildMinesweeperLeaderboardListState extends State { + Color getMedalColor(int index) { + switch (index) { + case (0): + return MihColors.getGoldColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + case (1): + return MihColors.getSilverColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + case (2): + return MihColors.getBronze( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + default: + return MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + } + } + @override Widget build(BuildContext context) { + final double width = MediaQuery.sizeOf(context).width; return Consumer2( builder: (BuildContext context, MzansiProfileProvider profileProvider, MihMineSweeperProvider mineSweeperProvider, Widget? child) { @@ -32,14 +50,15 @@ class _BuildMinesweeperLeaderboardListState }, itemCount: mineSweeperProvider.leaderboard!.length, itemBuilder: (context, index) { - return ListTile( - leading: Row( - mainAxisSize: MainAxisSize.min, + return Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: Row( children: [ Text( "#${index + 1}", style: TextStyle( fontSize: 25, + color: getMedalColor(index), ), ), const SizedBox(width: 10), @@ -49,36 +68,42 @@ class _BuildMinesweeperLeaderboardListState mineSweeperProvider.leaderboardUserPictures.isNotEmpty ? mineSweeperProvider.leaderboardUserPictures[index] : null, - width: 60, + width: 80, editable: false, fileNameController: null, userSelectedfile: null, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + frameColor: getMedalColor(index), backgroundColor: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onChange: () {}, ), + const SizedBox(width: 10), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "${mineSweeperProvider.leaderboard![index].username}${profileProvider.user!.username == mineSweeperProvider.leaderboard![index].username ? " (You)" : ""}", + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: getMedalColor(index), + ), + ), + Text( + "Score: ${mineSweeperProvider.leaderboard![index].game_score}\nTime: ${mineSweeperProvider.leaderboard![index].game_time}", + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 18, + // fontWeight: FontWeight.bold, + color: getMedalColor(index), + ), + ), + ], + ) ], ), - title: Text( - "${mineSweeperProvider.leaderboard![index].username}${profileProvider.user!.username == mineSweeperProvider.leaderboard![index].username ? " (You)" : ""}", - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - subtitle: Text( - "Score: ${mineSweeperProvider.leaderboard![index].game_score}\nTime: ${mineSweeperProvider.leaderboard![index].game_time}", - style: TextStyle( - fontSize: 18, - // fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), ); }, ); diff --git a/Frontend/lib/mih_packages/mine_sweeper/builders/build_my_scoreboard_list.dart b/Frontend/lib/mih_packages/mine_sweeper/builders/build_my_scoreboard_list.dart index 9b877c06..58dc3b23 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/builders/build_my_scoreboard_list.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/builders/build_my_scoreboard_list.dart @@ -15,8 +15,26 @@ class BuildMyScoreBoardList extends StatefulWidget { class _BuildMinesweeperLeaderboardListState extends State { + Color getMedalColor(int index) { + switch (index) { + case (0): + return MihColors.getGoldColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + case (1): + return MihColors.getSilverColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + case (2): + return MihColors.getBronze( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + default: + return MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"); + } + } + @override Widget build(BuildContext context) { + final double width = MediaQuery.sizeOf(context).width; return Consumer2( builder: (BuildContext context, MzansiProfileProvider profileProvider, MihMineSweeperProvider mineSweeperProvider, Widget? child) { @@ -31,36 +49,44 @@ class _BuildMinesweeperLeaderboardListState }, itemCount: mineSweeperProvider.myScoreboard!.length, itemBuilder: (context, index) { - return ListTile( - leading: Row( - mainAxisSize: MainAxisSize.min, + return Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: Row( children: [ Text( "#${index + 1}", style: TextStyle( fontSize: 25, + color: getMedalColor(index), ), ), + const SizedBox(width: 10), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Score: ${mineSweeperProvider.myScoreboard![index].game_score}", + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: getMedalColor(index), + ), + ), + Text( + "Time: ${mineSweeperProvider.myScoreboard![index].game_time}", + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 18, + // fontWeight: FontWeight.bold, + color: getMedalColor(index), + ), + ), + ], + ) ], ), - title: Text( - "Score: ${mineSweeperProvider.myScoreboard![index].game_score}", - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - subtitle: Text( - "Time: ${mineSweeperProvider.myScoreboard![index].game_time}", - style: TextStyle( - fontSize: 18, - // fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), ); }, ); diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart index c851e5e7..b7f62cab 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart @@ -29,20 +29,16 @@ class _MihMineSweeperLeaderBoardState extends State { MihMineSweeperProvider mineSweeperProvider = context.read(); filterController.text = mineSweeperProvider.difficulty; - if (mineSweeperProvider.leaderboard == null || - mineSweeperProvider.leaderboard!.isEmpty) { - KenLogger.success("getting data"); - await MihMinesweeperServices().getTop20Leaderboard(mineSweeperProvider); - List?> userPictures = []; - String userPicUrl = ""; - for (final ranking in mineSweeperProvider.leaderboard!) { - userPicUrl = - await MihFileApi.getMinioFileUrl(ranking.proPicUrl, context); - userPictures.add(NetworkImage(userPicUrl)); - } - mineSweeperProvider.setLeaderboardUserPictures( - leaderboardUserPictures: userPictures); + KenLogger.success("getting data"); + await MihMinesweeperServices().getTop20Leaderboard(mineSweeperProvider); + List?> userPictures = []; + String userPicUrl = ""; + for (final ranking in mineSweeperProvider.leaderboard!) { + userPicUrl = await MihFileApi.getMinioFileUrl(ranking.proPicUrl, context); + userPictures.add(NetworkImage(userPicUrl)); } + mineSweeperProvider.setLeaderboardUserPictures( + leaderboardUserPictures: userPictures); } void refreshLeaderBoard( diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart index 6933b0b1..c2d1a8ba 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart @@ -38,12 +38,12 @@ class _MineSweeperGameState extends State { Timer? _timer; int _milliseconds = 0; bool _isRunning = false; - static const int millisecondsPerUpdate = 10; + static const int millisecondsPerUpdate = 100; double timeStringToTotalSeconds(String timeString) { try { List parts = timeString.split(':'); - if (parts.length < 4) { + if (parts.length != 4) { return 0.0; } double hours = double.parse(parts[0]); @@ -51,7 +51,7 @@ class _MineSweeperGameState extends State { double seconds = double.parse(parts[2]); double milliseconds = double.parse(parts[3]); double totalSeconds = - (hours * 3600) + (minutes * 60) + seconds + (milliseconds / 1000); + (hours * 3600) + (minutes * 60) + seconds + (milliseconds / 100); return totalSeconds; } catch (e) { print("Error parsing time string: $e"); @@ -113,7 +113,7 @@ class _MineSweeperGameState extends State { String _formatTime() { Duration duration = Duration(milliseconds: _milliseconds); - final int hours = duration.inHours.remainder(60); + final int hours = duration.inHours; final int minutes = duration.inMinutes.remainder(60); final int seconds = duration.inSeconds.remainder(60); final int centiseconds = (duration.inMilliseconds.remainder(1000)) ~/ 10; @@ -735,7 +735,7 @@ class _MineSweeperGameState extends State { children: [ SpeedDialChild( child: Icon( - Icons.add, + Icons.rule_rounded, color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart index 4079f2f0..2bd762c7 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart @@ -18,9 +18,11 @@ class _MineSweeperQuickStartGuideState return Text( title, textAlign: TextAlign.center, - style: const TextStyle( + style: TextStyle( fontSize: 22, fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), ); } @@ -28,9 +30,11 @@ class _MineSweeperQuickStartGuideState Widget _buildSubSectionTitle(String title) { return Text( title, - style: const TextStyle( + style: TextStyle( fontSize: 17, fontWeight: FontWeight.w600, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), ); } @@ -41,7 +45,8 @@ class _MineSweeperQuickStartGuideState required Color color, }) { return Padding( - padding: const EdgeInsets.only(left: 8.0, top: 4.0, bottom: 4.0), + padding: + const EdgeInsets.only(left: 8.0, right: 8.0, top: 4.0, bottom: 4.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -58,7 +63,12 @@ class _MineSweeperQuickStartGuideState padding: const EdgeInsets.only(left: 10.0), child: Text( '• $point', - style: const TextStyle(fontSize: 16), + style: TextStyle( + fontSize: 16, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), ), )) .toList(), @@ -69,7 +79,7 @@ class _MineSweeperQuickStartGuideState Widget _buildNumberClue(String clue, String explanation) { return Padding( - padding: const EdgeInsets.only(left: 8.0, bottom: 4.0), + padding: const EdgeInsets.only(left: 8.0, right: 8.0, bottom: 4.0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -80,8 +90,8 @@ class _MineSweeperQuickStartGuideState text: TextSpan( style: TextStyle( fontSize: 16, - color: MihColors.getYellowColor( - MzansiInnovationHub.of(context)!.theme.mode != "Dark")), + color: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark")), children: [ TextSpan( text: 'If you see a $clue: ', @@ -99,7 +109,7 @@ class _MineSweeperQuickStartGuideState Widget _buildStrategyPoint(String title, String explanation, {bool isAction = false}) { return Padding( - padding: const EdgeInsets.only(left: 8.0, bottom: 4.0), + padding: const EdgeInsets.only(right: 8.0, left: 8.0, bottom: 4.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -107,7 +117,7 @@ class _MineSweeperQuickStartGuideState text: TextSpan( style: TextStyle( fontSize: 16, - color: MihColors.getSecondaryColor( + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark")), children: [ TextSpan( @@ -141,7 +151,7 @@ class _MineSweeperQuickStartGuideState Text('• ', style: TextStyle( fontSize: 18, - color: MihColors.getOrangeColor( + color: MihColors.getBronze( MzansiInnovationHub.of(context)!.theme.mode != "Dark"), fontWeight: FontWeight.bold)), Expanded( @@ -149,7 +159,7 @@ class _MineSweeperQuickStartGuideState text: TextSpan( style: TextStyle( fontSize: 16, - color: MihColors.getSecondaryColor( + color: MihColors.getBronze( MzansiInnovationHub.of(context)!.theme.mode == "Dark")), children: [ TextSpan( @@ -194,83 +204,144 @@ class _MineSweeperQuickStartGuideState 'Minesweeper is a puzzle game where you use numbers to figure out where the hidden bombs (mines) are located.', style: TextStyle(fontSize: 16), ), - const Divider(height: 30), - + // const Divider(height: 30), + const SizedBox(height: 15), // --- 1. Two Main Actions --- - _buildSectionTitle('1. Two Main Actions (Your Controls)'), - const SizedBox(height: 8), - _buildRulePoint( - title: 'Quick Tap (or Click): This is the Dig action.', - points: [ - 'Goal: To uncover a square and see a number clue.', - 'Risk: If you click a mine, the game ends!', - ], - color: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode != "Dark"), + Container( + decoration: BoxDecoration( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode != "Darl"), + borderRadius: BorderRadius.circular(15), + ), + child: Column( + children: [ + const SizedBox(height: 8), + _buildSectionTitle('1. Two Main Actions (Your Controls)'), + const SizedBox(height: 8), + _buildRulePoint( + title: 'Quick Tap (or Click): This is the Dig action.', + points: [ + 'Goal: To uncover a square and see a number clue.', + 'Risk: If you click a mine, the game ends!', + ], + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark"), + ), + _buildRulePoint( + title: + 'Tap and Hold (or Long Press): This is the Flag action (🚩).', + points: [ + 'Goal: To safely mark a square that you are **certain** is a mine.', + 'Benefit: You cannot accidentally click a square that is flagged.', + ], + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark"), + ), + const SizedBox(height: 4), + ], + ), ), - _buildRulePoint( - title: - 'Tap and Hold (or Long Press): This is the Flag action (🚩).', - points: [ - 'Goal: To safely mark a square that you are **certain** is a mine.', - 'Benefit: You cannot accidentally click a square that is flagged.', - ], - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode != "Dark"), - ), - const Divider(height: 30), - + const SizedBox(height: 15), // --- 2. The Golden Rule: Reading the Numbers --- - _buildSectionTitle('2. The Golden Rule: Reading the Numbers'), - const SizedBox(height: 8), - const Text( - 'The number tells you exactly how many mines are touching that square (including sides and corners).', - style: TextStyle(fontSize: 18, fontStyle: FontStyle.italic), + Container( + decoration: BoxDecoration( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode != "Darl"), + borderRadius: BorderRadius.circular(15), + ), + child: Column( + children: [ + const SizedBox(height: 8), + _buildSectionTitle('2. The Golden Rule: Reading the Numbers'), + const SizedBox(height: 8), + Text( + 'The number tells you exactly how many mines are touching that square (including sides and corners).', + style: TextStyle( + fontSize: 18, + fontStyle: FontStyle.italic, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Darl"), + ), + ), + const SizedBox(height: 8), + _buildNumberClue('Blank Space (a \'0\')', + 'Zero (0) mines are touching it. All surrounding squares are safe, and the game will open them for you automatically.'), + _buildNumberClue('\'1\'', + 'Only **one** mine is touching this square. You must find and flag that single mine.'), + _buildNumberClue('\'3\'', + 'Three mines are touching this square. You must find and flag all three.'), + const SizedBox(height: 4), + ], + ), ), - const SizedBox(height: 8), - _buildNumberClue('Blank Space (a \'0\')', - 'Zero (0) mines are touching it. All surrounding squares are safe, and the game will open them for you automatically.'), - _buildNumberClue('\'1\'', - 'Only **one** mine is touching this square. You must find and flag that single mine.'), - _buildNumberClue('\'3\'', - 'Three mines are touching this square. You must find and flag all three.'), - const Divider(height: 30), - + const SizedBox(height: 15), // --- 3. The Winning Strategy --- - _buildSectionTitle('3. The Winning Strategy (The Deduction Loop)'), - const SizedBox(height: 8), - const Text( - 'The game is won by uncovering every single safe square and correctly flagging all the mines. Use this two-step loop to clear the board:', - style: TextStyle(fontSize: 18), + Container( + decoration: BoxDecoration( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode != "Darl"), + borderRadius: BorderRadius.circular(15), + ), + child: Column( + children: [ + const SizedBox(height: 8), + _buildSectionTitle( + '3. The Winning Strategy (The Deduction Loop)'), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Text( + 'The game is won by uncovering every single safe square and correctly flagging all the mines. Use this two-step loop to clear the board:', + style: TextStyle( + fontSize: 18, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode != + "Darl"), + ), + ), + ), + const SizedBox(height: 8), + _buildSubSectionTitle('A. Find the Mines (Where to Flag 🚩)'), + _buildStrategyPoint( + 'Look for a number that only has one choice for a mine.', + 'Example: If a \'1\' is touching only one hidden square, that hidden square **must** be the mine.'), + _buildStrategyPoint('Action:', + 'Tap and Hold to place a **Flag** on the square you are sure is a mine.', + isAction: true), + const SizedBox(height: 12), + _buildSubSectionTitle( + 'B. Find the Safe Squares (Where to Dig)'), + _buildStrategyPoint( + 'Look for a number that has been \'satisfied\' by your flags.', + 'Example: You see a \'2\'. You have already placed two 🚩 flags touching it. The \'2\' is satisfied.'), + _buildStrategyPoint('Action:', + 'Quick Tap any of the remaining hidden squares touching that \'satisfied\' number. They **must be safe** because the mine requirement has already been met.', + isAction: true), + ], + ), ), - const SizedBox(height: 8), - - _buildSubSectionTitle('A. Find the Mines (Where to Flag 🚩)'), - _buildStrategyPoint( - 'Look for a number that only has one choice for a mine.', - 'Example: If a \'1\' is touching only one hidden square, that hidden square **must** be the mine.'), - _buildStrategyPoint('Action:', - 'Tap and Hold to place a **Flag** on the square you are sure is a mine.', - isAction: true), - - const SizedBox(height: 12), - - _buildSubSectionTitle('B. Find the Safe Squares (Where to Dig)'), - _buildStrategyPoint( - 'Look for a number that has been \'satisfied\' by your flags.', - 'Example: You see a \'2\'. You have already placed two 🚩 flags touching it. The \'2\' is satisfied.'), - _buildStrategyPoint('Action:', - 'Quick Tap any of the remaining hidden squares touching that \'satisfied\' number. They **must be safe** because the mine requirement has already been met.', - isAction: true), - - const Divider(height: 30), - + const SizedBox(height: 15), // --- Key Beginner Tip --- - _buildSectionTitle('✨ Key Beginner Tips'), - _buildTipPoint('Start on the Edges and Corners:', - 'Numbers on the edge or corner of the board are easier to solve because they have fewer surrounding squares to check.'), - _buildTipPoint('Don\'t Guess:', - 'If you are down to two squares and either one could be the mine, look somewhere else on the board for a guaranteed, safe move.'), + Container( + decoration: BoxDecoration( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode != "Darl"), + borderRadius: BorderRadius.circular(15), + ), + child: Column( + children: [ + const SizedBox(height: 8), + _buildSectionTitle('✨ Key Beginner Tips'), + const SizedBox(height: 8), + _buildTipPoint('Start on the Edges and Corners:', + 'Numbers on the edge or corner of the board are easier to solve because they have fewer surrounding squares to check.'), + _buildTipPoint('Don\'t Guess:', + 'If you are down to two squares and either one could be the mine, look somewhere else on the board for a guaranteed, safe move.'), + const SizedBox(height: 8), + ], + ), + ), ], ), ), diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart index df4b9d57..7d8316b1 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart @@ -31,13 +31,10 @@ class _MihMineSweeperLeaderBoardState extends State { MihMineSweeperProvider mineSweeperProvider = context.read(); filterController.text = mineSweeperProvider.difficulty; - if (mineSweeperProvider.myScoreboard == null || - mineSweeperProvider.myScoreboard!.isEmpty) { - KenLogger.success("getting data"); - await MihMinesweeperServices() - .getMyScoreboard(profileProvider, mineSweeperProvider); - KenLogger.success("${mineSweeperProvider.myScoreboard}"); - } + KenLogger.success("getting data"); + await MihMinesweeperServices() + .getMyScoreboard(profileProvider, mineSweeperProvider); + KenLogger.success("${mineSweeperProvider.myScoreboard}"); } void refreshLeaderBoard( From 771d809ce2e69072105466a7d4b2affaf6464e2f Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 31 Oct 2025 11:55:31 +0200 Subject: [PATCH 41/45] NEW: MIH MineSweeper Package pt4 --- .../package_tools/mine_sweeper_game.dart | 424 +++++++++--------- 1 file changed, 222 insertions(+), 202 deletions(-) diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart index c2d1a8ba..6a4b2ce6 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart @@ -274,7 +274,7 @@ class _MineSweeperGameState extends State { alertBody: Column( children: [ Text( - "Your lost this game of MIH MineSweeper!!!", + "Your lost this game of MIH Minesweeper!!!", textAlign: TextAlign.center, style: TextStyle( fontSize: 20, @@ -405,7 +405,7 @@ class _MineSweeperGameState extends State { alertBody: Column( children: [ Text( - "Your won this game of MIH MineSweeper!!!", + "Your won this game of MIH Minesweeper!!!", textAlign: TextAlign.center, style: TextStyle( fontSize: 20, @@ -565,226 +565,246 @@ class _MineSweeperGameState extends State { MihMineSweeperProvider mihMineSweeperProvider, MihBannerAdProvider adProvider, Widget? child) { - return Stack( - alignment: Alignment.topCenter, + return Column( children: [ - MihSingleChildScroll( - child: board.isEmpty && squaresLeft < 0 - // Start Up Message before setting up game - ? Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 50), - Icon( - MihIcons.mineSweeper, - size: 165, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - const SizedBox(height: 10), - Text( - "Welcom to Minesweeper, the first game of MIH.", - textAlign: TextAlign.center, - overflow: TextOverflow.visible, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - const SizedBox(height: 25), - Center( - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.normal, + Expanded( + child: Stack( + alignment: Alignment.topCenter, + children: [ + MihSingleChildScroll( + child: board.isEmpty && squaresLeft < 0 + // Start Up Message before setting up game + ? Padding( + padding: + const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.mineSweeper, + size: 165, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)! .theme .mode == "Dark"), ), - children: [ - TextSpan(text: "Press "), - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Icon( - Icons.menu, - size: 20, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), + const SizedBox(height: 10), + Text( + "Welcom to Minesweeper, the first game of MIH.", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + const SizedBox(height: 25), + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + children: [ + TextSpan(text: "Press "), + WidgetSpan( + alignment: + PlaceholderAlignment.middle, + child: Icon( + Icons.menu, + size: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + TextSpan( + text: + " to start a new game or learn how to play the minesweeper."), + ], + ), + ), + ), + ], + ), + ) + // Display Game Board when game started + : Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // Display game status + Row( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10.0), + child: Text( + 'Mines: ${mihMineSweeperProvider.totalMines}', + textAlign: TextAlign.left, + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10.0), + child: Text( + _formatTime().replaceAll("00:", ""), + textAlign: TextAlign.right, + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold), + ), ), ), - TextSpan( - text: - " to start a new game or learn how to play the minesweeper."), ], ), - ), - ), - ], - ), - ) - // Display Game Board when game started - : Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - // Display game status - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 10.0), - child: Text( - 'Mines: ${mihMineSweeperProvider.totalMines}', - textAlign: TextAlign.left, - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold), + Text( + mihMineSweeperProvider.difficulty, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: getDifficultyColor( + mihMineSweeperProvider), ), ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 10.0), - child: Text( - _formatTime().replaceAll("00:", ""), - textAlign: TextAlign.right, - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold), + + // const SizedBox( + // height: 30, + // ), + // The Board Grid + SizedBox( + width: mihMineSweeperProvider.columnCount * + 40.0, // Control size based on columns + height: mihMineSweeperProvider.rowCount * + 40.0, // Control size based on rows + child: GridView.builder( + physics: + const NeverScrollableScrollPhysics(), // Prevent scrolling + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: + mihMineSweeperProvider.columnCount, + crossAxisSpacing: 0, + mainAxisSpacing: 0, + ), + itemCount: mihMineSweeperProvider.rowCount * + mihMineSweeperProvider.columnCount, + itemBuilder: (context, index) { + int r = index ~/ + mihMineSweeperProvider + .columnCount; // Integer division for row + int c = index % + mihMineSweeperProvider + .columnCount; // Remainder for column + + return MineTile( + square: board[r][c], + onTap: () => handleTap( + profileProvider, + mihMineSweeperProvider, + adProvider, + r, + c), + onLongPress: () => handleLongPress(r, c), + ); + }, ), ), - ), - ], - ), - Text( - mihMineSweeperProvider.difficulty, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: getDifficultyColor(mihMineSweeperProvider), + SizedBox(height: 30), + // const SizedBox(height: 100), + ], ), - ), - - // const SizedBox( - // height: 30, - // ), - // The Board Grid - SizedBox( - width: mihMineSweeperProvider.columnCount * - 40.0, // Control size based on columns - height: mihMineSweeperProvider.rowCount * - 40.0, // Control size based on rows - child: GridView.builder( - physics: - const NeverScrollableScrollPhysics(), // Prevent scrolling - gridDelegate: - SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: - mihMineSweeperProvider.columnCount, - crossAxisSpacing: 0, - mainAxisSpacing: 0, + ), + Positioned( + right: 10, + bottom: 10, + child: MihFloatingMenu( + animatedIcon: AnimatedIcons.menu_close, + children: [ + SpeedDialChild( + child: Icon( + Icons.rule_rounded, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), ), - itemCount: mihMineSweeperProvider.rowCount * - mihMineSweeperProvider.columnCount, - itemBuilder: (context, index) { - int r = index ~/ - mihMineSweeperProvider - .columnCount; // Integer division for row - int c = index % - mihMineSweeperProvider - .columnCount; // Remainder for column - - return MineTile( - square: board[r][c], - onTap: () => handleTap(profileProvider, - mihMineSweeperProvider, adProvider, r, c), - onLongPress: () => handleLongPress(r, c), - ); + label: "Learn how to play", + labelBackgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onTap: () { + mihMineSweeperProvider.setToolIndex(2); }, ), - ), - SizedBox(height: 30), - MihBannerAd(), - // const SizedBox(height: 100), - ], - ), + SpeedDialChild( + child: Icon( + Icons.add, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + label: board.isEmpty && squaresLeft < 0 + ? "Start Game" + : "Reset Game", + labelBackgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onTap: () { + showStartGameWindow( + mihMineSweeperProvider, adProvider); + }, + ), + ]), + ) + ], + ), ), - Positioned( - right: 10, - bottom: 10, - child: MihFloatingMenu( - animatedIcon: AnimatedIcons.menu_close, - children: [ - SpeedDialChild( - child: Icon( - Icons.rule_rounded, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - label: "Learn how to play", - labelBackgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - labelStyle: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontWeight: FontWeight.bold, - ), - backgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onTap: () { - mihMineSweeperProvider.setToolIndex(2); - }, - ), - SpeedDialChild( - child: Icon( - Icons.add, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - label: board.isEmpty && squaresLeft < 0 - ? "Start Game" - : "Reset Game", - labelBackgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - labelStyle: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontWeight: FontWeight.bold, - ), - backgroundColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onTap: () { - showStartGameWindow(mihMineSweeperProvider, adProvider); - }, - ), - ]), - ) + MihBannerAd(), + SizedBox(height: 15), ], ); }, From cb25b932ba0f68aac5444eacde68603664e0446a Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 31 Oct 2025 11:55:49 +0200 Subject: [PATCH 42/45] NEW: Patient Manager Provider Setup pt4 --- .../patient_manager_provider.dart | 6 + .../package_tools/mih_business_home.dart | 3 - .../mih_business_user_search.dart | 2 +- .../build_mih_patient_search_list.dart | 303 ++++++++---------- .../package_tools/mih_patient_search.dart | 164 +++------- .../pat_manager/pat_manager.dart | 24 +- .../mih_access_controls_services.dart | 95 ++++++ .../mih_services/mih_patient_services.dart | 20 +- .../lib/mih_services/mih_service_calls.dart | 4 +- 9 files changed, 306 insertions(+), 315 deletions(-) diff --git a/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart b/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart index 160faaf8..03761c94 100644 --- a/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/patient_manager_provider.dart @@ -15,6 +15,7 @@ class PatientManagerProvider extends ChangeNotifier { List? consultationNotes; List? patientDocuments; List? patientClaimsDocuments; + List patientSearchResults = []; PatientManagerProvider({ this.patientProfileIndex = 0, @@ -75,4 +76,9 @@ class PatientManagerProvider extends ChangeNotifier { this.patientClaimsDocuments = patientClaimsDocuments ?? []; notifyListeners(); } + + void setPatientSearchResults({required List patientSearchResults}) { + this.patientSearchResults = patientSearchResults; + notifyListeners(); + } } diff --git a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart index b8c7746e..acfb992f 100644 --- a/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart +++ b/Frontend/lib/mih_packages/mih_home/package_tools/mih_business_home.dart @@ -1,5 +1,4 @@ import 'package:go_router/go_router.dart'; -import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; @@ -78,9 +77,7 @@ class _MihBusinessHomeState extends State // return []; // Return empty list if data isn't ready // } List> temp = []; - KenLogger.success("here"); if (mzansiProfileProvider.business == null && !widget.isLoading) { - KenLogger.success("here"); temp.add({ "Setup Business": MzansiSetupBusinessProfileTile( packageSize: packageSize, diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart index e15563b8..70d18e09 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart @@ -167,6 +167,7 @@ class _MihBusinessUserSearchState extends State { } Widget getBody(double width) { + // dscvds return MihSingleChildScroll( child: Column(mainAxisSize: MainAxisSize.max, children: [ Padding( @@ -187,7 +188,6 @@ class _MihBusinessUserSearchState extends State { searchController.clear(); userSearch = ""; }); - submitUserForm(); }, searchFocusNode: _searchFocusNode, ), diff --git a/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_mih_patient_search_list.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_mih_patient_search_list.dart index 68f98a06..bcbfb931 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_mih_patient_search_list.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/list_builders/build_mih_patient_search_list.dart @@ -1,38 +1,25 @@ -import 'dart:convert'; import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_access_controls_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_service_calls.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_success_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_warning_message.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; import 'package:flutter/material.dart'; -import 'package:supertokens_flutter/http.dart' as http; +import 'package:provider/provider.dart'; class BuildMihPatientSearchList extends StatefulWidget { - final List patients; - final AppUser signedInUser; - final Business? business; - final BusinessUser? businessUser; - final bool personalSelected; - const BuildMihPatientSearchList({ super.key, - required this.patients, - required this.signedInUser, - required this.business, - required this.businessUser, - required this.personalSelected, }); @override @@ -48,90 +35,6 @@ class _BuildPatientsListState extends State { TextEditingController accessStatusController = TextEditingController(); final baseAPI = AppEnviroment.baseApiUrl; - Future addPatientAccessAPICall(int index) async { - var response = await http.post( - Uri.parse("$baseAPI/access-requests/insert/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "business_id": widget.business!.business_id, - "app_id": widget.patients[index].app_id, - "date": dateController.text, - "time": timeController.text, - "access": "pending", - }), - ); - if (response.statusCode == 201) { - // Navigator.pushNamed(context, '/patient-manager/patient', - // arguments: widget.signedInUser); - String message = - "The appointment has been successfully booked!\n\nAn approval request as been sent to the patient.Once the access request has been approved, you will be able to access the patients profile. ou can check the status of your request in patient queue under the appointment."; - // "${fnameController.text} ${lnameController.text} patient profiole has been successfully added!\n"; - Navigator.pop(context); - Navigator.pop(context); - setState(() { - dateController.text = ""; - timeController.text = ""; - }); - Navigator.of(context).pushNamed( - '/patient-manager', - arguments: BusinessArguments( - widget.signedInUser, - widget.businessUser, - widget.business, - ), - ); - successPopUp(message); - addAccessReviewNotificationAPICall(index); - } else { - internetConnectionPopUp(); - } - } - - Future addAccessReviewNotificationAPICall(int index) async { - var response = await http.post( - Uri.parse("$baseAPI/notifications/insert/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "app_id": widget.patients[index].app_id, - "notification_type": "New Appointment Booked", - "notification_message": - "A new Appointment has been booked by ${widget.business!.Name} for the ${dateController.text} ${timeController.text}. Please approve the Access Review request.", - "action_path": "/mih-access", - }), - ); - if (response.statusCode == 201) { - // Navigator.pushNamed(context, '/patient-manager/patient', - // arguments: widget.signedInUser); - } else { - internetConnectionPopUp(); - } - } - - void internetConnectionPopUp() { - showDialog( - context: context, - builder: (context) { - return const MIHErrorMessage(errorType: "Internet Connection"); - }, - ); - } - - void successPopUp(String message) { - showDialog( - context: context, - builder: (context) { - return MIHSuccessMessage( - successType: "Success", - successMessage: message, - ); - }, - ); - } - void noAccessWarning() { showDialog( context: context, @@ -141,10 +44,12 @@ class _BuildPatientsListState extends State { ); } - Future hasAccessToProfile(int index) async { + Future hasAccessToProfile(MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, int index) async { var hasAccess = false; await MIHApiCalls.checkBusinessAccessToPatient( - widget.business!.business_id, widget.patients[index].app_id) + profileProvider.business!.business_id, + patientManagerProvider.patientSearchResults[index].app_id) .then((results) { if (results.isEmpty) { setState(() { @@ -163,10 +68,12 @@ class _BuildPatientsListState extends State { return hasAccess; } - Future getAccessStatusOfProfile(int index) async { + Future getAccessStatusOfProfile(MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, int index) async { var accessStatus = ""; await MIHApiCalls.checkBusinessAccessToPatient( - widget.business!.business_id, widget.patients[index].app_id) + profileProvider.business!.business_id, + patientManagerProvider.patientSearchResults[index].app_id) .then((results) { if (results.isEmpty) { setState(() { @@ -181,15 +88,22 @@ class _BuildPatientsListState extends State { return accessStatus; } - void patientProfileChoicePopUp(int index) async { + void patientProfileChoicePopUp( + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, + int index, + ) async { var hasAccess = false; String accessStatus = ""; - await hasAccessToProfile(index).then((result) { + await hasAccessToProfile(profileProvider, patientManagerProvider, index) + .then((result) { setState(() { hasAccess = result; }); }); - await getAccessStatusOfProfile(index).then((result) { + await getAccessStatusOfProfile( + profileProvider, patientManagerProvider, index) + .then((result) { setState(() { accessStatus = result; }); @@ -197,13 +111,22 @@ class _BuildPatientsListState extends State { if (accessStatus == "") { accessStatus = "No Access"; } - var idStars = '*' * (13 - 6); - String startedOutPatientIdNo = - "${widget.patients[index].id_no.substring(0, 6)}$idStars"; + String patientIdNo = + patientManagerProvider.patientSearchResults[index].id_no; + String displayedIdNo; + + if (patientIdNo.length >= 6) { + var idStars = '*' * (patientIdNo.length - 6); + displayedIdNo = "${patientIdNo.substring(0, 6)}$idStars"; + } else { + displayedIdNo = "${patientIdNo}******"; + } setState(() { - idController.text = startedOutPatientIdNo; - fnameController.text = widget.patients[index].first_name; - lnameController.text = widget.patients[index].last_name; + idController.text = displayedIdNo; + fnameController.text = + patientManagerProvider.patientSearchResults[index].first_name; + lnameController.text = + patientManagerProvider.patientSearchResults[index].last_name; accessStatusController.text = accessStatus.toUpperCase(); }); //print(accessStatus); @@ -362,17 +285,21 @@ class _BuildPatientsListState extends State { visible: hasAccess, child: Center( child: MihButton( - onPressed: () { + onPressed: () async { if (hasAccess) { + await MihPatientServices().getPatientDetails( + patientManagerProvider + .patientSearchResults[index].app_id, + patientManagerProvider); context.pop(); - context.pushNamed('patientManagerPatient', - extra: PatientViewArguments( - widget.signedInUser, - widget.patients[index], - widget.businessUser, - widget.business, - "business", - )); + context.pushNamed( + 'patientManagerPatient', + ); + // context.pushNamed( + // 'patientPatient', + // extra: patientManagerProvider + // .patientSearchResults![index].app_id, + // ); // Navigator.of(context) // .pushNamed('/patient-manager/patient', // arguments: PatientViewArguments( @@ -407,17 +334,19 @@ class _BuildPatientsListState extends State { visible: !hasAccess && accessStatus == "No Access", child: Center( child: MihButton( - onPressed: () { - MIHApiCalls.addPatientAccessAPICall( - widget.business!.business_id, - widget.patients[index].app_id, + onPressed: () async { + await MihAccessControlsServices + .addPatientAccessAPICall( + profileProvider.business!.business_id, + patientManagerProvider + .patientSearchResults[index].app_id, "patient", - widget.business!.Name, - widget.personalSelected, + profileProvider.business!.Name, + patientManagerProvider.personalMode, BusinessArguments( - widget.signedInUser, - widget.businessUser, - widget.business, + profileProvider.user!, + profileProvider.businessUser, + profileProvider.business, ), context, ); @@ -443,15 +372,16 @@ class _BuildPatientsListState extends State { visible: !hasAccess && accessStatus == "declined", child: Center( child: MihButton( - onPressed: () { - MIHApiCalls.reapplyPatientAccessAPICall( - widget.business!.business_id, - widget.patients[index].app_id, - widget.personalSelected, + onPressed: () async { + await MIHApiCalls.reapplyPatientAccessAPICall( + profileProvider.business!.business_id, + patientManagerProvider + .patientSearchResults[index].app_id, + patientManagerProvider.personalMode, BusinessArguments( - widget.signedInUser, - widget.businessUser, - widget.business, + profileProvider.user!, + profileProvider.businessUser, + profileProvider.business, ), context, ); @@ -491,20 +421,17 @@ class _BuildPatientsListState extends State { ); } - Widget isMainMember(int index) { - //var matchRE = RegExp(r'^[a-z]+$'); - // var firstLetterFName = widget.patients[index].first_name[0]; - // var firstLetterLName = widget.patients[index].last_name[0]; - // var fnameStar = '*' * 8; - // var lnameStar = '*' * 8; - - if (widget.patients[index].medical_aid_main_member == "Yes") { + Widget isMainMember( + PatientManagerProvider patientManagerProvider, int index) { + if (patientManagerProvider + .patientSearchResults[index].medical_aid_main_member == + "Yes") { return Row( mainAxisSize: MainAxisSize.max, children: [ Text( // "$firstLetterFName$fnameStar $firstLetterLName$lnameStar", - "${widget.patients[index].first_name} ${widget.patients[index].last_name}", + "${patientManagerProvider.patientSearchResults[index].first_name} ${patientManagerProvider.patientSearchResults[index].last_name}", style: TextStyle( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -523,7 +450,7 @@ class _BuildPatientsListState extends State { } else { return Text( // "$firstLetterFName$fnameStar $firstLetterLName$lnameStar", - "${widget.patients[index].first_name} ${widget.patients[index].last_name}", + "${patientManagerProvider.patientSearchResults[index].first_name} ${patientManagerProvider.patientSearchResults[index].last_name}", style: TextStyle( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), @@ -532,23 +459,37 @@ class _BuildPatientsListState extends State { } } - Widget hasMedicalAid(int index) { + Widget hasMedicalAid( + MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, + int index, + ) { + String patientIdNo = + patientManagerProvider.patientSearchResults[index].id_no; + String displayedIdNo; var medAidNoStar = '*' * 8; - var idStars = '*' * (13 - 6); - String startedOutPatientIdNo = - "${widget.patients[index].id_no.substring(0, 6)}$idStars"; - if (widget.patients[index].medical_aid == "Yes") { + if (patientIdNo.length >= 6) { + var idStars = '*' * (patientIdNo.length - 6); + displayedIdNo = "${patientIdNo.substring(0, 6)}$idStars"; + } else { + // If ID is shorter than 6 characters, just show it with stars + displayedIdNo = "${patientIdNo}******"; + } + + if (patientManagerProvider.patientSearchResults[index].medical_aid == + "Yes") { return ListTile( - title: isMainMember(index), + title: isMainMember(patientManagerProvider, index), subtitle: Text( - "ID No.: $startedOutPatientIdNo\nMedical Aid No.: $medAidNoStar", + "ID No.: $displayedIdNo\nMedical Aid No.: $medAidNoStar", style: TextStyle( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), ), onTap: () { - patientProfileChoicePopUp(index); + patientProfileChoicePopUp( + profileProvider, patientManagerProvider, index); // setState(() { // appointmentPopUp(index); // // Add popup to add patienmt to queue @@ -565,16 +506,17 @@ class _BuildPatientsListState extends State { ); } else { return ListTile( - title: isMainMember(index), + title: isMainMember(patientManagerProvider, index), subtitle: Text( - "ID No.: $startedOutPatientIdNo\nMedical Aid No.: $medAidNoStar", + "ID No.: $displayedIdNo\nMedical Aid No.: $medAidNoStar", style: TextStyle( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), ), onTap: () { - patientProfileChoicePopUp(index); + patientProfileChoicePopUp( + profileProvider, patientManagerProvider, index); // setState(() { // appointmentPopUp(index); // // Navigator.of(context).pushNamed('/patient-manager/patient', @@ -599,26 +541,35 @@ class _BuildPatientsListState extends State { fnameController.dispose(); lnameController.dispose(); accessStatusController.dispose(); + PatientManagerProvider patientManagerProvider = + context.read(); + patientManagerProvider.setPatientSearchResults(patientSearchResults: []); super.dispose(); } @override Widget build(BuildContext context) { - return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (BuildContext context, index) { - return Divider( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + PatientManagerProvider patientManagerProvider, Widget? child) { + return ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (BuildContext context, index) { + return Divider( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + itemCount: patientManagerProvider.patientSearchResults.length, + itemBuilder: (context, index) { + KenLogger.success( + "Search Results Count: ${patientManagerProvider.patientSearchResults.length}"); + return hasMedicalAid( + profileProvider, patientManagerProvider, index); + }, ); }, - itemCount: widget.patients.length, - itemBuilder: (context, index) { - //final patient = widget.patients[index].id_no.contains(widget.searchString); - //print(index); - return hasMedicalAid(index); - }, ); } } diff --git a/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/mih_patient_search.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/mih_patient_search.dart index 10d39928..a795732a 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/mih_patient_search.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/package_tools/mih_patient_search.dart @@ -1,32 +1,21 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; -import 'package:mzansi_innovation_hub/mih_services/mih_service_calls.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_patient_services.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/list_builders/build_mih_patient_search_list.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class MihPatientSearch extends StatefulWidget { - final AppUser signedInUser; - final Business? business; - final BusinessUser? businessUser; - final bool personalSelected; - const MihPatientSearch({ super.key, - required this.signedInUser, - required this.business, - required this.businessUser, - required this.personalSelected, }); @override @@ -40,71 +29,44 @@ class _MihPatientSearchState extends State { bool hasSearchedBefore = false; String _mihPatientSearchString = ""; String baseUrl = AppEnviroment.baseApiUrl; - late Future> _mihPatientSearchResults; Widget getPatientSearch(double width) { - return MihSingleChildScroll( - child: Column(mainAxisSize: MainAxisSize.max, children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: width / 20), - child: MihSearchBar( - controller: _mihPatientSearchController, - hintText: "Search Patient ID/ Aid No.", - prefixIcon: Icons.search, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - hintColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onPrefixIconTap: () { - submitPatientSearch(); - }, - onClearIconTap: () { - setState(() { - _mihPatientSearchController.clear(); - _mihPatientSearchString = ""; - }); - submitPatientSearch(); - //To-Do: Implement the search function - // print("To-Do: Implement the search function"); - }, - searchFocusNode: _searchFocusNode, - ), - ), - //spacer - const SizedBox(height: 10), - FutureBuilder( - future: _mihPatientSearchResults, - builder: (context, snapshot) { - //print("patient Liust ${snapshot.data}"); - if (snapshot.connectionState == ConnectionState.waiting) { - return const Mihloadingcircle(); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - List patientsList; - if (_mihPatientSearchString == "") { - patientsList = []; - } else { - patientsList = filterSearchResults( - snapshot.data!, _mihPatientSearchString); - //print(patientsList); - } - return displayPatientList(patientsList, _mihPatientSearchString); - } else { - return Center( - child: Text( - "Error pulling Patients Data\n$baseUrl/patients/search/$_mihPatientSearchString", - style: TextStyle( - fontSize: 25, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark")), - textAlign: TextAlign.center, - ), - ); - } - }, - ), - ]), + return Consumer( + builder: (BuildContext context, + PatientManagerProvider patientManagerProvider, Widget? child) { + return MihSingleChildScroll( + child: Column(mainAxisSize: MainAxisSize.max, children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: _mihPatientSearchController, + hintText: "Search Patient ID/ Aid No.", + prefixIcon: Icons.search, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + hintColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onPrefixIconTap: () { + submitPatientSearch(patientManagerProvider); + }, + onClearIconTap: () { + setState(() { + _mihPatientSearchController.clear(); + _mihPatientSearchString = ""; + }); + patientManagerProvider + .setPatientSearchResults(patientSearchResults: []); + }, + searchFocusNode: _searchFocusNode, + ), + ), + //spacer + const SizedBox(height: 10), + + displayPatientList(patientManagerProvider, _mihPatientSearchString), + ]), + ); + }, ); } @@ -121,16 +83,12 @@ class _MihPatientSearchState extends State { return templist; } - Widget displayPatientList(List patientsList, String searchString) { - if (patientsList.isNotEmpty) { - return BuildMihPatientSearchList( - patients: patientsList, - signedInUser: widget.signedInUser, - business: widget.business, - businessUser: widget.businessUser, - personalSelected: widget.personalSelected, - ); - } else if (patientsList.isEmpty && searchString != "") { + Widget displayPatientList( + PatientManagerProvider patientManagerProvider, String searchString) { + if (patientManagerProvider.patientSearchResults.isNotEmpty) { + return BuildMihPatientSearchList(); + } else if (patientManagerProvider.patientSearchResults.isEmpty && + searchString != "") { return Column( children: [ const SizedBox(height: 50), @@ -195,17 +153,6 @@ class _MihPatientSearchState extends State { TextSpan( text: "You can search using their ID Number or Medical Aid No."), - // WidgetSpan( - // alignment: PlaceholderAlignment.middle, - // child: Icon( - // Icons.menu, - // size: 20, - // color: MzansiInnovationHub.of(context)! - // .theme - // .secondaryColor(), - // ), - // ), - // TextSpan(text: " to add your first loyalty card"), ], ), ), @@ -213,30 +160,18 @@ class _MihPatientSearchState extends State { ], ), ); - // return Padding( - // padding: const EdgeInsets.only(top: 35.0), - // child: Center( - // child: Text( - // "Enter ID or Medical Aid No. of Patient", - // style: TextStyle( - // fontSize: 25, - // color: - // MihColors.getGreyColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark")), - // textAlign: TextAlign.center, - // ), - // ), - // ); } } - void submitPatientSearch() { + Future submitPatientSearch( + PatientManagerProvider patientManagerProvider) async { if (_mihPatientSearchController.text != "") { setState(() { _mihPatientSearchString = _mihPatientSearchController.text; - _mihPatientSearchResults = - MIHApiCalls.fetchPatients(_mihPatientSearchString); hasSearchedBefore = true; }); + await MihPatientServices.searchPatients( + patientManagerProvider, _mihPatientSearchString); } } @@ -257,7 +192,6 @@ class _MihPatientSearchState extends State { @override void initState() { super.initState(); - _mihPatientSearchResults = MIHApiCalls.fetchPatients("abc"); } @override diff --git a/Frontend/lib/mih_packages/patient_manager/pat_manager/pat_manager.dart b/Frontend/lib/mih_packages/patient_manager/pat_manager/pat_manager.dart index 2c0fe380..ff3add3b 100644 --- a/Frontend/lib/mih_packages/patient_manager/pat_manager/pat_manager.dart +++ b/Frontend/lib/mih_packages/patient_manager/pat_manager/pat_manager.dart @@ -5,6 +5,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_calendar_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/patient_manager_provider.dart'; +import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/package_tools/mih_patient_search.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/package_tools/my_patient_list.dart'; import 'package:mzansi_innovation_hub/mih_packages/patient_manager/pat_manager/package_tools/waiting_room.dart'; import 'package:flutter/material.dart'; @@ -42,7 +43,7 @@ class _PatManagerState extends State { mihCalendarProvider.selectedDay, mihCalendarProvider, ); - MihPatientServices().getPatientAccessListOfBusiness( + await MihPatientServices().getPatientAccessListOfBusiness( patientManagerProvider, profileProvider.business!.business_id); } setState(() { @@ -82,13 +83,9 @@ class _PatManagerState extends State { onTap: () { patientManagerProvider.setPatientProfileIndex(0); patientManagerProvider.setPatientManagerIndex(0); - if (!patientManagerProvider.personalMode) { - context.pop(); - } else { - context.goNamed( - 'mihHome', - ); - } + context.goNamed( + 'mihHome', + ); FocusScope.of(context).unfocus(); }, ); @@ -104,6 +101,9 @@ class _PatManagerState extends State { }; temp[const Icon(Icons.search)] = () { + context + .read() + .setPatientSearchResults(patientSearchResults: []); context.read().setPatientManagerIndex(2); }; return MihPackageTools( @@ -117,13 +117,7 @@ class _PatManagerState extends State { List toolBodies = [ WaitingRoom(), MyPatientList(), - Placeholder(), - // MihPatientSearch( - // signedInUser: widget.arguments.signedInUser, - // business: widget.arguments.business, - // personalSelected: widget.arguments.personalSelected, - // businessUser: widget.arguments.businessUser, - // ), + MihPatientSearch(), ]; return toolBodies; } diff --git a/Frontend/lib/mih_services/mih_access_controls_services.dart b/Frontend/lib/mih_services/mih_access_controls_services.dart index 65718929..322031f9 100644 --- a/Frontend/lib/mih_services/mih_access_controls_services.dart +++ b/Frontend/lib/mih_services/mih_access_controls_services.dart @@ -2,10 +2,13 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_access_controlls_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_notification_services.dart'; import 'package:supertokens_flutter/http.dart' as http; class MihAccessControlsServices { @@ -32,6 +35,98 @@ class MihAccessControlsServices { } } + /// This function is used to create patient access and trigger notification to patient + /// + /// Patameters:- + /// String business_id, + /// String app_id, + /// String type, + /// String requested_by, + /// BuildContext context, + /// + /// Returns void (triggers notification of success 201). + static Future addPatientAccessAPICall( + String business_id, + String app_id, + String type, + String requested_by, + bool personalSelected, + BusinessArguments args, + BuildContext context, + ) async { + var response = await http.post( + Uri.parse("${AppEnviroment.baseApiUrl}/access-requests/insert/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + // business_id: str + // app_id: str + // type: str + // requested_by: str + body: jsonEncode({ + "business_id": business_id, + "app_id": app_id, + "type": type, + "requested_by": requested_by, + }), + ); + if (response.statusCode == 201) { + await MihNotificationApis.addAccessRequestNotificationAPICall( + app_id, requested_by, personalSelected, args, context); + } else { + internetConnectionPopUp(context); + } + } + + /// This function is used to reapply for access to patient. + /// + /// Patameters:- + /// String business_id, + /// String app_id, + /// BuildContext context, + /// + /// Returns void (on success 200 navigate to /mih-access ). + static Future reapplyPatientAccessAPICall( + String business_id, + String app_id, + bool personalSelected, + BusinessArguments args, + BuildContext context, + ) async { + var response = await http.put( + Uri.parse("${AppEnviroment.baseApiUrl}/access-requests/re-apply/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + // business_id: str + // app_id: str + // status: str + // approved_by: str + body: jsonEncode({ + "business_id": business_id, + "app_id": app_id, + }), + ); + if (response.statusCode == 200) { + await MihNotificationApis.reapplyAccessRequestNotificationAPICall( + app_id, personalSelected, args, context); + //notification here + } else { + internetConnectionPopUp(context); + } + } + + static void internetConnectionPopUp(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage( + errorType: "Internet Connection", + ); + }, + ); + } + /// This function is used to UPDATE access the business has. /// /// Patameters:- diff --git a/Frontend/lib/mih_services/mih_patient_services.dart b/Frontend/lib/mih_services/mih_patient_services.dart index 8556a80f..a4b26c4d 100644 --- a/Frontend/lib/mih_services/mih_patient_services.dart +++ b/Frontend/lib/mih_services/mih_patient_services.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'package:file_picker/file_picker.dart'; -import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/files.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/notes.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.dart'; @@ -26,7 +25,6 @@ class MihPatientServices { ); if (response.statusCode == 200) { String body = response.body; - KenLogger.success(response.body); var jsonBody = jsonDecode(body); Patient patient = Patient.fromJson(jsonBody); patientManagerProvider.setSelectedPatient(selectedPatient: patient); @@ -36,6 +34,24 @@ class MihPatientServices { } } + static Future> searchPatients( + PatientManagerProvider patientManagerProvider, + String search, + ) async { + final response = await http + .get(Uri.parse("${AppEnviroment.baseApiUrl}/patients/search/$search")); + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List patients = + List.from(l.map((model) => Patient.fromJson(model))); + patientManagerProvider.setPatientSearchResults( + patientSearchResults: patients); + return patients; + } else { + throw Exception('failed to load patients'); + } + } + Future addPatientService( String id_no, String fname, diff --git a/Frontend/lib/mih_services/mih_service_calls.dart b/Frontend/lib/mih_services/mih_service_calls.dart index 4cda4a90..d0de0899 100644 --- a/Frontend/lib/mih_services/mih_service_calls.dart +++ b/Frontend/lib/mih_services/mih_service_calls.dart @@ -274,12 +274,10 @@ class MIHApiCalls { /// Patameters: String dsearch. /// /// Returns List. + static Future> fetchPatients(String search) async { final response = await http .get(Uri.parse("${AppEnviroment.baseApiUrl}/patients/search/$search")); - // errorCode = response.statusCode.toString(); - // errorBody = response.body; - if (response.statusCode == 200) { Iterable l = jsonDecode(response.body); List patients = From abd56d5a141425d890e21061794400e35e57c78c Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 31 Oct 2025 12:18:13 +0200 Subject: [PATCH 43/45] Clean up --- .../mzansi_directory_provider.dart | 6 +- .../mzansi_profile_provider.dart | 6 + .../mzansi_directory/mzansi_directory.dart | 4 +- .../package_tools/mih_search_mzansi.dart | 34 +++--- .../builders/build_user_list.dart | 26 ++-- .../mzansi_business_profile.dart | 3 + .../mih_business_user_search.dart | 111 +++++++----------- .../lib/mih_services/mih_user_services.dart | 2 + 8 files changed, 94 insertions(+), 98 deletions(-) diff --git a/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart b/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart index da94c4d8..59f148bc 100644 --- a/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mzansi_directory_provider.dart @@ -49,7 +49,11 @@ class MzansiDirectoryProvider extends ChangeNotifier { void setUserPosition(Position? position) { userPosition = position; - userLocation = "${position?.latitude}, ${position?.longitude}"; + if (position == null) { + userLocation = "Unknown Location"; + } else { + userLocation = "${position.latitude}, ${position.longitude}"; + } notifyListeners(); } diff --git a/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart b/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart index 0f4b9414..3570dc3c 100644 --- a/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart +++ b/Frontend/lib/mih_components/mih_providers/mzansi_profile_provider.dart @@ -20,6 +20,7 @@ class MzansiProfileProvider extends ChangeNotifier { ImageProvider? businessUserSignature; UserConsent? userConsent; List? employeeList; + List userSearchResults = []; MzansiProfileProvider({ this.personalHome = true, @@ -132,4 +133,9 @@ class MzansiProfileProvider extends ChangeNotifier { employeeList!.add(newEmployee); notifyListeners(); } + + void setUserearchResults({required List userSearchResults}) { + this.userSearchResults = userSearchResults; + notifyListeners(); + } } diff --git a/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart b/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart index f9710d97..baa1dda3 100644 --- a/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart +++ b/Frontend/lib/mih_packages/mzansi_directory/mzansi_directory.dart @@ -34,7 +34,9 @@ class _MzansiDirectoryState extends State { @override void initState() { super.initState(); - initialiseGPSLocation(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + initialiseGPSLocation(); + }); } @override diff --git a/Frontend/lib/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart b/Frontend/lib/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart index f3596d26..472a67db 100644 --- a/Frontend/lib/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart +++ b/Frontend/lib/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart @@ -11,6 +11,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_directory_provider.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/builders/build_business_search_resultsList.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/builders/build_user_search_results_list.dart'; @@ -40,7 +41,8 @@ class _MihSearchMzansiState extends State { bool filterOn = false; bool loadingSearchResults = false; - Future swapPressed(MzansiDirectoryProvider directoryProvider) async { + Future swapPressed(MzansiProfileProvider profileProvider, + MzansiDirectoryProvider directoryProvider) async { directoryProvider.setPersonalSearch(!directoryProvider.personalSearch); setState(() { if (filterOn) { @@ -52,7 +54,7 @@ class _MihSearchMzansiState extends State { businessTypeController.clear(); }); } - await searchPressed(directoryProvider); + await searchPressed(profileProvider, directoryProvider); } void clearAll(MzansiDirectoryProvider directoryProvider) { @@ -65,7 +67,8 @@ class _MihSearchMzansiState extends State { }); } - Future searchPressed(MzansiDirectoryProvider directoryProvider) async { + Future searchPressed(MzansiProfileProvider profileProvider, + MzansiDirectoryProvider directoryProvider) async { setState(() { loadingSearchResults = true; }); @@ -75,7 +78,7 @@ class _MihSearchMzansiState extends State { if (directoryProvider.personalSearch && directoryProvider.searchTerm.isNotEmpty) { final userResults = await MihUserServices() - .searchUsers(directoryProvider.searchTerm, context); + .searchUsers(profileProvider, directoryProvider.searchTerm, context); directoryProvider.setSearchedUsers(searchedUsers: userResults); } else { List? businessSearchResults = []; @@ -108,11 +111,11 @@ class _MihSearchMzansiState extends State { super.initState(); MzansiDirectoryProvider directoryProvider = context.read(); - directoryProvider.setSearchedUsers(searchedUsers: []); - setState(() { - availableBusinessTypes = - MihBusinessDetailsServices().fetchAllBusinessTypes(); - mzansiSearchController.text = ""; + availableBusinessTypes = + MihBusinessDetailsServices().fetchAllBusinessTypes(); + mzansiSearchController.text = ""; + WidgetsBinding.instance.addPostFrameCallback((_) async { + directoryProvider.setSearchedUsers(searchedUsers: []); }); } @@ -127,9 +130,9 @@ class _MihSearchMzansiState extends State { } Widget getBody(double width) { - return Consumer( - builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, - Widget? child) { + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + MzansiDirectoryProvider directoryProvider, Widget? child) { return MihSingleChildScroll( child: Column( children: [ @@ -149,7 +152,7 @@ class _MihSearchMzansiState extends State { suffixTools: [ IconButton( onPressed: () { - swapPressed(directoryProvider); + swapPressed(profileProvider, directoryProvider); }, icon: Icon( Icons.swap_horiz_rounded, @@ -167,7 +170,7 @@ class _MihSearchMzansiState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), onPrefixIconTap: () { - searchPressed(directoryProvider); + searchPressed(profileProvider, directoryProvider); }, onClearIconTap: () { clearAll(directoryProvider); @@ -234,7 +237,8 @@ class _MihSearchMzansiState extends State { MihButton( onPressed: () { if (businessTypeController.text.isNotEmpty) { - searchPressed(directoryProvider); + searchPressed( + profileProvider, directoryProvider); } else { MihAlertServices().errorAlert( "Business Type Not Selected", diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart index 2bfa71d1..cb3476fa 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart @@ -3,16 +3,12 @@ import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profil import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_add_employee_window.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class BuildUserList extends StatefulWidget { - final List users; - const BuildUserList({ super.key, - required this.users, }); @override @@ -28,12 +24,13 @@ class _BuildUserListState extends State { return "$firstLetter********@$end"; } - void addEmployeePopUp(int index, double width) { + void addEmployeePopUp( + MzansiProfileProvider profileProvider, int index, double width) { showDialog( context: context, barrierDismissible: false, builder: (context) => MihAddEmployeeWindow( - user: widget.users[index], + user: profileProvider.userSearchResults[index], ), ); } @@ -42,8 +39,8 @@ class _BuildUserListState extends State { Widget build(BuildContext context) { double screenWidth = MediaQuery.of(context).size.width; return Consumer( - builder: (BuildContext context, - MzansiProfileProvider mzansiProfileProvider, Widget? child) { + builder: (BuildContext context, MzansiProfileProvider profileProvider, + Widget? child) { return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), @@ -53,24 +50,25 @@ class _BuildUserListState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ); }, - itemCount: widget.users.length, + itemCount: profileProvider.userSearchResults.length, itemBuilder: (context, index) { var isYou = ""; - if (mzansiProfileProvider.user!.app_id == - widget.users[index].app_id) { + if (profileProvider.user!.app_id == + profileProvider.userSearchResults[index].app_id) { isYou = "(You)"; } return ListTile( - title: Text("@${widget.users[index].username} $isYou"), + title: Text( + "@${profileProvider.userSearchResults[index].username} $isYou"), subtitle: Text( - "Email: ${hideEmail(widget.users[index].email)}", + "Email: ${hideEmail(profileProvider.userSearchResults[index].email)}", style: TextStyle( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), ), onTap: () { - addEmployeePopUp(index, screenWidth); + addEmployeePopUp(profileProvider, index, screenWidth); }, ); }, diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart index 97f91792..69dd98ea 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart @@ -62,6 +62,9 @@ class _MzansiBusinessProfileState extends State { context.read().setBusinessIndex(2); }; temp[const Icon(Icons.add)] = () { + context + .read() + .setUserearchResults(userSearchResults: []); context.read().setBusinessIndex(3); }; temp[const Icon(Icons.star_rate_rounded)] = () { diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart index 70d18e09..c2bc32fb 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart @@ -3,12 +3,13 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/builders/build_user_list.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; +import 'package:provider/provider.dart'; class MihBusinessUserSearch extends StatefulWidget { const MihBusinessUserSearch({ @@ -28,25 +29,24 @@ class _MihBusinessUserSearchState extends State { String errorCode = ""; String errorBody = ""; - Future> fetchUsers(String search) async { - return MihUserServices().searchUsers(search, context); + Future> fetchUsers( + MzansiProfileProvider profileProvider, String search) async { + return MihUserServices().searchUsers(profileProvider, search, context); } - void submitUserForm() { + void submitUserForm(MzansiProfileProvider profileProvider) { if (searchController.text != "") { setState(() { userSearch = searchController.text; hasSearchedBefore = true; - userSearchResults = fetchUsers(userSearch); + userSearchResults = fetchUsers(profileProvider, userSearch); }); } } - Widget displayUserList(List userList) { - if (userList.isNotEmpty) { - return BuildUserList( - users: userList, - ); + Widget displayUserList(MzansiProfileProvider profileProvider) { + if (profileProvider.userSearchResults.isNotEmpty) { + return BuildUserList(); } if (hasSearchedBefore && userSearch.isNotEmpty) { return Column( @@ -145,7 +145,6 @@ class _MihBusinessUserSearchState extends State { @override void initState() { super.initState(); - userSearchResults = fetchUsers("abc"); } @override @@ -168,63 +167,41 @@ class _MihBusinessUserSearchState extends State { Widget getBody(double width) { // dscvds - return MihSingleChildScroll( - child: Column(mainAxisSize: MainAxisSize.max, children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: width / 20), - child: MihSearchBar( - controller: searchController, - hintText: "Search Users", - prefixIcon: Icons.search, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - hintColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - onPrefixIconTap: () { - submitUserForm(); - }, - onClearIconTap: () { - setState(() { - searchController.clear(); - userSearch = ""; - }); - }, - searchFocusNode: _searchFocusNode, - ), - ), - const SizedBox(height: 10), - FutureBuilder( - future: userSearchResults, - builder: (context, snapshot) { - //print("patient Liust ${snapshot.data}"); - if (snapshot.connectionState == ConnectionState.waiting) { - return const Mihloadingcircle(); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - List patientsList; - if (userSearch == "") { - patientsList = []; - } else { - patientsList = snapshot.data!; - //print(patientsList); - } - return displayUserList(patientsList); - } else { - return Center( - child: Text( - "$errorCode: Error pulling Patients Data\n/users/search/$userSearch\n$errorBody", - style: TextStyle( - fontSize: 25, - color: MihColors.getRedColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark")), - textAlign: TextAlign.center, + return Consumer( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + Widget? child) { + return MihSingleChildScroll( + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: width / 20), + child: MihSearchBar( + controller: searchController, + hintText: "Search Users", + prefixIcon: Icons.search, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + hintColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + onPrefixIconTap: () { + submitUserForm(profileProvider); + }, + onClearIconTap: () { + setState(() { + searchController.clear(); + userSearch = ""; + }); + }, + searchFocusNode: _searchFocusNode, ), - ); - } - }, - ), - ]), + ), + const SizedBox(height: 10), + displayUserList(profileProvider), + ], + ), + ); + }, ); } } diff --git a/Frontend/lib/mih_services/mih_user_services.dart b/Frontend/lib/mih_services/mih_user_services.dart index 3467f7f0..0d8dadbb 100644 --- a/Frontend/lib/mih_services/mih_user_services.dart +++ b/Frontend/lib/mih_services/mih_user_services.dart @@ -78,6 +78,7 @@ class MihUserServices { } Future> searchUsers( + MzansiProfileProvider profileProvider, String searchText, BuildContext context, ) async { @@ -91,6 +92,7 @@ class MihUserServices { Iterable l = jsonDecode(response.body); List users = List.from(l.map((model) => AppUser.fromJson(model))); + profileProvider.setUserearchResults(userSearchResults: users); return users; } else { throw Exception('failed to load users'); From 8e6f3d7d45f605d2dadcfd542073e45099d12445 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 31 Oct 2025 12:52:58 +0200 Subject: [PATCH 44/45] Android Config Changes --- Frontend/android/app/build.gradle.kts | 5 +++++ Frontend/android/app/proguard-rules.pro | 5 +++++ Frontend/pubspec.lock | 8 ++++++++ Frontend/pubspec.yaml | 1 + 4 files changed, 19 insertions(+) create mode 100644 Frontend/android/app/proguard-rules.pro diff --git a/Frontend/android/app/build.gradle.kts b/Frontend/android/app/build.gradle.kts index ad4ac4c6..c96f5437 100644 --- a/Frontend/android/app/build.gradle.kts +++ b/Frontend/android/app/build.gradle.kts @@ -55,6 +55,11 @@ android { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. signingConfig = signingConfigs.getByName("release") + isMinifyEnabled = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) } } } diff --git a/Frontend/android/app/proguard-rules.pro b/Frontend/android/app/proguard-rules.pro new file mode 100644 index 00000000..d216aea2 --- /dev/null +++ b/Frontend/android/app/proguard-rules.pro @@ -0,0 +1,5 @@ +# R8/ProGuard rules to prevent removal of necessary Facebook Infer annotations +-keep class com.facebook.infer.annotation.** { *; } +-keep interface com.facebook.infer.annotation.** { *; } +-dontwarn com.facebook.infer.annotation.Nullsafe$Mode +-dontwarn com.facebook.infer.annotation.Nullsafe \ No newline at end of file diff --git a/Frontend/pubspec.lock b/Frontend/pubspec.lock index 83c03080..697e5b35 100644 --- a/Frontend/pubspec.lock +++ b/Frontend/pubspec.lock @@ -297,6 +297,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" custom_rating_bar: dependency: "direct main" description: diff --git a/Frontend/pubspec.yaml b/Frontend/pubspec.yaml index 0c1b30b9..16c88d91 100644 --- a/Frontend/pubspec.yaml +++ b/Frontend/pubspec.yaml @@ -13,6 +13,7 @@ dependencies: flutter_web_plugins: sdk: flutter + cupertino_icons: ^1.0.8 font_awesome_flutter: ^10.7.0 syncfusion_flutter_core: ^29.2.10 syncfusion_flutter_pdfviewer: ^29.2.10 From ffe9f6e9fb2d7f0a25a329eeceb883170da60a2e Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Fri, 31 Oct 2025 12:53:37 +0200 Subject: [PATCH 45/45] NEW: Version Update --- Frontend/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/pubspec.yaml b/Frontend/pubspec.yaml index 16c88d91..9969b895 100644 --- a/Frontend/pubspec.yaml +++ b/Frontend/pubspec.yaml @@ -1,7 +1,7 @@ name: mzansi_innovation_hub description: "" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.2.1+98 +version: 1.2.2+99 # version: 1.1.1+97 #--- Updated version for upgrader package testing environment: